• Skip to content
  • Skip to link menu
KDE 4.3 API Reference
  • KDE API Reference
  • kdelibs
  • Sitemap
  • Contact Us
 

KDECore

k3serversocket.cpp

Go to the documentation of this file.
00001 /*  -*- C++ -*-
00002  *  Copyright (C) 2003 Thiago Macieira <thiago@kde.org>
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 "k3serversocket.h"
00026 
00027 #include <config.h>
00028 #include <config-network.h>
00029 
00030 #include <QSocketNotifier>
00031 #include <QMutex>
00032 
00033 #include "k3socketaddress.h"
00034 #include "k3resolver.h"
00035 #include "k3socketbase.h"
00036 #include "k3socketdevice.h"
00037 #include "k3bufferedsocket.h"
00038 
00039 using namespace KNetwork;
00040 
00041 class KNetwork::KServerSocketPrivate
00042 {
00043 public:
00044   KResolver resolver;
00045   KResolverResults resolverResults;
00046 
00047   enum { None, LookupDone, Bound, Listening } state;
00048   int backlog;
00049   int timeout;
00050 
00051   bool bindWhenFound : 1, listenWhenBound : 1, useKBufferedSocket : 1;
00052 
00053   KServerSocketPrivate()
00054     : state(None), timeout(0), bindWhenFound(false), listenWhenBound(false),
00055       useKBufferedSocket(true)
00056   {
00057     resolver.setFlags(KResolver::Passive);
00058     resolver.setFamily(KResolver::KnownFamily);
00059   }
00060 };
00061 
00062 KServerSocket::KServerSocket(QObject* parent)
00063   : QObject(parent), d(new KServerSocketPrivate)
00064 {
00065   QObject::connect(&d->resolver, SIGNAL(finished(const KNetwork::KResolverResults&)),
00066            this, SLOT(lookupFinishedSlot()));
00067 }
00068 
00069 KServerSocket::KServerSocket(const QString& service, QObject* parent)
00070   : QObject(parent), d(new KServerSocketPrivate)
00071 {
00072   QObject::connect(&d->resolver, SIGNAL(finished(const KNetwork::KResolverResults&)),
00073            this, SLOT(lookupFinishedSlot()));
00074   d->resolver.setServiceName(service);
00075 }
00076 
00077 KServerSocket::KServerSocket(const QString& node, const QString& service,
00078                  QObject* parent)
00079   : QObject(parent), d(new KServerSocketPrivate)
00080 {
00081   QObject::connect(&d->resolver, SIGNAL(finished(const KNetwork::KResolverResults&)),
00082            this, SLOT(lookupFinishedSlot()));
00083   setAddress(node, service);
00084 }
00085 
00086 KServerSocket::~KServerSocket()
00087 {
00088   close();
00089   delete d;
00090 }
00091 
00092 bool KServerSocket::setSocketOptions(int opts)
00093 {
00094   QMutexLocker locker(mutex());
00095   KSocketBase::setSocketOptions(opts); // call parent
00096   bool result = socketDevice()->setSocketOptions(opts); // and set the implementation
00097   copyError();
00098   return result;
00099 }
00100 
00101 KResolver& KServerSocket::resolver() const
00102 {
00103   return d->resolver;
00104 }
00105 
00106 const KResolverResults& KServerSocket::resolverResults() const
00107 {
00108   return d->resolverResults;
00109 }
00110 
00111 void KServerSocket::setResolutionEnabled(bool enable)
00112 {
00113   if (enable)
00114     d->resolver.setFlags(d->resolver.flags() & ~KResolver::NoResolve);
00115   else
00116     d->resolver.setFlags(d->resolver.flags() | KResolver::NoResolve);
00117 }
00118 
00119 void KServerSocket::setFamily(int families)
00120 {
00121   d->resolver.setFamily(families);
00122 }
00123 
00124 void KServerSocket::setAddress(const QString& service)
00125 {
00126   d->resolver.setNodeName(QString());
00127   d->resolver.setServiceName(service);
00128   d->resolverResults.empty();
00129   if (d->state <= KServerSocketPrivate::LookupDone)
00130     d->state = KServerSocketPrivate::None;
00131 }
00132 
00133 void KServerSocket::setAddress(const QString& node, const QString& service)
00134 {
00135   d->resolver.setNodeName(node);
00136   d->resolver.setServiceName(service);
00137   d->resolverResults.empty();
00138   if (d->state <= KServerSocketPrivate::LookupDone)
00139     d->state = KServerSocketPrivate::None;
00140 }
00141 
00142 void KServerSocket::setTimeout(int msec)
00143 {
00144   d->timeout = msec;
00145 }
00146 
00147 bool KServerSocket::lookup()
00148 {
00149   setError(NoError);
00150   if (d->resolver.isRunning() && !blocking())
00151     return true;        // already doing lookup
00152 
00153   if (d->state >= KServerSocketPrivate::LookupDone)
00154     return true;        // results are already available
00155 
00156   // make sure we have at least one parameter for lookup
00157   if (d->resolver.serviceName().isNull() &&
00158       !d->resolver.nodeName().isNull())
00159     d->resolver.setServiceName(QLatin1String(""));
00160 
00161   // don't restart the lookups if they had succeeded and
00162   // the input values weren't changed
00163 
00164   // reset results
00165   d->resolverResults = KResolverResults();
00166 
00167   if (d->resolver.status() <= 0)
00168     // if it's already running, there's no harm in calling again
00169     d->resolver.start();    // signal may emit
00170 
00171   if (blocking())
00172     {
00173       // we're in blocking mode operation
00174       // wait for the results
00175 
00176       d->resolver.wait();   // signal may be emitted again
00177       // lookupFinishedSlot has been called
00178     }
00179 
00180   return true;
00181 }
00182 
00183 bool KServerSocket::bind(const KResolverEntry& address)
00184 {
00185   if (socketDevice()->bind(address))
00186     {
00187       setError(NoError);
00188 
00189       d->state = KServerSocketPrivate::Bound;
00190       emit bound(address);
00191       return true;
00192     }
00193   copyError();
00194   return false;
00195 }
00196 
00197 bool KServerSocket::bind(const QString& node, const QString& service)
00198 {
00199   setAddress(node, service);
00200   return bind();
00201 }
00202 
00203 bool KServerSocket::bind(const QString& service)
00204 {
00205   setAddress(service);
00206   return bind();
00207 }
00208 
00209 bool KServerSocket::bind()
00210 {
00211   if (d->state >= KServerSocketPrivate::Bound)
00212     return true;
00213 
00214   if (d->state < KServerSocketPrivate::LookupDone)
00215     {
00216       if (!blocking())
00217     {
00218       d->bindWhenFound = true;
00219       bool ok = lookup();   // will call doBind
00220       if (d->state >= KServerSocketPrivate::Bound)
00221         d->bindWhenFound = false;
00222       return ok;
00223     }
00224 
00225       // not blocking
00226       if (!lookup())
00227     return false;
00228     }
00229 
00230   return doBind();
00231 }
00232 
00233 bool KServerSocket::listen(int backlog)
00234 {
00235   // WARNING
00236   // this function has to be reentrant
00237   // due to the mechanisms used for binding, this function might
00238   // end up calling itself
00239 
00240   if (d->state == KServerSocketPrivate::Listening)
00241     return true;        // already listening
00242 
00243   d->backlog = backlog;
00244 
00245   if (d->state < KServerSocketPrivate::Bound)
00246     {
00247       // we must bind
00248       // note that we can end up calling ourselves here
00249       d->listenWhenBound = true;
00250       if (!bind())
00251     {
00252       d->listenWhenBound = false;
00253       return false;
00254     }
00255 
00256       if (d->state < KServerSocketPrivate::Bound)
00257     // asynchronous lookup in progress...
00258     // we can't be blocking here anyways
00259     return true;
00260 
00261       d->listenWhenBound = false;
00262     }
00263 
00264   if (d->state < KServerSocketPrivate::Listening)
00265     return doListen();
00266 
00267   return true;
00268 }
00269 
00270 void KServerSocket::close()
00271 {
00272   socketDevice()->close();
00273   if (d->resolver.isRunning())
00274     d->resolver.cancel(false);
00275   d->state = KServerSocketPrivate::None;
00276   emit closed();
00277 }
00278 
00279 void KServerSocket::setAcceptBuffered(bool enable)
00280 {
00281   d->useKBufferedSocket = enable;
00282 }
00283 
00284 KStreamSocket* KServerSocket::accept()
00285 {
00286   if (d->state < KServerSocketPrivate::Listening)
00287     {
00288       if (!blocking())
00289     {
00290       listen();
00291       setError(WouldBlock);
00292       return NULL;
00293     }
00294       else if (!listen())
00295     // error happened during listen
00296     return false;
00297     }
00298 
00299   // check to see if we're doing a timeout
00300   if (blocking() && d->timeout > 0)
00301     {
00302       bool timedout;
00303       if (!socketDevice()->poll(d->timeout, &timedout))
00304     {
00305       copyError();
00306       return NULL;
00307     }
00308 
00309       if (timedout)
00310     return 0L;
00311     }
00312 
00313   // we're listening here
00314   KSocketDevice* accepted = socketDevice()->accept();
00315   if (!accepted)
00316     {
00317       // error happened during accept
00318       copyError();
00319       return NULL;
00320     }
00321 
00322   KStreamSocket* streamsocket;
00323   if (d->useKBufferedSocket)
00324     {
00325       streamsocket = new KBufferedSocket();
00326       streamsocket->setOpenMode(KStreamSocket::ReadWrite);
00327     }
00328   else
00329     {
00330       streamsocket = new KStreamSocket();
00331       streamsocket->setOpenMode(KStreamSocket::ReadWrite |
00332                 KStreamSocket::Unbuffered);
00333     }
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 
00341   return streamsocket;
00342 }
00343 
00344 KSocketAddress KServerSocket::localAddress() const
00345 {
00346   return socketDevice()->localAddress();
00347 }
00348 
00349 KSocketAddress KServerSocket::externalAddress() const
00350 {
00351   return socketDevice()->externalAddress();
00352 }
00353 
00354 void KServerSocket::lookupFinishedSlot()
00355 {
00356   if (d->resolver.isRunning() || d->state > KServerSocketPrivate::LookupDone)
00357     return;
00358 
00359   if (d->resolver.status() < 0)
00360     {
00361       setError(LookupFailure);
00362       emit gotError(LookupFailure);
00363       d->bindWhenFound = d->listenWhenBound = false;
00364       d->state = KServerSocketPrivate::None;
00365       return;
00366     }
00367 
00368   // lookup succeeded
00369   d->resolverResults = d->resolver.results();
00370   d->state = KServerSocketPrivate::LookupDone;
00371   emit hostFound();
00372 
00373   if (d->bindWhenFound)
00374     doBind();
00375 }
00376 
00377 void KServerSocket::copyError()
00378 {
00379   setError(socketDevice()->error());
00380 }
00381 
00382 bool KServerSocket::doBind()
00383 {
00384   d->bindWhenFound = false;
00385   // loop through the results and bind to the first that works
00386 
00387   KResolverResults::ConstIterator it = d->resolverResults.constBegin();
00388   for ( ; it != d->resolverResults.constEnd(); ++it)
00389     if (bind(*it))
00390       {
00391     if (d->listenWhenBound)
00392       return doListen();
00393     return true;
00394       }
00395     else
00396       socketDevice()->close();  // didn't work, try again
00397 
00398   // failed to bind
00399   emit gotError(error());
00400   return false;
00401 }
00402 
00403 bool KServerSocket::doListen()
00404 {
00405   if (!socketDevice()->listen(d->backlog))
00406     {
00407       copyError();
00408       emit gotError(error());
00409       return false;     // failed to listen
00410     }
00411 
00412   // set up ready accept signal
00413   QObject::connect(socketDevice()->readNotifier(), SIGNAL(activated(int)),
00414            this, SIGNAL(readyAccept()));
00415   d->state = KServerSocketPrivate::Listening;
00416   return true;
00417 }
00418 
00419 
00420 #include "k3serversocket.moc"

KDECore

Skip menu "KDECore"
  • Main Page
  • Modules
  • Namespace List
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Namespace Members
  • Class Members
  • Related Pages

kdelibs

Skip menu "kdelibs"
  • DNSSD
  • Interfaces
  •   KHexEdit
  •   KMediaPlayer
  •   KSpeech
  •   KTextEditor
  • Kate
  • kconf_update
  • KDE3Support
  •   KUnitTest
  • KDECore
  • KDED
  • KDEsu
  • KDEUI
  • KDocTools
  • KFile
  • KHTML
  • KImgIO
  • KInit
  • kio
  • KIOSlave
  • KJS
  •   KJS-API
  •   WTF
  • kjsembed
  • KNewStuff
  • KParts
  • KPty
  • Kross
  • KUtils
  • Nepomuk
  • Plasma
  • Solid
  • Sonnet
  • ThreadWeaver
Generated for kdelibs by doxygen 1.6.1
This website is maintained by Adriaan de Groot and Allen Winter.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal