kdecore Library API Documentation

kclientsocketbase.cpp

00001 /* -*- C++ -*- 00002 * Copyright (C) 2003,2005 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 <qsocketnotifier.h> 00028 #include <qtimer.h> 00029 #include <qmutex.h> 00030 00031 #include "ksocketaddress.h" 00032 #include "kresolver.h" 00033 #include "ksocketbase.h" 00034 #include "ksocketdevice.h" 00035 #include "kclientsocketbase.h" 00036 00037 using namespace KNetwork; 00038 00039 class KNetwork::KClientSocketBasePrivate 00040 { 00041 public: 00042 int state; 00043 00044 KResolver localResolver, peerResolver; 00045 KResolverResults localResults, peerResults; 00046 00047 bool enableRead : 1, enableWrite : 1; 00048 }; 00049 00050 KClientSocketBase::KClientSocketBase(QObject *parent, const char *name) 00051 : QObject(parent, name), d(new KClientSocketBasePrivate) 00052 { 00053 d->state = Idle; 00054 d->enableRead = true; 00055 d->enableWrite = false; 00056 } 00057 00058 KClientSocketBase::~KClientSocketBase() 00059 { 00060 close(); 00061 delete d; 00062 } 00063 00064 KClientSocketBase::SocketState KClientSocketBase::state() const 00065 { 00066 return static_cast<SocketState>(d->state); 00067 } 00068 00069 void KClientSocketBase::setState(SocketState state) 00070 { 00071 d->state = state; 00072 stateChanging(state); 00073 } 00074 00075 bool KClientSocketBase::setSocketOptions(int opts) 00076 { 00077 QMutexLocker locker(mutex()); 00078 KSocketBase::setSocketOptions(opts); // call parent 00079 00080 // don't create the device unnecessarily 00081 if (hasDevice()) 00082 { 00083 bool result = socketDevice()->setSocketOptions(opts); // and set the implementation 00084 copyError(); 00085 return result; 00086 } 00087 00088 return true; 00089 } 00090 00091 KResolver& KClientSocketBase::peerResolver() const 00092 { 00093 return d->peerResolver; 00094 } 00095 00096 const KResolverResults& KClientSocketBase::peerResults() const 00097 { 00098 return d->peerResults; 00099 } 00100 00101 KResolver& KClientSocketBase::localResolver() const 00102 { 00103 return d->localResolver; 00104 } 00105 00106 const KResolverResults& KClientSocketBase::localResults() const 00107 { 00108 return d->localResults; 00109 } 00110 00111 void KClientSocketBase::setResolutionEnabled(bool enable) 00112 { 00113 if (enable) 00114 { 00115 d->localResolver.setFlags(d->localResolver.flags() & ~KResolver::NoResolve); 00116 d->peerResolver.setFlags(d->peerResolver.flags() & ~KResolver::NoResolve); 00117 } 00118 else 00119 { 00120 d->localResolver.setFlags(d->localResolver.flags() | KResolver::NoResolve); 00121 d->peerResolver.setFlags(d->peerResolver.flags() | KResolver::NoResolve); 00122 } 00123 } 00124 00125 void KClientSocketBase::setFamily(int families) 00126 { 00127 d->localResolver.setFamily(families); 00128 d->peerResolver.setFamily(families); 00129 } 00130 00131 bool KClientSocketBase::lookup() 00132 { 00133 if (state() == HostLookup && !blocking()) 00134 return true; // already doing lookup 00135 00136 if (state() > HostLookup) 00137 return true; // results are already available 00138 00139 if (state() < HostLookup) 00140 { 00141 if (d->localResolver.serviceName().isNull() && 00142 !d->localResolver.nodeName().isNull()) 00143 d->localResolver.setServiceName(QString::fromLatin1("")); 00144 00145 // don't restart the lookups if they had succeeded and 00146 // the input values weren't changed 00147 QObject::connect(&d->peerResolver, SIGNAL(finished(KResolverResults)), 00148 this, SLOT(lookupFinishedSlot())); 00149 QObject::connect(&d->localResolver, SIGNAL(finished(KResolverResults)), 00150 this, SLOT(lookupFinishedSlot())); 00151 00152 if (d->localResolver.status() <= 0) 00153 d->localResolver.start(); 00154 if (d->peerResolver.status() <= 0) 00155 d->peerResolver.start(); 00156 00157 setState(HostLookup); 00158 emit stateChanged(HostLookup); 00159 00160 if (!d->localResolver.isRunning() && !d->peerResolver.isRunning()) 00161 { 00162 // if nothing is running, then the lookup results are still valid 00163 // pretend we had done lookup 00164 if (blocking()) 00165 lookupFinishedSlot(); 00166 else 00167 QTimer::singleShot(0, this, SLOT(lookupFinishedSlot())); 00168 } 00169 else 00170 { 00171 d->localResults = d->peerResults = KResolverResults(); 00172 } 00173 } 00174 00175 if (blocking()) 00176 { 00177 // we're in blocking mode operation 00178 // wait for the results 00179 00180 localResolver().wait(); 00181 peerResolver().wait(); 00182 00183 // lookupFinishedSlot has been called 00184 } 00185 00186 return true; 00187 } 00188 00189 bool KClientSocketBase::bind(const KResolverEntry& address) 00190 { 00191 if (state() == HostLookup || state() > Connecting) 00192 return false; 00193 00194 if (socketDevice()->bind(address)) 00195 { 00196 resetError(); 00197 00198 // don't set the state or emit signals if we are in a higher state 00199 if (state() < Bound) 00200 { 00201 setState(Bound); 00202 emit stateChanged(Bound); 00203 emit bound(address); 00204 } 00205 return true; 00206 } 00207 return false; 00208 } 00209 00210 bool KClientSocketBase::connect(const KResolverEntry& address) 00211 { 00212 if (state() == Connected) 00213 return true; // to be compliant with the other classes 00214 if (state() == HostLookup || state() > Connecting) 00215 return false; 00216 00217 bool ok = socketDevice()->connect(address); 00218 copyError(); 00219 00220 if (ok) 00221 { 00222 SocketState newstate; 00223 if (error() == InProgress) 00224 newstate = Connecting; 00225 else 00226 newstate = Connected; 00227 00228 if (state() < newstate) 00229 { 00230 setState(newstate); 00231 emit stateChanged(newstate); 00232 if (error() == NoError) 00233 { 00234 setFlags(IO_Sequential | IO_Raw | IO_ReadWrite | IO_Open | IO_Async); 00235 emit connected(address); 00236 } 00237 } 00238 00239 return true; 00240 } 00241 return false; 00242 } 00243 00244 bool KClientSocketBase::disconnect() 00245 { 00246 if (state() != Connected) 00247 return false; 00248 00249 bool ok = socketDevice()->disconnect(); 00250 copyError(); 00251 00252 if (ok) 00253 { 00254 setState(Unconnected); 00255 emit stateChanged(Unconnected); 00256 return true; 00257 } 00258 return false; 00259 } 00260 00261 void KClientSocketBase::close() 00262 { 00263 if (state() == Idle) 00264 return; // nothing to do 00265 00266 if (state() == HostLookup) 00267 { 00268 d->peerResolver.cancel(false); 00269 d->localResolver.cancel(false); 00270 } 00271 00272 d->localResults = d->peerResults = KResolverResults(); 00273 00274 socketDevice()->close(); 00275 setState(Idle); 00276 emit stateChanged(Idle); 00277 emit closed(); 00278 } 00279 00280 // This function is unlike all the others because it is const 00281 Q_LONG KClientSocketBase::bytesAvailable() const 00282 { 00283 return socketDevice()->bytesAvailable(); 00284 } 00285 00286 // All the functions below look really alike 00287 // Should I use a macro to define them? 00288 00289 Q_LONG KClientSocketBase::waitForMore(int msecs, bool *timeout) 00290 { 00291 resetError(); 00292 Q_LONG retval = socketDevice()->waitForMore(msecs, timeout); 00293 if (retval == -1) 00294 { 00295 copyError(); 00296 emit gotError(error()); 00297 } 00298 return retval; 00299 } 00300 00301 Q_LONG KClientSocketBase::readBlock(char *data, Q_ULONG maxlen) 00302 { 00303 resetError(); 00304 Q_LONG retval = socketDevice()->readBlock(data, maxlen); 00305 if (retval == -1) 00306 { 00307 copyError(); 00308 emit gotError(error()); 00309 } 00310 return retval; 00311 } 00312 00313 Q_LONG KClientSocketBase::readBlock(char *data, Q_ULONG maxlen, KSocketAddress& from) 00314 { 00315 resetError(); 00316 Q_LONG retval = socketDevice()->readBlock(data, maxlen, from); 00317 if (retval == -1) 00318 { 00319 copyError(); 00320 emit gotError(error()); 00321 } 00322 return retval; 00323 } 00324 00325 Q_LONG KClientSocketBase::peekBlock(char *data, Q_ULONG maxlen) 00326 { 00327 resetError(); 00328 Q_LONG retval = socketDevice()->peekBlock(data, maxlen); 00329 if (retval == -1) 00330 { 00331 copyError(); 00332 emit gotError(error()); 00333 } 00334 return retval; 00335 } 00336 00337 Q_LONG KClientSocketBase::peekBlock(char *data, Q_ULONG maxlen, KSocketAddress& from) 00338 { 00339 resetError(); 00340 Q_LONG retval = socketDevice()->peekBlock(data, maxlen, from); 00341 if (retval == -1) 00342 { 00343 copyError(); 00344 emit gotError(error()); 00345 } 00346 return retval; 00347 } 00348 00349 Q_LONG KClientSocketBase::writeBlock(const char *data, Q_ULONG len) 00350 { 00351 resetError(); 00352 Q_LONG retval = socketDevice()->writeBlock(data, len); 00353 if (retval == -1) 00354 { 00355 copyError(); 00356 emit gotError(error()); 00357 } 00358 return retval; 00359 } 00360 00361 Q_LONG KClientSocketBase::writeBlock(const char *data, Q_ULONG len, const KSocketAddress& to) 00362 { 00363 resetError(); 00364 Q_LONG retval = socketDevice()->writeBlock(data, len, to); 00365 if (retval == -1) 00366 { 00367 copyError(); 00368 emit gotError(error()); 00369 } 00370 return retval; 00371 } 00372 00373 KSocketAddress KClientSocketBase::localAddress() const 00374 { 00375 return socketDevice()->localAddress(); 00376 } 00377 00378 KSocketAddress KClientSocketBase::peerAddress() const 00379 { 00380 return socketDevice()->peerAddress(); 00381 } 00382 00383 bool KClientSocketBase::emitsReadyRead() const 00384 { 00385 return d->enableRead; 00386 } 00387 00388 void KClientSocketBase::enableRead(bool enable) 00389 { 00390 QMutexLocker locker(mutex()); 00391 00392 d->enableRead = enable; 00393 QSocketNotifier *n = socketDevice()->readNotifier(); 00394 if (n) 00395 n->setEnabled(enable); 00396 } 00397 00398 bool KClientSocketBase::emitsReadyWrite() const 00399 { 00400 return d->enableWrite; 00401 } 00402 00403 void KClientSocketBase::enableWrite(bool enable) 00404 { 00405 QMutexLocker locker(mutex()); 00406 00407 d->enableWrite = enable; 00408 QSocketNotifier *n = socketDevice()->writeNotifier(); 00409 if (n) 00410 n->setEnabled(enable); 00411 } 00412 00413 void KClientSocketBase::slotReadActivity() 00414 { 00415 if (d->enableRead) 00416 emit readyRead(); 00417 } 00418 00419 void KClientSocketBase::slotWriteActivity() 00420 { 00421 if (d->enableWrite) 00422 emit readyWrite(); 00423 } 00424 00425 void KClientSocketBase::lookupFinishedSlot() 00426 { 00427 if (d->peerResolver.isRunning() || d->localResolver.isRunning() || state() != HostLookup) 00428 return; 00429 00430 QObject::disconnect(&d->peerResolver, 0L, this, SLOT(lookupFinishedSlot())); 00431 QObject::disconnect(&d->localResolver, 0L, this, SLOT(lookupFinishedSlot())); 00432 if (d->peerResolver.status() < 0 || d->localResolver.status() < 0) 00433 { 00434 setState(Idle); // backtrack 00435 setError(IO_LookupError, LookupFailure); 00436 emit stateChanged(Idle); 00437 emit gotError(LookupFailure); 00438 return; 00439 } 00440 00441 d->localResults = d->localResolver.results(); 00442 d->peerResults = d->peerResolver.results(); 00443 setState(HostFound); 00444 emit stateChanged(HostFound); 00445 emit hostFound(); 00446 } 00447 00448 void KClientSocketBase::stateChanging(SocketState newState) 00449 { 00450 if (newState == Connected && socketDevice()) 00451 { 00452 QSocketNotifier *n = socketDevice()->readNotifier(); 00453 if (n) 00454 { 00455 n->setEnabled(d->enableRead); 00456 QObject::connect(n, SIGNAL(activated(int)), this, SLOT(slotReadActivity())); 00457 } 00458 else 00459 return; 00460 00461 n = socketDevice()->writeNotifier(); 00462 if (n) 00463 { 00464 n->setEnabled(d->enableWrite); 00465 QObject::connect(n, SIGNAL(activated(int)), this, SLOT(slotWriteActivity())); 00466 } 00467 else 00468 return; 00469 } 00470 } 00471 00472 void KClientSocketBase::copyError() 00473 { 00474 setError(socketDevice()->status(), socketDevice()->error()); 00475 } 00476 00477 #include "kclientsocketbase.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:26 2005 by doxygen 1.3.7 written by Dimitri van Heesch, © 1997-2003