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