kdecore Library API Documentation

kserversocket.cpp

00001 /*  -*- C++ -*-
00002  *  Copyright (C) 2003 Thiago Macieira <thiago.macieira@kdemail.net>
00003  *
00004  *
00005  *  Permission is hereby granted, free of charge, to any person obtaining
00006  *  a copy of this software and associated documentation files (the
00007  *  "Software"), to deal in the Software without restriction, including
00008  *  without limitation the rights to use, copy, modify, merge, publish,
00009  *  distribute, sublicense, and/or sell copies of the Software, and to
00010  *  permit persons to whom the Software is furnished to do so, subject to
00011  *  the following conditions:
00012  *
00013  *  The above copyright notice and this permission notice shall be included 
00014  *  in all copies or substantial portions of the Software.
00015  *
00016  *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
00017  *  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
00018  *  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
00019  *  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
00020  *  LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
00021  *  OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
00022  *  WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
00023  */
00024 
00025 #include <config.h>
00026 
00027 #include <qsocketnotifier.h>
00028 #include <qmutex.h>
00029 
00030 #include "ksocketaddress.h"
00031 #include "kresolver.h"
00032 #include "ksocketbase.h"
00033 #include "ksocketdevice.h"
00034 #include "kstreamsocket.h"
00035 #include "kbufferedsocket.h"
00036 #include "kserversocket.h"
00037 
00038 using namespace KNetwork;
00039 
00040 class KNetwork::KServerSocketPrivate
00041 {
00042 public:
00043   KResolver resolver;
00044   KResolverResults resolverResults;
00045 
00046   enum { None, LookupDone, Bound, Listening } state;
00047   int backlog;
00048   int timeout;
00049 
00050   bool bindWhenFound : 1, listenWhenBound : 1, useKBufferedSocket : 1;
00051 
00052   KServerSocketPrivate()
00053     : state(None), timeout(0), bindWhenFound(false), listenWhenBound(false),
00054       useKBufferedSocket(true)
00055   { 
00056     resolver.setFlags(KResolver::Passive);
00057     resolver.setFamily(KResolver::KnownFamily);
00058   }
00059 };
00060 
00061 KServerSocket::KServerSocket(QObject* parent, const char *name)
00062   : QObject(parent, name), d(new KServerSocketPrivate)
00063 {
00064   QObject::connect(&d->resolver, SIGNAL(finished(KResolverResults)), 
00065            this, SLOT(lookupFinishedSlot()));
00066 }
00067 
00068 KServerSocket::KServerSocket(const QString& service, QObject* parent, const char *name)
00069   : QObject(parent, name), d(new KServerSocketPrivate)
00070 {
00071   QObject::connect(&d->resolver, SIGNAL(finished(KResolverResults)), 
00072            this, SLOT(lookupFinishedSlot()));
00073   d->resolver.setServiceName(service);
00074 }
00075 
00076 KServerSocket::KServerSocket(const QString& node, const QString& service,
00077                  QObject* parent, const char* name)
00078   : QObject(parent, name), d(new KServerSocketPrivate)
00079 {
00080   QObject::connect(&d->resolver, SIGNAL(finished(KResolverResults)), 
00081            this, SLOT(lookupFinishedSlot()));
00082   setAddress(node, service);
00083 }
00084 
00085 KServerSocket::~KServerSocket()
00086 {
00087   close();
00088   delete d;
00089 }
00090 
00091 bool KServerSocket::setSocketOptions(int opts)
00092 {
00093   QMutexLocker locker(mutex());
00094   KSocketBase::setSocketOptions(opts); // call parent
00095   bool result = socketDevice()->setSocketOptions(opts); // and set the implementation
00096   copyError();
00097   return result;
00098 }
00099 
00100 KResolver& KServerSocket::resolver() const
00101 {
00102   return d->resolver;
00103 }
00104 
00105 const KResolverResults& KServerSocket::resolverResults() const
00106 {
00107   return d->resolverResults;
00108 }
00109 
00110 void KServerSocket::setResolutionEnabled(bool enable)
00111 {
00112   if (enable)
00113     d->resolver.setFlags(d->resolver.flags() & ~KResolver::NoResolve);
00114   else
00115     d->resolver.setFlags(d->resolver.flags() | KResolver::NoResolve);
00116 }
00117 
00118 void KServerSocket::setFamily(int families)
00119 {
00120   d->resolver.setFamily(families);
00121 }
00122 
00123 void KServerSocket::setAddress(const QString& service)
00124 {
00125   d->resolver.setNodeName(QString::null);
00126   d->resolver.setServiceName(service);
00127   d->resolverResults.empty();
00128 }
00129 
00130 void KServerSocket::setAddress(const QString& node, const QString& service)
00131 {
00132   d->resolver.setNodeName(node);
00133   d->resolver.setServiceName(service);
00134   d->resolverResults.empty();
00135 }
00136 
00137 void KServerSocket::setTimeout(int msec)
00138 {
00139   d->timeout = msec;
00140 }
00141 
00142 bool KServerSocket::lookup()
00143 {
00144   setError(NoError);
00145   if (d->resolver.isRunning() && !blocking())
00146     return true;        // already doing lookup
00147 
00148   if (d->state >= KServerSocketPrivate::LookupDone)
00149     return true;        // results are already available
00150 
00151   // make sure we have at least one parameter for lookup
00152   if (d->resolver.serviceName().isNull() &&
00153       !d->resolver.nodeName().isNull())
00154     d->resolver.setServiceName(QString::fromLatin1(""));
00155 
00156   // don't restart the lookups if they had succeeded and
00157   // the input values weren't changed
00158 
00159   // reset results
00160   d->resolverResults = KResolverResults();
00161 
00162   if (d->resolver.status() <= 0)
00163     // if it's already running, there's no harm in calling again
00164     d->resolver.start();    // signal may emit
00165 
00166   if (blocking())
00167     {
00168       // we're in blocking mode operation
00169       // wait for the results
00170 
00171       d->resolver.wait();   // signal may be emitted again
00172       // lookupFinishedSlot has been called
00173     }
00174 
00175   return true;
00176 }
00177 
00178 bool KServerSocket::bind(const KResolverEntry& address)
00179 {
00180   if (socketDevice()->bind(address))
00181     {
00182       setError(NoError);
00183 
00184       d->state = KServerSocketPrivate::Bound;
00185       emit bound(address);
00186       return true;
00187     }
00188   copyError();
00189   return false;
00190 }
00191 
00192 bool KServerSocket::bind(const QString& node, const QString& service)
00193 {
00194   setAddress(node, service);
00195   return bind();
00196 }
00197 
00198 bool KServerSocket::bind(const QString& service)
00199 {
00200   setAddress(service);
00201   return bind();
00202 }
00203 
00204 bool KServerSocket::bind()
00205 {
00206   if (d->state >= KServerSocketPrivate::Bound)
00207     return true;
00208 
00209   if (d->state < KServerSocketPrivate::LookupDone)
00210     {
00211       d->bindWhenFound = true;
00212       bool ok = lookup();   // will call bind again
00213       if (d->state >= KServerSocketPrivate::Bound)
00214     d->bindWhenFound = false;
00215       return ok;
00216     }
00217 
00218   if (!doBind())
00219     {
00220       setError(NotSupported);
00221       emit gotError(NotSupported);
00222       return false;
00223     }
00224   
00225   return true;;
00226 }
00227 
00228 bool KServerSocket::listen(int backlog)
00229 {
00230   // WARNING
00231   // this function has to be reentrant
00232   // due to the mechanisms used for binding, this function might
00233   // end up calling itself
00234 
00235   if (d->state == KServerSocketPrivate::Listening)
00236     return true;        // already listening
00237 
00238   if (d->state < KServerSocketPrivate::Bound)
00239     {
00240       // we must bind
00241       // note that we can end up calling ourselves here
00242       d->listenWhenBound = true;
00243       d->backlog = backlog;
00244       if (!bind())
00245     {
00246       d->listenWhenBound = false;
00247       return false;
00248     }
00249 
00250       if (d->state < KServerSocketPrivate::Bound)
00251     // asynchronous lookup in progress...
00252     // we can't be blocking here anyways
00253     return true;
00254 
00255       d->listenWhenBound = false;
00256     }
00257 
00258   if (d->state < KServerSocketPrivate::Listening)
00259     {
00260       if (!socketDevice()->listen(backlog))
00261     {
00262       copyError();
00263       emit gotError(error());
00264       return false;     // failed to listen
00265     }
00266 
00267       // set up ready accept signal
00268       QObject::connect(socketDevice()->readNotifier(), SIGNAL(activated(int)),
00269                this, SIGNAL(readyAccept()));
00270       d->state = KServerSocketPrivate::Listening;
00271       return true;
00272     }
00273 
00274   return true;
00275 }
00276 
00277 void KServerSocket::close()
00278 {
00279   socketDevice()->close();
00280   if (d->resolver.isRunning())
00281     d->resolver.cancel(false);
00282   d->state = KServerSocketPrivate::None;
00283   emit closed();
00284 }
00285 
00286 void KServerSocket::setAcceptBuffered(bool enable)
00287 {
00288   d->useKBufferedSocket = enable;
00289 }
00290 
00291 KActiveSocketBase* KServerSocket::accept()
00292 {
00293   if (d->state < KServerSocketPrivate::Listening)
00294     {
00295       if (!blocking())
00296     {
00297       listen();
00298       setError(WouldBlock);
00299       return NULL;
00300     }
00301       else if (!listen())
00302     // error happened during listen
00303     return false;
00304     }
00305 
00306   // check to see if we're doing a timeout
00307   if (blocking() && d->timeout > 0)
00308     {
00309       bool timedout;
00310       if (!socketDevice()->poll(d->timeout, &timedout))
00311     {
00312       copyError();
00313       return NULL;
00314     }
00315 
00316       if (timedout)
00317     return 0L;
00318     }
00319 
00320   // we're listening here
00321   KSocketDevice* accepted = socketDevice()->accept();
00322   if (!accepted)
00323     {
00324       // error happened during accept
00325       copyError();
00326       return NULL;
00327     }
00328 
00329   KStreamSocket* streamsocket;
00330   if (d->useKBufferedSocket)
00331     streamsocket = new KBufferedSocket();
00332   else
00333     streamsocket = new KStreamSocket();
00334   streamsocket->setSocketDevice(accepted);
00335 
00336   // FIXME!
00337   // when KStreamSocket can find out the state of the socket passed through
00338   // setSocketDevice, this will probably be unnecessary:
00339   streamsocket->setState(KStreamSocket::Connected);
00340   streamsocket->setFlags(IO_Sequential | IO_Raw | IO_ReadWrite | IO_Open | IO_Async);
00341 
00342   return streamsocket;
00343 }
00344 
00345 KSocketAddress KServerSocket::localAddress() const
00346 {
00347   return socketDevice()->localAddress();
00348 }
00349 
00350 KSocketAddress KServerSocket::externalAddress() const
00351 {
00352   return socketDevice()->externalAddress();
00353 }
00354 
00355 void KServerSocket::lookupFinishedSlot()
00356 {
00357   if (d->resolver.isRunning() || d->state > KServerSocketPrivate::LookupDone)
00358     return;
00359 
00360   if (d->resolver.status() < 0)
00361     {
00362       setError(LookupFailure);
00363       emit gotError(LookupFailure);
00364       d->bindWhenFound = d->listenWhenBound = false;
00365       d->state = KServerSocketPrivate::None;
00366       return;
00367     }
00368 
00369   // lookup succeeded
00370   d->resolverResults = d->resolver.results();
00371   d->state = KServerSocketPrivate::LookupDone;
00372   emit hostFound();
00373 
00374   if (d->bindWhenFound)
00375     doBind();
00376 }
00377 
00378 void KServerSocket::copyError()
00379 {
00380   setError(socketDevice()->error());
00381 }
00382 
00383 bool KServerSocket::doBind()
00384 {
00385   d->bindWhenFound = false;
00386   // loop through the results and bind to the first that works
00387 
00388   KResolverResults::ConstIterator it = d->resolverResults.begin();
00389   for ( ; it != d->resolverResults.end(); ++it)
00390     if (bind(*it))
00391       {
00392     if (d->listenWhenBound)
00393       listen(d->backlog);
00394     return true;
00395       }
00396 
00397   // failed to bind
00398   emit gotError(error());
00399   return false;
00400 }
00401 
00402 #include "kserversocket.moc"
KDE Logo
This file is part of the documentation for kdecore Library Version 3.3.2.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Fri Jul 22 10:16:19 2005 by doxygen 1.3.6 written by Dimitri van Heesch, © 1997-2003