# kdecore Library API Documentation

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

# kdatagramsocket.cpp

    00001 /*  -*- C++ -*-
    00002  *  Copyright (C) 2003,2004 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 <sys/types.h>
    00028 #include <sys/socket.h>
    00029
    00030 #include "ksocketaddress.h"
    00031 #include "kresolver.h"
    00032 #include "ksocketdevice.h"
    00033 #include "kdatagramsocket.h"
    00034
    00035 using namespace KNetwork;
    00036
    00037 /*
    00038  * TODO:
    00039  *
    00040  * don't use signals and slots to track state changes: use stateChanging
    00041  *
    00042  */
    00043
    00044 KDatagramSocket::KDatagramSocket(QObject* parent, const char *name)
    00045   : KClientSocketBase(parent, name), d(0L)
    00046 {
    00047   peerResolver().setFamily(KResolver::KnownFamily);
    00048   localResolver().setFamily(KResolver::KnownFamily);
    00049
    00050   peerResolver().setSocketType(SOCK_DGRAM);
    00051   localResolver().setSocketType(SOCK_DGRAM);
    00052
    00053   localResolver().setFlags(KResolver::Passive);
    00054
    00055   //  QObject::connect(localResolver(), SIGNAL(finished(KResolverResults)),
    00056   //           this, SLOT(lookupFinishedLocal()));
    00057   QObject::connect(&peerResolver(), SIGNAL(finished(KResolverResults)),
    00058            this, SLOT(lookupFinishedPeer()));
    00059   QObject::connect(this, SIGNAL(hostFound()), this, SLOT(lookupFinishedLocal()));
    00060 }
    00061
    00062 KDatagramSocket::~KDatagramSocket()
    00063 {
    00064   // KClientSocketBase's destructor closes the socket
    00065
    00066   //delete d;
    00067 }
    00068
    00069 bool KDatagramSocket::bind(const QString& node, const QString& service)
    00070 {
    00071   if (state() >= Bound)
    00072     return false;
    00073
    00074   if (localResolver().isRunning())
    00075     localResolver().cancel(false);
    00076
    00077   // no, we must do a host lookup
    00078   localResolver().setAddress(node, service);
    00079
    00080   if (!lookup())
    00081     return false;
    00082
    00083   // see if lookup has finished already
    00084   // this also catches blocking mode, since lookup has to finish
    00085   // its processing if we're in blocking mode
    00086   if (state() > HostLookup)
    00087     return doBind();
    00088
    00089   return true;
    00090 }
    00091
    00092 bool KDatagramSocket::connect(const QString& node, const QString& service)
    00093 {
    00094   if (state() >= Connected)
    00095     return true;        // already connected
    00096
    00097   if (peerResolver().nodeName() != node ||
    00098       peerResolver().serviceName() != service)
    00099     peerResolver().setAddress(node, service); // this resets the resolver's state
    00100
    00101   // KClientSocketBase::lookup only works if the state is Idle or HostLookup
    00102   // therefore, we store the old state, call the lookup routine and then set
    00103   // it back.
    00104   SocketState s = state();
    00105   setState(s == Connecting ? HostLookup : Idle);
    00106   bool ok = lookup();
    00107   if (!ok)
    00108     {
    00109       setState(s);      // go back
    00110       return false;
    00111     }
    00112
    00113   // check if lookup is finished
    00114   // if we're in blocking mode, then the lookup has to be finished
    00115   if (state() == HostLookup)
    00116     {
    00117       // it hasn't finished
    00118       setState(Connecting);
    00119       emit stateChanged(Connecting);
    00120       return true;
    00121     }
    00122
    00123   // it has to be finished here
    00124   if (state() != Connected)
    00125     {
    00126       setState(Connecting);
    00127       emit stateChanged(Connecting);
    00128       lookupFinishedPeer();
    00129     }
    00130
    00131   return state() == Connected;
    00132 }
    00133
    00134 KDatagramPacket KDatagramSocket::receive()
    00135 {
    00136   Q_LONG size = bytesAvailable();
    00137   if (size == 0)
    00138     {
    00139       // nothing available yet to read
    00140       // wait for data if we're not blocking
    00141       if (blocking())
    00142     socketDevice()->waitForMore(-1); // wait forever
    00143       else
    00144     {
    00145       // mimic error
    00146       setError(IO_ReadError, WouldBlock);
    00147       emit gotError(WouldBlock);
    00148       return KDatagramPacket();
    00149     }
    00150
    00151       // try again
    00152       size = bytesAvailable();
    00153     }
    00154
    00155   QByteArray data(size);
    00156   KSocketAddress address;
    00157
    00158   // now do the reading
    00159   size = readBlock(data.data(), size, address);
    00160   if (size < 0)
    00161     // error has been set
    00162     return KDatagramPacket();
    00163
    00164   data.resize(size);        // just to be sure
    00165   return KDatagramPacket(data, address);
    00166 }
    00167
    00168 Q_LONG KDatagramSocket::send(const KDatagramPacket& packet)
    00169 {
    00170   return writeBlock(packet.data(), packet.size(), packet.address());
    00171 }
    00172
    00173 void KDatagramSocket::lookupFinishedLocal()
    00174 {
    00175   // bind lookup has finished and succeeded
    00176   // state() == HostFound
    00177
    00178   if (!doBind())
    00179     return;         // failed binding
    00180
    00181   if (peerResults().count() > 0)
    00182     {
    00183       setState(Connecting);
    00184       emit stateChanged(Connecting);
    00185
    00186       lookupFinishedPeer();
    00187     }
    00188 }
    00189
    00190 void KDatagramSocket::lookupFinishedPeer()
    00191 {
    00192   // this function is called by lookupFinishedLocal above
    00193   // and is also connected to a signal
    00194   // so it might be called twice.
    00195
    00196   if (state() != Connecting)
    00197     return;
    00198
    00199   if (peerResults().count() == 0)
    00200     {
    00201       setState(Unconnected);
    00202       emit stateChanged(Unconnected);
    00203       return;
    00204     }
    00205
    00206   KResolverResults::ConstIterator it = peerResults().begin();
    00207   for ( ; it != peerResults().end(); ++it)
    00208     if (connect(*it))
    00209       {
    00210     // weee, we connected
    00211
    00212     setState(Connected);    // this sets up signals
    00213     //setupSignals();   // setState sets up the signals
    00214
    00215     emit stateChanged(Connected);
    00216     emit connected(*it);
    00217     return;
    00218       }
    00219
    00220   // no connection
    00221   copyError();
    00222   setState(Unconnected);
    00223   emit stateChanged(Unconnected);
    00224   emit gotError(error());
    00225 }
    00226
    00227 bool KDatagramSocket::doBind()
    00228 {
    00229   if (localResults().count() == 0)
    00230     return true;
    00231   if (state() >= Bound)
    00232     return true;        // already bound
    00233
    00234   KResolverResults::ConstIterator it = localResults().begin();
    00235   for ( ; it != localResults().end(); ++it)
    00236     if (bind(*it))
    00237       {
    00238     // bound
    00239     setupSignals();
    00240     return true;
    00241       }
    00242
    00243   // not bound
    00244   // no need to set state since it can only be HostFound already
    00245   copyError();
    00246   emit gotError(error());
    00247   return false;
    00248 }
    00249
    00250 void KDatagramSocket::setupSignals()
    00251 {
    00252   QSocketNotifier *n = socketDevice()->readNotifier();
    00253   if (n)
    00254     {
    00255       n->setEnabled(emitsReadyRead());
    00256       QObject::connect(n, SIGNAL(activated(int)), this, SLOT(slotReadActivity()));
    00257     }
    00258   else
    00259     return;
    00260
    00261   n = socketDevice()->writeNotifier();
    00262   if (n)
    00263     {
    00264       n->setEnabled(emitsReadyWrite());
    00265       QObject::connect(n, SIGNAL(activated(int)), this, SLOT(slotWriteActivity()));
    00266     }
    00267   else
    00268     return;
    00269 }
    00270
    00271 #include "kdatagramsocket.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:03 2005 by doxygen 1.4.1 written by Dimitri van Heesch, © 1997-2003