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