kdecore Library API Documentation

kresolverstandardworkers.cpp

00001 /*  -*- C++ -*-
00002  *  Copyright (C) 2003 Thiago Macieira <thiago.macieira@kdemail.net>
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 <config.h>
00026 
00027 #include <sys/types.h>
00028 #include <sys/socket.h>
00029 #include <sys/un.h>
00030 #include <netinet/in.h>
00031 #include <netdb.h>
00032 #include <errno.h>
00033 #include <string.h>
00034 #include <stdlib.h>
00035 
00036 #ifdef HAVE_NET_IF_H
00037 #include <net/if.h>
00038 #endif
00039 
00040 #include <qthread.h>
00041 #include <qmutex.h>
00042 #include <qstrlist.h>
00043 
00044 #include "kresolver.h"
00045 #include "ksocketaddress.h"
00046 #include "kresolver_p.h"
00047 #include "kresolverstandardworkers_p.h"
00048 
00049 struct hostent;
00050 struct addrinfo;
00051 
00052 using namespace KNetwork;
00053 using namespace KNetwork::Internal;
00054 
00055 namespace
00056 {
00057 #ifndef HAVE_GETADDRINFO
00058   class GetHostByNameThread: public KResolverWorkerBase
00059   {
00060   public:
00061     QCString m_hostname;    // might be different!
00062     Q_UINT16 m_port;
00063     int m_scopeid;
00064     int m_af;
00065     KResolverResults& results;
00066 
00067     GetHostByNameThread(const char * hostname, Q_UINT16 port,
00068             int scopeid, int af, KResolverResults* res) :
00069       m_hostname(hostname), m_port(port), m_scopeid(scopeid), m_af(af),
00070       results(*res)
00071     { }
00072 
00073     ~GetHostByNameThread()
00074     { }
00075 
00076     virtual bool preprocess()
00077     { return true; }
00078 
00079     virtual bool run();
00080 
00081     void processResults(hostent* he, int my_h_errno);
00082   };
00083 
00084   bool GetHostByNameThread::run()
00085   {
00086     /*
00087      * Note on the use of the system resolver functions:
00088      *
00089      * In all cases, we prefer to use the new getaddrinfo(3) call. That means
00090      * it will always be used if it is found.
00091      *
00092      * If it's not found, we have the option to use gethostbyname2_r, 
00093      * gethostbyname_r, gethostbyname2 and gethostbyname. If gethostbyname2_r
00094      * is defined, we will use it.
00095      *
00096      * If it's not defined, we have to choose between the non-reentrant
00097      * gethostbyname2 and the reentrant but IPv4-only gethostbyname_r:
00098      * we will choose gethostbyname2 if AF_INET6 is defined.
00099      *
00100      * Lastly, gethostbyname will be used if nothing else is present.
00101      */
00102 
00103     /*
00104      * Note on the use of mutexes:
00105      * if gethostbyname_r and gethostbyname2_r aren't available, we must assume
00106      * that all function calls are non-reentrant. Therefore, we will lock
00107      * a global mutex for protection.
00108      */
00109 
00110     hostent *resultptr;
00111     hostent my_results;
00112     unsigned buflen = 1024;
00113     int res;
00114     int my_h_errno;
00115     char *buf = 0L;
00116 
00117     // qDebug("ResolveThread::run(): started threaded gethostbyname for %s (af = %d)", 
00118     //     m_hostname.data(), m_af);
00119     do
00120       {
00121     res = 0;
00122     my_h_errno = HOST_NOT_FOUND;
00123 
00124 # ifdef HAVE_GETHOSTBYNAME2_R
00125     buf = new char[buflen];
00126     res = gethostbyname2_r(m_hostname, m_af, &my_results, buf, buflen,
00127                    &resultptr, &my_h_errno);
00128 
00129 # elif defined(HAVE_GETHOSTBYNAME_R) && (!defined(AF_INET6) || !defined(HAVE_GETHOSTBYNAME2))
00130     if (m_af == AF_INET)
00131       {
00132         buf = new char[buflen];
00133         res = gethostbyname_r(m_hostname, &my_results, buf, buflen,
00134                   &resultptr, &my_h_errno);
00135       }
00136     else
00137       resultptr = 0;        // signal error
00138 
00139 # elif defined(HAVE_GETHOSTBYNAME2)
00140     // must lock mutex
00141     QMutexLocker locker(&getXXbyYYmutex);
00142     resultptr = gethostbyname2(m_hostname, m_af);
00143     my_h_errno = h_errno;
00144 
00145 # else
00146     if (m_af == AF_INET)
00147       {
00148         // must lock mutex
00149         QMutexLocker locker(&getXXbyYYmutex);
00150         resultptr = gethostbyname(m_hostname);
00151         my_h_errno = h_errno;
00152       }
00153     else
00154       resultptr = 0;
00155 # endif
00156 
00157     if (resultptr != 0L)
00158       my_h_errno = 0;
00159     // qDebug("GetHostByNameThread::run(): gethostbyname for %s (af = %d) returned: %d",
00160     //       m_hostname.data(), m_af, my_h_errno);
00161 
00162     if (res == ERANGE)
00163       {
00164         // Enlarge the buffer
00165         buflen += 1024;
00166         delete [] buf;
00167         buf = new char[buflen];
00168       }
00169       }
00170     while (res == ERANGE);
00171     processResults(resultptr, my_h_errno);
00172 
00173     delete [] buf;
00174 
00175     finished();
00176     return results.error() == KResolver::NoError;
00177   }
00178 
00179   void GetHostByNameThread::processResults(hostent *he, int herrno)
00180   {
00181     if (herrno)
00182       {
00183     qDebug("KStandardWorker::processResults: got error %d", herrno);
00184     switch (herrno)
00185       {
00186       case HOST_NOT_FOUND:
00187         results.setError(KResolver::NoName);
00188         return;
00189 
00190       case TRY_AGAIN:
00191         results.setError(KResolver::TryAgain);
00192         return;
00193 
00194       case NO_RECOVERY:
00195         results.setError(KResolver::NonRecoverable);
00196         return;
00197 
00198       case NO_ADDRESS:
00199         results.setError(KResolver::NoName);
00200         return;
00201 
00202       default:
00203         results.setError(KResolver::UnknownError);
00204         return;
00205       }
00206       }
00207     else if (he == 0L)
00208       {
00209     results.setError(KResolver::NoName);
00210     return;         // this was an error
00211       }
00212 
00213     // clear any errors
00214     setError(KResolver::NoError);
00215     results.setError(KResolver::NoError);
00216 
00217     // we process results in the reverse order
00218     // that is, we prepend each result to the list of results
00219     int proto = protocol();
00220     int socktype = socketType();
00221     if (socktype == 0)
00222       socktype = SOCK_STREAM;   // default
00223 
00224     QString canon = KResolver::domainToUnicode(QString::fromLatin1(he->h_name));
00225     KInetSocketAddress sa;
00226     sa.setPort(m_port);
00227     if (he->h_addrtype != AF_INET)
00228       sa.setScopeId(m_scopeid); // this will also change the socket into IPv6
00229 
00230     for (int i = 0; he->h_addr_list[i]; i++)
00231       {
00232     sa.setHost(KIpAddress(he->h_addr_list[i], he->h_addrtype == AF_INET ? 4 : 6));
00233     results.prepend(KResolverEntry(sa, socktype, proto, canon, m_hostname));
00234     // qDebug("KStandardWorker::processResults: adding %s", sa.toString().latin1());
00235       }
00236     //  qDebug("KStandardWorker::processResults: added %d entries", i);
00237   }
00238 
00239 #else  // HAVE_GETADDRINFO
00240 
00241   class GetAddrInfoThread: public KResolverWorkerBase
00242   {
00243   public:
00244     QCString m_node;
00245     QCString m_serv;
00246     int m_af;
00247     KResolverResults& results;
00248 
00249     GetAddrInfoThread(const char* node, const char* serv, int af,
00250               KResolverResults* res) :
00251       m_node(node), m_serv(serv), m_af(af), results(*res)
00252     { }
00253 
00254     ~GetAddrInfoThread()
00255     { }
00256 
00257     virtual bool preprocess()
00258     { return true; }
00259 
00260     virtual bool run();
00261 
00262     void processResults(addrinfo* ai, int ret_code, KResolverResults& rr);
00263   };
00264 
00265   bool GetAddrInfoThread::run()
00266   {
00267 # ifdef NEED_MUTEX
00268     // in some platforms, getaddrinfo(3) is not thread-safe nor reentrant
00269     // therefore, we will lock a global mutex (defined in qresolver.cpp)
00270     // relating to all the lookup functions
00271 
00272     QMutexLocker locker(&getXXbyYYmutex);
00273 # endif
00274 
00275     // process hints
00276     addrinfo hint;
00277     memset(&hint, 0, sizeof(hint));
00278     hint.ai_family = m_af;
00279     hint.ai_socktype = socketType();
00280     hint.ai_protocol = protocol();
00281 
00282     if (hint.ai_socktype == 0)
00283       hint.ai_socktype = SOCK_STREAM; // default
00284 
00285     if (flags() & KResolver::Passive)
00286       hint.ai_flags |= AI_PASSIVE;
00287     if (flags() & KResolver::CanonName)
00288       hint.ai_flags |= AI_CANONNAME;
00289 # ifdef AI_NUMERICHOST
00290     if (flags() & KResolver::NoResolve)
00291       hint.ai_flags |= AI_NUMERICHOST;
00292 # endif
00293 
00294     // now we do the blocking processing
00295     if (m_node.isEmpty())
00296       m_node = "*";
00297 
00298     addrinfo *result;
00299     int res = getaddrinfo(m_node, m_serv, &hint, &result);
00300     // qDebug("QGetAddrInfoThread::run: getaddrinfo for [%s]:%s (af = %d); result = %d", 
00301     //     m_node.data(), m_serv.data(), m_af, res);
00302 
00303     if (res != 0)
00304       {
00305     switch (res)
00306       {
00307       case EAI_BADFLAGS:
00308         results.setError(KResolver::BadFlags);
00309         break;
00310 
00311 #ifdef EAI_NODATA
00312           // In some systems, EAI_NODATA was #define'd to EAI_NONAME which would break this case.
00313 #if EAI_NODATA != EAI_NONAME
00314       case EAI_NODATA:  // it was removed in RFC 3493
00315 #endif
00316 #endif
00317       case EAI_NONAME:
00318         results.setError(KResolver::NoName);
00319         break;
00320 
00321       case EAI_AGAIN:
00322         results.setError(KResolver::TryAgain);
00323         break;
00324 
00325       case EAI_FAIL:
00326         results.setError(KResolver::NonRecoverable);
00327         break;
00328 
00329       case EAI_FAMILY:
00330         results.setError(KResolver::UnsupportedFamily);
00331         break;
00332 
00333       case EAI_SOCKTYPE:
00334         results.setError(KResolver::UnsupportedSocketType);
00335         break;
00336 
00337       case EAI_SERVICE:
00338         results.setError(KResolver::UnsupportedService);
00339         break;
00340 
00341       case EAI_MEMORY:
00342         results.setError(KResolver::Memory);
00343         break;
00344 
00345       case EAI_SYSTEM:
00346         results.setError(KResolver::SystemError, errno);
00347         break;
00348 
00349       default:
00350         results.setError(KResolver::UnknownError, errno);
00351         break;
00352       }
00353 
00354     finished();
00355     return false;       // failed
00356       }
00357 
00358     // if we are here, lookup succeeded
00359     QString canon;
00360     const char *previous_canon = 0L;
00361 
00362     for (addrinfo* p = result; p; p = p->ai_next)
00363       {
00364     // cache the last canon name to avoid doing the ToUnicode processing unnecessarily
00365     if ((previous_canon && !p->ai_canonname) ||
00366         (!previous_canon && p->ai_canonname) ||
00367         (p->ai_canonname != previous_canon && 
00368          strcmp(p->ai_canonname, previous_canon) != 0))
00369       {
00370         canon = KResolver::domainToUnicode(QString::fromAscii(p->ai_canonname));
00371         previous_canon = p->ai_canonname;
00372       }
00373 
00374     results.append(KResolverEntry(p->ai_addr, p->ai_addrlen, p->ai_socktype, 
00375                       p->ai_protocol, canon, m_node));
00376       }
00377 
00378     freeaddrinfo(result);
00379     results.setError(KResolver::NoError);
00380     finished();
00381     return results.error() == KResolver::NoError;
00382   }
00383 
00384 #endif // HAVE_GETADDRINFO
00385 } // namespace
00386 
00387 bool KStandardWorker::sanityCheck()
00388 {
00389   // check that the requested values are sensible
00390 
00391   if (!nodeName().isEmpty())
00392     {
00393       QString node = nodeName();
00394       if (node.find('%') != -1)
00395     node.truncate(node.find('%'));
00396 
00397       if (node.isEmpty() || node == QString::fromLatin1("*") ||
00398       node == QString::fromLatin1("localhost"))
00399     m_encodedName.truncate(0);
00400       else
00401     {
00402       m_encodedName = KResolver::domainToAscii(node);
00403 
00404       if (m_encodedName.isNull())
00405         {
00406           qDebug("could not encode hostname '%s' (UTF-8)", node.utf8().data());
00407           setError(KResolver::NoName);
00408           return false;     // invalid hostname!
00409         }
00410 
00411       // qDebug("Using encoded hostname '%s' for '%s' (UTF-8)", m_encodedName.data(),
00412       //     node.utf8().data());
00413     }
00414     }
00415   else
00416     m_encodedName.truncate(0);  // just to be sure, but it should be clear already
00417 
00418   if (protocol() == -1)
00419     {
00420       setError(KResolver::NonRecoverable);
00421       return false;     // user passed invalid protocol name
00422     }
00423 
00424   return true;          // it's sane
00425 }
00426 
00427 bool KStandardWorker::resolveScopeId()
00428 {
00429   // we must test the original name, not the encoded one
00430   scopeid = 0;
00431   int pos = nodeName().findRev('%');
00432   if (pos == -1)
00433     return true;
00434 
00435   QString scopename = nodeName().mid(pos + 1);
00436 
00437   bool ok;
00438   scopeid = scopename.toInt(&ok);
00439   if (!ok)
00440     {
00441       // it's not a number
00442       // therefore, it's an interface name
00443 #ifdef HAVE_IF_NAMETOINDEX
00444       scopeid = if_nametoindex(scopename.latin1());
00445 #else
00446       scopeid = 0;
00447 #endif
00448     }
00449 
00450   return true;
00451 }
00452 
00453 bool KStandardWorker::resolveService()
00454 {
00455   // find the service first
00456   bool ok;
00457   port = serviceName().toUInt(&ok);
00458   if (!ok)
00459     {
00460       // service name does not contain a port number
00461       // must be a name
00462 
00463       if (serviceName().isEmpty() || serviceName().compare(QString::fromLatin1("*")) == 0)
00464     port = 0;
00465       else
00466     {
00467       // it's a name. We need the protocol name in order to lookup.
00468       QCString protoname = protocolName();
00469 
00470       if (protoname.isEmpty() && protocol())
00471         {
00472           protoname = KResolver::protocolName(protocol()).first();
00473 
00474           // if it's still empty...
00475           if (protoname.isEmpty())
00476         {
00477           // lookup failed!
00478           setError(KResolver::NoName);
00479           return false;
00480         }
00481         }
00482       else
00483         protoname = "tcp";
00484 
00485       // it's not, so we can do a port lookup
00486       int result = KResolver::servicePort(serviceName().latin1(), protoname);
00487       if (result == -1)
00488         {
00489           // lookup failed!
00490           setError(KResolver::NoName);
00491           return false;
00492         }
00493 
00494       // it worked, we have a port number
00495       port = (Q_UINT16)result;
00496     }
00497     }
00498 
00499   // we found a port
00500   return true;
00501 }
00502 
00503 KResolver::ErrorCodes KStandardWorker::addUnix()
00504 {
00505   // before trying to add, see if the user wants Unix sockets
00506   if ((familyMask() & KResolver::UnixFamily) == 0)
00507     // no, Unix sockets are not wanted
00508     return KResolver::UnsupportedFamily;
00509 
00510   // now check if the requested data are good for a Unix socket
00511   if (!m_encodedName.isEmpty())
00512     return KResolver::AddrFamily; // non local hostname
00513 
00514   if (protocol() || protocolName())
00515     return KResolver::BadFlags; // cannot have Unix sockets with protocols
00516 
00517   QString pathname = serviceName();
00518   if (pathname.isEmpty())
00519     return KResolver::NoName;;  // no path?
00520 
00521   if (pathname[0] != '/')
00522     // non absolute pathname
00523     // put it in /tmp
00524     pathname.prepend("/tmp/");
00525 
00526   //  qDebug("QNoResolveWorker::addUnix(): adding Unix socket for %s", pathname.local8Bit().data());
00527   KUnixSocketAddress sa(pathname);
00528   int socktype = socketType();
00529   if (socktype == 0)
00530     socktype = SOCK_STREAM; // default
00531 
00532   results.append(KResolverEntry(sa, socktype, 0));
00533   setError(KResolver::NoError);
00534  
00535   return KResolver::NoError;
00536 }
00537 
00538 bool KStandardWorker::resolveNumerically()
00539 {
00540   // if the NoResolve flag is active, our result from this point forward
00541   // will always be true, even if the resolution failed.
00542   // that indicates that our result is authoritative.
00543 
00544   bool wantV4 = familyMask() & KResolver::IPv4Family,
00545     wantV6 = familyMask() & KResolver::IPv6Family;
00546 
00547   if (!wantV6 && !wantV4)
00548     // no Internet address is wanted!
00549     return (flags() & KResolver::NoResolve);
00550 
00551   // now try to find results
00552   if (!resolveScopeId() || !resolveService())
00553     return (flags() & KResolver::NoResolve);
00554 
00555   // we have scope IDs and port numbers
00556   // now try to resolve the hostname numerically
00557   KInetSocketAddress sa;
00558   setError(KResolver::NoError);
00559   sa.setHost(KIpAddress(QString::fromLatin1(m_encodedName)));
00560   
00561   // if it failed, the length was reset to 0
00562   bool ok = sa.length() != 0;
00563 
00564   sa.setPort(port);
00565   if (sa.ipVersion() == 6)
00566     sa.setScopeId(scopeid);
00567   int proto = protocol();
00568   int socktype = socketType();
00569   if (socktype == 0)
00570     socktype = SOCK_STREAM;
00571 
00572   if (ok)
00573     {
00574       // the given hostname was successfully converted to an IP address
00575       // check if the user wanted this kind of address
00576 
00577       if ((sa.ipVersion() == 4 && wantV4) ||
00578       (sa.ipVersion() == 6 && wantV6))
00579     results.append(KResolverEntry(sa, socktype, proto));
00580       else
00581     {
00582       // Note: the address *IS* a numeric IP
00583       // but it's not of the kind the user asked for
00584       //
00585       // that means that it cannot be a Unix socket (because it's an IP)
00586       // and that means that no resolution will tell us otherwise
00587       //
00588       // This is a failed resolution
00589 
00590       setError(KResolver::AddrFamily);
00591       return true;
00592     }
00593     }
00594   else if (m_encodedName.isEmpty())
00595     {
00596       // user wanted localhost
00597       if (flags() & KResolver::Passive)
00598     {
00599       if (wantV6)
00600         {
00601           sa.setHost(KIpAddress::anyhostV6);
00602           results.append(KResolverEntry(sa, socktype, proto));
00603         }
00604 
00605       if (wantV4)
00606         {
00607           sa.setHost(KIpAddress::anyhostV4);
00608           results.append(KResolverEntry(sa, socktype, proto));
00609         }
00610     }
00611       else
00612     {
00613       if (wantV6)
00614         {
00615           sa.setHost(KIpAddress::localhostV6);
00616           results.append(KResolverEntry(sa, socktype, proto));
00617         }
00618 
00619       if (wantV4)
00620         {
00621           sa.setHost(KIpAddress::localhostV4);
00622           results.append(KResolverEntry(sa, socktype, proto));
00623         }
00624     }
00625 
00626       ok = true;
00627     }
00628   else
00629     {
00630       // probably bad flags, since the address is not convertible without 
00631       // resolution
00632 
00633       setError(KResolver::BadFlags);
00634       ok = false;
00635     }
00636 
00637   return ok || (flags() & KResolver::NoResolve);
00638 }
00639 
00640 bool KStandardWorker::preprocess()
00641 {
00642   // check sanity
00643   if (!sanityCheck())
00644     return false;
00645 
00646   // this worker class can only handle known families
00647   if (familyMask() & KResolver::UnknownFamily)
00648     {
00649       setError(KResolver::UnsupportedFamily);
00650       return false;     // we don't know about this
00651     }
00652 
00653   // check the socket types
00654   if (socketType() != SOCK_STREAM && socketType() != SOCK_DGRAM && socketType() != 0)
00655     {
00656       setError(KResolver::UnsupportedSocketType);
00657       return false;
00658     }
00659 
00660   // check if we can resolve all numerically
00661   // resolveNumerically always returns true if the NoResolve flag is set
00662   if (resolveNumerically() || m_encodedName.isEmpty())
00663     {
00664       // indeed, we have resolved numerically
00665       setError(addUnix());
00666       if (results.count())
00667     setError(KResolver::NoError);
00668       finished();
00669       return true;
00670     }
00671 
00672   // check if the user wants something we know about
00673 #ifdef AF_INET6
00674 # define mask   (KResolver::IPv6Family | KResolver::IPv4Family | KResolver::UnixFamily)
00675 #else
00676 # define mask   (KResolver::IPv4Family | KResolver::UnixFamily)
00677 #endif
00678 
00679   if ((familyMask() & mask) == 0)
00680     // errr... nothing we know about
00681     return false;
00682 
00683 #undef mask
00684 
00685   return true;          // it's ok
00686 }
00687 
00688 bool KStandardWorker::run()
00689 {
00690 #ifndef HAVE_GETADDRINFO
00691   // check the scope id first
00692   // since most of the resolutions won't have a scope id, this should be fast
00693   // and we won't have wasted time on services if this fails
00694   if (!resolveScopeId())
00695     return false;
00696 
00697   // resolve the service now, before entering the blocking operation
00698   if (!resolveService())
00699     return false;
00700 #endif
00701 
00702   // good
00703   // now we need the hostname
00704   setError(KResolver::NoName);
00705 
00706   // these are the family types that we know of
00707   struct
00708   {
00709     KResolver::SocketFamilies mask;
00710     int af;
00711   } families[] = { { KResolver::IPv4Family, AF_INET }
00712 #ifdef AF_INET6                   
00713           , { KResolver::IPv6Family, AF_INET6 }
00714 #endif
00715   };
00716   int familyCount = sizeof(families)/sizeof(families[0]);
00717   bool skipIPv6 = false;
00718   if (getenv("KDE_NO_IPV6"))
00719     skipIPv6 = true;
00720   resultList.setAutoDelete(true);
00721 
00722   for (int i = 0; i < familyCount; i++)
00723     if (familyMask() & families[i].mask)
00724       {
00725 #ifdef AF_INET6
00726     if (skipIPv6 && families[i].af == AF_INET6)
00727       continue;
00728 #endif
00729 
00730     KResolverWorkerBase *worker;
00731     KResolverResults *res = new KResolverResults;
00732     resultList.append(res);
00733 #ifdef HAVE_GETADDRINFO
00734     worker = new GetAddrInfoThread(m_encodedName, 
00735                        serviceName().latin1(),
00736                        families[i].af, res);
00737 #else
00738     worker = new GetHostByNameThread(m_encodedName, port, scopeid,
00739                      families[i].af, res);
00740 #endif
00741 
00742     enqueue(worker);
00743       }
00744 
00745   // not finished
00746   return true;
00747 }
00748 
00749 bool KStandardWorker::postprocess()
00750 {
00751   if (results.count())
00752     return true;        // no need
00753   // now copy over what we need from the underlying results
00754 
00755   // start backwards because IPv6 was launched later (if at all)
00756   if (resultList.isEmpty())
00757     {
00758       results.setError(KResolver::NoName);
00759       return true;
00760     }
00761 
00762   KResolverResults *rr = resultList.last();
00763   while (rr)
00764     {
00765       if (!rr->isEmpty())
00766     {
00767       results.setError(KResolver::NoError);
00768       KResolverResults::Iterator it = rr->begin();
00769       for ( ; it != rr->end(); ++it)
00770         results.append(*it);
00771     }
00772       else if (results.isEmpty())
00773     // this generated an error
00774     // copy the error code over
00775     setError(rr->error(), rr->systemError());
00776 
00777       rr = resultList.prev();
00778     }
00779 
00780   resultList.clear();
00781   return true;
00782 }
00783 
00784 #ifdef HAVE_GETADDRINFO
00785 KGetAddrinfoWorker::~KGetAddrinfoWorker()
00786 {
00787 }
00788 
00789 bool KGetAddrinfoWorker::preprocess()
00790 {
00791   // getaddrinfo(3) can always handle any kind of request that makes sense
00792   if (!sanityCheck())
00793     return false;
00794 
00795   if (flags() & KResolver::NoResolve)
00796     // oops, numeric resolution?
00797     return run();
00798 
00799   return true;
00800 }
00801 
00802 bool KGetAddrinfoWorker::run()
00803 {
00804   // make an AF_UNSPEC getaddrinfo(3) call
00805   GetAddrInfoThread worker(m_encodedName, serviceName().latin1(), 
00806                AF_UNSPEC, &results);
00807 
00808   if (!worker.run())
00809     {
00810       if (wantThis(AF_UNIX))
00811     {
00812       if (addUnix() == KResolver::NoError)
00813         setError(KResolver::NoError);
00814     }
00815       else
00816     setError(worker.results.error(), worker.results.systemError());
00817 
00818       return false;
00819     }
00820 
00821   // The worker has finished working
00822   // now copy over only what we may want
00823   // keep track of any Unix-domain sockets
00824 
00825   bool seen_unix = false;
00826   KResolverResults::Iterator it = results.begin();
00827   for ( ; it != results.end(); )
00828     {
00829       if ((*it).family() == AF_UNIX)
00830     seen_unix = true;
00831       if (!wantThis((*it).family()))
00832     it = results.remove(it);
00833       else
00834     ++it;
00835     }
00836 
00837   if (!seen_unix)
00838     addUnix();
00839 
00840   finished();
00841   return true;
00842 }
00843 
00844 bool KGetAddrinfoWorker::wantThis(int family)
00845 {
00846   // tells us if the user wants a socket of this family
00847 
00848 #ifdef AF_INET6
00849   if (family == AF_INET6 && familyMask() & KResolver::IPv6Family)
00850     return true;
00851 #endif
00852   if (family == AF_INET && familyMask() & KResolver::IPv4Family)
00853     return true;
00854   if (family == AF_UNIX && familyMask() & KResolver::UnixFamily)
00855     return true;
00856 
00857   // it's not a family we know about...
00858   if (familyMask() & KResolver::UnknownFamily)
00859     return true;
00860 
00861   return false;
00862 }
00863 
00864 #endif
00865 
00866 void KNetwork::Internal::initStandardWorkers()
00867 {
00868   // register the workers in the order we want them to be tried
00869   // note the no-resolving worker isn't registered. It's handled as a
00870   // special case in KResolverManager::findWorker
00871 
00872   KResolverWorkerFactoryBase::registerNewWorker(new KResolverWorkerFactory<KStandardWorker>);
00873 
00874 #ifdef HAVE_GETADDRINFO
00875   KResolverWorkerFactoryBase::registerNewWorker(new KResolverWorkerFactory<KGetAddrinfoWorker>);
00876 #endif
00877 }
KDE Logo
This file is part of the documentation for kdecore Library Version 3.3.2.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Fri Jul 22 10:16:18 2005 by doxygen 1.3.6 written by Dimitri van Heesch, © 1997-2003