kextsock.cpp

来自「将konqueror浏览器移植到ARM9 2410中」· C++ 代码 · 共 2,280 行 · 第 1/4 页

CPP
2,280
字号
/* *  This file is part of the KDE libraries *  Copyright (C) 2000,2001 Thiago Macieira <thiagom@mail.com> * *  $Id: kextsock.cpp,v 1.24.2.2 2001/10/24 19:43:45 waba Exp $ * *  This library is free software; you can redistribute it and/or *  modify it under the terms of the GNU Library General Public *  License as published by the Free Software Foundation; either *  version 2 of the License, or (at your option) any later version. * *  This library is distributed in the hope that it will be useful, *  but WITHOUT ANY WARRANTY; without even the implied warranty of *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU *  Library General Public License for more details. * *  You should have received a copy of the GNU Library General Public License *  along with this library; see the file COPYING.LIB.  If not, write to *  the Free Software Foundation, Inc., 59 Temple Place - Suite 330, *  Boston, MA 02111-1307, USA. **/#include <config.h>#include <sys/types.h>#include <sys/socket.h>#include <sys/times.h>#include <netinet/in.h>#include <sys/un.h>#ifdef HAVE_RES_INIT# include <arpa/nameser.h># include <resolv.h>#endif#include <stdio.h>#include <errno.h>#include <fcntl.h>#include <netdb.h>#include <stdlib.h>#include <unistd.h>#include <qglobal.h>#include <qstring.h>#include <qiodevice.h>#include <qsocketnotifier.h>#include <qdns.h>#include "kdebug.h"#include "kextsock.h"#include "ksockaddr.h"#include "ksocks.h"#ifndef HAVE_SOCKADDR_IN6// The system doesn't have sockaddr_in6// But we can tell netsupp.h to define it for us, according to the RFC#define CLOBBER_IN6#endif#include "netsupp.h"#include "kextsocklookup.h"//// Workarounds///* * getaddrinfo is defined in IEEE POSIX 1003.1g (Protocol Independent Interfaces) * and RFC 2553 (Basic Socket Interface for IPv6) extends that specification */#ifndef AI_NUMERICHOST	/* Some systems have getaddrinfo according to POSIX, but not the RFC */# define AI_NUMERICHOST		0#endif#ifdef offsetof# undef offsetof#endif#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)//// Internal class definitions//class KExtendedSocket::KExtendedSocketPrivate{public:  timeval timeout;		// connection/acception timeout  QString host;			// requested hostname  QString service;		// requested service  QString localhost;		// requested bind host or local hostname  QString localservice;		// requested bind service or local port  kde_addrinfo *resolution;	// the resolved addresses  kde_addrinfo *bindres;	// binding resolution  addrinfo *current;		// used by asynchronous connection  KSocketAddress *local;	// local socket address  KSocketAddress *peer;		// peer socket address  QSocketNotifier *qsnIn, *qsnOut;  int inMaxSize, outMaxSize;  bool emitRead, emitWrite;    KExtendedSocketLookup *dns, *dnsLocal;  KExtendedSocketPrivate() :    host(QString::null), service(QString::null), localhost(QString::null), localservice(QString::null),    resolution(0), bindres(0), current(0), local(0), peer(0),     qsnIn(0), qsnOut(0), inMaxSize(-1), outMaxSize(-1), emitRead(false), emitWrite(false),    dns(0), dnsLocal(0)  {    timeout.tv_sec = timeout.tv_usec = 0;  }};static bool process_flags(int flags, addrinfo &hint){  switch (flags & (KExtendedSocket::streamSocket | KExtendedSocket::datagramSocket | KExtendedSocket::rawSocket))    {    case 0:      /* No flags given, use default */    case KExtendedSocket::streamSocket:      /* streaming socket requested */      hint.ai_socktype = SOCK_STREAM;      break;    case KExtendedSocket::datagramSocket:      /* datagram packet socket requested */      hint.ai_socktype = SOCK_DGRAM;      break;    case KExtendedSocket::rawSocket:      /* raw socket requested. I wouldn't do this if I were you... */      hint.ai_socktype = SOCK_RAW;      break;    default:      /* the flags were used in an invalid manner */      return false;    }  /* check other flags */  hint.ai_flags |= (flags & KExtendedSocket::passiveSocket ? AI_PASSIVE : 0) |    (flags & KExtendedSocket::canonName ? AI_CANONNAME : 0) |    (flags & KExtendedSocket::noResolve ? AI_NUMERICHOST : 0);  return true;}static bool valid_family(addrinfo *p, int flags){  if (flags & KExtendedSocket::knownSocket)    {      if (p->ai_family == PF_INET)	{	  if (flags & 0x0e && (flags & 0x4) == 0)	    return false;	// user hasn't asked for Internet sockets	  if (flags & 0xf00 && (flags & 0x100) == 0)	    return false;	// user hasn't asked for IPv4 sockets	}#ifdef PF_INET6      else if (p->ai_family == PF_INET6)	{	  if (flags & 0x0e && (flags & 0x4) == 0)	    return false;	// user hasn't asked for Internet sockets	  if (flags & 0xf00 && (flags & 0x200) == 0)	    return false;	// user hasn't asked for IPv6 sockets	}#endif      else if (p->ai_family == PF_UNIX)	{	  if (flags & 0x0e && (flags & 0x2) == 0)	    return false;	// user hasn't asked for Unix Sockets	}      if (p->ai_family != PF_INET && p->ai_family != PF_UNIX#ifdef PF_INET6	  && p->ai_family != PF_INET6#endif	  )	return false;		// not a known socket      // if we got here, the family is acceptable    }  return true;}static QString pretty_sock(addrinfo *p){  KSocketAddress *sa;  QString ret;  sa = KSocketAddress::newAddress(p->ai_addr, p->ai_addrlen);  if (sa == NULL)    return QString::fromLocal8Bit("<invalid>");  switch (p->ai_family)    {    case AF_UNIX:      ret = QString::fromLocal8Bit("Unix ");      break;    case AF_INET:      ret = QString::fromLocal8Bit("Inet ");      break;#ifdef AF_INET6    case AF_INET6:      ret = QString::fromLocal8Bit("Inet6 ");      break;#endif    default:      ret = QString::fromLocal8Bit("<unknown> ");      break;    }  ret += sa->pretty();  return ret;}// "skips" at most len bytes from file descriptor fd// that is, we will try and read that much data and discard// it. We will stop when we have read those or when the read// function returns errorstatic int skipData(int fd, unsigned len){  char buf[1024];  unsigned skipped = 0;  while (len)    {      int count = sizeof(buf);      if ((unsigned)count > len)	count = len;      count = KSocks::self()->read(fd, buf, count);      if (count == -1)	return -1;      else	{	  len -= count;	  skipped += count;	}    }  return skipped;}// calls the correct deallocation routine// also uses by-reference parameter to simplify caller routines, because// we set the parameter to NULL after deallocationvoid local_freeaddrinfo(kde_addrinfo *&p){  if (p == NULL)    return;  if (p->origin == KAI_QDNS)    KExtendedSocketLookup::freeresults(p);  else    kde_freeaddrinfo(p);  p = NULL;}/* * class KExtendedSocketLookup (internal use) */kde_addrinfo* KExtendedSocketLookup::results(){  QValueList<QHostAddress> v4 = dnsIpv4.addresses(),    v6 = dnsIpv6.addresses();  addrinfo *p = NULL;  kde_addrinfo *res = new kde_addrinfo;  QValueList<QHostAddress>::Iterator it;  unsigned short port;  QString canon = dnsIpv4.canonicalName();  if (canon.isNull())    canon = dnsIpv6.canonicalName();  char* canonname;  if (!canon.isNull())    canonname = strdup(canon.latin1());  else    canonname = 0L;  if (hint.ai_socktype == 0)    hint.ai_socktype = SOCK_STREAM;  if (hint.ai_protocol == 0)    hint.ai_protocol = IPPROTO_TCP;  {    bool ok;    port = htons(servname.toUShort(&ok));    if (!ok)      {	struct servent *sent;	sent = getservbyname(servname.latin1(),			     hint.ai_protocol == SOCK_DGRAM ? "udp" : "tcp");	if (sent == NULL)	  port = 0;		// no service; error?	else	  port = sent->s_port;      }  }#ifdef AF_INET6  for (it = v6.begin(); it != v6.end(); ++it)    {      addrinfo *q = new addrinfo;      sockaddr_in6 *sin6 = new sockaddr_in6;      q->ai_flags = 0;      q->ai_family = AF_INET6;      q->ai_socktype = hint.ai_socktype;      q->ai_protocol = hint.ai_protocol;      q->ai_addrlen = sizeof(*sin6);      q->ai_addr = (sockaddr*)sin6;      q->ai_canonname = canonname;      q->ai_next = p;      memset(sin6, 0, sizeof(*sin6));# ifdef HAVE_SOCKADDR_SA_LEN      sin6->sin6_len = sizeof(*sin6);# endif      sin6->sin6_family = AF_INET6;      sin6->sin6_port = port;      KInetSocketAddress::stringToAddr(AF_INET6, (*it).toString().latin1(),				       (void*)&sin6->sin6_addr);      p = q;    }#endif  for (it = v4.begin(); it != v4.end(); ++it)    {      addrinfo *q = new addrinfo;      sockaddr_in *sin = new sockaddr_in;      q->ai_flags = 0;      q->ai_family = AF_INET;      q->ai_socktype = hint.ai_socktype;      q->ai_protocol = hint.ai_protocol;      q->ai_addrlen = sizeof(*sin);      q->ai_addr = (sockaddr*)sin;      q->ai_canonname = canonname;      q->ai_next = p;      memset(sin, 0, sizeof(*sin));# ifdef HAVE_SOCKADDR_SA_LEN      sin->sin_len = sizeof(*sin);# endif      sin->sin_family = AF_INET;      sin->sin_port = port;      *(Q_UINT32*)&sin->sin_addr = htonl((*it).ip4Addr());      p = q;    }  res->data = p;  return res;}void KExtendedSocketLookup::freeresults(kde_addrinfo *res){  addrinfo *ai = res->data;  if (ai->ai_canonname)    free(ai->ai_canonname);  while (ai)    {      struct addrinfo *ai2 = ai;      if (ai->ai_addr != NULL)	delete ai->ai_addr;      ai = ai->ai_next;      delete ai2;    }  delete res;}/* * class KExtendedSocket */// default constructorKExtendedSocket::KExtendedSocket() :  m_flags(0), m_status(0), m_syserror(0), sockfd(-1),  d(new KExtendedSocketPrivate){}// constructor with hostnameKExtendedSocket::KExtendedSocket(const QString& host, int port, int flags) :  m_flags(0), m_status(0), m_syserror(0), sockfd(-1),  d(new KExtendedSocketPrivate){  setAddress(host, port);  setSocketFlags(flags);}// sameKExtendedSocket::KExtendedSocket(const QString& host, const QString& service, int flags) :  m_flags(0), m_status(0), m_syserror(0), sockfd(-1),  d(new KExtendedSocketPrivate){  setAddress(host, service);  setSocketFlags(flags);}// destroy the classKExtendedSocket::~KExtendedSocket(){  closeNow();  local_freeaddrinfo(d->resolution);  local_freeaddrinfo(d->bindres);  if (d->local != NULL)    delete d->local;  if (d->peer != NULL)    delete d->peer;  if (d->qsnIn != NULL)    delete d->qsnIn;  if (d->qsnOut != NULL)    delete d->qsnOut;  delete d;}/* * Sets socket flags * This is only allowed if we are in nothing state */int KExtendedSocket::setSocketFlags(int flags){  if (m_status > nothing)    return -1;			// error!  return m_flags = flags;}/* * Sets socket target hostname * This is only allowed if we are in nothing state */bool KExtendedSocket::setHost(const QString& host){  if (m_status > nothing)    return false;		// error!  d->host = host;  return true;}/* * returns the hostname */QString KExtendedSocket::host() const{   return d->host; }/* * Sets the socket target port/service * Same thing: only state 'nothing' */bool KExtendedSocket::setPort(int port){  return setPort(QString::number(port));}bool KExtendedSocket::setPort(const QString& service){  if (m_status > nothing)    return false;		// error  d->service = service;  return true;}/* * returns the service port number */QString KExtendedSocket::port() const{   return d->service; }/* * sets the address */bool KExtendedSocket::setAddress(const QString& host, int port){   return setHost(host) && setPort(port); }/* * the same */bool KExtendedSocket::setAddress(const QString& host, const QString& serv){   return setHost(host) && setPort(serv); }/* * Sets the bind hostname * This is only valid in the 'nothing' state and if this is a  * passiveSocket socket */bool KExtendedSocket::setBindHost(const QString& host){  if (m_status > nothing || m_flags & passiveSocket)    return false;		// error  d->localhost = host;  return true;}/* * Unsets the bind hostname * same thing */bool KExtendedSocket::unsetBindHost(){  if (m_status > nothing || m_flags & passiveSocket)    return false;		// error  d->localhost.truncate(0);  return true;}/* * returns the binding host */QString KExtendedSocket::bindHost() const{  return d->localhost;}/* * Sets the bind port * Same condition as setBindHost */bool KExtendedSocket::setBindPort(int port){  return setBindPort(QString::number(port));}bool KExtendedSocket::setBindPort(const QString& service){  if (m_status > nothing || m_flags & passiveSocket)    return false;		// error  d->localservice = service;  return true;}/* * unsets the bind port */bool KExtendedSocket::unsetBindPort(){  if (m_status > nothing || m_flags & passiveSocket)    return false;  d->localservice.truncate(0);  return true;}/*

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?