ksrvresolverworker.cpp
00001 /* -*- C++ -*- 00002 * Copyright (C) 2005 Thiago Macieira <thiago@kde.org> 00003 * 00004 * This library is free software; you can redistribute it and/or 00005 * modify it under the terms of the GNU Library General Public 00006 * License as published by the Free Software Foundation; either 00007 * version 2 of the License, or (at your option) any later version. 00008 * 00009 * This library is distributed in the hope that it will be useful, 00010 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00012 * Library General Public License for more details. 00013 * 00014 * You should have received a copy of the GNU Library General Public License 00015 * along with this library; see the file COPYING.LIB. If not, write to 00016 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 00017 * Boston, MA 02110-1301, USA. 00018 */ 00019 00020 #include <config.h> 00021 00022 #include "ksrvresolverworker_p.h" 00023 00024 #include <sys/types.h> 00025 #include <sys/socket.h> 00026 #include <stdlib.h> 00027 00028 #include <qapplication.h> 00029 #include <qevent.h> 00030 00031 using namespace KNetwork; 00032 using namespace KNetwork::Internal; 00033 00034 namespace 00035 { 00036 struct KSrvStartEvent: public QCustomEvent 00037 { 00038 inline KSrvStartEvent() : QCustomEvent(QEvent::User) { } 00039 }; 00040 } 00041 00042 static void sortPriorityClass(KSrvResolverWorker::PriorityClass&) 00043 { 00044 // do nothing 00045 } 00046 00047 bool KSrvResolverWorker::preprocess() 00048 { 00049 // check if the resolver flags mention SRV-based lookup 00050 if ((flags() & (KResolver::NoSrv | KResolver::UseSrv)) != KResolver::UseSrv) 00051 return false; 00052 00053 QString node = nodeName(); 00054 if (node.find('%') != -1) 00055 node.truncate(node.find('%')); 00056 00057 if (node.isEmpty() || node == QString::fromLatin1("*") || 00058 node == QString::fromLatin1("localhost")) 00059 return false; // empty == localhost 00060 00061 encodedName = KResolver::domainToAscii(node); 00062 if (encodedName.isNull()) 00063 return false; 00064 00065 // we only work with Internet-based families 00066 if ((familyMask() & KResolver::InternetFamily) == 0) 00067 return false; 00068 00069 // SRV-based resolution only works if the service isn't numeric 00070 bool ok; 00071 serviceName().toUInt(&ok); 00072 if (ok) 00073 return false; // it is numeric 00074 00075 // check the protocol for something we know 00076 QCString protoname; 00077 int sockettype = socketType(); 00078 if (!protocolName().isEmpty()) 00079 protoname = protocolName(); 00080 else if (protocol() != 0) 00081 { 00082 QStrList names = KResolver::protocolName(protocol()); 00083 names.setAutoDelete(true); 00084 if (names.isEmpty()) 00085 return false; 00086 00087 protoname = "_"; 00088 protoname += names.at(0); 00089 } 00090 else if (sockettype == SOCK_STREAM || sockettype == 0) 00091 protoname = "_tcp"; 00092 else if (sockettype == SOCK_DGRAM) 00093 protoname = "_udp"; 00094 else 00095 return false; // unknown protocol and socket type 00096 00097 encodedName.prepend("."); 00098 encodedName.prepend(protoname); 00099 encodedName.prepend("."); 00100 encodedName.prepend(serviceName().latin1()); 00101 encodedName.prepend("_"); 00102 00103 // looks like something we could process 00104 return true; 00105 } 00106 00107 bool KSrvResolverWorker::run() 00108 { 00109 sem = new QSemaphore(1); 00110 // zero out 00111 sem->tryAccess(sem->available()); 00112 00113 QApplication::postEvent(this, new KSrvStartEvent); 00114 00115 // block 00116 (*sem)++; 00117 delete sem; 00118 sem = 0L; 00119 00120 if (rawResults.isEmpty()) 00121 { 00122 // normal lookup 00123 KResolver *r = new KResolver(nodeName(), serviceName()); 00124 r->setFlags(flags() | KResolver::NoSrv); 00125 r->setFamily(familyMask()); 00126 r->setSocketType(socketType()); 00127 r->setProtocol(protocol(), protocolName()); 00128 00129 enqueue(r); 00130 00131 Entry e; 00132 PriorityClass cl; 00133 e.resolver = r; 00134 cl.entries.append(e); 00135 myResults[0] = cl; 00136 00137 return true; 00138 } 00139 else if (rawResults.count() == 1 && rawResults.first().name == ".") 00140 { 00141 // no name 00142 setError(KResolver::NoName); 00143 finished(); 00144 return true; 00145 } 00146 else 00147 { 00148 // now process the results 00149 QValueList<QDns::Server>::ConstIterator it = rawResults.begin(); 00150 while (it != rawResults.end()) 00151 { 00152 const QDns::Server& srv = *it; 00153 PriorityClass& r = myResults[srv.priority]; 00154 r.totalWeight += srv.weight; 00155 00156 Entry e; 00157 e.name = srv.name; 00158 e.port = srv.port; 00159 e.weight = srv.weight; 00160 e.resolver = 0L; 00161 r.entries.append(e); 00162 00163 ++it; 00164 } 00165 rawResults.clear(); // free memory 00166 00167 Results::Iterator mapit; 00168 for (mapit = myResults.begin(); mapit != myResults.end(); ++mapit) 00169 { 00170 // sort the priority 00171 sortPriorityClass(*mapit); 00172 00173 QValueList<Entry>& entries = (*mapit).entries; 00174 00175 // start the resolvers 00176 for (QValueList<Entry>::Iterator it = entries.begin(); 00177 it != entries.end(); ++it) 00178 { 00179 Entry &e = *it; 00180 00181 KResolver* r = new KResolver(e.name, QString::number(e.port)); 00182 r->setFlags(flags() | KResolver::NoSrv); 00183 r->setFamily(familyMask()); 00184 r->setSocketType(socketType()); 00185 r->setProtocol(protocol(), protocolName()); 00186 00187 enqueue(r); 00188 e.resolver = r; 00189 } 00190 } 00191 00192 return true; 00193 } 00194 } 00195 00196 bool KSrvResolverWorker::postprocess() 00197 { 00198 setError(KResolver::NoName); 00199 if (myResults.isEmpty()) 00200 return false; 00201 00202 Results::Iterator mapit, mapend; 00203 for (mapit = myResults.begin(), mapend = myResults.end(); 00204 mapit != mapend; ++mapit) 00205 { 00206 QValueList<Entry>::Iterator it = (*mapit).entries.begin(), 00207 end = (*mapit).entries.end(); 00208 for ( ; it != end; ++it) 00209 { 00210 Entry &e = *it; 00211 KResolverResults r = e.resolver->results(); 00212 if (r.isEmpty() && results.isEmpty()) 00213 setError(r.error(), r.systemError()); 00214 else 00215 { 00216 setError(KResolver::NoError); 00217 results += r; 00218 } 00219 } 00220 } 00221 00222 finished(); 00223 return true; 00224 } 00225 00226 void KSrvResolverWorker::customEvent(QCustomEvent*) 00227 { 00228 dns = new QDns(QString::fromLatin1(encodedName), QDns::Srv); 00229 QObject::connect(dns, SIGNAL(resultsReady()), this, SLOT(dnsResultsReady())); 00230 } 00231 00232 void KSrvResolverWorker::dnsResultsReady() 00233 { 00234 (*sem)--; 00235 rawResults = dns->servers(); 00236 dns->deleteLater(); 00237 dns = 0L; 00238 } 00239 00240 namespace KNetwork 00241 { 00242 namespace Internal 00243 { 00244 00245 void initSrvWorker() KDE_NO_EXPORT; 00246 void initSrvWorker() 00247 { 00248 if (getenv("KDE_NO_SRV") != NULL) 00249 return; 00250 00251 KResolverWorkerFactoryBase::registerNewWorker(new KResolverWorkerFactory<KSrvResolverWorker>); 00252 } 00253 00254 } 00255 } 00256 00257 #include "ksrvresolverworker_p.moc"