diff options
author | Timothy Pearson <[email protected]> | 2011-11-06 15:56:40 -0600 |
---|---|---|
committer | Timothy Pearson <[email protected]> | 2011-11-06 15:56:40 -0600 |
commit | e16866e072f94410321d70daedbcb855ea878cac (patch) | |
tree | ee3f52eabde7da1a0e6ca845fb9c2813cf1558cf /tdecore/network/kresolverstandardworkers.cpp | |
parent | a58c20c1a7593631a1b50213c805507ebc16adaf (diff) | |
download | tdelibs-e16866e072f94410321d70daedbcb855ea878cac.tar.gz tdelibs-e16866e072f94410321d70daedbcb855ea878cac.zip |
Actually move the kde files that were renamed in the last commit
Diffstat (limited to 'tdecore/network/kresolverstandardworkers.cpp')
-rw-r--r-- | tdecore/network/kresolverstandardworkers.cpp | 1028 |
1 files changed, 1028 insertions, 0 deletions
diff --git a/tdecore/network/kresolverstandardworkers.cpp b/tdecore/network/kresolverstandardworkers.cpp new file mode 100644 index 000000000..6236cc15d --- /dev/null +++ b/tdecore/network/kresolverstandardworkers.cpp @@ -0,0 +1,1028 @@ +/* -*- C++ -*- + * Copyright (C) 2003,2004 Thiago Macieira <[email protected]> + * + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#include <config.h> + +#include <sys/types.h> +#include <sys/socket.h> +#include <sys/un.h> +#include <netinet/in.h> +#include <netdb.h> +#include <errno.h> +#include <string.h> +#include <stdlib.h> +#include <unistd.h> + +#ifdef HAVE_NET_IF_H +#include <net/if.h> +#endif + +#include <tqthread.h> +#include <tqmutex.h> +#include <tqstrlist.h> +#include <tqfile.h> + +#include "kdebug.h" +#include "kglobal.h" +#include "kstandarddirs.h" +#include "kapplication.h" + +#include "kresolver.h" +#include "ksocketaddress.h" +#include "kresolverstandardworkers_p.h" + +struct hostent; +struct addrinfo; + +using namespace KNetwork; +using namespace KNetwork::Internal; + +static bool hasIPv6() +{ +#ifndef AF_INET6 + return false; +#else + if (getenv("KDE_NO_IPV6") != 0L) + return false; + + int fd = ::socket(AF_INET6, SOCK_STREAM, 0); + if (fd == -1) + return false; + + ::close(fd); + return true; +#endif +} + +// blacklist management +static TQMutex blacklistMutex; // KDE4: change to a QReadWriteLock +TQStringList KBlacklistWorker::blacklist; + +void KBlacklistWorker::init() +{ + // HACK! + // FIXME KDE4: How do I detect there is an instance, without triggering + // its creation or an assertion fault? + if (!KGlobal::_instance) + return; + + static bool beenhere = false; + + if (beenhere) + return; + + beenhere = true; + loadBlacklist(); +} + +void KBlacklistWorker::loadBlacklist() +{ + TQMutexLocker locker(&blacklistMutex); + TQStringList filelist = KGlobal::dirs()->findAllResources("config", "ipv6blacklist"); + + TQStringList::ConstIterator it = filelist.constBegin(), + end = filelist.constEnd(); + for ( ; it != end; ++it) + { + // for each file, each line is a domainname to be blacklisted + TQFile f(*it); + if (!f.open(IO_ReadOnly)) + continue; + + TQTextStream stream(&f); + stream.setEncoding(TQTextStream::Latin1); + for (TQString line = stream.readLine(); !line.isNull(); + line = stream.readLine()) + { + if (line.isEmpty()) + continue; + + // make sure there are no surrounding whitespaces + // and that it starts with . + line = line.stripWhiteSpace(); + if (line[0] != '.') + line.prepend('.'); + + blacklist.append(line.lower()); + } + } +} + +// checks the blacklist to see if the domain is listed +// it matches the domain ending part +bool KBlacklistWorker::isBlacklisted(const TQString& host) +{ + KBlacklistWorker::init(); + + // empty hostnames cannot be blacklisted + if (host.isEmpty()) + return false; + + // KDE4: QLatin1String + TQString ascii = TQString::tqfromLatin1(KResolver::domainToAscii(host)); + + TQMutexLocker locker(&blacklistMutex); + + // now find out if this hostname is present + TQStringList::ConstIterator it = blacklist.constBegin(), + end = blacklist.constEnd(); + for ( ; it != end; ++it) + if (ascii.endsWith(*it)) + return true; + + // no match: + return false; +} + +bool KBlacklistWorker::preprocess() +{ + if (isBlacklisted(nodeName())) + { + results.setError(KResolver::NoName); + finished(); + return true; + } + return false; +} + +bool KBlacklistWorker::run() +{ + results.setError(KResolver::NoName); + finished(); + return false; // resolution failure +} + +namespace +{ + /* + * Note on the use of the system resolver functions: + * + * In all cases, we prefer to use the new getaddrinfo(3) call. That means + * it will always be used if it is found. + * + * If it's not found, we have the option to use gethostbyname2_r, + * gethostbyname_r, gethostbyname2 and gethostbyname. If gethostbyname2_r + * is defined, we will use it. + * + * If it's not defined, we have to choose between the non-reentrant + * gethostbyname2 and the reentrant but IPv4-only gethostbyname_r: + * we will choose gethostbyname2 if AF_INET6 is defined. + * + * Lastly, gethostbyname will be used if nothing else is present. + */ + +#ifndef HAVE_GETADDRINFO + +# if defined(HAVE_GETHOSTBYNAME2_R) +# define USE_GETHOSTBYNAME2_R +# elif defined(HAVE_GETHOSTBYNAME_R) && (!defined(AF_INET6) || !defined(HAVE_GETHOSTBYNAME2)) +# define USE_GETHOSTBYNAME_R +# elif defined(HAVE_GETHOSTBYNAME2) +# define USE_GETHOSTBYNAME2) +# else +# define USE_GETHOSTBYNAME +# endif + + class GetHostByNameThread: public KResolverWorkerBase + { + public: + TQCString m_hostname; // might be different! + TQ_UINT16 m_port; + int m_scopeid; + int m_af; + KResolverResults& results; + + GetHostByNameThread(const char * hostname, TQ_UINT16 port, + int scopeid, int af, KResolverResults* res) : + m_hostname(hostname), m_port(port), m_scopeid(scopeid), m_af(af), + results(*res) + { } + + ~GetHostByNameThread() + { } + + virtual bool preprocess() + { return true; } + + virtual bool run(); + + void processResults(hostent* he, int my_h_errno); + }; + + bool GetHostByNameThread::run() + { + + hostent *resultptr; + hostent my_results; + unsigned buflen = 1024; + int res; + int my_h_errno; + char *buf = 0L; + + // qDebug("ResolveThread::run(): started threaded gethostbyname for %s (af = %d)", + // m_hostname.data(), m_af); + + ResolverLocker resLock( this ); + do + { + res = 0; + my_h_errno = HOST_NOT_FOUND; + + // check blacklist + if (m_af != AF_INET && + KBlacklistWorker::isBlacklisted(TQString::tqfromLatin1(m_hostname))) + break; + +# ifdef USE_GETHOSTBYNAME2_R + buf = new char[buflen]; + res = gethostbyname2_r(m_hostname, m_af, &my_results, buf, buflen, + &resultptr, &my_h_errno); + +# elif defined(USE_GETHOSTBYNAME_R) + if (m_af == AF_INET) + { + buf = new char[buflen]; + res = gethostbyname_r(m_hostname, &my_results, buf, buflen, + &resultptr, &my_h_errno); + } + else + resultptr = 0; // signal error + +# elif defined(USE_GETHOSTBYNAME2) + // must lock mutex + resultptr = gethostbyname2(m_hostname, m_af); + my_h_errno = h_errno; + +# else + if (m_af == AF_INET) + { + // must lock mutex + resultptr = gethostbyname(m_hostname); + my_h_errno = h_errno; + } + else + resultptr = 0; +# endif + + if (resultptr != 0L) + my_h_errno = 0; + // qDebug("GetHostByNameThread::run(): gethostbyname for %s (af = %d) returned: %d", + // m_hostname.data(), m_af, my_h_errno); + + if (res == ERANGE) + { + // Enlarge the buffer + buflen += 1024; + delete [] buf; + buf = new char[buflen]; + } + + if ((res == ERANGE || my_h_errno != 0) && checkResolver()) + { + // resolver needs updating, so we might as well do it now + resLock.openClose(); + } + } + while (res == ERANGE); + processResults(resultptr, my_h_errno); + + delete [] buf; + + finished(); + return results.error() == KResolver::NoError; + } + + void GetHostByNameThread::processResults(hostent *he, int herrno) + { + if (herrno) + { + qDebug("KStandardWorker::processResults: got error %d", herrno); + switch (herrno) + { + case HOST_NOT_FOUND: + results.setError(KResolver::NoName); + return; + + case TRY_AGAIN: + results.setError(KResolver::TryAgain); + return; + + case NO_RECOVERY: + results.setError(KResolver::NonRecoverable); + return; + + case NO_ADDRESS: + results.setError(KResolver::NoName); + return; + + default: + results.setError(KResolver::UnknownError); + return; + } + } + else if (he == 0L) + { + results.setError(KResolver::NoName); + return; // this was an error + } + + // clear any errors + setError(KResolver::NoError); + results.setError(KResolver::NoError); + + // we process results in the reverse order + // that is, we prepend each result to the list of results + int proto = protocol(); + int socktype = socketType(); + if (socktype == 0) + socktype = SOCK_STREAM; // default + + TQString canon = KResolver::domainToUnicode(TQString::tqfromLatin1(he->h_name)); + KInetSocketAddress sa; + sa.setPort(m_port); + if (he->h_addrtype != AF_INET) + sa.setScopeId(m_scopeid); // this will also change the socket into IPv6 + + for (int i = 0; he->h_addr_list[i]; i++) + { + sa.setHost(KIpAddress(he->h_addr_list[i], he->h_addrtype == AF_INET ? 4 : 6)); + results.prepend(KResolverEntry(sa, socktype, proto, canon, m_hostname)); + // qDebug("KStandardWorker::processResults: adding %s", sa.toString().latin1()); + } + // qDebug("KStandardWorker::processResults: added %d entries", i); + } + +#else // HAVE_GETADDRINFO + + class GetAddrInfoThread: public KResolverWorkerBase + { + public: + TQCString m_node; + TQCString m_serv; + int m_af; + int m_flags; + KResolverResults& results; + + GetAddrInfoThread(const char* node, const char* serv, int af, int flags, + KResolverResults* res) : + m_node(node), m_serv(serv), m_af(af), m_flags(flags), results(*res) + { } + + ~GetAddrInfoThread() + { } + + virtual bool preprocess() + { return true; } + + virtual bool run(); + + void processResults(addrinfo* ai, int ret_code, KResolverResults& rr); + }; + + bool GetAddrInfoThread::run() + { + // check blacklist + if ((m_af != AF_INET && m_af != AF_UNSPEC) && + KBlacklistWorker::isBlacklisted(TQString::tqfromLatin1(m_node))) + { + results.setError(KResolver::NoName); + finished(); + return false; // failed + } + + do + { + ResolverLocker resLock( this ); + + // process hints + addrinfo hint; + memset(&hint, 0, sizeof(hint)); + hint.ai_family = m_af; + hint.ai_socktype = socketType(); + hint.ai_protocol = protocol(); + + if (hint.ai_socktype == 0) + hint.ai_socktype = SOCK_STREAM; // default + + if (m_flags & KResolver::Passive) + hint.ai_flags |= AI_PASSIVE; + if (m_flags & KResolver::CanonName) + hint.ai_flags |= AI_CANONNAME; +# ifdef AI_NUMERICHOST + if (m_flags & KResolver::NoResolve) + hint.ai_flags |= AI_NUMERICHOST; +# endif +# ifdef AI_ADDRCONFIG + hint.ai_flags |= AI_ADDRCONFIG; +# endif + + // now we do the blocking processing + if (m_node.isEmpty()) + m_node = "*"; + + addrinfo *result; + int res = getaddrinfo(m_node, m_serv, &hint, &result); + // kdDebug(179) << k_funcinfo << "getaddrinfo(\"" + // << m_node << "\", \"" << m_serv << "\", af=" + // << m_af << ") returned " << res << endl; + + if (res != 0) + { + if (checkResolver()) + { + // resolver requires reinitialisation + resLock.openClose(); + continue; + } + + switch (res) + { + case EAI_BADFLAGS: + results.setError(KResolver::BadFlags); + break; + +#ifdef EAI_NODATA + // In some systems, EAI_NODATA was #define'd to EAI_NONAME which would break this case. +#if EAI_NODATA != EAI_NONAME + case EAI_NODATA: // it was removed in RFC 3493 +#endif +#endif + case EAI_NONAME: + results.setError(KResolver::NoName); + break; + + case EAI_AGAIN: + results.setError(KResolver::TryAgain); + break; + + case EAI_FAIL: + results.setError(KResolver::NonRecoverable); + break; + + case EAI_FAMILY: + results.setError(KResolver::UnsupportedFamily); + break; + + case EAI_SOCKTYPE: + results.setError(KResolver::UnsupportedSocketType); + break; + + case EAI_SERVICE: + results.setError(KResolver::UnsupportedService); + break; + + case EAI_MEMORY: + results.setError(KResolver::Memory); + break; + + case EAI_SYSTEM: + results.setError(KResolver::SystemError, errno); + break; + + default: + results.setError(KResolver::UnknownError, errno); + break; + } + + finished(); + return false; // failed + } + + // if we are here, lookup succeeded + TQString canon; + const char *previous_canon = 0L; + + for (addrinfo* p = result; p; p = p->ai_next) + { + // cache the last canon name to avoid doing the ToUnicode processing unnecessarily + if ((previous_canon && !p->ai_canonname) || + (!previous_canon && p->ai_canonname) || + (p->ai_canonname != previous_canon && + strcmp(p->ai_canonname, previous_canon) != 0)) + { + canon = KResolver::domainToUnicode(TQString::fromAscii(p->ai_canonname)); + previous_canon = p->ai_canonname; + } + + results.append(KResolverEntry(p->ai_addr, p->ai_addrlen, p->ai_socktype, + p->ai_protocol, canon, m_node)); + } + + freeaddrinfo(result); + results.setError(KResolver::NoError); + finished(); + return results.error() == KResolver::NoError; + } + while (true); + } + +#endif // HAVE_GETADDRINFO +} // namespace + +bool KStandardWorker::sanityCheck() +{ + // check that the requested values are sensible + + if (!nodeName().isEmpty()) + { + TQString node = nodeName(); + if (node.find('%') != -1) + node.truncate(node.find('%')); + + if (node.isEmpty() || node == TQString::tqfromLatin1("*") || + node == TQString::tqfromLatin1("localhost")) + m_encodedName.truncate(0); + else + { + m_encodedName = KResolver::domainToAscii(node); + + if (m_encodedName.isNull()) + { + qDebug("could not encode hostname '%s' (UTF-8)", node.utf8().data()); + setError(KResolver::NoName); + return false; // invalid hostname! + } + + // qDebug("Using encoded hostname '%s' for '%s' (UTF-8)", m_encodedName.data(), + // node.utf8().data()); + } + } + else + m_encodedName.truncate(0); // just to be sure, but it should be clear already + + if (protocol() == -1) + { + setError(KResolver::NonRecoverable); + return false; // user passed invalid protocol name + } + + return true; // it's sane +} + +bool KStandardWorker::resolveScopeId() +{ + // we must test the original name, not the encoded one + scopeid = 0; + int pos = nodeName().findRev('%'); + if (pos == -1) + return true; + + TQString scopename = nodeName().mid(pos + 1); + + bool ok; + scopeid = scopename.toInt(&ok); + if (!ok) + { + // it's not a number + // therefore, it's an interface name +#ifdef HAVE_IF_NAMETOINDEX + scopeid = if_nametoindex(scopename.latin1()); +#else + scopeid = 0; +#endif + } + + return true; +} + +bool KStandardWorker::resolveService() +{ + // find the service first + bool ok; + port = serviceName().toUInt(&ok); + if (!ok) + { + // service name does not contain a port number + // must be a name + + if (serviceName().isEmpty() || serviceName().compare(TQString::tqfromLatin1("*")) == 0) + port = 0; + else + { + // it's a name. We need the protocol name in order to lookup. + TQCString protoname = protocolName(); + + if (protoname.isEmpty() && protocol()) + { + protoname = KResolver::protocolName(protocol()).first(); + + // if it's still empty... + if (protoname.isEmpty()) + { + // lookup failed! + setError(KResolver::NoName); + return false; + } + } + else + protoname = "tcp"; + + // it's not, so we can do a port lookup + int result = KResolver::servicePort(serviceName().latin1(), protoname); + if (result == -1) + { + // lookup failed! + setError(KResolver::NoName); + return false; + } + + // it worked, we have a port number + port = (TQ_UINT16)result; + } + } + + // we found a port + return true; +} + +KResolver::ErrorCodes KStandardWorker::addUnix() +{ + // before trying to add, see if the user wants Unix sockets + if ((familyMask() & KResolver::UnixFamily) == 0) + // no, Unix sockets are not wanted + return KResolver::UnsupportedFamily; + + // now check if the requested data are good for a Unix socket + if (!m_encodedName.isEmpty()) + return KResolver::AddrFamily; // non local hostname + + if (protocol() || !protocolName().isEmpty()) + return KResolver::BadFlags; // cannot have Unix sockets with protocols + + TQString pathname = serviceName(); + if (pathname.isEmpty()) + return KResolver::NoName;; // no path? + + if (pathname[0] != '/') + // non absolute pathname + // put it in /tmp + pathname.prepend("/tmp/"); + + // qDebug("QNoResolveWorker::addUnix(): adding Unix socket for %s", pathname.local8Bit().data()); + KUnixSocketAddress sa(pathname); + int socktype = socketType(); + if (socktype == 0) + socktype = SOCK_STREAM; // default + + results.append(KResolverEntry(sa, socktype, 0)); + setError(KResolver::NoError); + + return KResolver::NoError; +} + +bool KStandardWorker::resolveNumerically() +{ + // if the NoResolve flag is active, our result from this point forward + // will always be true, even if the resolution failed. + // that indicates that our result is authoritative. + + bool wantV4 = familyMask() & KResolver::IPv4Family, + wantV6 = familyMask() & KResolver::IPv6Family; + + if (!wantV6 && !wantV4) + // no Internet address is wanted! + return (flags() & KResolver::NoResolve); + + // now try to find results + if (!resolveScopeId() || !resolveService()) + return (flags() & KResolver::NoResolve); + + // we have scope IDs and port numbers + // now try to resolve the hostname numerically + KInetSocketAddress sa; + setError(KResolver::NoError); + sa.setHost(KIpAddress(TQString::tqfromLatin1(m_encodedName))); + + // if it failed, the length was reset to 0 + bool ok = sa.length() != 0; + + sa.setPort(port); + if (sa.ipVersion() == 6) + sa.setScopeId(scopeid); + int proto = protocol(); + int socktype = socketType(); + if (socktype == 0) + socktype = SOCK_STREAM; + + if (ok) + { + // the given hostname was successfully converted to an IP address + // check if the user wanted this kind of address + + if ((sa.ipVersion() == 4 && wantV4) || + (sa.ipVersion() == 6 && wantV6)) + results.append(KResolverEntry(sa, socktype, proto)); + else + { + // Note: the address *IS* a numeric IP + // but it's not of the kind the user asked for + // + // that means that it cannot be a Unix socket (because it's an IP) + // and that means that no resolution will tell us otherwise + // + // This is a failed resolution + + setError(KResolver::AddrFamily); + return true; + } + } + else if (m_encodedName.isEmpty()) + { + // user wanted localhost + if (flags() & KResolver::Passive) + { + if (wantV6) + { + sa.setHost(KIpAddress::anyhostV6); + results.append(KResolverEntry(sa, socktype, proto)); + } + + if (wantV4) + { + sa.setHost(KIpAddress::anyhostV4); + results.append(KResolverEntry(sa, socktype, proto)); + } + } + else + { + if (wantV6) + { + sa.setHost(KIpAddress::localhostV6); + results.append(KResolverEntry(sa, socktype, proto)); + } + + if (wantV4) + { + sa.setHost(KIpAddress::localhostV4); + results.append(KResolverEntry(sa, socktype, proto)); + } + } + + ok = true; + } + else + { + // probably bad flags, since the address is not convertible without + // resolution + + setError(KResolver::BadFlags); + ok = false; + } + + return ok || (flags() & KResolver::NoResolve); +} + +bool KStandardWorker::preprocess() +{ + // check sanity + if (!sanityCheck()) + return false; + + // this worker class can only handle known families + if (familyMask() & KResolver::UnknownFamily) + { + setError(KResolver::UnsupportedFamily); + return false; // we don't know about this + } + + // check the socket types + if (socketType() != SOCK_STREAM && socketType() != SOCK_DGRAM && socketType() != 0) + { + setError(KResolver::UnsupportedSocketType); + return false; + } + + // check if we can resolve all numerically + // resolveNumerically always returns true if the NoResolve flag is set + if (resolveNumerically() || m_encodedName.isEmpty()) + { + // indeed, we have resolved numerically + setError(addUnix()); + if (results.count()) + setError(KResolver::NoError); + finished(); + return true; + } + + // check if the user wants something we know about +#ifdef AF_INET6 +# define mask (KResolver::IPv6Family | KResolver::IPv4Family | KResolver::UnixFamily) +#else +# define mask (KResolver::IPv4Family | KResolver::UnixFamily) +#endif + + if ((familyMask() & mask) == 0) + // errr... nothing we know about + return false; + +#undef mask + + return true; // it's ok +} + +bool KStandardWorker::run() +{ +#ifndef HAVE_GETADDRINFO + // check the scope id first + // since most of the resolutions won't have a scope id, this should be fast + // and we won't have wasted time on services if this fails + if (!resolveScopeId()) + return false; + + // resolve the service now, before entering the blocking operation + if (!resolveService()) + return false; +#endif + + // good + // now we need the hostname + setError(KResolver::NoName); + + // these are the family types that we know of + struct + { + KResolver::SocketFamilies mask; + int af; + } families[] = { { KResolver::IPv4Family, AF_INET } +#ifdef AF_INET6 + , { KResolver::IPv6Family, AF_INET6 } +#endif + }; + int familyCount = sizeof(families)/sizeof(families[0]); + bool skipIPv6 = !hasIPv6(); + resultList.setAutoDelete(true); + + for (int i = 0; i < familyCount; i++) + if (familyMask() & families[i].mask) + { +#ifdef AF_INET6 + if (skipIPv6 && families[i].af == AF_INET6) + continue; +#endif + + KResolverWorkerBase *worker; + KResolverResults *res = new KResolverResults; + resultList.append(res); +#ifdef HAVE_GETADDRINFO + worker = new GetAddrInfoThread(m_encodedName, + serviceName().latin1(), + families[i].af, flags(), res); +#else + worker = new GetHostByNameThread(m_encodedName, port, scopeid, + families[i].af, res); +#endif + + enqueue(worker); + } + + // not finished + return true; +} + +bool KStandardWorker::postprocess() +{ + if (results.count()) + return true; // no need + // now copy over what we need from the underlying results + + // start backwards because IPv6 was launched later (if at all) + if (resultList.isEmpty()) + { + results.setError(KResolver::NoName); + return true; + } + + KResolverResults *rr = resultList.last(); + while (rr) + { + if (!rr->isEmpty()) + { + results.setError(KResolver::NoError); + KResolverResults::Iterator it = rr->begin(); + for ( ; it != rr->end(); ++it) + results.append(*it); + } + else if (results.isEmpty()) + // this generated an error + // copy the error code over + setError(rr->error(), rr->systemError()); + + rr = resultList.prev(); + } + + resultList.clear(); + return true; +} + +#ifdef HAVE_GETADDRINFO +KGetAddrinfoWorker::~KGetAddrinfoWorker() +{ +} + +bool KGetAddrinfoWorker::preprocess() +{ + // getaddrinfo(3) can always handle any kind of request that makes sense + if (!sanityCheck()) + return false; + + if (flags() & KResolver::NoResolve) + // oops, numeric resolution? + return run(); + + return true; +} + +bool KGetAddrinfoWorker::run() +{ + // make an AF_UNSPEC getaddrinfo(3) call + GetAddrInfoThread worker(m_encodedName, serviceName().latin1(), + AF_UNSPEC, flags(), &results); + + if (!worker.run()) + { + if (wantThis(AF_UNIX)) + { + if (addUnix() == KResolver::NoError) + setError(KResolver::NoError); + } + else + setError(worker.results.error(), worker.results.systemError()); + + return false; + } + + // The worker has finished working + // now copy over only what we may want + // keep track of any Unix-domain sockets + + bool seen_unix = false; + KResolverResults::Iterator it = results.begin(); + for ( ; it != results.end(); ) + { + if ((*it).family() == AF_UNIX) + seen_unix = true; + if (!wantThis((*it).family())) + it = results.remove(it); + else + ++it; + } + + if (!seen_unix) + addUnix(); + + finished(); + return true; +} + +bool KGetAddrinfoWorker::wantThis(int family) +{ + // tells us if the user wants a socket of this family + +#ifdef AF_INET6 + if (family == AF_INET6 && familyMask() & KResolver::IPv6Family) + return true; +#endif + if (family == AF_INET && familyMask() & KResolver::IPv4Family) + return true; + if (family == AF_UNIX && familyMask() & KResolver::UnixFamily) + return true; + + // it's not a family we know about... + if (familyMask() & KResolver::UnknownFamily) + return true; + + return false; +} + +#endif + +void KNetwork::Internal::initStandardWorkers() +{ + //KResolverWorkerFactoryBase::registerNewWorker(new KResolverWorkerFactory<KBlacklistWorker>); + KResolverWorkerFactoryBase::registerNewWorker(new KResolverWorkerFactory<KStandardWorker>); + +#ifdef HAVE_GETADDRINFO + KResolverWorkerFactoryBase::registerNewWorker(new KResolverWorkerFactory<KGetAddrinfoWorker>); +#endif +} |