# kdecore Library API Documentation

Overview | Class Hierarchy | Classes | Classes (annotated) | Members | Namespaces | Source Files

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

This file is part of the documentation for kdecore Library Version 3.4.1.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Sat Jun 11 20:18:10 2005 by doxygen 1.4.1 written by Dimitri van Heesch, © 1997-2003