kdecore Library API Documentation

kclientsocketbase.cpp

00001 /* -*- C++ -*- 00002 * Copyright (C) 2003 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 Q_LONG KClientSocketBase::bytesAvailable() const 00281 { 00282 return socketDevice()->bytesAvailable(); 00283 } 00284 00285 Q_LONG KClientSocketBase::waitForMore(int msecs, bool *timeout) 00286 { 00287 return socketDevice()->waitForMore(msecs, timeout); 00288 } 00289 00290 Q_LONG KClientSocketBase::readBlock(char *data, Q_ULONG maxlen) 00291 { 00292 return socketDevice()->readBlock(data, maxlen); 00293 } 00294 00295 Q_LONG KClientSocketBase::readBlock(char *data, Q_ULONG maxlen, KSocketAddress& from) 00296 { 00297 return socketDevice()->readBlock(data, maxlen, from); 00298 } 00299 00300 Q_LONG KClientSocketBase::peekBlock(char *data, Q_ULONG maxlen) 00301 { 00302 return socketDevice()->peekBlock(data, maxlen); 00303 } 00304 00305 Q_LONG KClientSocketBase::peekBlock(char *data, Q_ULONG maxlen, KSocketAddress& from) 00306 { 00307 return socketDevice()->peekBlock(data, maxlen, from); 00308 } 00309 00310 Q_LONG KClientSocketBase::writeBlock(const char *data, Q_ULONG len) 00311 { 00312 return socketDevice()->writeBlock(data, len); 00313 } 00314 00315 Q_LONG KClientSocketBase::writeBlock(const char *data, Q_ULONG len, const KSocketAddress& to) 00316 { 00317 return socketDevice()->writeBlock(data, len, to); 00318 } 00319 00320 KSocketAddress KClientSocketBase::localAddress() const 00321 { 00322 return socketDevice()->localAddress(); 00323 } 00324 00325 KSocketAddress KClientSocketBase::peerAddress() const 00326 { 00327 return socketDevice()->peerAddress(); 00328 } 00329 00330 bool KClientSocketBase::emitsReadyRead() const 00331 { 00332 return d->enableRead; 00333 } 00334 00335 void KClientSocketBase::enableRead(bool enable) 00336 { 00337 QMutexLocker locker(mutex()); 00338 00339 d->enableRead = enable; 00340 QSocketNotifier *n = socketDevice()->readNotifier(); 00341 if (n) 00342 n->setEnabled(enable); 00343 } 00344 00345 bool KClientSocketBase::emitsReadyWrite() const 00346 { 00347 return d->enableWrite; 00348 } 00349 00350 void KClientSocketBase::enableWrite(bool enable) 00351 { 00352 QMutexLocker locker(mutex()); 00353 00354 d->enableWrite = enable; 00355 QSocketNotifier *n = socketDevice()->writeNotifier(); 00356 if (n) 00357 n->setEnabled(enable); 00358 } 00359 00360 void KClientSocketBase::slotReadActivity() 00361 { 00362 if (d->enableRead) 00363 emit readyRead(); 00364 } 00365 00366 void KClientSocketBase::slotWriteActivity() 00367 { 00368 if (d->enableWrite) 00369 emit readyWrite(); 00370 } 00371 00372 void KClientSocketBase::lookupFinishedSlot() 00373 { 00374 if (d->peerResolver.isRunning() || d->localResolver.isRunning() || state() != HostLookup) 00375 return; 00376 00377 QObject::disconnect(&d->peerResolver, 0L, this, SLOT(lookupFinishedSlot())); 00378 QObject::disconnect(&d->localResolver, 0L, this, SLOT(lookupFinishedSlot())); 00379 if (d->peerResolver.status() < 0 || d->localResolver.status() < 0) 00380 { 00381 setState(Idle); // backtrack 00382 setError(IO_LookupError, LookupFailure); 00383 emit stateChanged(Idle); 00384 emit gotError(LookupFailure); 00385 return; 00386 } 00387 00388 d->localResults = d->localResolver.results(); 00389 d->peerResults = d->peerResolver.results(); 00390 setState(HostFound); 00391 emit stateChanged(HostFound); 00392 emit hostFound(); 00393 } 00394 00395 void KClientSocketBase::stateChanging(SocketState newState) 00396 { 00397 if (newState == Connected && socketDevice()) 00398 { 00399 QSocketNotifier *n = socketDevice()->readNotifier(); 00400 if (n) 00401 { 00402 n->setEnabled(d->enableRead); 00403 QObject::connect(n, SIGNAL(activated(int)), this, SLOT(slotReadActivity())); 00404 } 00405 else 00406 return; 00407 00408 n = socketDevice()->writeNotifier(); 00409 if (n) 00410 { 00411 n->setEnabled(d->enableWrite); 00412 QObject::connect(n, SIGNAL(activated(int)), this, SLOT(slotWriteActivity())); 00413 } 00414 else 00415 return; 00416 } 00417 } 00418 00419 void KClientSocketBase::copyError() 00420 { 00421 setError(socketDevice()->status(), socketDevice()->error()); 00422 } 00423 00424 #include "kclientsocketbase.moc"
KDE Logo
This file is part of the documentation for kdecore Library Version 3.3.1.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Sun Oct 17 11:26:06 2004 by doxygen 1.3.8 written by Dimitri van Heesch, © 1997-2003