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