kstreamsocket.cpp
/* -*- C++ -*-
* Copyright (C) 2003 Thiago Macieira <thiago.macieira@kdemail.net>
*
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include <config.h>
#include <qsocketnotifier.h>
#include <qdatetime.h>
#include <qtimer.h>
#include <qguardedptr.h>
#include "ksocketaddress.h"
#include "kresolver.h"
#include "ksocketdevice.h"
#include "kstreamsocket.h"
using namespace KNetwork;
class KNetwork::KStreamSocketPrivate
{
public:
KResolverResults::ConstIterator local, peer;
QTime startTime;
QTimer timer;
int timeout;
inline KStreamSocketPrivate()
: timeout(0)
{ }
};
KStreamSocket::KStreamSocket(const QString& node, const QString& service,
QObject* parent, const char *name)
: KClientSocketBase(parent, name), d(new KStreamSocketPrivate)
{
peerResolver().setNodeName(node);
peerResolver().setServiceName(service);
peerResolver().setFamily(KResolver::KnownFamily);
localResolver().setFamily(KResolver::KnownFamily);
setSocketOptions(socketOptions() & ~Blocking);
QObject::connect(&d->timer, SIGNAL(timeout()), this, SLOT(timeoutSlot()));
}
KStreamSocket::~KStreamSocket()
{
delete d;
// KClientSocketBase's destructor closes the socket
}
int KStreamSocket::timeout() const
{
return d->timeout;
}
int KStreamSocket::remainingTimeout() const
{
if (state() != Connecting)
return timeout();
if (timeout() <= 0)
return 0;
return timeout() - d->startTime.elapsed();
}
void KStreamSocket::setTimeout(int msecs)
{
d->timeout = msecs;
if (state() == Connecting)
d->timer.changeInterval(msecs);
}
bool KStreamSocket::bind(const QString& node, const QString& service)
{
if (state() != Idle)
return false;
if (!node.isNull())
localResolver().setNodeName(node);
if (!service.isNull())
localResolver().setServiceName(service);
return true;
}
bool KStreamSocket::connect(const QString& node, const QString& service)
{
if (state() == Connected)
return true; // already connected
if (state() > Connected)
return false; // can't do much here
if (!node.isNull())
peerResolver().setNodeName(node);
if (!service.isNull())
peerResolver().setServiceName(service);
if (state() == Connecting && !blocking())
{
setError(IO_ConnectError, InProgress);
emit gotError(InProgress);
return true; // we're already connecting
}
if (state() < HostFound)
{
// connection hasn't started yet
if (!blocking())
{
QObject::connect(this, SIGNAL(hostFound()), SLOT(hostFoundSlot()));
return lookup();
}
// blocking mode
if (!lookup())
return false; // lookup failure
}
/*
* lookup results are available here
*/
if (timeout() > 0)
{
if (!blocking() && !d->timer.isActive())
d->timer.start(timeout(), true);
else
{
// blocking connection with timeout
// this must be handled as a special case because it requires a
// non-blocking socket
d->timer.stop(); // no need for a timer here
socketDevice()->setBlocking(false);
while (true)
{
connectionEvent();
if (state() < Connecting)
return false; // error connecting
if (state() == Connected)
return true; // connected!
if (remainingTimeout() <= 0)
{
// we've timed out
timeoutSlot();
return false;
}
if (socketDevice()->error() == InProgress)
{
bool timedout;
socketDevice()->poll(remainingTimeout(), &timedout);
if (timedout)
{
timeoutSlot();
return false;
}
}
}
}
}
connectionEvent();
return error() == NoError;
}
bool KStreamSocket::connect(const KResolverEntry& entry)
{
return KClientSocketBase::connect(entry);
}
void KStreamSocket::hostFoundSlot()
{
QObject::disconnect(this, SLOT(hostFoundSlot()));
if (timeout() > 0)
d->timer.start(timeout(), true);
QTimer::singleShot(0, this, SLOT(connectionEvent()));
}
void KStreamSocket::connectionEvent()
{
if (state() != HostFound && state() != Connecting)
return; // nothing to do
const KResolverResults& peer = peerResults();
if (state() == HostFound)
{
d->startTime.start();
setState(Connecting);
emit stateChanged(Connecting);
d->peer = peer.begin();
d->local = localResults().begin(); // just to be on the safe side
}
while (d->peer != peer.end())
{
const KResolverEntry &r = *d->peer;
if (socketDevice()->socket() != -1)
{
// we have an existing file descriptor
// this means that we've got activity in it (connection result)
if (socketDevice()->connect(r) && socketDevice()->error() == NoError)
{
// yes, it did connect!
connectionSucceeded(r);
return;
}
else if (socketDevice()->error() == InProgress)
// nope, still in progress
return;
// no, the socket failed to connect
copyError();
socketDevice()->close();
++d->peer;
continue;
}
// try to bind
if (!bindLocallyFor(r))
{
// could not find a matching family
++d->peer;
continue;
}
{
bool skip = false;
emit aboutToConnect(r, skip);
if (skip)
{
++d->peer;
continue;
}
}
if (socketDevice()->connect(r) || socketDevice()->error() == InProgress)
{
// socket is attempting to connect
if (socketDevice()->error() == InProgress)
{
QSocketNotifier *n = socketDevice()->readNotifier();
QObject::connect(n, SIGNAL(activated(int)),
this, SLOT(connectionEvent()));
n->setEnabled(true);
n = socketDevice()->writeNotifier();
QObject::connect(n, SIGNAL(activated(int)),
this, SLOT(connectionEvent()));
n->setEnabled(true);
return; // wait for activity
}
// socket has connected
connectionSucceeded(r);
return;
}
// connection failed
// try next
copyError();
socketDevice()->close();
++d->peer;
}
// that was the last item
socketDevice()->setSocketOptions(socketOptions());
setState(Idle);
emit stateChanged(Idle);
emit gotError(error());
return;
}
void KStreamSocket::timeoutSlot()
{
if (state() != Connecting)
return;
// halt the connections
socketDevice()->close(); // this also kills the notifiers
setError(IO_TimeOutError, Timeout);
setState(HostFound);
emit stateChanged(HostFound);
QGuardedPtr<KStreamSocket> that = this;
emit gotError(Timeout);
if (!that.isNull())
emit timedOut();
}
bool KStreamSocket::bindLocallyFor(const KResolverEntry& peer)
{
const KResolverResults& local = localResults();
if (local.isEmpty())
// user doesn't want to bind to any specific local address
return true;
bool foundone = false;
// scan the local resolution for a matching family
for (d->local = local.begin(); d->local != local.end(); ++d->local)
if ((*d->local).family() == peer.family())
{
// found a suitable address!
foundone = true;
if (socketDevice()->bind(*d->local))
return true;
}
if (!foundone)
{
// found nothing
setError(IO_BindError, NotSupported);
emit gotError(NotSupported);
}
else
copyError();
return false;
}
void KStreamSocket::connectionSucceeded(const KResolverEntry& peer)
{
QObject::disconnect(socketDevice()->readNotifier(), 0, this, SLOT(connectionEvent()));
QObject::disconnect(socketDevice()->writeNotifier(), 0, this, SLOT(connectionEvent()));
resetError();
setFlags(IO_Sequential | IO_Raw | IO_ReadWrite | IO_Open | IO_Async);
setState(Connected);
socketDevice()->setSocketOptions(socketOptions());
d->timer.stop();
emit stateChanged(Connected);
if (!localResults().isEmpty())
emit bound(*d->local);
emit connected(peer);
}
#include "kstreamsocket.moc"
KNetwork::KStreamSocket::connect
virtual bool connect(const QString &node=QString::null, const QString &service=QString::null)
Reimplemented from KClientSocketBase.
Definition: kstreamsocket.cpp:108
KNetwork::KSocketBase::blocking
bool blocking() const
Retrieves this socket's blocking mode.
Definition: ksocketbase.cpp:81
KNetwork::KSocketBase::socketDevice
KSocketDevice * socketDevice() const
Retrieves the socket implementation used on this socket.
Definition: ksocketbase.cpp:116
KNetwork::KClientSocketBase::state
SocketState state() const
Returns the current state for this socket.
Definition: kclientsocketbase.cpp:64
KNetwork::KStreamSocket::remainingTimeout
int remainingTimeout() const
Retrieves the remaining timeout time (in milliseconds).
Definition: kstreamsocket.cpp:78
KNetwork::KStreamSocket::timeout
int timeout() const
Retrieves the timeout value (in milliseconds).
Definition: kstreamsocket.cpp:73
KNetwork::KResolverEntry
One resolution entry.
Definition: kresolver.h:66
KNetwork::KActiveSocketBase::resetError
void resetError()
Resets the socket error code and the I/O Device's status.
Definition: ksocketbase.cpp:315
KNetwork::KSocketDevice::writeNotifier
QSocketNotifier * writeNotifier() const
Returns a socket notifier for output on this socket.
Definition: ksocketdevice.cpp:627
KNetwork::KResolver::setFamily
void setFamily(int families)
Sets the allowed socket families.
Definition: kresolver.cpp:397
KNetwork::KClientSocketBase::lookup
virtual bool lookup()
Starts the lookup for peer and local hostnames as well as their services.
Definition: kclientsocketbase.cpp:131
KNetwork::KClientSocketBase::localResolver
KResolver & localResolver() const
Returns the internal KResolver object used for looking up the local host name and service...
Definition: kclientsocketbase.cpp:101
KNetwork::KSocketBase::error
SocketError error() const
Retrieves the socket error code.
Definition: ksocketbase.cpp:160
KNetwork::KClientSocketBase::aboutToConnect
void aboutToConnect(const KResolverEntry &remote, bool &skip)
This signal is emitted when the socket is about to connect to an address (but before doing so)...
KNetwork::KClientSocketBase::gotError
void gotError(int code)
This signal is emitted when this object finds an error.
KNetwork::KClientSocketBase::hostFound
void hostFound()
This signal is emitted when the lookup is successfully completed.
KNetwork::KResolverResults
Name and service resolution results.
Definition: kresolver.h:197
KNetwork::KSocketDevice::setSocketOptions
virtual bool setSocketOptions(int opts)
This implementation sets the options on the socket.
Definition: ksocketdevice.cpp:110
KNetwork::KClientSocketBase::setSocketOptions
virtual bool setSocketOptions(int opts)
Sets the socket options.
Definition: kclientsocketbase.cpp:75
KNetwork::KClientSocketBase::connect
virtual bool connect(const QString &node=QString::null, const QString &service=QString::null)=0
Attempts to connect to the these hostname and service, or use the default ones if none are given...
KNetwork::KResolver::setServiceName
void setServiceName(const QString &service)
Sets the service name to be resolved.
Definition: kresolver.cpp:360
KNetwork::KSocketDevice::readNotifier
QSocketNotifier * readNotifier() const
Returns a socket notifier for input on this socket.
Definition: ksocketdevice.cpp:609
KNetwork::KStreamSocket::timedOut
void timedOut()
This signal is emitted when a connection timeout occurs.
KNetwork::KClientSocketBase::copyError
void copyError()
Convenience function to set this object's error code to match that of the socket device.
Definition: kclientsocketbase.cpp:472
KNetwork::KSocketDevice::bind
virtual bool bind(const KResolverEntry &address)
Binds this socket to the given address.
Definition: ksocketdevice.cpp:232
KNetwork::KActiveSocketBase::setError
void setError(int status, SocketError error)
Sets the socket's error code and the I/O Device's status.
Definition: ksocketbase.cpp:309
KNetwork::KClientSocketBase::peerResults
const KResolverResults & peerResults() const
Returns the internal list of resolved results for the peer address.
Definition: kclientsocketbase.cpp:96
KNetwork::KStreamSocket::~KStreamSocket
virtual ~KStreamSocket()
Destructor.
Definition: kstreamsocket.cpp:67
KNetwork::KClientSocketBase::connected
void connected(const KResolverEntry &remote)
This socket is emitted when the socket successfully connects to a remote address. ...
KNetwork::KSocketDevice::socket
int socket() const
Returns the file descriptor for this socket.
Definition: ksocketdevice.h:122
KNetwork::KClientSocketBase::setState
void setState(SocketState state)
Sets the socket state to state.
Definition: kclientsocketbase.cpp:69
KNetwork::KClientSocketBase::stateChanged
void stateChanged(int newstate)
This signal is emitted whenever the socket state changes.
KNetwork::KStreamSocket::setTimeout
void setTimeout(int msecs)
Sets the timeout value.
Definition: kstreamsocket.cpp:88
KNetwork::KStreamSocket::bind
virtual bool bind(const QString &node=QString::null, const QString &service=QString::null)
Binds this socket to the given nodename and service, or use the default ones if none are given...
Definition: kstreamsocket.cpp:96
KNetwork::KResolver::setNodeName
void setNodeName(const QString &nodename)
Sets the nodename for the resolution.
Definition: kresolver.cpp:348
KNetwork::KSocketDevice::connect
virtual bool connect(const KResolverEntry &address)
Connect to a remote host.
Definition: ksocketdevice.cpp:276
KNetwork::KClientSocketBase::bound
void bound(const KResolverEntry &local)
This signal is emitted when the socket successfully binds to an address.
KNetwork::KSocketDevice::close
virtual void close()
Closes the socket.
Definition: ksocketdevice.cpp:180
KNetwork::KSocketDevice::poll
virtual bool poll(bool *input, bool *output, bool *exception=0L, int timeout=-1, bool *timedout=0L)
Executes a poll in the socket, via select(2) or poll(2).
Definition: ksocketdevice.cpp:663
KNetwork::KResolverEntry::family
int family() const
Retrieves the family associated with this socket address.
Definition: kresolver.cpp:150
KNetwork::KClientSocketBase
Abstract client socket class.
Definition: kclientsocketbase.h:49
KNetwork::KStreamSocket::KStreamSocket
KStreamSocket(const QString &node=QString::null, const QString &service=QString::null, QObject *parent=0L, const char *name=0L)
Default constructor.
Definition: kstreamsocket.cpp:53
KNetwork::KSocketBase::setBlocking
virtual bool setBlocking(bool enable)
Sets this socket's blocking mode.
Definition: ksocketbase.cpp:76
KNetwork::KClientSocketBase::localResults
const KResolverResults & localResults() const
Returns the internal list of resolved results for the local address.
Definition: kclientsocketbase.cpp:106
KNetwork::KSocketBase::socketOptions
virtual int socketOptions() const
Retrieves the socket options that have been set.
Definition: ksocketbase.cpp:71
KNetwork::KClientSocketBase::peerResolver
KResolver & peerResolver() const
Returns the internal KResolver object used for looking up the peer host name and service.
Definition: kclientsocketbase.cpp:91

KDE Home | KDE Accessibility Home | Description of Access Keys