kserversocket.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 <qmutex.h>
#include "ksocketaddress.h"
#include "kresolver.h"
#include "ksocketbase.h"
#include "ksocketdevice.h"
#include "kstreamsocket.h"
#include "kbufferedsocket.h"
#include "kserversocket.h"
using namespace KNetwork;
class KNetwork::KServerSocketPrivate
{
public:
KResolver resolver;
KResolverResults resolverResults;
enum { None, LookupDone, Bound, Listening } state;
int backlog;
int timeout;
bool bindWhenFound : 1, listenWhenBound : 1, useKBufferedSocket : 1;
KServerSocketPrivate()
: state(None), timeout(0), bindWhenFound(false), listenWhenBound(false),
useKBufferedSocket(true)
{
resolver.setFlags(KResolver::Passive);
resolver.setFamily(KResolver::KnownFamily);
}
};
KServerSocket::KServerSocket(QObject* parent, const char *name)
: QObject(parent, name), d(new KServerSocketPrivate)
{
QObject::connect(&d->resolver, SIGNAL(finished(KResolverResults)),
this, SLOT(lookupFinishedSlot()));
}
KServerSocket::KServerSocket(const QString& service, QObject* parent, const char *name)
: QObject(parent, name), d(new KServerSocketPrivate)
{
QObject::connect(&d->resolver, SIGNAL(finished(KResolverResults)),
this, SLOT(lookupFinishedSlot()));
d->resolver.setServiceName(service);
}
KServerSocket::KServerSocket(const QString& node, const QString& service,
QObject* parent, const char* name)
: QObject(parent, name), d(new KServerSocketPrivate)
{
QObject::connect(&d->resolver, SIGNAL(finished(KResolverResults)),
this, SLOT(lookupFinishedSlot()));
setAddress(node, service);
}
KServerSocket::~KServerSocket()
{
close();
delete d;
}
bool KServerSocket::setSocketOptions(int opts)
{
QMutexLocker locker(mutex());
KSocketBase::setSocketOptions(opts); // call parent
bool result = socketDevice()->setSocketOptions(opts); // and set the implementation
copyError();
return result;
}
KResolver& KServerSocket::resolver() const
{
return d->resolver;
}
const KResolverResults& KServerSocket::resolverResults() const
{
return d->resolverResults;
}
void KServerSocket::setResolutionEnabled(bool enable)
{
if (enable)
d->resolver.setFlags(d->resolver.flags() & ~KResolver::NoResolve);
else
d->resolver.setFlags(d->resolver.flags() | KResolver::NoResolve);
}
void KServerSocket::setFamily(int families)
{
d->resolver.setFamily(families);
}
void KServerSocket::setAddress(const QString& service)
{
d->resolver.setNodeName(QString::null);
d->resolver.setServiceName(service);
d->resolverResults.empty();
if (d->state <= KServerSocketPrivate::LookupDone)
d->state = KServerSocketPrivate::None;
}
void KServerSocket::setAddress(const QString& node, const QString& service)
{
d->resolver.setNodeName(node);
d->resolver.setServiceName(service);
d->resolverResults.empty();
if (d->state <= KServerSocketPrivate::LookupDone)
d->state = KServerSocketPrivate::None;
}
void KServerSocket::setTimeout(int msec)
{
d->timeout = msec;
}
bool KServerSocket::lookup()
{
setError(NoError);
if (d->resolver.isRunning() && !blocking())
return true; // already doing lookup
if (d->state >= KServerSocketPrivate::LookupDone)
return true; // results are already available
// make sure we have at least one parameter for lookup
if (d->resolver.serviceName().isNull() &&
!d->resolver.nodeName().isNull())
d->resolver.setServiceName(QString::fromLatin1(""));
// don't restart the lookups if they had succeeded and
// the input values weren't changed
// reset results
d->resolverResults = KResolverResults();
if (d->resolver.status() <= 0)
// if it's already running, there's no harm in calling again
d->resolver.start(); // signal may emit
if (blocking())
{
// we're in blocking mode operation
// wait for the results
d->resolver.wait(); // signal may be emitted again
// lookupFinishedSlot has been called
}
return true;
}
bool KServerSocket::bind(const KResolverEntry& address)
{
if (socketDevice()->bind(address))
{
setError(NoError);
d->state = KServerSocketPrivate::Bound;
emit bound(address);
return true;
}
copyError();
return false;
}
bool KServerSocket::bind(const QString& node, const QString& service)
{
setAddress(node, service);
return bind();
}
bool KServerSocket::bind(const QString& service)
{
setAddress(service);
return bind();
}
bool KServerSocket::bind()
{
if (d->state >= KServerSocketPrivate::Bound)
return true;
if (d->state < KServerSocketPrivate::LookupDone)
{
if (!blocking())
{
d->bindWhenFound = true;
bool ok = lookup(); // will call doBind
if (d->state >= KServerSocketPrivate::Bound)
d->bindWhenFound = false;
return ok;
}
// not blocking
if (!lookup())
return false;
}
return doBind();
}
bool KServerSocket::listen(int backlog)
{
// WARNING
// this function has to be reentrant
// due to the mechanisms used for binding, this function might
// end up calling itself
if (d->state == KServerSocketPrivate::Listening)
return true; // already listening
d->backlog = backlog;
if (d->state < KServerSocketPrivate::Bound)
{
// we must bind
// note that we can end up calling ourselves here
d->listenWhenBound = true;
if (!bind())
{
d->listenWhenBound = false;
return false;
}
if (d->state < KServerSocketPrivate::Bound)
// asynchronous lookup in progress...
// we can't be blocking here anyways
return true;
d->listenWhenBound = false;
}
if (d->state < KServerSocketPrivate::Listening)
return doListen();
return true;
}
void KServerSocket::close()
{
socketDevice()->close();
if (d->resolver.isRunning())
d->resolver.cancel(false);
d->state = KServerSocketPrivate::None;
emit closed();
}
void KServerSocket::setAcceptBuffered(bool enable)
{
d->useKBufferedSocket = enable;
}
KActiveSocketBase* KServerSocket::accept()
{
if (d->state < KServerSocketPrivate::Listening)
{
if (!blocking())
{
listen();
setError(WouldBlock);
return NULL;
}
else if (!listen())
// error happened during listen
return false;
}
// check to see if we're doing a timeout
if (blocking() && d->timeout > 0)
{
bool timedout;
if (!socketDevice()->poll(d->timeout, &timedout))
{
copyError();
return NULL;
}
if (timedout)
return 0L;
}
// we're listening here
KSocketDevice* accepted = socketDevice()->accept();
if (!accepted)
{
// error happened during accept
copyError();
return NULL;
}
KStreamSocket* streamsocket;
if (d->useKBufferedSocket)
streamsocket = new KBufferedSocket();
else
streamsocket = new KStreamSocket();
streamsocket->setSocketDevice(accepted);
// FIXME!
// when KStreamSocket can find out the state of the socket passed through
// setSocketDevice, this will probably be unnecessary:
streamsocket->setState(KStreamSocket::Connected);
streamsocket->setFlags(IO_Sequential | IO_Raw | IO_ReadWrite | IO_Open | IO_Async);
return streamsocket;
}
KSocketAddress KServerSocket::localAddress() const
{
return socketDevice()->localAddress();
}
KSocketAddress KServerSocket::externalAddress() const
{
return socketDevice()->externalAddress();
}
void KServerSocket::lookupFinishedSlot()
{
if (d->resolver.isRunning() || d->state > KServerSocketPrivate::LookupDone)
return;
if (d->resolver.status() < 0)
{
setError(LookupFailure);
emit gotError(LookupFailure);
d->bindWhenFound = d->listenWhenBound = false;
d->state = KServerSocketPrivate::None;
return;
}
// lookup succeeded
d->resolverResults = d->resolver.results();
d->state = KServerSocketPrivate::LookupDone;
emit hostFound();
if (d->bindWhenFound)
doBind();
}
void KServerSocket::copyError()
{
setError(socketDevice()->error());
}
bool KServerSocket::doBind()
{
d->bindWhenFound = false;
// loop through the results and bind to the first that works
KResolverResults::ConstIterator it = d->resolverResults.begin();
for ( ; it != d->resolverResults.end(); ++it)
if (bind(*it))
{
if (d->listenWhenBound)
return doListen();
return true;
}
else
socketDevice()->close(); // didn't work, try again
// failed to bind
emit gotError(error());
return false;
}
bool KServerSocket::doListen()
{
if (!socketDevice()->listen(d->backlog))
{
copyError();
emit gotError(error());
return false; // failed to listen
}
// set up ready accept signal
QObject::connect(socketDevice()->readNotifier(), SIGNAL(activated(int)),
this, SIGNAL(readyAccept()));
d->state = KServerSocketPrivate::Listening;
return true;
}
#include "kserversocket.moc"
KNetwork::KServerSocket::externalAddress
virtual KSocketAddress externalAddress() const
Returns this socket's externally-visible address if know.
Definition: kserversocket.cpp:342
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::KStreamSocket
Simple stream socket.
Definition: kstreamsocket.h:97
KNetwork::KServerSocket::localAddress
virtual KSocketAddress localAddress() const
Returns this socket's local address.
Definition: kserversocket.cpp:337
KNetwork::KServerSocket::resolverResults
const KResolverResults & resolverResults() const
Returns the internal list of resolved results for the binding address.
Definition: kserversocket.cpp:105
KNetwork::KSocketDevice::accept
virtual KSocketDevice * accept()
Accepts a new incoming connection.
Definition: ksocketdevice.cpp:309
KNetwork::KActiveSocketBase
Abstract class for active sockets.
Definition: ksocketbase.h:443
KNetwork::KResolverEntry
One resolution entry.
Definition: kresolver.h:66
KNetwork::KResolver
Name and service resolution class.
Definition: kresolver.h:295
KNetwork::KSocketBase::error
SocketError error() const
Retrieves the socket error code.
Definition: ksocketbase.cpp:160
KNetwork::KSocketAddress
A generic socket address.
Definition: ksocketaddress.h:423
KNetwork::KServerSocket::bound
void bound(const KResolverEntry &local)
This signal is emitted when the socket successfully binds to an address.
KNetwork::KServerSocket::listen
virtual bool listen(int backlog=5)
Puts this socket into listening mode.
Definition: kserversocket.cpp:232
KNetwork::KServerSocket::setAddress
void setAddress(const QString &service)
Sets the address on which we will listen.
Definition: kserversocket.cpp:123
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::KServerSocket::~KServerSocket
~KServerSocket()
Destructor.
Definition: kserversocket.cpp:85
KNetwork::KServerSocket::gotError
void gotError(int code)
This signal is emitted when this object finds an error.
KNetwork::KServerSocket::KServerSocket
KServerSocket(QObject *parent=0L, const char *name=0L)
Default constructor.
Definition: kserversocket.cpp:61
KNetwork::KSocketBase::mutex
QMutex * mutex() const
Returns the internal mutex for this class.
Definition: ksocketbase.cpp:278
KNetwork::KSocketBase::setError
void setError(SocketError error)
Sets the socket's error code.
Definition: ksocketbase.cpp:155
KNetwork::KBufferedSocket
Buffered stream sockets.
Definition: kbufferedsocket.h:58
KNetwork::KServerSocket::setResolutionEnabled
void setResolutionEnabled(bool enable)
Enables or disables name resolution.
Definition: kserversocket.cpp:110
KNetwork::KServerSocket::setTimeout
void setTimeout(int msecs)
Sets the timeout for accepting.
Definition: kserversocket.cpp:141
KNetwork::KClientSocketBase::setState
void setState(SocketState state)
Sets the socket state to state.
Definition: kclientsocketbase.cpp:69
KNetwork::KSocketBase::setSocketOptions
virtual bool setSocketOptions(int opts)
Set the given socket options.
Definition: ksocketbase.cpp:65
KNetwork::KServerSocket::closed
void closed()
This signal is emitted when the socket completes the closing/shut down process.
KNetwork::KServerSocket::hostFound
void hostFound()
This signal is emitted when the lookup is successfully completed.
KNetwork::KServerSocket::accept
virtual KActiveSocketBase * accept()
Accepts one incoming connection and return the associated, open socket.
Definition: kserversocket.cpp:283
KNetwork::KServerSocket::bind
virtual bool bind()
Binds the socket to the addresses previously set with setAddress.
Definition: kserversocket.cpp:208
KNetwork::KSocketDevice::close
virtual void close()
Closes the socket.
Definition: ksocketdevice.cpp:180
KNetwork::KSocketBase::setSocketDevice
virtual void setSocketDevice(KSocketDevice *device)
Sets the socket implementation to be used on this socket.
Definition: ksocketbase.cpp:136
KNetwork::KSocketDevice::localAddress
virtual KSocketAddress localAddress() const
Returns this socket's local address.
Definition: ksocketdevice.cpp:530
KNetwork::KServerSocket::close
virtual void close()
Closes this socket.
Definition: kserversocket.cpp:269
KNetwork::KServerSocket::readyAccept
void readyAccept()
This signal is emitted whenever the socket is ready for accepting – i.e., there is at least one conn...
KNetwork::KServerSocket::copyError
void copyError()
Convenience function to set this object's error code to match that of the socket device.
Definition: kserversocket.cpp:370
KNetwork::KSocketDevice
Low-level socket functionality.
Definition: ksocketdevice.h:50
KNetwork::KServerSocket::setAcceptBuffered
void setAcceptBuffered(bool enable)
Toggles whether the accepted socket will be buffered or not.
Definition: kserversocket.cpp:278
KNetwork::KServerSocket::setFamily
void setFamily(int families)
Sets the allowed families for the resolutions.
Definition: kserversocket.cpp:118
KNetwork::KServerSocket::resolver
KResolver & resolver() const
Returns the internal KResolver object used for looking up the host name and service.
Definition: kserversocket.cpp:100
KNetwork::KServerSocket::setSocketOptions
virtual bool setSocketOptions(int opts)
Sets the socket options.
Definition: kserversocket.cpp:91
KNetwork::KSocketDevice::externalAddress
virtual KSocketAddress externalAddress() const
Returns this socket's externally visible local address.
Definition: ksocketdevice.cpp:602
KNetwork::KServerSocket::lookup
virtual bool lookup()
Starts the lookup for peer and local hostnames as well as their services.
Definition: kserversocket.cpp:146

KDE Home | KDE Accessibility Home | Description of Access Keys