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 + -
显示快捷键?