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

KDECore

kresolverstandardworkers.cpp

Go to the documentation of this file.
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 }

KDECore

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

API Reference

Skip menu "API Reference"
  • dcop
  • DNSSD
  • interfaces
  • Kate
  • kconf_update
  • KDECore
  • KDED
  • kdefx
  • KDEsu
  • kdeui
  • KDocTools
  • KHTML
  • KImgIO
  • KInit
  • kio
  • kioslave
  • KJS
  • KNewStuff
  • KParts
  • KUtils
Generated for API Reference by doxygen 1.5.9
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