KDECore
k3resolverstandardworkers.cpp
Go to the documentation of this file.
00001 /* -*- C++ -*- 00002 * Copyright (C) 2003,2004 Thiago Macieira <thiago@kde.org> 00003 * 00004 * 00005 * Permission is hereby granted, free of charge, to any person obtaining 00006 * a copy of this software and associated documentation files (the 00007 * "Software"), to deal in the Software without restriction, including 00008 * without limitation the rights to use, copy, modify, merge, publish, 00009 * distribute, sublicense, and/or sell copies of the Software, and to 00010 * permit persons to whom the Software is furnished to do so, subject to 00011 * the following conditions: 00012 * 00013 * The above copyright notice and this permission notice shall be included 00014 * in all copies or substantial portions of the Software. 00015 * 00016 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 00017 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 00018 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 00019 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 00020 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 00021 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 00022 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 00023 */ 00024 00025 #include "k3resolverstandardworkers_p.h" 00026 00027 #include <config.h> 00028 #include <config-network.h> 00029 00030 #include <sys/types.h> 00031 #include <sys/socket.h> 00032 #include <sys/un.h> 00033 #include <netinet/in.h> 00034 #include <netdb.h> 00035 #include <errno.h> 00036 #include <string.h> 00037 #include <stdlib.h> 00038 #include <unistd.h> 00039 00040 #ifdef HAVE_NET_IF_H 00041 #include <net/if.h> 00042 #endif 00043 00044 #include <QFile> 00045 #include <QList> 00046 #include <QMutex> 00047 #include <QTextStream> 00048 #include <QThread> 00049 #ifdef Q_WS_WIN 00050 #include <winsock2.h> 00051 #endif 00052 00053 #include "kdebug.h" 00054 #include "kglobal.h" 00055 #include "kstandarddirs.h" 00056 00057 #include "k3resolver.h" 00058 #include "k3socketaddress.h" 00059 00060 struct hostent; 00061 struct addrinfo; 00062 00063 using namespace KNetwork; 00064 using namespace KNetwork::Internal; 00065 00066 static bool hasIPv6() 00067 { 00068 #ifdef Q_WS_WIN 00069 extern void KNetwork_initSocket(); 00070 KNetwork_initSocket(); 00071 #endif 00072 #ifdef AF_INET6 00073 if (!qgetenv("KDE_NO_IPV6").isEmpty()) 00074 return false; 00075 00076 # ifdef Q_WS_WIN 00077 SOCKET s = ::socket(AF_INET6, SOCK_STREAM, 0); 00078 if (s == INVALID_SOCKET) 00079 return false; 00080 ::closesocket(s); 00081 # else 00082 int fd = ::socket(AF_INET6, SOCK_STREAM, 0); 00083 if (fd == -1) 00084 return false; 00085 ::close(fd); 00086 # endif 00087 return true; 00088 #else 00089 return false; 00090 #endif 00091 } 00092 00093 // blacklist management 00094 static QMutex blacklistMutex; // KDE4: change to a QReadWriteLock 00095 QStringList KBlacklistWorker::blacklist; 00096 00097 void KBlacklistWorker::init() 00098 { 00099 if (!KGlobal::hasMainComponent()) 00100 return; 00101 00102 static bool beenhere = false; 00103 00104 if (beenhere) 00105 return; 00106 00107 beenhere = true; 00108 loadBlacklist(); 00109 } 00110 00111 void KBlacklistWorker::loadBlacklist() 00112 { 00113 QMutexLocker locker(&blacklistMutex); 00114 QStringList filelist = KGlobal::dirs()->findAllResources("config", QLatin1String("ipv6blacklist")); 00115 00116 QStringList::ConstIterator it = filelist.constBegin(), 00117 end = filelist.constEnd(); 00118 for ( ; it != end; ++it) 00119 { 00120 // for each file, each line is a domainname to be blacklisted 00121 QFile f(*it); 00122 if (!f.open(QIODevice::ReadOnly)) 00123 continue; 00124 00125 QTextStream stream(&f); 00126 stream.setCodec("latin1"); 00127 for (QString line = stream.readLine(); !line.isNull(); 00128 line = stream.readLine()) 00129 { 00130 if (line.isEmpty()) 00131 continue; 00132 00133 // make sure there are no surrounding whitespaces 00134 // and that it starts with . 00135 line = line.trimmed(); 00136 if (line[0] != QLatin1Char('.')) 00137 line.prepend(QLatin1Char('.')); 00138 00139 blacklist.append(line.toLower()); 00140 } 00141 } 00142 } 00143 00144 // checks the blacklist to see if the domain is listed 00145 // it matches the domain ending part 00146 bool KBlacklistWorker::isBlacklisted(const QString& host) 00147 { 00148 KBlacklistWorker::init(); 00149 00150 // empty hostnames cannot be blacklisted 00151 if (host.isEmpty()) 00152 return false; 00153 00154 QString ascii = QLatin1String(KResolver::domainToAscii(host)); 00155 00156 QMutexLocker locker(&blacklistMutex); 00157 00158 // now find out if this hostname is present 00159 QStringList::ConstIterator it = blacklist.constBegin(), 00160 end = blacklist.constEnd(); 00161 for ( ; it != end; ++it) 00162 if (ascii.endsWith(*it)) 00163 return true; 00164 00165 // no match: 00166 return false; 00167 } 00168 00169 bool KBlacklistWorker::preprocess() 00170 { 00171 if (isBlacklisted(nodeName())) 00172 { 00173 results.setError(KResolver::NoName); 00174 finished(); 00175 return true; 00176 } 00177 return false; 00178 } 00179 00180 bool KBlacklistWorker::run() 00181 { 00182 results.setError(KResolver::NoName); 00183 finished(); 00184 return false; // resolution failure 00185 } 00186 00187 namespace 00188 { 00189 /* 00190 * Note on the use of the system resolver functions: 00191 * 00192 * In all cases, we prefer to use the new getaddrinfo(3) call. That means 00193 * it will always be used if it is found. 00194 * 00195 * If it's not found, we have the option to use gethostbyname2_r, 00196 * gethostbyname_r, gethostbyname2 and gethostbyname. If gethostbyname2_r 00197 * is defined, we will use it. 00198 * 00199 * If it's not defined, we have to choose between the non-reentrant 00200 * gethostbyname2 and the reentrant but IPv4-only gethostbyname_r: 00201 * we will choose gethostbyname2 if AF_INET6 is defined. 00202 * 00203 * Lastly, gethostbyname will be used if nothing else is present. 00204 */ 00205 00206 #ifndef HAVE_GETADDRINFO 00207 00208 # if defined(HAVE_GETHOSTBYNAME2_R) 00209 # define USE_GETHOSTBYNAME2_R 00210 # elif defined(HAVE_GETHOSTBYNAME_R) && (!defined(AF_INET6) || !defined(HAVE_GETHOSTBYNAME2)) 00211 # define USE_GETHOSTBYNAME_R 00212 # elif defined(HAVE_GETHOSTBYNAME2) 00213 # define USE_GETHOSTBYNAME2) 00214 # else 00215 # define USE_GETHOSTBYNAME 00216 # endif 00217 00218 class GetHostByNameThread: public KResolverWorkerBase 00219 { 00220 public: 00221 QByteArray m_hostname; // might be different! 00222 quint16 m_port; 00223 int m_scopeid; 00224 int m_af; 00225 KResolverResults& results; 00226 00227 GetHostByNameThread(const char * hostname, quint16 port, 00228 int scopeid, int af, KResolverResults* res) : 00229 m_hostname(hostname), m_port(port), m_scopeid(scopeid), m_af(af), 00230 results(*res) 00231 { } 00232 00233 ~GetHostByNameThread() 00234 { } 00235 00236 virtual bool preprocess() 00237 { return true; } 00238 00239 virtual bool run(); 00240 00241 void processResults(hostent* he, int my_h_errno); 00242 }; 00243 00244 bool GetHostByNameThread::run() 00245 { 00246 00247 hostent *resultptr; 00248 hostent my_results; 00249 unsigned buflen = 1024; 00250 int res; 00251 int my_h_errno; 00252 char *buf = 0L; 00253 00254 // qDebug("ResolveThread::run(): started threaded gethostbyname for %s (af = %d)", 00255 // m_hostname.data(), m_af); 00256 00257 ResolverLocker resLock( this ); 00258 do 00259 { 00260 res = 0; 00261 my_h_errno = HOST_NOT_FOUND; 00262 00263 // check blacklist 00264 if (m_af != AF_INET && 00265 KBlacklistWorker::isBlacklisted(QLatin1String(m_hostname))) 00266 break; 00267 00268 # ifdef USE_GETHOSTBYNAME2_R 00269 buf = new char[buflen]; 00270 res = gethostbyname2_r(m_hostname, m_af, &my_results, buf, buflen, 00271 &resultptr, &my_h_errno); 00272 00273 # elif defined(USE_GETHOSTBYNAME_R) 00274 if (m_af == AF_INET) 00275 { 00276 buf = new char[buflen]; 00277 res = gethostbyname_r(m_hostname, &my_results, buf, buflen, 00278 &resultptr, &my_h_errno); 00279 } 00280 else 00281 resultptr = 0; // signal error 00282 00283 # elif defined(USE_GETHOSTBYNAME2) 00284 // must lock mutex 00285 resultptr = gethostbyname2(m_hostname, m_af); 00286 my_h_errno = h_errno; 00287 00288 # else 00289 if (m_af == AF_INET) 00290 { 00291 // must lock mutex 00292 resultptr = gethostbyname(m_hostname); 00293 my_h_errno = h_errno; 00294 } 00295 else 00296 resultptr = 0; 00297 # endif 00298 00299 if (resultptr != 0L) 00300 my_h_errno = 0; 00301 // qDebug("GetHostByNameThread::run(): gethostbyname for %s (af = %d) returned: %d", 00302 // m_hostname.data(), m_af, my_h_errno); 00303 00304 if (res == ERANGE) 00305 { 00306 // Enlarge the buffer 00307 buflen += 1024; 00308 delete [] buf; 00309 buf = new char[buflen]; 00310 } 00311 00312 if ((res == ERANGE || my_h_errno != 0) && checkResolver()) 00313 { 00314 // resolver needs updating, so we might as well do it now 00315 resLock.openClose(); 00316 } 00317 } 00318 while (res == ERANGE); 00319 processResults(resultptr, my_h_errno); 00320 00321 delete [] buf; 00322 00323 finished(); 00324 return results.error() == KResolver::NoError; 00325 } 00326 00327 void GetHostByNameThread::processResults(hostent *he, int herrno) 00328 { 00329 if (herrno) 00330 { 00331 qDebug("KStandardWorker::processResults: got error %d", herrno); 00332 switch (herrno) 00333 { 00334 case HOST_NOT_FOUND: 00335 results.setError(KResolver::NoName); 00336 return; 00337 00338 case TRY_AGAIN: 00339 results.setError(KResolver::TryAgain); 00340 return; 00341 00342 case NO_RECOVERY: 00343 results.setError(KResolver::NonRecoverable); 00344 return; 00345 00346 case NO_ADDRESS: 00347 results.setError(KResolver::NoName); 00348 return; 00349 00350 default: 00351 results.setError(KResolver::UnknownError); 00352 return; 00353 } 00354 } 00355 else if (he == 0L) 00356 { 00357 results.setError(KResolver::NoName); 00358 return; // this was an error 00359 } 00360 00361 // clear any errors 00362 setError(KResolver::NoError); 00363 results.setError(KResolver::NoError); 00364 00365 // we process results in the reverse order 00366 // that is, we prepend each result to the list of results 00367 int proto = protocol(); 00368 int socktype = socketType(); 00369 if (socktype == 0) 00370 socktype = SOCK_STREAM; // default 00371 00372 QString canon = KResolver::domainToUnicode(QLatin1String(he->h_name)); 00373 KInetSocketAddress sa; 00374 sa.setPort(m_port); 00375 if (he->h_addrtype != AF_INET) 00376 sa.setScopeId(m_scopeid); // this will also change the socket into IPv6 00377 00378 for (int i = 0; he->h_addr_list[i]; i++) 00379 { 00380 sa.setHost(KIpAddress(he->h_addr_list[i], he->h_addrtype == AF_INET ? 4 : 6)); 00381 results.prepend(KResolverEntry(sa, socktype, proto, canon, m_hostname)); 00382 // qDebug("KStandardWorker::processResults: adding %s", sa.toString().toLatin1().constData()); 00383 } 00384 // qDebug("KStandardWorker::processResults: added %d entries", i); 00385 } 00386 00387 #else // HAVE_GETADDRINFO 00388 00389 class GetAddrInfoThread: public KResolverWorkerBase 00390 { 00391 public: 00392 QByteArray m_node; 00393 QByteArray m_serv; 00394 int m_af; 00395 int m_flags; 00396 KResolverResults& results; 00397 00398 GetAddrInfoThread(const char* node, const char* serv, int af, int flags, 00399 KResolverResults* res) : 00400 m_node(node), m_serv(serv), m_af(af), m_flags(flags), results(*res) 00401 { } 00402 00403 ~GetAddrInfoThread() 00404 { } 00405 00406 virtual bool preprocess() 00407 { return true; } 00408 00409 virtual bool run(); 00410 00411 void processResults(addrinfo* ai, int ret_code, KResolverResults& rr); 00412 }; 00413 00414 bool GetAddrInfoThread::run() 00415 { 00416 // check blacklist 00417 if ((m_af != AF_INET && m_af != AF_UNSPEC) && 00418 KBlacklistWorker::isBlacklisted(QLatin1String(m_node))) 00419 { 00420 results.setError(KResolver::NoName); 00421 finished(); 00422 return false; // failed 00423 } 00424 00425 do 00426 { 00427 ResolverLocker resLock( this ); 00428 00429 // process hints 00430 addrinfo hint; 00431 memset(&hint, 0, sizeof(hint)); 00432 hint.ai_family = m_af; 00433 hint.ai_socktype = socketType(); 00434 hint.ai_protocol = protocol(); 00435 00436 if (hint.ai_socktype == 0) 00437 hint.ai_socktype = SOCK_STREAM; // default 00438 00439 if (m_flags & KResolver::Passive) 00440 hint.ai_flags |= AI_PASSIVE; 00441 if (m_flags & KResolver::CanonName) 00442 hint.ai_flags |= AI_CANONNAME; 00443 # ifdef AI_NUMERICHOST 00444 if (m_flags & KResolver::NoResolve) 00445 hint.ai_flags |= AI_NUMERICHOST; 00446 # endif 00447 # ifdef AI_ADDRCONFIG 00448 hint.ai_flags |= AI_ADDRCONFIG; 00449 # endif 00450 00451 // now we do the blocking processing 00452 if (m_node.isEmpty()) 00453 m_node = "*"; // krazy:exclude=doublequote_chars 00454 00455 addrinfo *result; 00456 int res = getaddrinfo(m_node, m_serv, &hint, &result); 00457 // kDebug(179) << "getaddrinfo(\"" 00458 // << m_node << "\", \"" << m_serv << "\", af=" 00459 // << m_af << ") returned " << res << endl; 00460 00461 if (res != 0) 00462 { 00463 if (checkResolver()) 00464 { 00465 // resolver requires reinitialisation 00466 resLock.openClose(); 00467 continue; 00468 } 00469 00470 switch (res) 00471 { 00472 case EAI_BADFLAGS: 00473 results.setError(KResolver::BadFlags); 00474 break; 00475 00476 #ifdef EAI_NODATA 00477 // In some systems, EAI_NODATA was #define'd to EAI_NONAME which would break this case. 00478 #if EAI_NODATA != EAI_NONAME 00479 case EAI_NODATA: // it was removed in RFC 3493 00480 #endif 00481 #endif 00482 case EAI_NONAME: 00483 results.setError(KResolver::NoName); 00484 break; 00485 00486 case EAI_AGAIN: 00487 results.setError(KResolver::TryAgain); 00488 break; 00489 00490 case EAI_FAIL: 00491 results.setError(KResolver::NonRecoverable); 00492 break; 00493 00494 case EAI_FAMILY: 00495 results.setError(KResolver::UnsupportedFamily); 00496 break; 00497 00498 case EAI_SOCKTYPE: 00499 results.setError(KResolver::UnsupportedSocketType); 00500 break; 00501 00502 case EAI_SERVICE: 00503 results.setError(KResolver::UnsupportedService); 00504 break; 00505 00506 case EAI_MEMORY: 00507 results.setError(KResolver::Memory); 00508 break; 00509 00510 #ifdef EAI_SYSTEM // not available on windows 00511 case EAI_SYSTEM: 00512 results.setError(KResolver::SystemError, errno); 00513 break; 00514 #endif 00515 default: 00516 results.setError(KResolver::UnknownError, errno); 00517 break; 00518 } 00519 00520 finished(); 00521 return false; // failed 00522 } 00523 00524 // if we are here, lookup succeeded 00525 QString canon; 00526 const char *previous_canon = 0L; 00527 00528 for (addrinfo* p = result; p; p = p->ai_next) 00529 { 00530 // cache the last canon name to avoid doing the ToUnicode processing unnecessarily 00531 if ((previous_canon && !p->ai_canonname) || 00532 (!previous_canon && p->ai_canonname) || 00533 (p->ai_canonname != previous_canon && 00534 strcmp(p->ai_canonname, previous_canon) != 0)) 00535 { 00536 canon = KResolver::domainToUnicode(QString::fromAscii(p->ai_canonname)); 00537 previous_canon = p->ai_canonname; 00538 } 00539 00540 results.append(KResolverEntry(p->ai_addr, p->ai_addrlen, p->ai_socktype, 00541 p->ai_protocol, canon, m_node)); 00542 } 00543 00544 freeaddrinfo(result); 00545 results.setError(KResolver::NoError); 00546 finished(); 00547 return results.error() == KResolver::NoError; 00548 } 00549 while (true); 00550 } 00551 00552 #endif // HAVE_GETADDRINFO 00553 } // namespace 00554 00555 KStandardWorker::~KStandardWorker() 00556 { 00557 qDeleteAll(resultList); 00558 } 00559 00560 bool KStandardWorker::sanityCheck() 00561 { 00562 // check that the requested values are sensible 00563 00564 if (!nodeName().isEmpty()) 00565 { 00566 QString node = nodeName(); 00567 if (node.indexOf(QLatin1Char('%')) != -1) 00568 node.truncate(node.indexOf(QLatin1Char('%'))); 00569 00570 if (node.isEmpty() || node == QLatin1String("*") || 00571 node == QLatin1String("localhost")) 00572 m_encodedName.truncate(0); 00573 else 00574 { 00575 m_encodedName = KResolver::domainToAscii(node); 00576 00577 if (m_encodedName.isNull()) 00578 { 00579 qDebug("could not encode hostname '%s' (UTF-8)", node.toUtf8().data()); 00580 setError(KResolver::NoName); 00581 return false; // invalid hostname! 00582 } 00583 00584 // qDebug("Using encoded hostname '%s' for '%s' (UTF-8)", m_encodedName.data(), 00585 // node.toUtf8().data()); 00586 } 00587 } 00588 else 00589 m_encodedName.truncate(0); // just to be sure, but it should be clear already 00590 00591 if (protocol() == -1) 00592 { 00593 setError(KResolver::NonRecoverable); 00594 return false; // user passed invalid protocol name 00595 } 00596 00597 return true; // it's sane 00598 } 00599 00600 bool KStandardWorker::resolveScopeId() 00601 { 00602 // we must test the original name, not the encoded one 00603 scopeid = 0; 00604 int pos = nodeName().lastIndexOf(QLatin1Char('%')); 00605 if (pos == -1) 00606 return true; 00607 00608 QString scopename = nodeName().mid(pos + 1); 00609 00610 bool ok; 00611 scopeid = scopename.toInt(&ok); 00612 if (!ok) 00613 { 00614 // it's not a number 00615 // therefore, it's an interface name 00616 #ifdef HAVE_IF_NAMETOINDEX 00617 scopeid = if_nametoindex(scopename.toLatin1()); 00618 #else 00619 scopeid = 0; 00620 #endif 00621 } 00622 00623 return true; 00624 } 00625 00626 bool KStandardWorker::resolveService() 00627 { 00628 // find the service first 00629 bool ok; 00630 port = serviceName().toUInt(&ok); 00631 if (!ok) 00632 { 00633 // service name does not contain a port number 00634 // must be a name 00635 00636 if (serviceName().isEmpty() || serviceName().compare(QLatin1String("*")) == 0) 00637 port = 0; 00638 else 00639 { 00640 // it's a name. We need the protocol name in order to lookup. 00641 QByteArray protoname = protocolName(); 00642 00643 if (protoname.isEmpty() && protocol()) 00644 { 00645 protoname = KResolver::protocolName(protocol()).first(); 00646 00647 // if it's still empty... 00648 if (protoname.isEmpty()) 00649 { 00650 // lookup failed! 00651 setError(KResolver::NoName); 00652 return false; 00653 } 00654 } 00655 else 00656 protoname = "tcp"; 00657 00658 // it's not, so we can do a port lookup 00659 int result = KResolver::servicePort(serviceName().toLatin1(), protoname); 00660 if (result == -1) 00661 { 00662 // lookup failed! 00663 setError(KResolver::NoName); 00664 return false; 00665 } 00666 00667 // it worked, we have a port number 00668 port = (quint16)result; 00669 } 00670 } 00671 00672 // we found a port 00673 return true; 00674 } 00675 00676 KResolver::ErrorCodes KStandardWorker::addUnix() 00677 { 00678 // before trying to add, see if the user wants Unix sockets 00679 if ((familyMask() & KResolver::UnixFamily) == 0) 00680 // no, Unix sockets are not wanted 00681 return KResolver::UnsupportedFamily; 00682 00683 // now check if the requested data are good for a Unix socket 00684 if (!m_encodedName.isEmpty()) 00685 return KResolver::AddrFamily; // non local hostname 00686 00687 if (protocol() || !protocolName().isNull()) 00688 return KResolver::BadFlags; // cannot have Unix sockets with protocols 00689 00690 QString pathname = serviceName(); 00691 if (pathname.isEmpty()) 00692 return KResolver::NoName;; // no path? 00693 00694 if (pathname[0] != QLatin1Char('/')) 00695 // non absolute pathname 00696 // put it in /tmp 00697 pathname.prepend(QLatin1String("/tmp/")); 00698 00699 // qDebug("QNoResolveWorker::addUnix(): adding Unix socket for %s", pathname.toLocal8Bit().data()); 00700 KUnixSocketAddress sa(pathname); 00701 int socktype = socketType(); 00702 if (socktype == 0) 00703 socktype = SOCK_STREAM; // default 00704 00705 results.append(KResolverEntry(sa, socktype, 0)); 00706 setError(KResolver::NoError); 00707 00708 return KResolver::NoError; 00709 } 00710 00711 bool KStandardWorker::resolveNumerically() 00712 { 00713 // if the NoResolve flag is active, our result from this point forward 00714 // will always be true, even if the resolution failed. 00715 // that indicates that our result is authoritative. 00716 00717 bool wantV4 = familyMask() & KResolver::IPv4Family, 00718 wantV6 = familyMask() & KResolver::IPv6Family; 00719 00720 if (!wantV6 && !wantV4) 00721 // no Internet address is wanted! 00722 return (flags() & KResolver::NoResolve); 00723 00724 // now try to find results 00725 if (!resolveScopeId() || !resolveService()) 00726 return (flags() & KResolver::NoResolve); 00727 00728 // we have scope IDs and port numbers 00729 // now try to resolve the hostname numerically 00730 KInetSocketAddress sa; 00731 setError(KResolver::NoError); 00732 sa.setHost(KIpAddress(QLatin1String(m_encodedName))); 00733 00734 // if it failed, the length was reset to 0 00735 bool ok = sa.length() != 0; 00736 00737 sa.setPort(port); 00738 if (sa.ipVersion() == 6) 00739 sa.setScopeId(scopeid); 00740 int proto = protocol(); 00741 int socktype = socketType(); 00742 if (socktype == 0) 00743 socktype = SOCK_STREAM; 00744 00745 if (ok) 00746 { 00747 // the given hostname was successfully converted to an IP address 00748 // check if the user wanted this kind of address 00749 00750 if ((sa.ipVersion() == 4 && wantV4) || 00751 (sa.ipVersion() == 6 && wantV6)) 00752 results.append(KResolverEntry(sa, socktype, proto)); 00753 else 00754 { 00755 // Note: the address *IS* a numeric IP 00756 // but it's not of the kind the user asked for 00757 // 00758 // that means that it cannot be a Unix socket (because it's an IP) 00759 // and that means that no resolution will tell us otherwise 00760 // 00761 // This is a failed resolution 00762 00763 setError(KResolver::AddrFamily); 00764 return true; 00765 } 00766 } 00767 else if (m_encodedName.isEmpty()) 00768 { 00769 // user wanted localhost 00770 if (flags() & KResolver::Passive) 00771 { 00772 if (wantV6) 00773 { 00774 sa.setHost(KIpAddress::anyhostV6); 00775 results.append(KResolverEntry(sa, socktype, proto)); 00776 } 00777 00778 if (wantV4) 00779 { 00780 sa.setHost(KIpAddress::anyhostV4); 00781 results.append(KResolverEntry(sa, socktype, proto)); 00782 } 00783 } 00784 else 00785 { 00786 if (wantV6) 00787 { 00788 sa.setHost(KIpAddress::localhostV6); 00789 results.append(KResolverEntry(sa, socktype, proto)); 00790 } 00791 00792 if (wantV4) 00793 { 00794 sa.setHost(KIpAddress::localhostV4); 00795 results.append(KResolverEntry(sa, socktype, proto)); 00796 } 00797 } 00798 00799 ok = true; 00800 } 00801 else 00802 { 00803 // probably bad flags, since the address is not convertible without 00804 // resolution 00805 00806 setError(KResolver::BadFlags); 00807 ok = false; 00808 } 00809 00810 return ok || (flags() & KResolver::NoResolve); 00811 } 00812 00813 bool KStandardWorker::preprocess() 00814 { 00815 // check sanity 00816 if (!sanityCheck()) 00817 return false; 00818 00819 // this worker class can only handle known families 00820 if (familyMask() & KResolver::UnknownFamily) 00821 { 00822 setError(KResolver::UnsupportedFamily); 00823 return false; // we don't know about this 00824 } 00825 00826 // check the socket types 00827 if (socketType() != SOCK_STREAM && socketType() != SOCK_DGRAM && socketType() != 0) 00828 { 00829 setError(KResolver::UnsupportedSocketType); 00830 return false; 00831 } 00832 00833 // check if we can resolve all numerically 00834 // resolveNumerically always returns true if the NoResolve flag is set 00835 if (resolveNumerically() || m_encodedName.isEmpty()) 00836 { 00837 // indeed, we have resolved numerically 00838 setError(addUnix()); 00839 if (results.count()) 00840 setError(KResolver::NoError); 00841 finished(); 00842 return true; 00843 } 00844 00845 // check if the user wants something we know about 00846 #ifdef AF_INET6 00847 # define mask (KResolver::IPv6Family | KResolver::IPv4Family | KResolver::UnixFamily) 00848 #else 00849 # define mask (KResolver::IPv4Family | KResolver::UnixFamily) 00850 #endif 00851 00852 if ((familyMask() & mask) == 0) 00853 // errr... nothing we know about 00854 return false; 00855 00856 #undef mask 00857 00858 return true; // it's ok 00859 } 00860 00861 bool KStandardWorker::run() 00862 { 00863 #ifndef HAVE_GETADDRINFO 00864 // check the scope id first 00865 // since most of the resolutions won't have a scope id, this should be fast 00866 // and we won't have wasted time on services if this fails 00867 if (!resolveScopeId()) 00868 return false; 00869 00870 // resolve the service now, before entering the blocking operation 00871 if (!resolveService()) 00872 return false; 00873 #endif 00874 00875 // good 00876 // now we need the hostname 00877 setError(KResolver::NoName); 00878 00879 // these are the family types that we know of 00880 struct 00881 { 00882 KResolver::SocketFamilies mask; 00883 int af; 00884 } families[] = { { KResolver::IPv4Family, AF_INET } 00885 #ifdef AF_INET6 00886 , { KResolver::IPv6Family, AF_INET6 } 00887 #endif 00888 }; 00889 int familyCount = sizeof(families)/sizeof(families[0]); 00890 bool skipIPv6 = !hasIPv6(); 00891 00892 for (int i = 0; i < familyCount; i++) 00893 if (familyMask() & families[i].mask) 00894 { 00895 #ifdef AF_INET6 00896 if (skipIPv6 && families[i].af == AF_INET6) 00897 continue; 00898 #endif 00899 00900 KResolverWorkerBase *worker; 00901 KResolverResults *res = new KResolverResults; 00902 resultList.append(res); 00903 #ifdef HAVE_GETADDRINFO 00904 worker = new GetAddrInfoThread(m_encodedName, 00905 serviceName().toLatin1(), 00906 families[i].af, flags(), res); 00907 #else 00908 worker = new GetHostByNameThread(m_encodedName, port, scopeid, 00909 families[i].af, res); 00910 #endif 00911 00912 enqueue(worker); 00913 } 00914 00915 // not finished 00916 return true; 00917 } 00918 00919 bool KStandardWorker::postprocess() 00920 { 00921 if (results.count()) 00922 return true; // no need 00923 // now copy over what we need from the underlying results 00924 00925 // start backwards because IPv6 was launched later (if at all) 00926 if (resultList.isEmpty()) 00927 { 00928 results.setError(KResolver::NoName); 00929 return true; 00930 } 00931 00932 for (int i = resultList.size(); i > 0; --i) 00933 { 00934 KResolverResults* rr = resultList.at(i - 1); 00935 if (!rr->isEmpty()) 00936 { 00937 results.setError(KResolver::NoError); 00938 KResolverResults::Iterator it = rr->begin(); 00939 for ( ; it != rr->end(); ++it) 00940 results.append(*it); 00941 } 00942 else if (results.isEmpty()) 00943 // this generated an error 00944 // copy the error code over 00945 setError(rr->error(), rr->systemError()); 00946 00947 delete rr; 00948 resultList[i - 1] = 0L; 00949 } 00950 00951 resultList.clear(); 00952 return true; 00953 } 00954 00955 #ifdef HAVE_GETADDRINFO 00956 KGetAddrinfoWorker::~KGetAddrinfoWorker() 00957 { 00958 } 00959 00960 bool KGetAddrinfoWorker::preprocess() 00961 { 00962 // getaddrinfo(3) can always handle any kind of request that makes sense 00963 if (!sanityCheck()) 00964 return false; 00965 00966 if (flags() & KResolver::NoResolve) 00967 // oops, numeric resolution? 00968 return run(); 00969 00970 return true; 00971 } 00972 00973 bool KGetAddrinfoWorker::run() 00974 { 00975 // make an AF_UNSPEC getaddrinfo(3) call 00976 GetAddrInfoThread worker(m_encodedName, serviceName().toLatin1(), 00977 AF_UNSPEC, flags(), &results); 00978 00979 if (!worker.run()) 00980 { 00981 if (wantThis(AF_UNIX)) 00982 { 00983 if (addUnix() == KResolver::NoError) 00984 setError(KResolver::NoError); 00985 } 00986 else 00987 setError(worker.results.error(), worker.results.systemError()); 00988 00989 return false; 00990 } 00991 00992 // The worker has finished working 00993 // now copy over only what we may want 00994 // keep track of any Unix-domain sockets 00995 00996 bool seen_unix = false; 00997 int i = 0; 00998 while ( i < results.count() ) 00999 { 01000 const KResolverEntry& res = results[i]; 01001 if (res.family() == AF_UNIX) 01002 seen_unix = true; 01003 if (!wantThis(res.family())) 01004 results.removeAt(i); 01005 else 01006 ++i; 01007 } 01008 01009 if (!seen_unix) 01010 addUnix(); 01011 01012 finished(); 01013 return true; 01014 } 01015 01016 bool KGetAddrinfoWorker::wantThis(int family) 01017 { 01018 // tells us if the user wants a socket of this family 01019 01020 #ifdef AF_INET6 01021 if (family == AF_INET6 && familyMask() & KResolver::IPv6Family) 01022 return true; 01023 #endif 01024 if (family == AF_INET && familyMask() & KResolver::IPv4Family) 01025 return true; 01026 if (family == AF_UNIX && familyMask() & KResolver::UnixFamily) 01027 return true; 01028 01029 // it's not a family we know about... 01030 if (familyMask() & KResolver::UnknownFamily) 01031 return true; 01032 01033 return false; 01034 } 01035 01036 #endif 01037 01038 void KNetwork::Internal::initStandardWorkers() 01039 { 01040 //KResolverWorkerFactoryBase::registerNewWorker(new KResolverWorkerFactory<KBlacklistWorker>); 01041 KResolverWorkerFactoryBase::registerNewWorker(new KResolverWorkerFactory<KStandardWorker>); 01042 01043 #ifdef HAVE_GETADDRINFO 01044 KResolverWorkerFactoryBase::registerNewWorker(new KResolverWorkerFactory<KGetAddrinfoWorker>); 01045 #endif 01046 }
KDE 4.6 API Reference