kdecore Library API Documentation

kresolverstandardworkers.cpp

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