• Skip to content
  • Skip to link menu
KDE 4.3 API Reference
  • KDE API Reference
  • kdelibs
  • Sitemap
  • Contact Us
 

KDECore

k3resolverstandardworkers.cpp

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

KDECore

Skip menu "KDECore"
  • Main Page
  • Modules
  • Namespace List
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Namespace Members
  • Class Members
  • Related Pages

kdelibs

Skip menu "kdelibs"
  • DNSSD
  • Interfaces
  •   KHexEdit
  •   KMediaPlayer
  •   KSpeech
  •   KTextEditor
  • Kate
  • kconf_update
  • KDE3Support
  •   KUnitTest
  • KDECore
  • KDED
  • KDEsu
  • KDEUI
  • KDocTools
  • KFile
  • KHTML
  • KImgIO
  • KInit
  • kio
  • KIOSlave
  • KJS
  •   KJS-API
  •   WTF
  • kjsembed
  • KNewStuff
  • KParts
  • KPty
  • Kross
  • KUtils
  • Nepomuk
  • Plasma
  • Solid
  • Sonnet
  • ThreadWeaver
Generated for kdelibs by doxygen 1.6.1
This website is maintained by Adriaan de Groot and Allen Winter.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal