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(TQObject* 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 // TQObject::connect(localResolver(), TQT_SIGNAL(finished(KResolverResults)), 00056 // this, TQT_SLOT(lookupFinishedLocal())); 00057 TQObject::connect(&peerResolver(), TQT_SIGNAL(finished(KResolverResults)), 00058 this, TQT_SLOT(lookupFinishedPeer())); 00059 TQObject::connect(this, TQT_SIGNAL(hostFound()), this, TQT_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 TQString& node, const TQString& 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 TQString& node, const TQString& 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 TQ_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 TQByteArray data(size); 00156 KSocketAddress address; 00157 00158 // now do the reading 00159 size = tqreadBlock(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 TQ_LONG KDatagramSocket::send(const KDatagramPacket& packet) 00169 { 00170 return tqwriteBlock(packet.data(), packet.size(), packet.address()); 00171 } 00172 00173 TQ_LONG KDatagramSocket::tqwriteBlock(const char *data, TQ_ULONG len, const KSocketAddress& to) 00174 { 00175 if (to.family() != AF_UNSPEC) 00176 { 00177 // make sure the socket is open at this point 00178 if (!socketDevice()->isOpen()) 00179 // error handling will happen below 00180 socketDevice()->create(to.family(), SOCK_DGRAM, 0); 00181 } 00182 return KClientSocketBase::tqwriteBlock(data, len, to); 00183 } 00184 00185 void KDatagramSocket::lookupFinishedLocal() 00186 { 00187 // bind lookup has finished and succeeded 00188 // state() == HostFound 00189 00190 if (!doBind()) 00191 return; // failed binding 00192 00193 if (peerResults().count() > 0) 00194 { 00195 setState(Connecting); 00196 emit stateChanged(Connecting); 00197 00198 lookupFinishedPeer(); 00199 } 00200 } 00201 00202 void KDatagramSocket::lookupFinishedPeer() 00203 { 00204 // this function is called by lookupFinishedLocal above 00205 // and is also connected to a signal 00206 // so it might be called twice. 00207 00208 if (state() != Connecting) 00209 return; 00210 00211 if (peerResults().count() == 0) 00212 { 00213 setState(Unconnected); 00214 emit stateChanged(Unconnected); 00215 return; 00216 } 00217 00218 KResolverResults::ConstIterator it = peerResults().begin(); 00219 for ( ; it != peerResults().end(); ++it) 00220 if (connect(*it)) 00221 { 00222 // weee, we connected 00223 00224 setState(Connected); // this sets up signals 00225 //setupSignals(); // setState sets up the signals 00226 00227 emit stateChanged(Connected); 00228 emit connected(*it); 00229 return; 00230 } 00231 00232 // no connection 00233 copyError(); 00234 setState(Unconnected); 00235 emit stateChanged(Unconnected); 00236 emit gotError(error()); 00237 } 00238 00239 bool KDatagramSocket::doBind() 00240 { 00241 if (localResults().count() == 0) 00242 return true; 00243 if (state() >= Bound) 00244 return true; // already bound 00245 00246 KResolverResults::ConstIterator it = localResults().begin(); 00247 for ( ; it != localResults().end(); ++it) 00248 if (bind(*it)) 00249 { 00250 // bound 00251 setupSignals(); 00252 return true; 00253 } 00254 00255 // not bound 00256 // no need to set state since it can only be HostFound already 00257 copyError(); 00258 emit gotError(error()); 00259 return false; 00260 } 00261 00262 void KDatagramSocket::setupSignals() 00263 { 00264 TQSocketNotifier *n = socketDevice()->readNotifier(); 00265 if (n) 00266 { 00267 n->setEnabled(emitsReadyRead()); 00268 TQObject::connect(n, TQT_SIGNAL(activated(int)), this, TQT_SLOT(slotReadActivity())); 00269 } 00270 else 00271 return; 00272 00273 n = socketDevice()->writeNotifier(); 00274 if (n) 00275 { 00276 n->setEnabled(emitsReadyWrite()); 00277 TQObject::connect(n, TQT_SIGNAL(activated(int)), this, TQT_SLOT(slotWriteActivity())); 00278 } 00279 else 00280 return; 00281 } 00282 00283 #include "kdatagramsocket.moc"