kresolverstandardworkers.cpp
来自「konqueror3 embedded版本, KDE环境下的当家浏览器的嵌入式版」· C++ 代码 · 共 1,029 行 · 第 1/2 页
CPP
1,029 行
/* -*- C++ -*- * Copyright (C) 2003,2004 Thiago Macieira <thiago.macieira@kdemail.net> * * * 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 <qthread.h>#include <qmutex.h>#include <qstrlist.h>#include <qfile.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 managementstatic QMutex blacklistMutex; // KDE4: change to a QReadWriteLockQStringList 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(){ QMutexLocker locker(&blacklistMutex); QStringList filelist = KGlobal::dirs()->findAllResources("config", "ipv6blacklist"); QStringList::ConstIterator it = filelist.constBegin(), end = filelist.constEnd(); for ( ; it != end; ++it) { // for each file, each line is a domainname to be blacklisted QFile f(*it); if (!f.open(IO_ReadOnly)) continue; QTextStream stream(&f); stream.setEncoding(QTextStream::Latin1); for (QString 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 partbool KBlacklistWorker::isBlacklisted(const QString& host){ KBlacklistWorker::init(); // empty hostnames cannot be blacklisted if (host.isEmpty()) return false; // KDE4: QLatin1String QString ascii = QString::fromLatin1(KResolver::domainToAscii(host)); QMutexLocker locker(&blacklistMutex); // now find out if this hostname is present QStringList::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: QCString m_hostname; // might be different! Q_UINT16 m_port; int m_scopeid; int m_af; KResolverResults& results; GetHostByNameThread(const char * hostname, Q_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(QString::fromLatin1(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 QString canon = KResolver::domainToUnicode(QString::fromLatin1(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: QCString m_node; QCString 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(QString::fromLatin1(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 QString canon; const char *previous_canon = 0L;
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?