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

KDECore

k3clientsocketbase.cpp

Go to the documentation of this file.
00001 /*  -*- C++ -*-
00002  *  Copyright (C) 2003,2005 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 "k3clientsocketbase.h"
00026 
00027 #include <config.h>
00028 #include <config-network.h>
00029 
00030 #include <QSocketNotifier>
00031 #include <QTimer>
00032 #include <QMutex>
00033 
00034 #include "k3socketaddress.h"
00035 #include "k3resolver.h"
00036 #include "k3socketbase.h"
00037 #include "k3socketdevice.h"
00038 
00039 using namespace KNetwork;
00040 
00041 class KNetwork::KClientSocketBasePrivate
00042 {
00043 public:
00044   int state;
00045 
00046   KResolver localResolver, peerResolver;
00047   KResolverResults localResults, peerResults;
00048 
00049   bool enableRead : 1, enableWrite : 1;
00050 };
00051 
00052 KClientSocketBase::KClientSocketBase(QObject *parent)
00053   : KActiveSocketBase(parent), d(new KClientSocketBasePrivate)
00054 {
00055   d->state = Idle;
00056   d->enableRead = true;
00057   d->enableWrite = false;
00058 }
00059 
00060 KClientSocketBase::~KClientSocketBase()
00061 {
00062   close();
00063   delete d;
00064 }
00065 
00066 KClientSocketBase::SocketState KClientSocketBase::state() const
00067 {
00068   return static_cast<SocketState>(d->state);
00069 }
00070 
00071 void KClientSocketBase::setState(SocketState state)
00072 {
00073   d->state = state;
00074   stateChanging(state);
00075 }
00076 
00077 bool KClientSocketBase::setSocketOptions(int opts)
00078 {
00079   QMutexLocker locker(mutex());
00080   KSocketBase::setSocketOptions(opts); // call parent
00081 
00082   // don't create the device unnecessarily
00083   if (hasDevice())
00084     {
00085       bool result = socketDevice()->setSocketOptions(opts); // and set the implementation
00086       copyError();
00087       return result;
00088     }
00089 
00090   return true;
00091 }
00092 
00093 KResolver& KClientSocketBase::peerResolver() const
00094 {
00095   return d->peerResolver;
00096 }
00097 
00098 const KResolverResults& KClientSocketBase::peerResults() const
00099 {
00100   return d->peerResults;
00101 }
00102 
00103 KResolver& KClientSocketBase::localResolver() const
00104 {
00105   return d->localResolver;
00106 }
00107 
00108 const KResolverResults& KClientSocketBase::localResults() const
00109 {
00110   return d->localResults;
00111 }
00112 
00113 void KClientSocketBase::setResolutionEnabled(bool enable)
00114 {
00115   if (enable)
00116     {
00117       d->localResolver.setFlags(d->localResolver.flags() & ~KResolver::NoResolve);
00118       d->peerResolver.setFlags(d->peerResolver.flags() & ~KResolver::NoResolve);
00119     }
00120   else
00121     {
00122       d->localResolver.setFlags(d->localResolver.flags() | KResolver::NoResolve);
00123       d->peerResolver.setFlags(d->peerResolver.flags() | KResolver::NoResolve);
00124     }
00125 }
00126 
00127 void KClientSocketBase::setFamily(int families)
00128 {
00129   d->localResolver.setFamily(families);
00130   d->peerResolver.setFamily(families);
00131 }
00132 
00133 bool KClientSocketBase::lookup()
00134 {
00135   if (state() == HostLookup && !blocking())
00136     return true;        // already doing lookup
00137 
00138   if (state() > HostLookup)
00139     return true;        // results are already available
00140 
00141   if (state() < HostLookup)
00142     {
00143       if (d->localResolver.serviceName().isNull() &&
00144       !d->localResolver.nodeName().isNull())
00145     d->localResolver.setServiceName(QLatin1String(""));
00146 
00147       // don't restart the lookups if they had succeeded and
00148       // the input values weren't changed
00149       QObject::connect(&d->peerResolver,
00150                SIGNAL(finished(const KNetwork::KResolverResults&)),
00151                this, SLOT(lookupFinishedSlot()));
00152       QObject::connect(&d->localResolver,
00153                SIGNAL(finished(const KNetwork::KResolverResults&)),
00154                this, SLOT(lookupFinishedSlot()));
00155 
00156       if (d->localResolver.status() <= 0)
00157     d->localResolver.start();
00158       if (d->peerResolver.status() <= 0)
00159     d->peerResolver.start();
00160 
00161       setState(HostLookup);
00162       emit stateChanged(HostLookup);
00163 
00164       if (!d->localResolver.isRunning() && !d->peerResolver.isRunning())
00165     {
00166       // if nothing is running, then the lookup results are still valid
00167       // pretend we had done lookup
00168       if (blocking())
00169         lookupFinishedSlot();
00170       else
00171         QTimer::singleShot(0, this, SLOT(lookupFinishedSlot()));
00172     }
00173       else
00174     {
00175       d->localResults = d->peerResults = KResolverResults();
00176     }
00177     }
00178 
00179   if (blocking())
00180     {
00181       // we're in blocking mode operation
00182       // wait for the results
00183 
00184       localResolver().wait();
00185       peerResolver().wait();
00186 
00187       // lookupFinishedSlot has been called
00188     }
00189 
00190   return true;
00191 }
00192 
00193 bool KClientSocketBase::bind(const KResolverEntry& address)
00194 {
00195   if (state() == HostLookup || state() > Connecting)
00196     return false;
00197 
00198   if (socketDevice()->bind(address))
00199     {
00200       resetError();
00201 
00202       // don't set the state or emit signals if we are in a higher state
00203       if (state() < Bound)
00204     {
00205       setState(Bound);
00206       emit stateChanged(Bound);
00207       emit bound(address);
00208     }
00209       return true;
00210     }
00211   return false;
00212 }
00213 
00214 bool KClientSocketBase::connect(const KResolverEntry& address, OpenMode mode)
00215 {
00216   if (state() == Connected)
00217     return true;        // to be compliant with the other classes
00218   if (state() == HostLookup || state() > Connecting)
00219     return false;
00220 
00221   bool ok = socketDevice()->connect(address);
00222   copyError();
00223 
00224   if (ok)
00225     {
00226       SocketState newstate;
00227       if (error() == InProgress)
00228     newstate = Connecting;
00229       else
00230     newstate = Connected;
00231 
00232       if (state() < newstate)
00233     {
00234       setState(newstate);
00235       emit stateChanged(newstate);
00236       if (error() == NoError)
00237         {
00238           KActiveSocketBase::open(mode | Unbuffered);
00239           emit connected(address);
00240         }
00241     }
00242 
00243       return true;
00244     }
00245   return false;
00246 }
00247 
00248 bool KClientSocketBase::disconnect()
00249 {
00250   if (state() != Connected)
00251     return false;
00252 
00253   bool ok = socketDevice()->disconnect();
00254   copyError();
00255 
00256   if (ok)
00257     {
00258       setState(Unconnected);
00259       emit stateChanged(Unconnected);
00260       return true;
00261     }
00262   return false;
00263 }
00264 
00265 bool KClientSocketBase::open(OpenMode mode)
00266 {
00267     return connect(QString(), QString(), mode);
00268 }
00269 
00270 void KClientSocketBase::close()
00271 {
00272   if (state() == Idle)
00273     return;             // nothing to do
00274 
00275   if (state() == HostLookup)
00276     {
00277       d->peerResolver.cancel(false);
00278       d->localResolver.cancel(false);
00279     }
00280 
00281   d->localResults = d->peerResults = KResolverResults();
00282 
00283   socketDevice()->close();
00284   KActiveSocketBase::close();
00285   setState(Idle);
00286   emit stateChanged(Idle);
00287   emit closed();
00288 }
00289 
00290 bool KClientSocketBase::flush()
00291 {
00292     return false;
00293 }
00294 
00295 // This function is unlike all the others because it is const
00296 qint64 KClientSocketBase::bytesAvailable() const
00297 {
00298   return socketDevice()->bytesAvailable();
00299 }
00300 
00301 // All the functions below look really alike
00302 // Should I use a macro to define them?
00303 
00304 qint64 KClientSocketBase::waitForMore(int msecs, bool *timeout)
00305 {
00306   resetError();
00307   qint64 retval = socketDevice()->waitForMore(msecs, timeout);
00308   if (retval == -1)
00309     {
00310       copyError();
00311       emit gotError(error());
00312     }
00313   return retval;
00314 }
00315 
00316 qint64 KClientSocketBase::readData(char *data, qint64 maxlen, KSocketAddress* from)
00317 {
00318   resetError();
00319   qint64 retval = socketDevice()->readData(data, maxlen, from);
00320   if (retval == -1)
00321     {
00322       copyError();
00323       emit gotError(error());
00324     }
00325   return retval;
00326 }
00327 
00328 qint64 KClientSocketBase::peekData(char *data, qint64 maxlen, KSocketAddress* from)
00329 {
00330   resetError();
00331   qint64 retval = socketDevice()->peekData(data, maxlen, from);
00332   if (retval == -1)
00333     {
00334       copyError();
00335       emit gotError(error());
00336     }
00337   return retval;
00338 }
00339 
00340 qint64 KClientSocketBase::writeData(const char *data, qint64 len, const KSocketAddress* to)
00341 {
00342   resetError();
00343   qint64 retval = socketDevice()->writeData(data, len, to);
00344   if (retval == -1)
00345     {
00346       copyError();
00347       emit gotError(error());
00348     }
00349   else
00350     emit bytesWritten(retval);
00351   return retval;
00352 }
00353 
00354 KSocketAddress KClientSocketBase::localAddress() const
00355 {
00356   return socketDevice()->localAddress();
00357 }
00358 
00359 KSocketAddress KClientSocketBase::peerAddress() const
00360 {
00361   return socketDevice()->peerAddress();
00362 }
00363 
00364 bool KClientSocketBase::emitsReadyRead() const
00365 {
00366   return d->enableRead;
00367 }
00368 
00369 void KClientSocketBase::enableRead(bool enable)
00370 {
00371   QMutexLocker locker(mutex());
00372 
00373   d->enableRead = enable;
00374   QSocketNotifier *n = socketDevice()->readNotifier();
00375   if (n)
00376     n->setEnabled(enable);
00377 }
00378 
00379 bool KClientSocketBase::emitsReadyWrite() const
00380 {
00381   return d->enableWrite;
00382 }
00383 
00384 void KClientSocketBase::enableWrite(bool enable)
00385 {
00386   QMutexLocker locker(mutex());
00387 
00388   d->enableWrite = enable;
00389   QSocketNotifier *n = socketDevice()->writeNotifier();
00390   if (n)
00391     n->setEnabled(enable);
00392 }
00393 
00394 void KClientSocketBase::slotReadActivity()
00395 {
00396   if (d->enableRead)
00397     emit readyRead();
00398 }
00399 
00400 void KClientSocketBase::slotWriteActivity()
00401 {
00402   if (d->enableWrite)
00403     emit readyWrite();
00404 }
00405 
00406 void KClientSocketBase::lookupFinishedSlot()
00407 {
00408   if (d->peerResolver.isRunning() || d->localResolver.isRunning() || state() != HostLookup)
00409     return;
00410 
00411   QObject::disconnect(&d->peerResolver, 0L, this, SLOT(lookupFinishedSlot()));
00412   QObject::disconnect(&d->localResolver, 0L, this, SLOT(lookupFinishedSlot()));
00413   if (d->peerResolver.status() < 0 || d->localResolver.status() < 0)
00414     {
00415       setState(Idle);       // backtrack
00416       setError(LookupFailure);
00417       emit stateChanged(Idle);
00418       emit gotError(LookupFailure);
00419       return;
00420     }
00421 
00422   d->localResults = d->localResolver.results();
00423   d->peerResults = d->peerResolver.results();
00424   setState(HostFound);
00425   emit stateChanged(HostFound);
00426   emit hostFound();
00427 }
00428 
00429 void KClientSocketBase::stateChanging(SocketState newState)
00430 {
00431   if (newState == Connected && socketDevice())
00432     {
00433       QSocketNotifier *n = socketDevice()->readNotifier();
00434       if (n)
00435     {
00436       n->setEnabled(d->enableRead);
00437       QObject::connect(n, SIGNAL(activated(int)), this, SLOT(slotReadActivity()));
00438     }
00439       else
00440     return;
00441 
00442       n = socketDevice()->writeNotifier();
00443       if (n)
00444     {
00445       n->setEnabled(d->enableWrite);
00446       QObject::connect(n, SIGNAL(activated(int)), this, SLOT(slotWriteActivity()));
00447     }
00448       else
00449     return;
00450     }
00451 }
00452 
00453 void KClientSocketBase::copyError()
00454 {
00455   setError(socketDevice()->error());
00456 }
00457 
00458 #include "k3clientsocketbase.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
  • Kross
  • KUtils
  • Nepomuk
  • Solid
  • Sonnet
  • ThreadWeaver
Generated for kdelibs by doxygen 1.5.4
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