kdecore Library: kclientsocketbase.cpp Source File (kdecore Library)

| # kdecore Library API Documentation
Overview | Class Hierarchy | Classes | Classes (annotated) | Members | Namespaces | Source Files

# kclientsocketbase.cpp

    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"

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:02 2005 by doxygen 1.4.1 written by Dimitri van Heesch, © 1997-2003