kextsock.cpp
来自「konqueror3 embedded版本, KDE环境下的当家浏览器的嵌入式版」· C++ 代码 · 共 2,230 行 · 第 1/4 页
CPP
2,230 行
/* * This file is part of the KDE libraries * Copyright (C) 2000-2004 Thiago Macieira <thiago.macieira@kdemail.net> * * 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., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. **/#include <config.h>#include <sys/types.h>#include <sys/socket.h>#include <sys/times.h>#include <netinet/in.h>#include <arpa/inet.h>#include <sys/un.h>#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 <qguardedptr.h>#include "kresolver.h"#include "kdebug.h"#include "kextsock.h"#include "ksockaddr.h"#include "ksocks.h"#ifdef __CYGWIN__#include "netsupp.h"#endif using namespace KNetwork;//// Internal class definitions//class KExtendedSocketPrivate{public: int flags; // socket flags int status; // status int syserror; // the system error value timeval timeout; // connection/acception timeout KResolver resRemote; // the resolved addresses KResolver resLocal; // binding resolution unsigned current; // used by the asynchronous connection ::KSocketAddress *local; // local socket address ::KSocketAddress *peer; // peer socket address QSocketNotifier *qsnIn, *qsnOut; int inMaxSize, outMaxSize; bool emitRead : 1, emitWrite : 1; mutable bool addressReusable : 1, ipv6only : 1; KExtendedSocketPrivate() : flags(0), status(0), syserror(0), current(0), local(0), peer(0), qsnIn(0), qsnOut(0), inMaxSize(-1), outMaxSize(-1), emitRead(false), emitWrite(false), addressReusable(false), ipv6only(false) { timeout.tv_sec = timeout.tv_usec = 0; }};// translate KExtendedSocket flags into KResolver onesstatic bool process_flags(int flags, int& socktype, int& familyMask, int& outflags){ switch (flags & (KExtendedSocket::streamSocket | KExtendedSocket::datagramSocket | KExtendedSocket::rawSocket)) { case 0: /* No flags given, use default */ case KExtendedSocket::streamSocket: /* streaming socket requested */ socktype = SOCK_STREAM; break; case KExtendedSocket::datagramSocket: /* datagram packet socket requested */ socktype = SOCK_DGRAM; break; case KExtendedSocket::rawSocket: /* raw socket requested. I wouldn't do this if I were you... */ socktype = SOCK_RAW; break; default: /* the flags were used in an invalid manner */ return false; } if (flags & KExtendedSocket::knownSocket) { familyMask = 0; if ((flags & KExtendedSocket::unixSocket) == KExtendedSocket::unixSocket) familyMask |= KResolver::UnixFamily; switch ((flags & (KExtendedSocket::ipv6Socket|KExtendedSocket::ipv4Socket))) { case KExtendedSocket::ipv4Socket: familyMask |= KResolver::IPv4Family; break; case KExtendedSocket::ipv6Socket: familyMask |= KResolver::IPv6Family; break; case KExtendedSocket::inetSocket: familyMask |= KResolver::InternetFamily; break; } // those are all the families we know about } else familyMask = KResolver::KnownFamily; /* check other flags */ outflags = (flags & KExtendedSocket::passiveSocket ? KResolver::Passive : 0) | (flags & KExtendedSocket::canonName ? KResolver::CanonName : 0) | (flags & KExtendedSocket::noResolve ? KResolver::NoResolve : 0); if (getenv("KDE_NO_IPV6")) familyMask &= ~KResolver::IPv6Family; return true;}// "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;}/* * class KExtendedSocket */// default constructorKExtendedSocket::KExtendedSocket() : sockfd(-1), d(new KExtendedSocketPrivate){}// constructor with hostnameKExtendedSocket::KExtendedSocket(const QString& host, int port, int flags) : sockfd(-1), d(new KExtendedSocketPrivate){ setAddress(host, port); setSocketFlags(flags);}// sameKExtendedSocket::KExtendedSocket(const QString& host, const QString& service, int flags) : sockfd(-1), d(new KExtendedSocketPrivate){ setAddress(host, service); setSocketFlags(flags);}// destroy the classKExtendedSocket::~KExtendedSocket(){ closeNow(); 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;}void KExtendedSocket::reset(){ closeNow(); release(); d->current = 0; d->status = nothing; d->syserror = 0;}int KExtendedSocket::socketStatus() const{ return d->status;}void KExtendedSocket::setSocketStatus(int newstatus){ d->status = newstatus;}void KExtendedSocket::setError(int errorcode, int syserror){ setStatus(errorcode); d->syserror = syserror;}int KExtendedSocket::systemError() const{ return d->syserror;}/* * Sets socket flags * This is only allowed if we are in nothing state */int KExtendedSocket::setSocketFlags(int flags){ if (d->status > nothing) return -1; // error! return d->flags = flags;}int KExtendedSocket::socketFlags() const{ return d->flags;}/* * Sets socket target hostname * This is only allowed if we are in nothing state */bool KExtendedSocket::setHost(const QString& host){ if (d->status > nothing) return false; // error! d->resRemote.setNodeName(host); return true;}/* * returns the hostname */QString KExtendedSocket::host() const{ return d->resRemote.nodeName();}/* * 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 (d->status > nothing) return false; // error d->resRemote.setServiceName(service); return true;}/* * returns the service port number */QString KExtendedSocket::port() const{ return d->resRemote.serviceName();}/* * 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 not a * passiveSocket socket */bool KExtendedSocket::setBindHost(const QString& host){ if (d->status > nothing || d->flags & passiveSocket) return false; // error d->resLocal.setServiceName(host); return true;}/* * Unsets the bind hostname * same thing */bool KExtendedSocket::unsetBindHost(){ return setBindHost(QString::null);}/* * returns the binding host */QString KExtendedSocket::bindHost() const{ return d->resLocal.serviceName();}/* * 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 (d->status > nothing || d->flags & passiveSocket) return false; // error d->resLocal.setServiceName(service); return true;}/* * unsets the bind port */bool KExtendedSocket::unsetBindPort(){ return setBindPort(QString::null);}/* * returns the binding port */QString KExtendedSocket::bindPort() const{ return d->resLocal.serviceName();}/* * sets the binding address */bool KExtendedSocket::setBindAddress(const QString& host, int port){ return setBindHost(host) && setBindPort(port);}/* * same */bool KExtendedSocket::setBindAddress(const QString& host, const QString& service){ return setBindHost(host) && setBindPort(service);}/* * unsets binding address */bool KExtendedSocket::unsetBindAddress(){ return unsetBindHost() && unsetBindPort();}/* * sets the timeout for the connection */bool KExtendedSocket::setTimeout(int secs, int usecs){ if (d->status >= connected) // closed? return false; d->timeout.tv_sec = secs; d->timeout.tv_usec = usecs; return true;}/* * returns the timeout */timeval KExtendedSocket::timeout() const{ return d->timeout;}/* * Sets the blocking mode on this socket */bool KExtendedSocket::setBlockingMode(bool enable){ cleanError(); if (d->status < created) return false; if (sockfd == -1) return false; // error! int fdflags = fcntl(sockfd, F_GETFL, 0); if (fdflags == -1) return false; // error! if (!enable) fdflags |= O_NONBLOCK; else fdflags &= ~O_NONBLOCK; if (fcntl(sockfd, F_SETFL, fdflags) == -1) { setError(IO_UnspecifiedError, errno); return false; } return true;}/* * Returns the blocking mode on the socket */bool KExtendedSocket::blockingMode(){ cleanError(); if (d->status < created) return false; // sockets not created are in blocking mode if (sockfd == -1) return false; // error int fdflags = fcntl(sockfd, F_GETFL, 0); if (fdflags == -1) { setError(IO_UnspecifiedError, errno); return false; } return (fdflags & O_NONBLOCK) == 0; // non-blocking == false}/* * Sets the reusability flag for this socket in the OS */bool KExtendedSocket::setAddressReusable(bool enable){ cleanError(); d->addressReusable = enable; if (d->status < created) return true; if (sockfd == -1) return true; if (!setAddressReusable(sockfd, enable)) { setError(IO_UnspecifiedError, errno); return false; } return true;}bool KExtendedSocket::setAddressReusable(int fd, bool enable){ if (fd == -1) return false; int on = enable; // just to be on the safe side if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char*)&on, sizeof(on)) == -1) return false; return true;}/* * Retrieves the reusability flag for this socket */bool KExtendedSocket::addressReusable(){ cleanError(); if (d->status < created) return d->addressReusable; if (sockfd == -1) return d->addressReusable; int on; socklen_t onsiz = sizeof(on); if (getsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, (char*)&on, &onsiz) == -1) { setError(IO_UnspecifiedError, errno); return false; } return on != 0;}/* * Set the IPV6_V6ONLY flag */bool KExtendedSocket::setIPv6Only(bool enable){#ifdef IPV6_V6ONLY cleanError();
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?