# kdecore Library API Documentation

Overview | Class Hierarchy | Classes | Classes (annotated) | Members | Namespaces | Source Files

# 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   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"

This file is part of the documentation for kdecore Library Version 3.4.1.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Sat Jun 11 20:18:10 2005 by doxygen 1.4.1 written by Dimitri van Heesch, © 1997-2003