diff options
Diffstat (limited to 'kdecore/kextsock.cpp')
-rw-r--r-- | kdecore/kextsock.cpp | 2251 |
1 files changed, 0 insertions, 2251 deletions
diff --git a/kdecore/kextsock.cpp b/kdecore/kextsock.cpp deleted file mode 100644 index 5aad239bd..000000000 --- a/kdecore/kextsock.cpp +++ /dev/null @@ -1,2251 +0,0 @@ -/* - * 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 <tqglobal.h> -#include <tqstring.h> -#include <tqiodevice.h> -#include <tqsocketnotifier.h> -#include <tqguardedptr.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 - - TQSocketNotifier *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 ones -static 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 error -static 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 constructor -KExtendedSocket::KExtendedSocket() : - sockfd(-1), d(new KExtendedSocketPrivate) -{ -} - -// constructor with hostname -KExtendedSocket::KExtendedSocket(const TQString& host, int port, int flags) : - sockfd(-1), d(new KExtendedSocketPrivate) -{ - setAddress(host, port); - setSocketFlags(flags); -} - -// same -KExtendedSocket::KExtendedSocket(const TQString& host, const TQString& service, int flags) : - sockfd(-1), d(new KExtendedSocketPrivate) -{ - setAddress(host, service); - setSocketFlags(flags); -} - -// destroy the class -KExtendedSocket::~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; -} - -#ifdef USE_QT3 -void KExtendedSocket::reset() -#endif // USE_QT3 -#ifdef USE_QT4 -bool KExtendedSocket::reset() -#endif // USE_QT4 -{ - 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) -{ - setqStatus(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 TQString& host) -{ - if (d->status > nothing) - return false; // error! - - d->resRemote.setNodeName(host); - return true; -} - -/* - * returns the hostname - */ -TQString 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(TQString::number(port)); -} - -bool KExtendedSocket::setPort(const TQString& service) -{ - if (d->status > nothing) - return false; // error - - d->resRemote.setServiceName(service); - return true; -} - -/* - * returns the service port number - */ -TQString KExtendedSocket::port() const -{ - return d->resRemote.serviceName(); -} - -/* - * sets the address - */ -bool KExtendedSocket::setAddress(const TQString& host, int port) -{ - return setHost(host) && setPort(port); -} - -/* - * the same - */ -bool KExtendedSocket::setAddress(const TQString& host, const TQString& 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 TQString& 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(TQString::null); -} - -/* - * returns the binding host - */ -TQString KExtendedSocket::bindHost() const -{ - return d->resLocal.serviceName(); -} - -/* - * Sets the bind port - * Same condition as setBindHost - */ -bool KExtendedSocket::setBindPort(int port) -{ - return setBindPort(TQString::number(port)); -} - -bool KExtendedSocket::setBindPort(const TQString& 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(TQString::null); -} - -/* - * returns the binding port - */ -TQString KExtendedSocket::bindPort() const -{ - return d->resLocal.serviceName(); -} - -/* - * sets the binding address - */ -bool KExtendedSocket::setBindAddress(const TQString& host, int port) -{ - return setBindHost(host) && setBindPort(port); -} - -/* - * same - */ -bool KExtendedSocket::setBindAddress(const TQString& host, const TQString& 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(); - - d->ipv6only = enable; - if (sockfd == -1) - return true; // can't set on a non-existing socket - - int on = enable; - - if (setsockopt(sockfd, IPPROTO_IPV6, IPV6_V6ONLY, - (char *)&on, sizeof(on)) == -1) - { - setError(IO_UnspecifiedError, errno); - return false; - } - else - return true; - -#else - // we don't have the IPV6_V6ONLY constant in this system - d->ipv6only = enable; - - setError(IO_UnspecifiedError, ENOSYS); - return false; // can't set if we don't know about this flag -#endif -} - -/* - * retrieve the IPV6_V6ONLY flag - */ -bool KExtendedSocket::isIPv6Only() -{ -#ifdef IPV6_V6ONLY - cleanError(); - - if (d->status < created || sockfd == -1) - return d->ipv6only; - - int on; - socklen_t onsiz = sizeof(on); - if (getsockopt(sockfd, IPPROTO_IPV6, IPV6_V6ONLY, - (char *)&on, &onsiz) == -1) - { - setError(IO_UnspecifiedError, errno); - return false; - } - - return d->ipv6only = on; - -#else - // we don't have the constant - setError(IO_UnspecifiedError, ENOSYS); - return false; -#endif -} - -/* - * Sets the buffer sizes in this socket - * Also, we create or delete the socket notifiers - */ -bool KExtendedSocket::setBufferSize(int rsize, int wsize) -{ - cleanError(); - if (d->status < created) - return false; - - if (sockfd == -1) - return false; - - if (d->flags & passiveSocket) - return false; // no I/O on passive sockets - - if (rsize < -2) - return false; - - if (wsize < -2) - return false; - - // LOCK BUFFER MUTEX - - // The input socket notifier is always enabled - // That happens because we want to be notified of when the socket gets - // closed - if (d->qsnIn == NULL) - { - d->qsnIn = new TQSocketNotifier(sockfd, TQSocketNotifier::Read); - TQObject::connect(d->qsnIn, TQT_SIGNAL(activated(int)), this, TQT_SLOT(socketActivityRead())); - d->qsnIn->setEnabled(true); - } - - if (rsize == 0 && d->flags & inputBufferedSocket) - { - // user wants to disable input buffering - d->flags &= ~inputBufferedSocket; - - consumeReadBuffer(readBufferSize(), NULL, true); - d->inMaxSize = 0; - } - else if (rsize != -2) - { - // enabling input buffering - if (rsize) - d->flags |= inputBufferedSocket; - d->inMaxSize = rsize; - - if (rsize > 0 && (unsigned)rsize < readBufferSize()) - // input buffer has more data than the new size; discard - consumeReadBuffer(readBufferSize() - rsize, NULL, true); - - } - - if (wsize == 0 && d->flags & outputBufferedSocket) - { - // disabling output buffering - d->flags &= ~outputBufferedSocket; - if (d->qsnOut && !d->emitWrite) - d->qsnOut->setEnabled(false); - consumeWriteBuffer(writeBufferSize()); - d->outMaxSize = 0; - } - else if (wsize != -2) - { - // enabling input buffering - if (wsize) - d->flags |= outputBufferedSocket; - d->outMaxSize = wsize; - - if (wsize > 0 && (unsigned)wsize < writeBufferSize()) - // output buffer is bigger than it is to become; shrink - consumeWriteBuffer(writeBufferSize() - wsize); - - if (d->qsnOut == NULL) - { - d->qsnOut = new TQSocketNotifier(sockfd, TQSocketNotifier::Write); - TQObject::connect(d->qsnOut, TQT_SIGNAL(activated(int)), this, TQT_SLOT(socketActivityWrite())); - // if the class is being created now, there's nothing to write yet - // so socketActivityWrite() will get called once and disable - // the notifier - } - } - - // UNLOCK BUFFER MUTEX - - setFlags((mode() & ~IO_Raw) | ((d->flags & bufferedSocket) ? 0 : IO_Raw)); - - // check we didn't turn something off we shouldn't - if (d->emitWrite && d->qsnOut == NULL) - { - d->qsnOut = new TQSocketNotifier(sockfd, TQSocketNotifier::Write); - TQObject::connect(d->qsnOut, TQT_SIGNAL(activated(int)), this, TQT_SLOT(socketActivityWrite())); - } - - return true; -} - -/* - * Finds the local address for this socket - * if we have done this already, we return it. Otherwise, we'll have - * to find the socket name - */ -const ::KSocketAddress *KExtendedSocket::localAddress() -{ - if (d->local != NULL) - return d->local; - if (d->status < bound) - return NULL; - - return d->local = localAddress(sockfd); -} - -/* - * Same thing, but for peer address. Which means this does not work on - * passiveSocket and that we require to be connected already. Also note that - * the behavior on connectionless sockets is not defined here. - */ -const ::KSocketAddress* KExtendedSocket::peerAddress() -{ - if (d->peer != NULL) - return d->peer; - if (d->flags & passiveSocket || d->status < connected) - return NULL; - - return d->peer = peerAddress(sockfd); -} - -/* - * Perform the lookup on the addresses given - */ -int KExtendedSocket::lookup() -{ - if (startAsyncLookup() != 0) - return -1; - - if (!d->resRemote.wait() || !d->resLocal.wait()) - { - d->status = nothing; - return -1; - } - - d->status = lookupDone; - if (d->resRemote.error() != KResolver::NoError) - return d->resRemote.error(); - if (d->resLocal.error() != KResolver::NoError) - return d->resLocal.error(); - return 0; -} - -/* - * Performs an asynchronous lookup on the given address(es) - */ -int KExtendedSocket::startAsyncLookup() -{ - cleanError(); - if (d->status > lookupInProgress) - return -1; - if (d->status == lookupInProgress) - // already in progress - return 0; - - /* check socket type flags */ - int socktype, familyMask, flags; - if (!process_flags(d->flags, socktype, familyMask, flags)) - return -2; - - // perform the global lookup before - if (!d->resRemote.isRunning()) - { - d->resRemote.setFlags(flags); - d->resRemote.setFamily(familyMask); - d->resRemote.setSocketType(socktype); - TQObject::connect(&d->resRemote, TQT_SIGNAL(finished(KResolverResults)), - this, TQT_SLOT(dnsResultsReady())); - - if (!d->resRemote.start()) - { - setError(IO_LookupError, d->resRemote.error()); - return d->resRemote.error(); - } - } - - if ((d->flags & passiveSocket) == 0 && !d->resLocal.isRunning()) - { - /* keep flags, but make this passive */ - flags |= KResolver::Passive; - d->resLocal.setFlags(flags); - d->resLocal.setFamily(familyMask); - d->resLocal.setSocketType(socktype); - TQObject::connect(&d->resLocal, TQT_SIGNAL(finished(KResolverResults)), - this, TQT_SLOT(dnsResultsReady())); - - if (!d->resLocal.start()) - { - setError(IO_LookupError, d->resLocal.error()); - return d->resLocal.error(); - } - } - - // if we are here, there were no errors - if (d->resRemote.isRunning() || d->resLocal.isRunning()) - d->status = lookupInProgress; // only if there actually is a running lookup - else - { - d->status = lookupDone; - emit lookupFinished(d->resRemote.results().count() + - d->resLocal.results().count()); - } - return 0; -} - -void KExtendedSocket::cancelAsyncLookup() -{ - cleanError(); - if (d->status != lookupInProgress) - return; // what's to cancel? - - d->status = nothing; - d->resLocal.cancel(false); - d->resRemote.cancel(false); -} - -int KExtendedSocket::listen(int N) -{ - cleanError(); - if ((d->flags & passiveSocket) == 0 || d->status >= listening) - return -2; - if (d->status < lookupDone) - if (lookup() != 0) - return -2; // error! - if (d->resRemote.error()) - return -2; - - // doing the loop: - KResolverResults::const_iterator it; - KResolverResults res = d->resRemote.results(); - for (it = res.begin(); it != res.end(); ++it) - { - //kdDebug(170) << "Trying to listen on " << (*it).address().toString() << endl; - sockfd = ::socket((*it).family(), (*it).socketType(), (*it).protocol()); - if (sockfd == -1) - { - // socket failed creating - //kdDebug(170) << "Failed to create: " << perror << endl; - continue; - } - - fcntl(sockfd, F_SETFD, FD_CLOEXEC); - - if (d->addressReusable) - setAddressReusable(sockfd, true); - setIPv6Only(d->ipv6only); - cleanError(); - if (KSocks::self()->bind(sockfd, (*it).address().address(), (*it).length()) == -1) - { - //kdDebug(170) << "Failed to bind: " << perror << endl; - ::close(sockfd); - sockfd = -1; - continue; - } - - // ok, socket has bound - // kdDebug(170) << "Socket bound: " << sockfd << endl; - - d->status = bound; - break; - } - - if (sockfd == -1) - { - setError(IO_ListenError, errno); - //kdDebug(170) << "Listen error - sockfd is -1 " << endl; - return -1; - } - - d->status = bound; - setFlags(IO_Sequential | IO_Raw | IO_ReadWrite); - - int retval = KSocks::self()->listen(sockfd, N); - if (retval == -1) - setError(IO_ListenError, errno); - else - { - d->status = listening; - d->qsnIn = new TQSocketNotifier(sockfd, TQSocketNotifier::Read); - TQObject::connect(d->qsnIn, TQT_SIGNAL(activated(int)), this, TQT_SLOT(socketActivityRead())); - } - return retval == -1 ? -1 : 0; -} - -int KExtendedSocket::accept(KExtendedSocket *&sock) -{ - cleanError(); - sock = NULL; - if ((d->flags & passiveSocket) == 0 || d->status >= accepting) - return -2; - if (d->status < listening) - if (listen() < 0) - return -2; // error! - - // let's see - // if we have a timeout in place, we have to place this socket in non-blocking - // mode - bool block = blockingMode(); - struct sockaddr sa; - ksocklen_t len = sizeof(sa); - sock = NULL; - - if (d->timeout.tv_sec > 0 || d->timeout.tv_usec > 0) - { - fd_set set; - - setBlockingMode(false); // turn on non-blocking - FD_ZERO(&set); - FD_SET(sockfd, &set); - - //kdDebug(170).form("Accepting on %d with %d.%06d second timeout\n", - // sockfd, d->timeout.tv_sec, d->timeout.tv_usec); - // check if there is anything to accept now - int retval = KSocks::self()->select(sockfd + 1, &set, NULL, NULL, &d->timeout); - if (retval == -1) - { - setError(IO_UnspecifiedError, errno); - return -1; // system error - } - else if (retval == 0 || !FD_ISSET(sockfd, &set)) - { - setError(IO_TimeOutError, 0); - return -3; // timeout - } - } - - // it's common stuff here - int newfd = KSocks::self()->accept(sockfd, &sa, &len); - - if (newfd == -1) - { - setError(IO_AcceptError, errno); - kdWarning(170) << "Error accepting on socket " << sockfd << ":" - << perror << endl; - return -1; - } - - fcntl(newfd, F_SETFD, FD_CLOEXEC); - - //kdDebug(170).form("Socket %d accepted socket %d\n", sockfd, newfd); - - setBlockingMode(block); // restore blocking mode - - sock = new KExtendedSocket; - sock->d->status = connected; - sock->sockfd = newfd; - sock->setFlags(IO_Sequential | IO_Raw | IO_ReadWrite | IO_Open | IO_Async); - sock->setBufferSize(0, 0); // always unbuffered here. User can change that later - - return 0; -} - -/* - * tries to connect - * - * FIXME! - * This function is critical path. It has to be cleaned up and made faster - */ -int KExtendedSocket::connect() -{ - cleanError(); - if (d->flags & passiveSocket || d->status >= connected) - return -2; - if (d->status < lookupDone) - if (lookup() != 0) - return -2; - - timeval end, now; - timeval timeout_copy = d->timeout; - // Ok, things are a little tricky here - // Let me explain - // getaddrinfo() will return several different families of sockets - // When we have to bind before we connect, we have to make sure we're binding - // and connecting to the same family, or things won't work - - KResolverResults remote = d->resRemote.results(), - local = d->resLocal.results(); - KResolverResults::const_iterator it, it2; - //kdDebug(170) << "Starting connect to " << host() << '|' << port() - // << ": have " << local.count() << " local entries and " - // << remote.count() << " remote" << endl; - - int ret = -1; - for (it = remote.begin(), it2 = local.begin(); it != remote.end(); ++it) - { - bool doingtimeout = d->timeout.tv_sec > 0 || d->timeout.tv_usec > 0; - if (doingtimeout) - { - gettimeofday(&end, NULL); - end.tv_usec += d->timeout.tv_usec; - end.tv_sec += d->timeout.tv_sec; - if (end.tv_usec > 1000*1000) - { - end.tv_usec -= 1000*1000; - end.tv_sec++; - } - //kdDebug(170).form("Connection with timeout of %d.%06d seconds (ends in %d.%06d)\n", - // d->timeout.tv_sec, d->timeout.tv_usec, end.tv_sec, end.tv_usec); - } - - //kdDebug(170) << "Trying to connect to " << (*it).address().toString() << endl; - if (it2 != local.end()) - { -// //kdDebug(170) << "Searching bind socket for family " << p->ai_family << endl; - if ((*it).family() != (*it2).family()) - // differing families, scan local for a matching family - for (it2 = local.begin(); it2 != local.end(); ++it2) - if ((*it).family() == (*it2).family()) - break; - - if ((*it).family() != (*it2).family()) - { - // no matching families for this - //kdDebug(170) << "No matching family for bind socket\n"; - it2 = local.begin(); - continue; - } - - //kdDebug(170) << "Binding on " << (*it2).address().toString() << " before connect" << endl; - errno = 0; - sockfd = ::socket((*it).family(), (*it).socketType(), (*it).protocol()); - setError(IO_ConnectError, errno); - if (sockfd == -1) - continue; // cannot create this socket - fcntl(sockfd, F_SETFD, FD_CLOEXEC); - if (d->addressReusable) - setAddressReusable(sockfd, true); - setIPv6Only(d->ipv6only); - cleanError(); - if (KSocks::self()->bind(sockfd, (*it2).address(), (*it2).length())) - { - //kdDebug(170) << "Bind failed: " << perror << endl; - ::close(sockfd); - sockfd = -1; - continue; - } - } - else - { - // no need to bind, just create - sockfd = ::socket((*it).family(), (*it).socketType(), (*it).protocol()); - if (sockfd == -1) - { - setError(IO_ConnectError, errno); - continue; - } - fcntl(sockfd, F_SETFD, FD_CLOEXEC); - if (d->addressReusable) - setAddressReusable(sockfd, true); - setIPv6Only(d->ipv6only); - cleanError(); - } - -// kdDebug(170) << "Socket " << sockfd << " created" << endl; - d->status = created; - - // check if we have to do timeout - if (doingtimeout && KSocks::self()->hasWorkingAsyncConnect()) - { - fd_set rd, wr; - - setBlockingMode(false); - - // now try and connect - if (KSocks::self()->connect(sockfd, (*it).address(), (*it).length()) == -1) - { - // this could be EWOULDBLOCK - if (errno != EWOULDBLOCK && errno != EINPROGRESS) - { - //kdDebug(170) << "Socket " << sockfd << " did not connect: " << perror << endl; - setError(IO_ConnectError, errno); - ::close(sockfd); - sockfd = -1; - continue; // nope, another error - } - - FD_ZERO(&rd); - FD_ZERO(&wr); - FD_SET(sockfd, &rd); - FD_SET(sockfd, &wr); - - int retval = KSocks::self()->select(sockfd + 1, &rd, &wr, NULL, &d->timeout); - if (retval == -1) - { - setError(IO_FatalError, errno); - continue; // system error - } - else if (retval == 0) - { - ::close(sockfd); - sockfd = -1; -// kdDebug(170) << "Time out while trying to connect to " << -// (*it).address().toString() << endl; - setError(IO_TimeOutError, 0); - ret = -3; // time out - - d->timeout.tv_usec += timeout_copy.tv_usec; - d->timeout.tv_sec += timeout_copy.tv_sec; - if (d->timeout.tv_usec < 0) - { - d->timeout.tv_usec += 1000*1000; - d->timeout.tv_sec--; - } - - continue; - } - - // adjust remaining time - gettimeofday(&now, NULL); - d->timeout.tv_sec = end.tv_sec - now.tv_sec; - d->timeout.tv_usec = end.tv_usec - now.tv_usec; - if (d->timeout.tv_usec < 0) - { - d->timeout.tv_usec += 1000*1000; - d->timeout.tv_sec--; - } -// kdDebug(170).form("Socket %d activity; %d.%06d seconds remaining\n", -// sockfd, d->timeout.tv_sec, d->timeout.tv_usec); - - // this means that an event occurred in the socket - int errcode; - socklen_t len = sizeof(errcode); - retval = getsockopt(sockfd, SOL_SOCKET, SO_ERROR, (char*)&errcode, - &len); - if (retval == -1 || errcode != 0) - { - // socket did not connect - //kdDebug(170) << "Socket " << sockfd << " did not connect: " - // << strerror(errcode) << endl; - ::close(sockfd); - sockfd = -1; - - // this is HIGHLY UNLIKELY - if (d->timeout.tv_sec == 0 && d->timeout.tv_usec == 0) - { - d->status = lookupDone; - setError(IO_TimeOutError, 0); - return -3; // time out - } - - setError(IO_ConnectError, errcode); - continue; - } - } - - // getting here means it connected - // setBufferSize() takes care of creating the socket notifiers - setBlockingMode(true); - d->status = connected; - setFlags(IO_Sequential | IO_Raw | IO_ReadWrite | IO_Open | IO_Async); - setBufferSize(d->flags & inputBufferedSocket ? -1 : 0, - d->flags & outputBufferedSocket ? -1 : 0); - emit connectionSuccess(); -// kdDebug(170) << "Socket " << sockfd << " connected\n"; - return 0; - } - else - { - // without timeouts - if (KSocks::self()->connect(sockfd, (*it).address(), (*it).length()) == -1) - { - //kdDebug(170) << "Socket " << sockfd << " to " << (*it).address().toString() - // << " did not connect: " << perror << endl; - setError(IO_ConnectError, errno); - ::close(sockfd); - sockfd = -1; - continue; - } - - d->status = connected; - setFlags(IO_Sequential | IO_Raw | IO_ReadWrite | IO_Open | IO_Async); - setBufferSize(d->flags & inputBufferedSocket ? -1 : 0, - d->flags & outputBufferedSocket ? -1 : 0); - emit connectionSuccess(); -// kdDebug(170) << "Socket " << sockfd << " connected\n"; - return 0; // it connected - } - } - - // getting here means no socket connected or stuff like that - emit connectionFailed(d->syserror); - //kdDebug(170) << "Failed to connect\n"; - return ret; -} - -int KExtendedSocket::startAsyncConnect() -{ - cleanError(); - // check status - if (d->status >= connected || d->flags & passiveSocket) - return -2; - - if (d->status == connecting) - // already on async connect - return 0; - - // check if we have to do lookup - // if we do, then we'll use asynchronous lookup and use - // signal lookupFinished to do connection - if (d->status < lookupDone) - { - TQObject::connect(this, TQT_SIGNAL(lookupFinished(int)), this, TQT_SLOT(startAsyncConnectSlot())); - if (d->status < lookupInProgress) - return startAsyncLookup(); - else - return 0; // we still have to wait - } - - // here we have d->status >= lookupDone and <= connecting - // we can do our connection - d->status = connecting; - TQGuardedPtr<TQObject> p = TQT_TQOBJECT(this); - connectionEvent(); - if (!p) - return -1; // We have been deleted. - if (d->status < connecting) - return -1; - return 0; -} - -void KExtendedSocket::cancelAsyncConnect() -{ - if (d->status != connecting) - return; - - if (sockfd != -1) - { - // we have a waiting connection - if (d->qsnIn) - delete d->qsnIn; - if (d->qsnOut) - delete d->qsnOut; - d->qsnIn = d->qsnOut = NULL; - - ::close(sockfd); - sockfd = -1; - } - d->status = lookupDone; -} - -bool KExtendedSocket::open(TQ_OpenMode mode) -{ - if (mode != IO_Raw | IO_ReadWrite) - return false; // invalid open mode - - if (d->flags & passiveSocket) - return listen() == 0; - else if (d->status < connecting) - return connect() == 0; - else - return false; -} - -void KExtendedSocket::close() -{ - if (sockfd == -1 || d->status >= closing) - return; // nothing to close - - // LOCK BUFFER MUTEX - if (d->flags & outputBufferedSocket && writeBufferSize() > 0) - { - // write buffer not empty, go into closing state - d->status = closing; - if (d->qsnIn) - delete d->qsnIn; - d->qsnIn = NULL; - // we keep the outgoing socket notifier because we want - // to send data, but not receive - } - else - { - // nope, write buffer is empty - // we can close now - if (d->qsnIn) - delete d->qsnIn; - if (d->qsnOut) - delete d->qsnOut; - d->qsnIn = d->qsnOut = NULL; - - ::close(sockfd); - d->status = done; - emit closed(readBufferSize() != 0 ? availRead : 0); - } - // UNLOCK BUFFER MUTEX -} - - -void KExtendedSocket::closeNow() -{ - if (d->status >= done) - return; // nothing to close - - // close the socket - delete d->qsnIn; - delete d->qsnOut; - d->qsnIn = d->qsnOut = NULL; - - if (d->status > connecting && sockfd != -1) - { - ::close(sockfd); - sockfd = -1; - } - else if (d->status == connecting) - cancelAsyncConnect(); - else if (d->status == lookupInProgress) - cancelAsyncLookup(); - - d->status = done; - - emit closed(closedNow | - (readBufferSize() != 0 ? availRead : 0) | - (writeBufferSize() != 0 ? dirtyWrite : 0)); -} - -void KExtendedSocket::release() -{ - // release our hold on the socket - sockfd = -1; - d->status = done; - - d->resRemote.cancel(false); - d->resLocal.cancel(false); - - if (d->local != NULL) - delete d->local; - if (d->peer != NULL) - delete d->peer; - - d->peer = d->local = NULL; - - if (d->qsnIn != NULL) - delete d->qsnIn; - if (d->qsnOut != NULL) - delete d->qsnOut; - - d->qsnIn = d->qsnOut = NULL; - - // now that the socket notificators are done with, we can flush out the buffers - consumeReadBuffer(readBufferSize(), NULL, true); - consumeWriteBuffer(writeBufferSize()); - - // don't delete d - // leave that for the destructor -} - -void KExtendedSocket::flush() -{ - cleanError(); - if (d->status < connected || d->status >= done || d->flags & passiveSocket) - return; - - if (sockfd == -1) - return; - - if ((d->flags & outputBufferedSocket) == 0) - return; // nothing to do - - // LOCK MUTEX - - unsigned written = 0; - unsigned offset = outBufIndex; // this happens only for the first - while (writeBufferSize() - written > 0) - { - // we have to write each output buffer in outBuf - // but since we can have several very small buffers, we can make things - // better by concatenating a few of them into a big buffer - // question is: how big should that buffer be? 16 kB should be enough - - TQByteArray buf(16384); - TQByteArray *a = outBuf.first(); - unsigned count = 0; - - while (a && count + (a->size() - offset) <= buf.size()) - { - memcpy(buf.data() + count, a->data() + offset, a->size() - offset); - count += a->size() - offset; - offset = 0; - a = outBuf.next(); - } - - // see if we can still fit more - if (a && count < buf.size()) - { - // getting here means this buffer (a) is larger than - // (buf.size() - count) (even for count == 0). - memcpy(buf.data() + count, a->data() + offset, buf.size() - count); - offset += buf.size() - count; - count = buf.size(); - } - - // now try to write those bytes - int wrote = KSocks::self()->write(sockfd, buf, count); - - if (wrote == -1) - { - // could be EAGAIN (EWOULDBLOCK) - setError(IO_WriteError, errno); - break; - } - written += wrote; - - if ((unsigned)wrote != count) - break; - } - if (written) - { - consumeWriteBuffer(written); - emit bytesWritten(written); - } - - // UNLOCK MUTEX -} - - -TQT_TQIO_LONG KExtendedSocket::tqreadBlock(char *data, TQT_TQIO_ULONG maxlen) -{ - cleanError(); - if (d->status < connected || d->flags & passiveSocket) - return -2; - - int retval; - - if ((d->flags & inputBufferedSocket) == 0) - { - // we aren't buffering this socket, so just pass along - // the call to the real read method - - if (sockfd == -1) - return -2; - if (data) - retval = KSocks::self()->read(sockfd, data, maxlen); - else - retval = skipData(sockfd, maxlen); - if (retval == -1) - setError(IO_ReadError, errno); - } - else - { - // this socket is being buffered. So read from the buffer - - // LOCK BUFFER MUTEX - - retval = consumeReadBuffer(maxlen, data); - if (retval == 0) - { - // consumeReadBuffer returns 0 only if the buffer is - // empty - if (sockfd == -1) - return 0; // buffer is clear now, indicate EOF - setError(IO_ReadError, EWOULDBLOCK); - retval = -1; - } - - // UNLOCK BUFFER MUTEX - - } - return retval; -} - -TQT_TQIO_LONG KExtendedSocket::tqwriteBlock(const char *data, TQT_TQIO_ULONG len) -{ - cleanError(); - if (d->status < connected || d->status >= closing || d->flags & passiveSocket) - return -2; - if (sockfd == -1) - return -2; - - if (len == 0) - return 0; // what's to write? - - int retval; - - if ((d->flags & outputBufferedSocket) == 0) - { - // socket not buffered. Just call write - retval = KSocks::self()->write(sockfd, data, len); - if (retval == -1) - setError(IO_WriteError, errno); - else - emit bytesWritten(retval); - } - else - { - // socket is buffered. Feed the write buffer - - // LOCK BUFFER MUTEX - - register unsigned wsize = writeBufferSize(); - if (d->outMaxSize == (int)wsize) // (int) to get rid of annoying warning - { - // buffer is full! - setError(IO_WriteError, EWOULDBLOCK); - retval = -1; - } - else - { - if (d->outMaxSize != -1 && wsize + len > (unsigned)d->outMaxSize) - // we cannot write all data. Write just as much as to fill the buffer - len = d->outMaxSize - wsize; - - // len > 0 here - retval = feedWriteBuffer(len, data); - if (wsize == 0 || d->emitWrite) - // buffer was empty, which means that the notifier is probably disabled - d->qsnOut->setEnabled(true); - } - - // UNLOCK BUFFER MUTEX - } - - return retval; -} - -int KExtendedSocket::peekBlock(char *data, uint maxlen) -{ - if (d->status < connected || d->flags & passiveSocket) - return -2; - if (sockfd == -1) - return -2; - - // need to LOCK MUTEX around this call... - - if (d->flags & inputBufferedSocket) - return consumeReadBuffer(maxlen, data, false); - - return 0; -} - -int KExtendedSocket::unreadBlock(const char *, uint) -{ - // Always return -1, indicating this is not supported - setError(IO_ReadError, ENOSYS); - return -1; -} - -#ifdef USE_QT3 -int KExtendedSocket::bytesAvailable() const -#endif // USE_QT3 -#ifdef USE_QT4 -qint64 KExtendedSocket::bytesAvailable() const -#endif // USE_QT4 -{ - if (d->status < connected || d->flags & passiveSocket) - return -2; - - // as of now, we don't do any extra processing - // we only work in input-buffered sockets - if (d->flags & inputBufferedSocket) - return KBufferedIO::bytesAvailable(); - - return 0; // TODO: FIONREAD ioctl -} - -int KExtendedSocket::waitForMore(int msecs) -{ - cleanError(); - if (d->flags & passiveSocket || d->status < connected || d->status >= closing) - return -2; - if (sockfd == -1) - return -2; - - fd_set rd; - FD_ZERO(&rd); - FD_SET(sockfd, &rd); - timeval tv; - tv.tv_sec = msecs / 1000; - tv.tv_usec = (msecs % 1000) * 1000; - - int retval = KSocks::self()->select(sockfd + 1, &rd, NULL, NULL, &tv); - if (retval == -1) - { - setError(IO_FatalError, errno); - return -1; - } - else if (retval != 0) - socketActivityRead(); // do read processing - - return bytesAvailable(); -} - -int KExtendedSocket::getch() -{ - unsigned char c; - int retval; - retval = tqreadBlock((char*)&c, sizeof(c)); - - if (retval < 0) - return retval; - return c; -} - -int KExtendedSocket::putch(int ch) -{ - unsigned char c = (char)ch; - return tqwriteBlock((char*)&c, sizeof(c)); -} - -// sets the emission of the readyRead signal -void KExtendedSocket::enableRead(bool enable) -{ - // check if we can disable the socket notifier - // saves us a few cycles - // this is so because in buffering mode, we rely on these signals - // being emitted to do our I/O. We couldn't disable them here - if (!enable && (d->flags & inputBufferedSocket) == 0 && d->qsnIn) - d->qsnIn->setEnabled(false); - else if (enable && d->qsnIn) - // we can enable it always - d->qsnIn->setEnabled(true); - d->emitRead = enable; -} - -// sets the emission of the readyWrite signal -void KExtendedSocket::enableWrite(bool enable) -{ - // same thing as above - if (!enable && (d->flags & outputBufferedSocket) == 0 && d->qsnOut) - d->qsnOut->setEnabled(false); - else if (enable && d->qsnOut) - // we can enable it always - d->qsnOut->setEnabled(true); - d->emitWrite = enable; -} - -// protected slot -// this is connected to d->qsnIn::activated(int) -void KExtendedSocket::socketActivityRead() -{ - if (d->flags & passiveSocket) - { - emit readyAccept(); - return; - } - if (d->status == connecting) - { - connectionEvent(); - return; - } - if (d->status != connected) - return; - - // do we need to do I/O here? - if (d->flags & inputBufferedSocket) - { - // aye. Do read from the socket and feed our buffer - TQByteArray a; - char buf[1024]; - int len, totalread = 0; - - // LOCK MUTEX - - unsigned cursize = readBufferSize(); - - if (d->inMaxSize == -1 || cursize < (unsigned)d->inMaxSize) - { - do - { - // check that we can read that many bytes - if (d->inMaxSize != -1 && d->inMaxSize - (cursize + totalread) < sizeof(buf)) - // no, that would overrun the buffer - // note that this will also make us exit the loop - len = d->inMaxSize - (cursize + totalread); - else - len = sizeof(buf); - - len = KSocks::self()->read(sockfd, buf, len); - if (len > 0) - { - // normal read operation - a.resize(a.size() + len); - memcpy(a.data() + totalread, buf, len); - totalread += len; // totalread == a.size() now - } - else if (len == 0) - { - // EOF condition here - ::close(sockfd); - sockfd = -1; // we're closed - d->qsnIn->deleteLater(); - delete d->qsnOut; - d->qsnIn = d->qsnOut = NULL; - d->status = done; - emit closed(involuntary | - (readBufferSize() ? availRead : 0) | - (writeBufferSize() ? dirtyWrite : 0)); - return; - } - else - { - // error! - setError(IO_ReadError, errno); - return; - } - // will loop only for normal read operations - } - while (len == sizeof(buf)); - - feedReadBuffer(a.size(), a.data()); - } - - // UNLOCK MUTEX - } - else - { - // No input buffering, but the notifier fired - // That means that either there is data to be read or that the - // socket closed. - - // try to read one byte. If we can't, then the socket got closed - - char c; - int len = KSocks::self()->recv(sockfd, &c, sizeof(c), MSG_PEEK); - if (len == 0) - { - // yes, it's an EOF condition - d->qsnIn->setEnabled(false); - ::close(sockfd); - sockfd = -1; - d->status = done; - emit closed(involuntary); - return; - } - } - - if (d->emitRead) - emit readyRead(); -} - -void KExtendedSocket::socketActivityWrite() -{ - if (d->flags & passiveSocket) - return; - if (d->status == connecting) - { - connectionEvent(); - return; - } - if (d->status != connected && d->status != closing) - return; - - flush(); - - bool empty = writeBufferSize() == 0; - - if (d->emitWrite && empty) - emit readyWrite(); - else if (!d->emitWrite) - { - // check if we can disable the notifier - d->qsnOut->setEnabled(!empty); // leave it enabled only if we have more data to send - } - if (d->status == closing && empty) - { - // done sending the missing data! - d->status = done; - - delete d->qsnOut; - ::close(sockfd); - - d->qsnOut = NULL; - sockfd = -1; - emit closed(delayed | (readBufferSize() ? availRead : 0)); - } -} - -// this function is called whenever we have a "connection event" -// that is, whenever our asynchronously connecting socket throws -// an event -void KExtendedSocket::connectionEvent() -{ - if (d->status != connecting) - return; // move along. There's nothing to see here - - KResolverResults remote = d->resRemote.results(); - if (remote.count() == 0) - { - // We have a problem! Abort? - kdError(170) << "KExtendedSocket::connectionEvent() called but no data available!\n"; - return; - } - - int errcode = 0; - - if (sockfd != -1) - { - // our socket has activity - // find out what it was - int retval; - socklen_t len = sizeof(errcode); - retval = getsockopt(sockfd, SOL_SOCKET, SO_ERROR, (char*)&errcode, &len); - - if (retval == -1 || errcode != 0) - { - // socket activity and there was error? - // that means the socket probably did not connect - if (d->qsnIn) - delete d->qsnIn; - if (d->qsnOut) - delete d->qsnOut; - ::close(sockfd); - - sockfd = -1; - d->qsnIn = d->qsnOut = NULL; - d->current++; - setError(IO_ConnectError, errcode); - } - else - { - // hmm, socket activity and there was no error? - // that means it connected - // YAY! - cleanError(); - d->status = connected; - setBlockingMode(true); - setFlags(IO_Sequential | IO_Raw | IO_ReadWrite | IO_Open | IO_Async); - setBufferSize(d->flags & inputBufferedSocket ? -1 : 0, - d->flags & outputBufferedSocket ? -1 : 0); - emit connectionSuccess(); - return; - } - } - - // ok, we have to try something here - // and sockfd == -1 - KResolverResults local = d->resLocal.results(); - unsigned localidx = 0; - for ( ; d->current < remote.count(); d->current++) - { - // same code as in connect() - if (local.count() != 0) - { - // scan bindres for a local resuls family - for (localidx = 0; localidx < local.count(); localidx++) - if (remote[d->current].family() == local[localidx].family()) - break; - - if (remote[d->current].family() != local[localidx].family()) - { - // no matching families for this - continue; - } - - errno = 0; - sockfd = ::socket(remote[d->current].family(), remote[d->current].socketType(), - remote[d->current].protocol()); - setError(IO_ConnectError, errno); - errcode = errno; - if (sockfd == -1) - continue; // cannot create this socket - fcntl(sockfd, F_SETFD, FD_CLOEXEC); - if (d->addressReusable) - setAddressReusable(sockfd, true); - setIPv6Only(d->ipv6only); - cleanError(); - if (KSocks::self()->bind(sockfd, local[localidx].address(), - local[localidx].length()) == -1) - { - ::close(sockfd); - sockfd = -1; - continue; - } - } - else - { - // no need to bind, just create - sockfd = ::socket(remote[d->current].family(), remote[d->current].socketType(), - remote[d->current].protocol()); - if (sockfd == -1) - { - setError(IO_ConnectError, errno); - errcode = errno; - continue; - } - fcntl(sockfd, F_SETFD, FD_CLOEXEC); - if (d->addressReusable) - setAddressReusable(sockfd, true); - setIPv6Only(d->ipv6only); - cleanError(); - } - - if (KSocks::self()->hasWorkingAsyncConnect()) - setBlockingMode(false); - if (KSocks::self()->connect(sockfd, remote[d->current].address(), - remote[d->current].length()) == -1) - { - if (errno != EWOULDBLOCK && errno != EINPROGRESS) - { - setError(IO_ConnectError, errno); - ::close(sockfd); - sockfd = -1; - errcode = errno; - continue; - } - - // error here is either EWOULDBLOCK or EINPROGRESS - // so, it is a good condition - d->qsnIn = new TQSocketNotifier(sockfd, TQSocketNotifier::Read); - TQObject::connect(d->qsnIn, TQT_SIGNAL(activated(int)), this, TQT_SLOT(socketActivityRead())); - d->qsnOut = new TQSocketNotifier(sockfd, TQSocketNotifier::Write); - TQObject::connect(d->qsnOut, TQT_SIGNAL(activated(int)), this, TQT_SLOT(socketActivityWrite())); - - // ok, let the Qt event loop do the selecting for us - return; - } - - // eh, what? - // the non-blocking socket returned valid connection? - // already? - // I suppose that could happen... - cleanError(); - d->status = connected; - setBlockingMode(true); - setFlags(IO_Sequential | IO_Raw | IO_ReadWrite | IO_Open | IO_Async); - setBufferSize(d->flags & inputBufferedSocket ? -1 : 0, - d->flags & outputBufferedSocket ? -1 : 0); - emit connectionSuccess(); - return; - } - - // if we got here, it means that there are no more options to connect - d->status = lookupDone; // go back - emit connectionFailed(errcode); -} - -void KExtendedSocket::dnsResultsReady() -{ - // check that this function was called in a valid state - if (d->status != lookupInProgress) - return; - - // valid state. Are results fully ready? - if (d->resRemote.isRunning() || d->resLocal.isRunning()) - // no, still waiting for answer in one of the lookups - return; - - // ok, we have all results - // count how many results we have - int n = d->resRemote.results().count() + d->resLocal.results().count(); - - if (n) - { - d->status = lookupDone; - cleanError(); - } - else - { - d->status = nothing; - setError(IO_LookupError, KResolver::NoName); - } - - emit lookupFinished(n); - - return; -} - -void KExtendedSocket::startAsyncConnectSlot() -{ - TQObject::disconnect(this, TQT_SIGNAL(lookupFinished(int)), this, TQT_SLOT(startAsyncConnectSlot())); - - if (d->status == lookupDone) - startAsyncConnect(); -} - -int KExtendedSocket::resolve(sockaddr *sock, ksocklen_t len, TQString &host, - TQString &port, int flags) -{ - kdDebug(170) << "Deprecated function called:" << k_funcinfo << endl; - - int err; - char h[NI_MAXHOST], s[NI_MAXSERV]; - - h[0] = s[0] = '\0'; - - err = getnameinfo(sock, len, h, sizeof(h) - 1, s, sizeof(s) - 1, flags); - host = TQString::fromUtf8(h); - port = TQString::fromUtf8(s); - - return err; -} - -int KExtendedSocket::resolve(::KSocketAddress *sock, TQString &host, TQString &port, - int flags) -{ - return resolve(sock->data, sock->datasize, host, port, flags); -} - -TQPtrList<KAddressInfo> KExtendedSocket::lookup(const TQString& host, const TQString& port, - int userflags, int *error) -{ - kdDebug(170) << "Deprecated function called:" << k_funcinfo << endl; - - int socktype, familyMask, flags; - unsigned i; - TQPtrList<KAddressInfo> l; - - /* check socket type flags */ - if (!process_flags(userflags, socktype, familyMask, flags)) - return l; - -// kdDebug(170) << "Performing lookup on " << host << "|" << port << endl; - KResolverResults res = KResolver::resolve(host, port, flags, familyMask); - if (res.error()) - { - if (error) - *error = res.error(); - return l; - } - - for (i = 0; i < res.count(); i++) - { - KAddressInfo *ai = new KAddressInfo(); - - // I should have known that using addrinfo was going to come - // and bite me back some day... - ai->ai = (addrinfo *) malloc(sizeof(addrinfo)); - memset(ai->ai, 0, sizeof(addrinfo)); - - ai->ai->ai_family = res[i].family(); - ai->ai->ai_socktype = res[i].socketType(); - ai->ai->ai_protocol = res[i].protocol(); - TQString canon = res[i].canonicalName(); - if (!canon.isEmpty()) - { - ai->ai->ai_canonname = (char *) malloc(canon.length()+1); - strcpy(ai->ai->ai_canonname, canon.ascii()); // ASCII here is intentional - } - if ((ai->ai->ai_addrlen = res[i].length())) - { - ai->ai->ai_addr = (struct sockaddr *) malloc(res[i].length()); - memcpy(ai->ai->ai_addr, res[i].address().address(), res[i].length()); - } - else - { - ai->ai->ai_addr = 0; - } - - ai->addr = ::KSocketAddress::newAddress(ai->ai->ai_addr, ai->ai->ai_addrlen); - - l.append(ai); - } - - if ( error ) - *error = 0; // all is fine! - - return l; -} - -::KSocketAddress *KExtendedSocket::localAddress(int fd) -{ - ::KSocketAddress *local; - struct sockaddr static_sa, *sa = &static_sa; - ksocklen_t len = sizeof(static_sa); - - /* find out the socket length, in advance - * we use a sockaddr allocated on the heap just not to pass down - * a NULL pointer to the first call. Some systems are reported to - * set len to 0 if we pass NULL as the sockaddr */ - if (KSocks::self()->getsockname(fd, sa, &len) == -1) - return NULL; // error! - - /* was it enough? */ - if (len > sizeof(static_sa) -#ifdef HAVE_STRUCT_SOCKADDR_SA_LEN - || sa->sa_len > sizeof(static_sa) -#endif - ) - { - /* nope, malloc a new socket with the proper size */ - -#ifdef HAVE_STRUCT_SOCKADDR_SA_LEN - if (sa->sa_len != len) - len = sa->sa_len; -#endif - - sa = (sockaddr*)malloc(len); - if (sa == NULL) - return NULL; // out of memory - - if (KSocks::self()->getsockname(fd, sa, &len) == -1) - { - free(sa); - return NULL; - } - - local = ::KSocketAddress::newAddress(sa, len); - free(sa); - } - else - local = ::KSocketAddress::newAddress(sa, len); - - return local; -} - -/* This is exactly the same code as localAddress, except - * we call getpeername here */ -::KSocketAddress *KExtendedSocket::peerAddress(int fd) -{ - ::KSocketAddress *peer; - struct sockaddr static_sa, *sa = &static_sa; - ksocklen_t len = sizeof(static_sa); - - /* find out the socket length, in advance - * we use a sockaddr allocated on the heap just not to pass down - * a NULL pointer to the first call. Some systems are reported to - * set len to 0 if we pass NULL as the sockaddr */ - if (KSocks::self()->getpeername(fd, sa, &len) == -1) - return NULL; // error! - - /* was it enough? */ - if (len > sizeof(static_sa) -#ifdef HAVE_STRUCT_SOCKADDR_SA_LEN - || sa->sa_len > sizeof(static_sa) -#endif - ) - { - /* nope, malloc a new socket with the proper size */ - -#ifdef HAVE_STRUCT_SOCKADDR_SA_LEN - if (sa->sa_len != len) - len = sa->sa_len; -#endif - - sa = (sockaddr*)malloc(len); - if (sa == NULL) - return NULL; // out of memory - - if (KSocks::self()->getpeername(fd, sa, &len) == -1) - { - free(sa); - return NULL; - } - - peer = ::KSocketAddress::newAddress(sa, len); - free(sa); - } - else - peer = ::KSocketAddress::newAddress(sa, len); - - return peer; -} - -TQString KExtendedSocket::strError(int code, int syserr) -{ - const char * msg; - if (code == IO_LookupError) - msg = gai_strerror(syserr); - else - msg = strerror(syserr); - - return TQString::fromLocal8Bit(msg); -} - - -TQSocketNotifier *KExtendedSocket::readNotifier() { return d->qsnIn; } -TQSocketNotifier *KExtendedSocket::writeNotifier() { return d->qsnOut; } - -/* - * class KAddressInfo - */ - -#if 0 -KAddressInfo::KAddressInfo(addrinfo *p) -{ - ai = (addrinfo *) malloc(sizeof(addrinfo)); - memcpy(ai, p, sizeof(addrinfo)); - ai->ai_next = NULL; - if (p->ai_canonname) - { - ai->ai_canonname = (char *) malloc(strlen(p->ai_canonname)+1); - strcpy(ai->ai_canonname, p->ai_canonname); - } - if (p->ai_addr && p->ai_addrlen) - { - ai->ai_addr = (struct sockaddr *) malloc(p->ai_addrlen); - memcpy(ai->ai_addr, p->ai_addr, p->ai_addrlen); - } - else - { - ai->ai_addr = 0; - ai->ai_addrlen = 0; - } - - addr = ::KSocketAddress::newAddress(ai->ai_addr, ai->ai_addrlen); -} -#endif -KAddressInfo::~KAddressInfo() -{ - if (ai && ai->ai_canonname) - free(ai->ai_canonname); - - if (ai && ai->ai_addr) - free(ai->ai_addr); - - if (ai) - free(ai); - delete addr; -} - -int KAddressInfo::flags() const -{ - return ai->ai_flags; -} - -int KAddressInfo::family() const -{ - return ai->ai_family; -} - -int KAddressInfo::socktype() const -{ - return ai->ai_socktype; -} - -int KAddressInfo::protocol() const -{ - return ai->ai_protocol; -} - -const char* KAddressInfo::canonname() const -{ - return ai->ai_canonname; -} - -void KExtendedSocket::virtual_hook( int id, void* data ) -{ KBufferedIO::virtual_hook( id, data ); } - -#include "kextsock.moc" |