File indexing completed on 2024-04-21 14:55:23

0001 /*  -*- C++ -*-
0002  *  Copyright (C) 2003,2004 Thiago Macieira <thiago@kde.org>
0003  *
0004  *
0005  *  Permission is hereby granted, free of charge, to any person obtaining
0006  *  a copy of this software and associated documentation files (the
0007  *  "Software"), to deal in the Software without restriction, including
0008  *  without limitation the rights to use, copy, modify, merge, publish,
0009  *  distribute, sublicense, and/or sell copies of the Software, and to
0010  *  permit persons to whom the Software is furnished to do so, subject to
0011  *  the following conditions:
0012  *
0013  *  The above copyright notice and this permission notice shall be included
0014  *  in all copies or substantial portions of the Software.
0015  *
0016  *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
0017  *  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
0018  *  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
0019  *  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
0020  *  LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
0021  *  OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
0022  *  WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
0023  */
0024 
0025 #include "k3resolverstandardworkers_p.h"
0026 
0027 #include <config-network.h>
0028 
0029 #include <sys/types.h>
0030 #include <sys/socket.h>
0031 #include <sys/un.h>
0032 #include <netinet/in.h>
0033 #include <netdb.h>
0034 #include <errno.h>
0035 #include <string.h>
0036 #include <stdlib.h>
0037 #include <unistd.h>
0038 
0039 #if HAVE_NET_IF_H
0040 #include <net/if.h>
0041 #endif
0042 
0043 #include <QFile>
0044 #include <QList>
0045 #include <QMutex>
0046 #include <QTextStream>
0047 #include <QThread>
0048 #ifdef Q_OS_WIN
0049 #include <winsock2.h>
0050 #endif
0051 
0052 #include "kdebug.h"
0053 #include "kglobal.h"
0054 #include "kcomponentdata.h"
0055 #include "kstandarddirs.h"
0056 
0057 #include "k3resolver.h"
0058 #include "k3socketaddress.h"
0059 
0060 struct hostent;
0061 struct addrinfo;
0062 
0063 using namespace KNetwork;
0064 using namespace KNetwork::Internal;
0065 
0066 static bool hasIPv6()
0067 {
0068 #ifdef Q_OS_WIN
0069     extern void KNetwork_initSocket();
0070     KNetwork_initSocket();
0071 #endif
0072 #ifdef AF_INET6
0073     if (!qgetenv("KDE_NO_IPV6").isEmpty()) {
0074         return false;
0075     }
0076 
0077 # ifdef Q_OS_WIN
0078     SOCKET s = ::socket(AF_INET6, SOCK_STREAM, 0);
0079     if (s == INVALID_SOCKET) {
0080         return false;
0081     }
0082     ::closesocket(s);
0083 # else
0084     int fd = ::socket(AF_INET6, SOCK_STREAM, 0);
0085     if (fd == -1) {
0086         return false;
0087     }
0088     ::close(fd);
0089 # endif
0090     return true;
0091 #else
0092     return false;
0093 #endif
0094 }
0095 
0096 // blacklist management
0097 static QMutex blacklistMutex;   // KDE4: change to a QReadWriteLock
0098 QStringList KBlacklistWorker::blacklist;
0099 
0100 void KBlacklistWorker::init()
0101 {
0102     if (!KComponentData::hasMainComponent()) {
0103         return;
0104     }
0105 
0106     static bool beenhere = false;
0107 
0108     if (beenhere) {
0109         return;
0110     }
0111 
0112     beenhere = true;
0113     loadBlacklist();
0114 }
0115 
0116 void KBlacklistWorker::loadBlacklist()
0117 {
0118     QMutexLocker locker(&blacklistMutex);
0119     QStringList filelist = KGlobal::dirs()->findAllResources("config", QLatin1String("ipv6blacklist"));
0120 
0121     QStringList::ConstIterator it = filelist.constBegin(),
0122                                end = filelist.constEnd();
0123     for (; it != end; ++it) {
0124         // for each file, each line is a domainname to be blacklisted
0125         QFile f(*it);
0126         if (!f.open(QIODevice::ReadOnly)) {
0127             continue;
0128         }
0129 
0130         QTextStream stream(&f);
0131         stream.setCodec("latin1");
0132         for (QString line = stream.readLine(); !line.isNull();
0133                 line = stream.readLine()) {
0134             if (line.isEmpty()) {
0135                 continue;
0136             }
0137 
0138             // make sure there are no surrounding whitespaces
0139             // and that it starts with .
0140             line = line.trimmed();
0141             if (line[0] != QLatin1Char('.')) {
0142                 line.prepend(QLatin1Char('.'));
0143             }
0144 
0145             blacklist.append(line.toLower());
0146         }
0147     }
0148 }
0149 
0150 // checks the blacklist to see if the domain is listed
0151 // it matches the domain ending part
0152 bool KBlacklistWorker::isBlacklisted(const QString &host)
0153 {
0154     KBlacklistWorker::init();
0155 
0156     // empty hostnames cannot be blacklisted
0157     if (host.isEmpty()) {
0158         return false;
0159     }
0160 
0161     QString ascii = QLatin1String(KResolver::domainToAscii(host));
0162 
0163     QMutexLocker locker(&blacklistMutex);
0164 
0165     // now find out if this hostname is present
0166     QStringList::ConstIterator it = blacklist.constBegin(),
0167                                end = blacklist.constEnd();
0168     for (; it != end; ++it)
0169         if (ascii.endsWith(*it)) {
0170             return true;
0171         }
0172 
0173     // no match:
0174     return false;
0175 }
0176 
0177 bool KBlacklistWorker::preprocess()
0178 {
0179     if (isBlacklisted(nodeName())) {
0180         results.setError(KResolver::NoName);
0181         finished();
0182         return true;
0183     }
0184     return false;
0185 }
0186 
0187 bool KBlacklistWorker::run()
0188 {
0189     results.setError(KResolver::NoName);
0190     finished();
0191     return false;         // resolution failure
0192 }
0193 
0194 namespace
0195 {
0196 /*
0197  * Note on the use of the system resolver functions:
0198  *
0199  * In all cases, we prefer to use the new getaddrinfo(3) call. That means
0200  * it will always be used if it is found.
0201  *
0202  * If it's not found, we have the option to use gethostbyname2_r,
0203  * gethostbyname_r, gethostbyname2 and gethostbyname. If gethostbyname2_r
0204  * is defined, we will use it.
0205  *
0206  * If it's not defined, we have to choose between the non-reentrant
0207  * gethostbyname2 and the reentrant but IPv4-only gethostbyname_r:
0208  * we will choose gethostbyname2 if AF_INET6 is defined.
0209  *
0210  * Lastly, gethostbyname will be used if nothing else is present.
0211  */
0212 
0213 #if !HAVE_GETADDRINFO
0214 
0215 # if HAVE_GETHOSTBYNAME2_R
0216 #  define USE_GETHOSTBYNAME2_R
0217 # elif HAVE_GETHOSTBYNAME_R && (!defined(AF_INET6) || !HAVE_GETHOSTBYNAME2)
0218 #  define USE_GETHOSTBYNAME_R
0219 # elif HAVE_GETHOSTBYNAME2
0220 #  define USE_GETHOSTBYNAME2
0221 # else
0222 #  define USE_GETHOSTBYNAME
0223 # endif
0224 
0225 class GetHostByNameThread: public KResolverWorkerBase
0226 {
0227 public:
0228     QByteArray m_hostname;  // might be different!
0229     quint16 m_port;
0230     int m_scopeid;
0231     int m_af;
0232     KResolverResults &results;
0233 
0234     GetHostByNameThread(const char *hostname, quint16 port,
0235                         int scopeid, int af, KResolverResults *res) :
0236         m_hostname(hostname), m_port(port), m_scopeid(scopeid), m_af(af),
0237         results(*res)
0238     { }
0239 
0240     ~GetHostByNameThread()
0241     { }
0242 
0243     virtual bool preprocess()
0244     {
0245         return true;
0246     }
0247 
0248     virtual bool run();
0249 
0250     void processResults(hostent *he, int my_h_errno);
0251 };
0252 
0253 bool GetHostByNameThread::run()
0254 {
0255 
0256     hostent *resultptr;
0257     hostent my_results;
0258     unsigned buflen = 1024;
0259     int res;
0260     int my_h_errno;
0261     char *buf = 0L;
0262 
0263     // qDebug("ResolveThread::run(): started threaded gethostbyname for %s (af = %d)",
0264     //     m_hostname.data(), m_af);
0265 
0266     ResolverLocker resLock(this);
0267     do {
0268         res = 0;
0269         my_h_errno = HOST_NOT_FOUND;
0270 
0271         // check blacklist
0272         if (m_af != AF_INET &&
0273                 KBlacklistWorker::isBlacklisted(QLatin1String(m_hostname))) {
0274             break;
0275         }
0276 
0277 # ifdef USE_GETHOSTBYNAME2_R
0278         buf = new char[buflen];
0279         res = gethostbyname2_r(m_hostname, m_af, &my_results, buf, buflen,
0280                                &resultptr, &my_h_errno);
0281 
0282 # elif defined(USE_GETHOSTBYNAME_R)
0283         if (m_af == AF_INET) {
0284             buf = new char[buflen];
0285             res = gethostbyname_r(m_hostname, &my_results, buf, buflen,
0286                                   &resultptr, &my_h_errno);
0287         } else {
0288             resultptr = 0;    // signal error
0289         }
0290 
0291 # elif defined(USE_GETHOSTBYNAME2)
0292         // must lock mutex
0293         resultptr = gethostbyname2(m_hostname, m_af);
0294         my_h_errno = h_errno;
0295 
0296 # else
0297         if (m_af == AF_INET) {
0298             // must lock mutex
0299             resultptr = gethostbyname(m_hostname);
0300             my_h_errno = h_errno;
0301         } else {
0302             resultptr = 0;
0303         }
0304 # endif
0305 
0306         if (resultptr != 0L) {
0307             my_h_errno = 0;
0308         }
0309         // qDebug("GetHostByNameThread::run(): gethostbyname for %s (af = %d) returned: %d",
0310         //       m_hostname.data(), m_af, my_h_errno);
0311 
0312         if (res == ERANGE) {
0313             // Enlarge the buffer
0314             buflen += 1024;
0315             delete [] buf;
0316             buf = new char[buflen];
0317         }
0318 
0319         if ((res == ERANGE || my_h_errno != 0) && checkResolver()) {
0320             // resolver needs updating, so we might as well do it now
0321             resLock.openClose();
0322         }
0323     } while (res == ERANGE);
0324     processResults(resultptr, my_h_errno);
0325 
0326     delete [] buf;
0327 
0328     finished();
0329     return results.error() == KResolver::NoError;
0330 }
0331 
0332 void GetHostByNameThread::processResults(hostent *he, int herrno)
0333 {
0334     if (herrno) {
0335         qDebug("KStandardWorker::processResults: got error %d", herrno);
0336         switch (herrno) {
0337         case HOST_NOT_FOUND:
0338             results.setError(KResolver::NoName);
0339             return;
0340 
0341         case TRY_AGAIN:
0342             results.setError(KResolver::TryAgain);
0343             return;
0344 
0345         case NO_RECOVERY:
0346             results.setError(KResolver::NonRecoverable);
0347             return;
0348 
0349         case NO_ADDRESS:
0350             results.setError(KResolver::NoName);
0351             return;
0352 
0353         default:
0354             results.setError(KResolver::UnknownError);
0355             return;
0356         }
0357     } else if (he == 0L) {
0358         results.setError(KResolver::NoName);
0359         return;         // this was an error
0360     }
0361 
0362     // clear any errors
0363     setError(KResolver::NoError);
0364     results.setError(KResolver::NoError);
0365 
0366     // we process results in the reverse order
0367     // that is, we prepend each result to the list of results
0368     int proto = protocol();
0369     int socktype = socketType();
0370     if (socktype == 0) {
0371         socktype = SOCK_STREAM;    // default
0372     }
0373 
0374     QString canon = KResolver::domainToUnicode(QLatin1String(he->h_name));
0375     KInetSocketAddress sa;
0376     sa.setPort(m_port);
0377     if (he->h_addrtype != AF_INET) {
0378         sa.setScopeId(m_scopeid);    // this will also change the socket into IPv6
0379     }
0380 
0381     for (int i = 0; he->h_addr_list[i]; i++) {
0382         sa.setHost(KIpAddress(he->h_addr_list[i], he->h_addrtype == AF_INET ? 4 : 6));
0383         results.prepend(KResolverEntry(sa, socktype, proto, canon, m_hostname));
0384         // qDebug("KStandardWorker::processResults: adding %s", sa.toString().toLatin1().constData());
0385     }
0386     //  qDebug("KStandardWorker::processResults: added %d entries", i);
0387 }
0388 
0389 #else  // HAVE_GETADDRINFO
0390 
0391 class GetAddrInfoThread: public KResolverWorkerBase
0392 {
0393 public:
0394     QByteArray m_node;
0395     QByteArray m_serv;
0396     int m_af;
0397     int m_flags;
0398     KResolverResults &results;
0399 
0400     GetAddrInfoThread(const char *node, const char *serv, int af, int flags,
0401                       KResolverResults *res) :
0402         m_node(node), m_serv(serv), m_af(af), m_flags(flags), results(*res)
0403     { }
0404 
0405     ~GetAddrInfoThread() override
0406     { }
0407 
0408     bool preprocess() override
0409     {
0410         return true;
0411     }
0412 
0413     bool run() override;
0414 
0415     void processResults(addrinfo *ai, int ret_code, KResolverResults &rr);
0416 };
0417 
0418 bool GetAddrInfoThread::run()
0419 {
0420     // check blacklist
0421     if ((m_af != AF_INET && m_af != AF_UNSPEC) &&
0422             KBlacklistWorker::isBlacklisted(QLatin1String(m_node))) {
0423         results.setError(KResolver::NoName);
0424         finished();
0425         return false;       // failed
0426     }
0427 
0428     do {
0429         ResolverLocker resLock(this);
0430 
0431         // process hints
0432         addrinfo hint;
0433         memset(&hint, 0, sizeof(hint));
0434         hint.ai_family = m_af;
0435         hint.ai_socktype = socketType();
0436         hint.ai_protocol = protocol();
0437 
0438         if (hint.ai_socktype == 0) {
0439             hint.ai_socktype = SOCK_STREAM;    // default
0440         }
0441 
0442         if (m_flags & KResolver::Passive) {
0443             hint.ai_flags |= AI_PASSIVE;
0444         }
0445         if (m_flags & KResolver::CanonName) {
0446             hint.ai_flags |= AI_CANONNAME;
0447         }
0448 # ifdef AI_NUMERICHOST
0449         if (m_flags & KResolver::NoResolve) {
0450             hint.ai_flags |= AI_NUMERICHOST;
0451         }
0452 # endif
0453 # ifdef AI_ADDRCONFIG
0454         hint.ai_flags |= AI_ADDRCONFIG;
0455 # endif
0456 
0457         // now we do the blocking processing
0458         if (m_node.isEmpty()) {
0459             m_node = "*";    // krazy:exclude=doublequote_chars
0460         }
0461 
0462         addrinfo *result;
0463         int res = getaddrinfo(m_node, m_serv, &hint, &result);
0464         //    kDebug(179) << "getaddrinfo(\""
0465         //       << m_node << "\", \"" << m_serv << "\", af="
0466         //       << m_af << ") returned " << res << endl;
0467 
0468         if (res != 0) {
0469             if (checkResolver()) {
0470                 // resolver requires reinitialisation
0471                 resLock.openClose();
0472                 continue;
0473             }
0474 
0475             switch (res) {
0476             case EAI_BADFLAGS:
0477                 results.setError(KResolver::BadFlags);
0478                 break;
0479 
0480 #ifdef EAI_NODATA
0481                 // In some systems, EAI_NODATA was #define'd to EAI_NONAME which would break this case.
0482 #if EAI_NODATA != EAI_NONAME
0483             case EAI_NODATA:  // it was removed in RFC 3493
0484 #endif
0485 #endif
0486             case EAI_NONAME:
0487                 results.setError(KResolver::NoName);
0488                 break;
0489 
0490             case EAI_AGAIN:
0491                 results.setError(KResolver::TryAgain);
0492                 break;
0493 
0494             case EAI_FAIL:
0495                 results.setError(KResolver::NonRecoverable);
0496                 break;
0497 
0498             case EAI_FAMILY:
0499                 results.setError(KResolver::UnsupportedFamily);
0500                 break;
0501 
0502             case EAI_SOCKTYPE:
0503                 results.setError(KResolver::UnsupportedSocketType);
0504                 break;
0505 
0506             case EAI_SERVICE:
0507                 results.setError(KResolver::UnsupportedService);
0508                 break;
0509 
0510             case EAI_MEMORY:
0511                 results.setError(KResolver::Memory);
0512                 break;
0513 
0514 #ifdef EAI_SYSTEM // not available on windows
0515             case EAI_SYSTEM:
0516                 results.setError(KResolver::SystemError, errno);
0517                 break;
0518 #endif
0519             default:
0520                 results.setError(KResolver::UnknownError, errno);
0521                 break;
0522             }
0523 
0524             finished();
0525             return false;       // failed
0526         }
0527 
0528         // if we are here, lookup succeeded
0529         QString canon;
0530         const char *previous_canon = nullptr;
0531 
0532         for (addrinfo *p = result; p; p = p->ai_next) {
0533             // cache the last canon name to avoid doing the ToUnicode processing unnecessarily
0534             if ((previous_canon && !p->ai_canonname) ||
0535                     (!previous_canon && p->ai_canonname) ||
0536                     (p->ai_canonname != previous_canon &&
0537                      strcmp(p->ai_canonname, previous_canon) != 0)) {
0538                 canon = KResolver::domainToUnicode(QString::fromLatin1(p->ai_canonname));
0539                 previous_canon = p->ai_canonname;
0540             }
0541 
0542             results.append(KResolverEntry(p->ai_addr, p->ai_addrlen, p->ai_socktype,
0543                                           p->ai_protocol, canon, m_node));
0544         }
0545 
0546         freeaddrinfo(result);
0547         results.setError(KResolver::NoError);
0548         finished();
0549         return results.error() == KResolver::NoError;
0550     } while (true);
0551 }
0552 
0553 #endif // HAVE_GETADDRINFO
0554 } // namespace
0555 
0556 KStandardWorker::~KStandardWorker()
0557 {
0558     qDeleteAll(resultList);
0559 }
0560 
0561 bool KStandardWorker::sanityCheck()
0562 {
0563     // check that the requested values are sensible
0564 
0565     if (!nodeName().isEmpty()) {
0566         QString node = nodeName();
0567         if (node.indexOf(QLatin1Char('%')) != -1) {
0568             node.truncate(node.indexOf(QLatin1Char('%')));
0569         }
0570 
0571         if (node.isEmpty() || node == QLatin1String("*") ||
0572                 node == QLatin1String("localhost")) {
0573             m_encodedName.truncate(0);
0574         } else {
0575             m_encodedName = KResolver::domainToAscii(node);
0576 
0577             if (m_encodedName.isNull()) {
0578                 qDebug("could not encode hostname '%s' (UTF-8)", node.toUtf8().data());
0579                 setError(KResolver::NoName);
0580                 return false;     // invalid hostname!
0581             }
0582 
0583             // qDebug("Using encoded hostname '%s' for '%s' (UTF-8)", m_encodedName.data(),
0584             //     node.toUtf8().data());
0585         }
0586     } else {
0587         m_encodedName.truncate(0);    // just to be sure, but it should be clear already
0588     }
0589 
0590     if (protocol() == -1) {
0591         setError(KResolver::NonRecoverable);
0592         return false;     // user passed invalid protocol name
0593     }
0594 
0595     return true;          // it's sane
0596 }
0597 
0598 bool KStandardWorker::resolveScopeId()
0599 {
0600     // we must test the original name, not the encoded one
0601     scopeid = 0;
0602     int pos = nodeName().lastIndexOf(QLatin1Char('%'));
0603     if (pos == -1) {
0604         return true;
0605     }
0606 
0607     QString scopename = nodeName().mid(pos + 1);
0608 
0609     bool ok;
0610     scopeid = scopename.toInt(&ok);
0611     if (!ok) {
0612         // it's not a number
0613         // therefore, it's an interface name
0614 #if HAVE_IF_NAMETOINDEX
0615         scopeid = if_nametoindex(scopename.toLatin1());
0616 #else
0617         scopeid = 0;
0618 #endif
0619     }
0620 
0621     return true;
0622 }
0623 
0624 bool KStandardWorker::resolveService()
0625 {
0626     // find the service first
0627     bool ok;
0628     port = serviceName().toUInt(&ok);
0629     if (!ok) {
0630         // service name does not contain a port number
0631         // must be a name
0632 
0633         if (serviceName().isEmpty() || serviceName().compare(QLatin1String("*")) == 0) {
0634             port = 0;
0635         } else {
0636             // it's a name. We need the protocol name in order to lookup.
0637             QByteArray protoname = protocolName();
0638 
0639             if (protoname.isEmpty() && protocol()) {
0640                 protoname = KResolver::protocolName(protocol()).first();
0641 
0642                 // if it's still empty...
0643                 if (protoname.isEmpty()) {
0644                     // lookup failed!
0645                     setError(KResolver::NoName);
0646                     return false;
0647                 }
0648             } else {
0649                 protoname = "tcp";
0650             }
0651 
0652             // it's not, so we can do a port lookup
0653             int result = KResolver::servicePort(serviceName().toLatin1(), protoname);
0654             if (result == -1) {
0655                 // lookup failed!
0656                 setError(KResolver::NoName);
0657                 return false;
0658             }
0659 
0660             // it worked, we have a port number
0661             port = (quint16)result;
0662         }
0663     }
0664 
0665     // we found a port
0666     return true;
0667 }
0668 
0669 KResolver::ErrorCodes KStandardWorker::addUnix()
0670 {
0671     // before trying to add, see if the user wants Unix sockets
0672     if ((familyMask() & KResolver::UnixFamily) == 0)
0673         // no, Unix sockets are not wanted
0674     {
0675         return KResolver::UnsupportedFamily;
0676     }
0677 
0678     // now check if the requested data are good for a Unix socket
0679     if (!m_encodedName.isEmpty()) {
0680         return KResolver::AddrFamily;    // non local hostname
0681     }
0682 
0683     if (protocol() || !protocolName().isNull()) {
0684         return KResolver::BadFlags;    // cannot have Unix sockets with protocols
0685     }
0686 
0687     QString pathname = serviceName();
0688     if (pathname.isEmpty()) {
0689         return KResolver::NoName;
0690     };  // no path?
0691 
0692     if (pathname[0] != QLatin1Char('/'))
0693         // non absolute pathname
0694         // put it in /tmp
0695     {
0696         pathname.prepend(QLatin1String("/tmp/"));
0697     }
0698 
0699     //  qDebug("QNoResolveWorker::addUnix(): adding Unix socket for %s", pathname.toLocal8Bit().data());
0700     KUnixSocketAddress sa(pathname);
0701     int socktype = socketType();
0702     if (socktype == 0) {
0703         socktype = SOCK_STREAM;    // default
0704     }
0705 
0706     results.append(KResolverEntry(sa, socktype, 0));
0707     setError(KResolver::NoError);
0708 
0709     return KResolver::NoError;
0710 }
0711 
0712 bool KStandardWorker::resolveNumerically()
0713 {
0714     // if the NoResolve flag is active, our result from this point forward
0715     // will always be true, even if the resolution failed.
0716     // that indicates that our result is authoritative.
0717 
0718     bool wantV4 = familyMask() & KResolver::IPv4Family,
0719          wantV6 = familyMask() & KResolver::IPv6Family;
0720 
0721     if (!wantV6 && !wantV4)
0722         // no Internet address is wanted!
0723     {
0724         return (flags() & KResolver::NoResolve);
0725     }
0726 
0727     // now try to find results
0728     if (!resolveScopeId() || !resolveService()) {
0729         return (flags() & KResolver::NoResolve);
0730     }
0731 
0732     // we have scope IDs and port numbers
0733     // now try to resolve the hostname numerically
0734     KInetSocketAddress sa;
0735     setError(KResolver::NoError);
0736     sa.setHost(KIpAddress(QLatin1String(m_encodedName)));
0737 
0738     // if it failed, the length was reset to 0
0739     bool ok = sa.length() != 0;
0740 
0741     sa.setPort(port);
0742     if (sa.ipVersion() == 6) {
0743         sa.setScopeId(scopeid);
0744     }
0745     int proto = protocol();
0746     int socktype = socketType();
0747     if (socktype == 0) {
0748         socktype = SOCK_STREAM;
0749     }
0750 
0751     if (ok) {
0752         // the given hostname was successfully converted to an IP address
0753         // check if the user wanted this kind of address
0754 
0755         if ((sa.ipVersion() == 4 && wantV4) ||
0756                 (sa.ipVersion() == 6 && wantV6)) {
0757             results.append(KResolverEntry(sa, socktype, proto));
0758         } else {
0759             // Note: the address *IS* a numeric IP
0760             // but it's not of the kind the user asked for
0761             //
0762             // that means that it cannot be a Unix socket (because it's an IP)
0763             // and that means that no resolution will tell us otherwise
0764             //
0765             // This is a failed resolution
0766 
0767             setError(KResolver::AddrFamily);
0768             return true;
0769         }
0770     } else if (m_encodedName.isEmpty()) {
0771         // user wanted localhost
0772         if (flags() & KResolver::Passive) {
0773             if (wantV6) {
0774                 sa.setHost(KIpAddress::anyhostV6);
0775                 results.append(KResolverEntry(sa, socktype, proto));
0776             }
0777 
0778             if (wantV4) {
0779                 sa.setHost(KIpAddress::anyhostV4);
0780                 results.append(KResolverEntry(sa, socktype, proto));
0781             }
0782         } else {
0783             if (wantV6) {
0784                 sa.setHost(KIpAddress::localhostV6);
0785                 results.append(KResolverEntry(sa, socktype, proto));
0786             }
0787 
0788             if (wantV4) {
0789                 sa.setHost(KIpAddress::localhostV4);
0790                 results.append(KResolverEntry(sa, socktype, proto));
0791             }
0792         }
0793 
0794         ok = true;
0795     } else {
0796         // probably bad flags, since the address is not convertible without
0797         // resolution
0798 
0799         setError(KResolver::BadFlags);
0800         ok = false;
0801     }
0802 
0803     return ok || (flags() & KResolver::NoResolve);
0804 }
0805 
0806 bool KStandardWorker::preprocess()
0807 {
0808     // check sanity
0809     if (!sanityCheck()) {
0810         return false;
0811     }
0812 
0813     // this worker class can only handle known families
0814     if (familyMask() & KResolver::UnknownFamily) {
0815         setError(KResolver::UnsupportedFamily);
0816         return false;     // we don't know about this
0817     }
0818 
0819     // check the socket types
0820     if (socketType() != SOCK_STREAM && socketType() != SOCK_DGRAM && socketType() != 0) {
0821         setError(KResolver::UnsupportedSocketType);
0822         return false;
0823     }
0824 
0825     // check if we can resolve all numerically
0826     // resolveNumerically always returns true if the NoResolve flag is set
0827     if (resolveNumerically() || m_encodedName.isEmpty()) {
0828         // indeed, we have resolved numerically
0829         setError(addUnix());
0830         if (results.count()) {
0831             setError(KResolver::NoError);
0832         }
0833         finished();
0834         return true;
0835     }
0836 
0837     // check if the user wants something we know about
0838 #ifdef AF_INET6
0839 # define mask   (KResolver::IPv6Family | KResolver::IPv4Family | KResolver::UnixFamily)
0840 #else
0841 # define mask   (KResolver::IPv4Family | KResolver::UnixFamily)
0842 #endif
0843 
0844     if ((familyMask() & mask) == 0)
0845         // errr... nothing we know about
0846     {
0847         return false;
0848     }
0849 
0850 #undef mask
0851 
0852     return true;          // it's ok
0853 }
0854 
0855 bool KStandardWorker::run()
0856 {
0857 #if !HAVE_GETADDRINFO
0858     // check the scope id first
0859     // since most of the resolutions won't have a scope id, this should be fast
0860     // and we won't have wasted time on services if this fails
0861     if (!resolveScopeId()) {
0862         return false;
0863     }
0864 
0865     // resolve the service now, before entering the blocking operation
0866     if (!resolveService()) {
0867         return false;
0868     }
0869 #endif
0870 
0871     // good
0872     // now we need the hostname
0873     setError(KResolver::NoName);
0874 
0875     // these are the family types that we know of
0876     struct {
0877         KResolver::SocketFamilies mask;
0878         int af;
0879     } families[] = { { KResolver::IPv4Family, AF_INET }
0880 #ifdef AF_INET6
0881         , { KResolver::IPv6Family, AF_INET6 }
0882 #endif
0883     };
0884     int familyCount = sizeof(families) / sizeof(families[0]);
0885     bool skipIPv6 = !hasIPv6();
0886 
0887     for (int i = 0; i < familyCount; i++)
0888         if (familyMask() & families[i].mask) {
0889 #ifdef AF_INET6
0890             if (skipIPv6 && families[i].af == AF_INET6) {
0891                 continue;
0892             }
0893 #endif
0894 
0895             KResolverWorkerBase *worker;
0896             KResolverResults *res = new KResolverResults;
0897             resultList.append(res);
0898 #if HAVE_GETADDRINFO
0899             worker = new GetAddrInfoThread(m_encodedName,
0900                                            serviceName().toLatin1(),
0901                                            families[i].af, flags(), res);
0902 #else
0903             worker = new GetHostByNameThread(m_encodedName, port, scopeid,
0904                                              families[i].af, res);
0905 #endif
0906 
0907             enqueue(worker);
0908         }
0909 
0910     // not finished
0911     return true;
0912 }
0913 
0914 bool KStandardWorker::postprocess()
0915 {
0916     if (results.count()) {
0917         return true;    // no need
0918     }
0919     // now copy over what we need from the underlying results
0920 
0921     // start backwards because IPv6 was launched later (if at all)
0922     if (resultList.isEmpty()) {
0923         results.setError(KResolver::NoName);
0924         return true;
0925     }
0926 
0927     for (int i = resultList.size(); i > 0; --i) {
0928         KResolverResults *rr = resultList.at(i - 1);
0929         if (!rr->isEmpty()) {
0930             results.setError(KResolver::NoError);
0931             KResolverResults::Iterator it = rr->begin();
0932             for (; it != rr->end(); ++it) {
0933                 results.append(*it);
0934             }
0935         } else if (results.isEmpty())
0936             // this generated an error
0937             // copy the error code over
0938         {
0939             setError(rr->error(), rr->systemError());
0940         }
0941 
0942         delete rr;
0943         resultList[i - 1] = nullptr;
0944     }
0945 
0946     resultList.clear();
0947     return true;
0948 }
0949 
0950 #if HAVE_GETADDRINFO
0951 KGetAddrinfoWorker::~KGetAddrinfoWorker()
0952 {
0953 }
0954 
0955 bool KGetAddrinfoWorker::preprocess()
0956 {
0957     // getaddrinfo(3) can always handle any kind of request that makes sense
0958     if (!sanityCheck()) {
0959         return false;
0960     }
0961 
0962     if (flags() & KResolver::NoResolve)
0963         // oops, numeric resolution?
0964     {
0965         return run();
0966     }
0967 
0968     return true;
0969 }
0970 
0971 bool KGetAddrinfoWorker::run()
0972 {
0973     // make an AF_UNSPEC getaddrinfo(3) call
0974     GetAddrInfoThread worker(m_encodedName, serviceName().toLatin1(),
0975                              AF_UNSPEC, flags(), &results);
0976 
0977     if (!worker.run()) {
0978         if (wantThis(AF_UNIX)) {
0979             if (addUnix() == KResolver::NoError) {
0980                 setError(KResolver::NoError);
0981             }
0982         } else {
0983             setError(worker.results.error(), worker.results.systemError());
0984         }
0985 
0986         return false;
0987     }
0988 
0989     // The worker has finished working
0990     // now copy over only what we may want
0991     // keep track of any Unix-domain sockets
0992 
0993     bool seen_unix = false;
0994     int i = 0;
0995     while (i < results.count()) {
0996         const KResolverEntry &res = results[i];
0997         if (res.family() == AF_UNIX) {
0998             seen_unix = true;
0999         }
1000         if (!wantThis(res.family())) {
1001             results.removeAt(i);
1002         } else {
1003             ++i;
1004         }
1005     }
1006 
1007     if (!seen_unix) {
1008         addUnix();
1009     }
1010 
1011     finished();
1012     return true;
1013 }
1014 
1015 bool KGetAddrinfoWorker::wantThis(int family)
1016 {
1017     // tells us if the user wants a socket of this family
1018 
1019 #ifdef AF_INET6
1020     if (family == AF_INET6 && familyMask() & KResolver::IPv6Family) {
1021         return true;
1022     }
1023 #endif
1024     if (family == AF_INET && familyMask() & KResolver::IPv4Family) {
1025         return true;
1026     }
1027     if (family == AF_UNIX && familyMask() & KResolver::UnixFamily) {
1028         return true;
1029     }
1030 
1031     // it's not a family we know about...
1032     if (familyMask() & KResolver::UnknownFamily) {
1033         return true;
1034     }
1035 
1036     return false;
1037 }
1038 
1039 #endif
1040 
1041 void KNetwork::Internal::initStandardWorkers()
1042 {
1043     //KResolverWorkerFactoryBase::registerNewWorker(new KResolverWorkerFactory<KBlacklistWorker>);
1044     KResolverWorkerFactoryBase::registerNewWorker(new KResolverWorkerFactory<KStandardWorker>);
1045 
1046 #if HAVE_GETADDRINFO
1047     KResolverWorkerFactoryBase::registerNewWorker(new KResolverWorkerFactory<KGetAddrinfoWorker>);
1048 #endif
1049 }