kdecore Library API Documentation

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"
KDE Logo
This file is part of the documentation for kdecore Library Version 3.4.3.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Sun Oct 9 07:54:00 2005 by doxygen 1.4.4 written by Dimitri van Heesch, © 1997-2003