summaryrefslogtreecommitdiffstats
path: root/kdecore/kextsock.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'kdecore/kextsock.cpp')
-rw-r--r--kdecore/kextsock.cpp2251
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"