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

KDECore

k3streamsocket.cpp

Go to the documentation of this file.
00001 /*  -*- C++ -*-
00002  *  Copyright (C) 2003 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 "k3streamsocket.h"
00026 
00027 #include <config.h>
00028 #include <config-network.h>
00029 
00030 #include <QSocketNotifier>
00031 #include <QDateTime>
00032 #include <QTimer>
00033 #include <QPointer>
00034 
00035 #include "k3socketaddress.h"
00036 #include "k3resolver.h"
00037 #include "k3socketdevice.h"
00038 
00039 using namespace KNetwork;
00040 
00041 class KNetwork::KStreamSocketPrivate
00042 {
00043 public:
00044   KResolverResults::ConstIterator local, peer;
00045   QTime startTime;
00046   QTimer timer;
00047 
00048   int timeout;
00049 
00050   inline KStreamSocketPrivate()
00051     : timeout(0)
00052   { }
00053 };
00054 
00055 KStreamSocket::KStreamSocket(const QString& node, const QString& service,
00056                  QObject* parent)
00057   : KClientSocketBase(parent), d(new KStreamSocketPrivate)
00058 {
00059   peerResolver().setNodeName(node);
00060   peerResolver().setServiceName(service);
00061   peerResolver().setFamily(KResolver::KnownFamily);
00062   localResolver().setFamily(KResolver::KnownFamily);
00063 
00064   setSocketOptions(socketOptions() & ~Blocking);
00065 
00066   QObject::connect(&d->timer, SIGNAL(timeout()), this, SLOT(timeoutSlot()));
00067 }
00068 
00069 KStreamSocket::~KStreamSocket()
00070 {
00071   delete d;
00072   // KClientSocketBase's destructor closes the socket
00073 }
00074 
00075 int KStreamSocket::timeout() const
00076 {
00077   return d->timeout;
00078 }
00079 
00080 int KStreamSocket::remainingTimeout() const
00081 {
00082   if (state() != Connecting)
00083     return timeout();
00084   if (timeout() <= 0)
00085     return 0;
00086 
00087   return timeout() - d->startTime.elapsed();
00088 }
00089 
00090 void KStreamSocket::setTimeout(int msecs)
00091 {
00092   d->timeout = msecs;
00093 
00094   if (state() == Connecting)
00095     d->timer.start(msecs);
00096 }
00097 
00098 bool KStreamSocket::bind(const QString& node, const QString& service)
00099 {
00100   if (state() != Idle)
00101     return false;
00102 
00103   if (!node.isNull())
00104     localResolver().setNodeName(node);
00105   if (!service.isNull())
00106     localResolver().setServiceName(service);
00107   return true;
00108 }
00109 
00110 bool KStreamSocket::bind(const KResolverEntry& entry)
00111 {
00112     return KClientSocketBase::bind(entry);
00113 }
00114 
00115 bool KStreamSocket::connect(const QString& node, const QString& service,
00116                 OpenMode mode)
00117 {
00118   Q_UNUSED(mode);
00119   if (state() == Connected)
00120     return true;        // already connected
00121 
00122   if (state() > Connected)
00123     return false;       // can't do much here
00124 
00125   if (!node.isNull())
00126     peerResolver().setNodeName(node);
00127   if (!service.isNull())
00128     peerResolver().setServiceName(service);
00129 
00130   if (state() == Connecting && !blocking())
00131     {
00132       setError(InProgress);
00133       emit gotError(InProgress);
00134       return true;      // we're already connecting
00135     }
00136 
00137   if (state() < HostFound)
00138     {
00139       // connection hasn't started yet
00140       if (!blocking())
00141     {
00142       QObject::connect(this, SIGNAL(hostFound()), SLOT(hostFoundSlot()));
00143       return lookup();
00144     }
00145 
00146       // blocking mode
00147       if (!lookup())
00148     return false;       // lookup failure
00149     }
00150 
00151   /*
00152    * lookup results are available here
00153    */
00154 
00155   if (timeout() > 0)
00156     {
00157       if (!blocking() && !d->timer.isActive())
00158        {
00159          d->timer.setSingleShot(true);
00160          d->timer.start(timeout());
00161        }
00162       else
00163     {
00164       // blocking connection with timeout
00165       // this must be handled as a special case because it requires a
00166       // non-blocking socket
00167 
00168       d->timer.stop();  // no need for a timer here
00169 
00170       socketDevice()->setBlocking(false);
00171       while (true)
00172         {
00173           connectionEvent();
00174           if (state() < Connecting)
00175         return false;   // error connecting
00176           if (state() == Connected)
00177         return true;    // connected!
00178 
00179           if (remainingTimeout() <= 0)
00180         {
00181           // we've timed out
00182           timeoutSlot();
00183           return false;
00184         }
00185 
00186           if (socketDevice()->error() == InProgress)
00187         {
00188           bool timedout;
00189           socketDevice()->poll(remainingTimeout(), &timedout);
00190           if (timedout)
00191             {
00192               timeoutSlot();
00193               return false;
00194             }
00195         }
00196         }
00197     }
00198     }
00199 
00200   connectionEvent();
00201   return error() == NoError;
00202 }
00203 
00204 bool KStreamSocket::connect(const KResolverEntry& entry, OpenMode mode)
00205 {
00206   return KClientSocketBase::connect(entry, mode);
00207 }
00208 
00209 void KStreamSocket::hostFoundSlot()
00210 {
00211   QObject::disconnect(this, SLOT(hostFoundSlot()));
00212   if (timeout() > 0)
00213    {
00214     d->timer.setSingleShot(true);
00215     d->timer.start(timeout());
00216    }
00217   QTimer::singleShot(0, this, SLOT(connectionEvent()));
00218 }
00219 
00220 void KStreamSocket::connectionEvent()
00221 {
00222   if (state() != HostFound && state() != Connecting)
00223     return;         // nothing to do
00224 
00225   const KResolverResults& peer = peerResults();
00226   if (state() == HostFound)
00227     {
00228       d->startTime.start();
00229 
00230       setState(Connecting);
00231       emit stateChanged(Connecting);
00232       d->peer = peer.begin();
00233       d->local = localResults().begin(); // just to be on the safe side
00234     }
00235 
00236   while (d->peer != peer.end())
00237     {
00238       const KResolverEntry &r = *d->peer;
00239 
00240       if (socketDevice()->socket() != -1)
00241     {
00242       // we have an existing file descriptor
00243       // this means that we've got activity in it (connection result)
00244       if (socketDevice()->connect(r) && socketDevice()->error() == NoError)
00245         {
00246           // yes, it did connect!
00247           connectionSucceeded(r);
00248           return;
00249         }
00250       else if (socketDevice()->error() == InProgress)
00251         // nope, still in progress
00252         return;
00253 
00254       // no, the socket failed to connect
00255       copyError();
00256       socketDevice()->close();
00257       ++d->peer;
00258       continue;
00259     }
00260 
00261       // try to bind
00262       if (!bindLocallyFor(r))
00263     {
00264       // could not find a matching family
00265       ++d->peer;
00266       continue;
00267     }
00268 
00269       {
00270     bool skip = false;
00271     emit aboutToConnect(r, skip);
00272     if (skip)
00273       {
00274         ++d->peer;
00275         continue;
00276       }
00277       }
00278 
00279       if (socketDevice()->connect(r) || socketDevice()->error() == InProgress)
00280     {
00281       // socket is attempting to connect
00282       if (socketDevice()->error() == InProgress)
00283         {
00284           QSocketNotifier *n = socketDevice()->readNotifier();
00285           QObject::connect(n, SIGNAL(activated(int)),
00286                    this, SLOT(connectionEvent()));
00287           n->setEnabled(true);
00288 
00289           n = socketDevice()->writeNotifier();
00290           QObject::connect(n, SIGNAL(activated(int)),
00291                    this, SLOT(connectionEvent()));
00292           n->setEnabled(true);
00293 
00294           return;       // wait for activity
00295         }
00296 
00297       // socket has connected
00298       connectionSucceeded(r);
00299       return;
00300     }
00301 
00302       // connection failed
00303       // try next
00304       copyError();
00305       socketDevice()->close();
00306       ++d->peer;
00307     }
00308 
00309   // that was the last item
00310   socketDevice()->setSocketOptions(socketOptions());
00311   setState(Idle);
00312   emit stateChanged(Idle);
00313   emit gotError(error());
00314   return;
00315 }
00316 
00317 void KStreamSocket::timeoutSlot()
00318 {
00319   if (state() != Connecting)
00320     return;
00321 
00322   // halt the connections
00323   socketDevice()->close();  // this also kills the notifiers
00324 
00325   setError(Timeout);
00326   setState(HostFound);
00327   emit stateChanged(HostFound);
00328 
00329   QPointer<KStreamSocket> that = this;
00330   emit gotError(Timeout);
00331 
00332   if (!that.isNull())
00333     emit timedOut();
00334 }
00335 
00336 bool KStreamSocket::bindLocallyFor(const KResolverEntry& peer)
00337 {
00338   const KResolverResults& local = localResults();
00339 
00340   if (local.isEmpty())
00341     // user doesn't want to bind to any specific local address
00342     return true;
00343 
00344   bool foundone = false;
00345   // scan the local resolution for a matching family
00346   for (d->local = local.begin(); d->local != local.end(); ++d->local)
00347     if ((*d->local).family() == peer.family())
00348       {
00349     // found a suitable address!
00350     foundone = true;
00351 
00352     if (socketDevice()->bind(*d->local))
00353       return true;
00354       }
00355 
00356   if (!foundone)
00357     {
00358       // found nothing
00359       setError(NotSupported);
00360       emit gotError(NotSupported);
00361     }
00362   else
00363     copyError();
00364   return false;
00365 }
00366 
00367 void KStreamSocket::connectionSucceeded(const KResolverEntry& peer)
00368 {
00369   QObject::disconnect(socketDevice()->readNotifier(), 0, this, SLOT(connectionEvent()));
00370   QObject::disconnect(socketDevice()->writeNotifier(), 0, this, SLOT(connectionEvent()));
00371 
00372   resetError();
00373   KActiveSocketBase::open(ReadWrite | Unbuffered);
00374   setState(Connected);
00375   socketDevice()->setSocketOptions(socketOptions());
00376   d->timer.stop();
00377   emit stateChanged(Connected);
00378 
00379   if (!localResults().isEmpty())
00380     emit bound(*d->local);
00381   emit connected(peer);
00382 }
00383 
00384 #include "k3streamsocket.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
  • Plasma
  • Solid
  • Sonnet
  • ThreadWeaver
Generated for kdelibs by doxygen 1.5.7
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