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

KDECore

kserversocket.cpp

Go to the documentation of this file.
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   if (d->state <= KServerSocketPrivate::LookupDone)
00129     d->state = KServerSocketPrivate::None;
00130 }
00131 
00132 void KServerSocket::setAddress(const QString& node, const QString& service)
00133 {
00134   d->resolver.setNodeName(node);
00135   d->resolver.setServiceName(service);
00136   d->resolverResults.empty();
00137   if (d->state <= KServerSocketPrivate::LookupDone)
00138     d->state = KServerSocketPrivate::None;
00139 }
00140 
00141 void KServerSocket::setTimeout(int msec)
00142 {
00143   d->timeout = msec;
00144 }
00145 
00146 bool KServerSocket::lookup()
00147 {
00148   setError(NoError);
00149   if (d->resolver.isRunning() && !blocking())
00150     return true;        // already doing lookup
00151 
00152   if (d->state >= KServerSocketPrivate::LookupDone)
00153     return true;        // results are already available
00154 
00155   // make sure we have at least one parameter for lookup
00156   if (d->resolver.serviceName().isNull() &&
00157       !d->resolver.nodeName().isNull())
00158     d->resolver.setServiceName(QString::fromLatin1(""));
00159 
00160   // don't restart the lookups if they had succeeded and
00161   // the input values weren't changed
00162 
00163   // reset results
00164   d->resolverResults = KResolverResults();
00165 
00166   if (d->resolver.status() <= 0)
00167     // if it's already running, there's no harm in calling again
00168     d->resolver.start();    // signal may emit
00169 
00170   if (blocking())
00171     {
00172       // we're in blocking mode operation
00173       // wait for the results
00174 
00175       d->resolver.wait();   // signal may be emitted again
00176       // lookupFinishedSlot has been called
00177     }
00178 
00179   return true;
00180 }
00181 
00182 bool KServerSocket::bind(const KResolverEntry& address)
00183 {
00184   if (socketDevice()->bind(address))
00185     {
00186       setError(NoError);
00187 
00188       d->state = KServerSocketPrivate::Bound;
00189       emit bound(address);
00190       return true;
00191     }
00192   copyError();
00193   return false;
00194 }
00195 
00196 bool KServerSocket::bind(const QString& node, const QString& service)
00197 {
00198   setAddress(node, service);
00199   return bind();
00200 }
00201 
00202 bool KServerSocket::bind(const QString& service)
00203 {
00204   setAddress(service);
00205   return bind();
00206 }
00207 
00208 bool KServerSocket::bind()
00209 {
00210   if (d->state >= KServerSocketPrivate::Bound)
00211     return true;
00212 
00213   if (d->state < KServerSocketPrivate::LookupDone)
00214     {
00215       if (!blocking())
00216     {
00217       d->bindWhenFound = true;
00218       bool ok = lookup();   // will call doBind
00219       if (d->state >= KServerSocketPrivate::Bound)
00220         d->bindWhenFound = false;
00221       return ok;
00222     }
00223 
00224       // not blocking
00225       if (!lookup())
00226     return false;
00227     }
00228 
00229   return doBind();
00230 }
00231 
00232 bool KServerSocket::listen(int backlog)
00233 {
00234   // WARNING
00235   // this function has to be reentrant
00236   // due to the mechanisms used for binding, this function might
00237   // end up calling itself
00238 
00239   if (d->state == KServerSocketPrivate::Listening)
00240     return true;        // already listening
00241 
00242   d->backlog = backlog;
00243 
00244   if (d->state < KServerSocketPrivate::Bound)
00245     {
00246       // we must bind
00247       // note that we can end up calling ourselves here
00248       d->listenWhenBound = true;
00249       if (!bind())
00250     {
00251       d->listenWhenBound = false;
00252       return false;
00253     }
00254 
00255       if (d->state < KServerSocketPrivate::Bound)
00256     // asynchronous lookup in progress...
00257     // we can't be blocking here anyways
00258     return true;
00259 
00260       d->listenWhenBound = false;
00261     }
00262 
00263   if (d->state < KServerSocketPrivate::Listening)
00264     return doListen();
00265 
00266   return true;
00267 }
00268 
00269 void KServerSocket::close()
00270 {
00271   socketDevice()->close();
00272   if (d->resolver.isRunning())
00273     d->resolver.cancel(false);
00274   d->state = KServerSocketPrivate::None;
00275   emit closed();
00276 }
00277 
00278 void KServerSocket::setAcceptBuffered(bool enable)
00279 {
00280   d->useKBufferedSocket = enable;
00281 }
00282 
00283 KActiveSocketBase* KServerSocket::accept()
00284 {
00285   if (d->state < KServerSocketPrivate::Listening)
00286     {
00287       if (!blocking())
00288     {
00289       listen();
00290       setError(WouldBlock);
00291       return NULL;
00292     }
00293       else if (!listen())
00294     // error happened during listen
00295     return false;
00296     }
00297 
00298   // check to see if we're doing a timeout
00299   if (blocking() && d->timeout > 0)
00300     {
00301       bool timedout;
00302       if (!socketDevice()->poll(d->timeout, &timedout))
00303     {
00304       copyError();
00305       return NULL;
00306     }
00307 
00308       if (timedout)
00309     return 0L;
00310     }
00311 
00312   // we're listening here
00313   KSocketDevice* accepted = socketDevice()->accept();
00314   if (!accepted)
00315     {
00316       // error happened during accept
00317       copyError();
00318       return NULL;
00319     }
00320 
00321   KStreamSocket* streamsocket;
00322   if (d->useKBufferedSocket)
00323     streamsocket = new KBufferedSocket();
00324   else
00325     streamsocket = new KStreamSocket();
00326   streamsocket->setSocketDevice(accepted);
00327 
00328   // FIXME!
00329   // when KStreamSocket can find out the state of the socket passed through
00330   // setSocketDevice, this will probably be unnecessary:
00331   streamsocket->setState(KStreamSocket::Connected);
00332   streamsocket->setFlags(IO_Sequential | IO_Raw | IO_ReadWrite | IO_Open | IO_Async);
00333 
00334   return streamsocket;
00335 }
00336 
00337 KSocketAddress KServerSocket::localAddress() const
00338 {
00339   return socketDevice()->localAddress();
00340 }
00341 
00342 KSocketAddress KServerSocket::externalAddress() const
00343 {
00344   return socketDevice()->externalAddress();
00345 }
00346 
00347 void KServerSocket::lookupFinishedSlot()
00348 {
00349   if (d->resolver.isRunning() || d->state > KServerSocketPrivate::LookupDone)
00350     return;
00351 
00352   if (d->resolver.status() < 0)
00353     {
00354       setError(LookupFailure);
00355       emit gotError(LookupFailure);
00356       d->bindWhenFound = d->listenWhenBound = false;
00357       d->state = KServerSocketPrivate::None;
00358       return;
00359     }
00360 
00361   // lookup succeeded
00362   d->resolverResults = d->resolver.results();
00363   d->state = KServerSocketPrivate::LookupDone;
00364   emit hostFound();
00365 
00366   if (d->bindWhenFound)
00367     doBind();
00368 }
00369 
00370 void KServerSocket::copyError()
00371 {
00372   setError(socketDevice()->error());
00373 }
00374 
00375 bool KServerSocket::doBind()
00376 {
00377   d->bindWhenFound = false;
00378   // loop through the results and bind to the first that works
00379 
00380   KResolverResults::ConstIterator it = d->resolverResults.begin();
00381   for ( ; it != d->resolverResults.end(); ++it)
00382     if (bind(*it))
00383       {
00384     if (d->listenWhenBound)
00385       return doListen();
00386     return true;
00387       }
00388     else
00389       socketDevice()->close();  // didn't work, try again
00390 
00391   // failed to bind
00392   emit gotError(error());
00393   return false;
00394 }
00395 
00396 bool KServerSocket::doListen()
00397 {
00398   if (!socketDevice()->listen(d->backlog))
00399     {
00400       copyError();
00401       emit gotError(error());
00402       return false;     // failed to listen
00403     }
00404   
00405   // set up ready accept signal
00406   QObject::connect(socketDevice()->readNotifier(), SIGNAL(activated(int)),
00407            this, SIGNAL(readyAccept()));
00408   d->state = KServerSocketPrivate::Listening;
00409   return true;
00410 }
00411 
00412 
00413 #include "kserversocket.moc"

KDECore

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

API Reference

Skip menu "API Reference"
  • dcop
  • DNSSD
  • interfaces
  • Kate
  • kconf_update
  • KDECore
  • KDED
  • kdefx
  • KDEsu
  • kdeui
  • KDocTools
  • KHTML
  • KImgIO
  • KInit
  • kio
  • kioslave
  • KJS
  • KNewStuff
  • KParts
  • KUtils
Generated for API Reference by doxygen 1.5.9
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