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

KDECore

kclientsocketbase.cpp

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