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