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.0.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Thu Apr 14 00:03:28 2005 by doxygen 1.3.7 written by Dimitri van Heesch, © 1997-2003