KDECore
k3serversocket.cpp
Go to the documentation of this file.
00001 /* -*- C++ -*- 00002 * Copyright (C) 2003 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 "k3serversocket.h" 00026 00027 #include <config.h> 00028 #include <config-network.h> 00029 00030 #include <QSocketNotifier> 00031 #include <QMutex> 00032 00033 #include "k3socketaddress.h" 00034 #include "k3resolver.h" 00035 #include "k3socketbase.h" 00036 #include "k3socketdevice.h" 00037 #include "k3bufferedsocket.h" 00038 00039 using namespace KNetwork; 00040 00041 class KNetwork::KServerSocketPrivate 00042 { 00043 public: 00044 KResolver resolver; 00045 KResolverResults resolverResults; 00046 00047 enum { None, LookupDone, Bound, Listening } state; 00048 int backlog; 00049 int timeout; 00050 00051 bool bindWhenFound : 1, listenWhenBound : 1, useKBufferedSocket : 1; 00052 00053 KServerSocketPrivate() 00054 : state(None), timeout(0), bindWhenFound(false), listenWhenBound(false), 00055 useKBufferedSocket(true) 00056 { 00057 resolver.setFlags(KResolver::Passive); 00058 resolver.setFamily(KResolver::KnownFamily); 00059 } 00060 }; 00061 00062 KServerSocket::KServerSocket(QObject* parent) 00063 : QObject(parent), d(new KServerSocketPrivate) 00064 { 00065 QObject::connect(&d->resolver, SIGNAL(finished(const KNetwork::KResolverResults&)), 00066 this, SLOT(lookupFinishedSlot())); 00067 } 00068 00069 KServerSocket::KServerSocket(const QString& service, QObject* parent) 00070 : QObject(parent), d(new KServerSocketPrivate) 00071 { 00072 QObject::connect(&d->resolver, SIGNAL(finished(const KNetwork::KResolverResults&)), 00073 this, SLOT(lookupFinishedSlot())); 00074 d->resolver.setServiceName(service); 00075 } 00076 00077 KServerSocket::KServerSocket(const QString& node, const QString& service, 00078 QObject* parent) 00079 : QObject(parent), d(new KServerSocketPrivate) 00080 { 00081 QObject::connect(&d->resolver, SIGNAL(finished(const KNetwork::KResolverResults&)), 00082 this, SLOT(lookupFinishedSlot())); 00083 setAddress(node, service); 00084 } 00085 00086 KServerSocket::~KServerSocket() 00087 { 00088 close(); 00089 delete d; 00090 } 00091 00092 bool KServerSocket::setSocketOptions(int opts) 00093 { 00094 QMutexLocker locker(mutex()); 00095 KSocketBase::setSocketOptions(opts); // call parent 00096 bool result = socketDevice()->setSocketOptions(opts); // and set the implementation 00097 copyError(); 00098 return result; 00099 } 00100 00101 KResolver& KServerSocket::resolver() const 00102 { 00103 return d->resolver; 00104 } 00105 00106 const KResolverResults& KServerSocket::resolverResults() const 00107 { 00108 return d->resolverResults; 00109 } 00110 00111 void KServerSocket::setResolutionEnabled(bool enable) 00112 { 00113 if (enable) 00114 d->resolver.setFlags(d->resolver.flags() & ~KResolver::NoResolve); 00115 else 00116 d->resolver.setFlags(d->resolver.flags() | KResolver::NoResolve); 00117 } 00118 00119 void KServerSocket::setFamily(int families) 00120 { 00121 d->resolver.setFamily(families); 00122 } 00123 00124 void KServerSocket::setAddress(const QString& service) 00125 { 00126 d->resolver.setNodeName(QString()); 00127 d->resolver.setServiceName(service); 00128 d->resolverResults.empty(); 00129 if (d->state <= KServerSocketPrivate::LookupDone) 00130 d->state = KServerSocketPrivate::None; 00131 } 00132 00133 void KServerSocket::setAddress(const QString& node, const QString& service) 00134 { 00135 d->resolver.setNodeName(node); 00136 d->resolver.setServiceName(service); 00137 d->resolverResults.empty(); 00138 if (d->state <= KServerSocketPrivate::LookupDone) 00139 d->state = KServerSocketPrivate::None; 00140 } 00141 00142 void KServerSocket::setTimeout(int msec) 00143 { 00144 d->timeout = msec; 00145 } 00146 00147 bool KServerSocket::lookup() 00148 { 00149 setError(NoError); 00150 if (d->resolver.isRunning() && !blocking()) 00151 return true; // already doing lookup 00152 00153 if (d->state >= KServerSocketPrivate::LookupDone) 00154 return true; // results are already available 00155 00156 // make sure we have at least one parameter for lookup 00157 if (d->resolver.serviceName().isNull() && 00158 !d->resolver.nodeName().isNull()) 00159 d->resolver.setServiceName(QLatin1String("")); 00160 00161 // don't restart the lookups if they had succeeded and 00162 // the input values weren't changed 00163 00164 // reset results 00165 d->resolverResults = KResolverResults(); 00166 00167 if (d->resolver.status() <= 0) 00168 // if it's already running, there's no harm in calling again 00169 d->resolver.start(); // signal may emit 00170 00171 if (blocking()) 00172 { 00173 // we're in blocking mode operation 00174 // wait for the results 00175 00176 d->resolver.wait(); // signal may be emitted again 00177 // lookupFinishedSlot has been called 00178 } 00179 00180 return true; 00181 } 00182 00183 bool KServerSocket::bind(const KResolverEntry& address) 00184 { 00185 if (socketDevice()->bind(address)) 00186 { 00187 setError(NoError); 00188 00189 d->state = KServerSocketPrivate::Bound; 00190 emit bound(address); 00191 return true; 00192 } 00193 copyError(); 00194 return false; 00195 } 00196 00197 bool KServerSocket::bind(const QString& node, const QString& service) 00198 { 00199 setAddress(node, service); 00200 return bind(); 00201 } 00202 00203 bool KServerSocket::bind(const QString& service) 00204 { 00205 setAddress(service); 00206 return bind(); 00207 } 00208 00209 bool KServerSocket::bind() 00210 { 00211 if (d->state >= KServerSocketPrivate::Bound) 00212 return true; 00213 00214 if (d->state < KServerSocketPrivate::LookupDone) 00215 { 00216 if (!blocking()) 00217 { 00218 d->bindWhenFound = true; 00219 bool ok = lookup(); // will call doBind 00220 if (d->state >= KServerSocketPrivate::Bound) 00221 d->bindWhenFound = false; 00222 return ok; 00223 } 00224 00225 // not blocking 00226 if (!lookup()) 00227 return false; 00228 } 00229 00230 return doBind(); 00231 } 00232 00233 bool KServerSocket::listen(int backlog) 00234 { 00235 // WARNING 00236 // this function has to be reentrant 00237 // due to the mechanisms used for binding, this function might 00238 // end up calling itself 00239 00240 if (d->state == KServerSocketPrivate::Listening) 00241 return true; // already listening 00242 00243 d->backlog = backlog; 00244 00245 if (d->state < KServerSocketPrivate::Bound) 00246 { 00247 // we must bind 00248 // note that we can end up calling ourselves here 00249 d->listenWhenBound = true; 00250 if (!bind()) 00251 { 00252 d->listenWhenBound = false; 00253 return false; 00254 } 00255 00256 if (d->state < KServerSocketPrivate::Bound) 00257 // asynchronous lookup in progress... 00258 // we can't be blocking here anyways 00259 return true; 00260 00261 d->listenWhenBound = false; 00262 } 00263 00264 if (d->state < KServerSocketPrivate::Listening) 00265 return doListen(); 00266 00267 return true; 00268 } 00269 00270 void KServerSocket::close() 00271 { 00272 socketDevice()->close(); 00273 if (d->resolver.isRunning()) 00274 d->resolver.cancel(false); 00275 d->state = KServerSocketPrivate::None; 00276 emit closed(); 00277 } 00278 00279 void KServerSocket::setAcceptBuffered(bool enable) 00280 { 00281 d->useKBufferedSocket = enable; 00282 } 00283 00284 KStreamSocket* KServerSocket::accept() 00285 { 00286 if (d->state < KServerSocketPrivate::Listening) 00287 { 00288 if (!blocking()) 00289 { 00290 listen(); 00291 setError(WouldBlock); 00292 return NULL; 00293 } 00294 else if (!listen()) 00295 // error happened during listen 00296 return false; 00297 } 00298 00299 // check to see if we're doing a timeout 00300 if (blocking() && d->timeout > 0) 00301 { 00302 bool timedout; 00303 if (!socketDevice()->poll(d->timeout, &timedout)) 00304 { 00305 copyError(); 00306 return NULL; 00307 } 00308 00309 if (timedout) 00310 return 0L; 00311 } 00312 00313 // we're listening here 00314 KSocketDevice* accepted = socketDevice()->accept(); 00315 if (!accepted) 00316 { 00317 // error happened during accept 00318 copyError(); 00319 return NULL; 00320 } 00321 00322 KStreamSocket* streamsocket; 00323 if (d->useKBufferedSocket) 00324 { 00325 streamsocket = new KBufferedSocket(); 00326 streamsocket->setOpenMode(KStreamSocket::ReadWrite); 00327 } 00328 else 00329 { 00330 streamsocket = new KStreamSocket(); 00331 streamsocket->setOpenMode(KStreamSocket::ReadWrite | 00332 KStreamSocket::Unbuffered); 00333 } 00334 streamsocket->setSocketDevice(accepted); 00335 00336 // FIXME! 00337 // when KStreamSocket can find out the state of the socket passed through 00338 // setSocketDevice, this will probably be unnecessary: 00339 streamsocket->setState(KStreamSocket::Connected); 00340 00341 return streamsocket; 00342 } 00343 00344 KSocketAddress KServerSocket::localAddress() const 00345 { 00346 return socketDevice()->localAddress(); 00347 } 00348 00349 KSocketAddress KServerSocket::externalAddress() const 00350 { 00351 return socketDevice()->externalAddress(); 00352 } 00353 00354 void KServerSocket::lookupFinishedSlot() 00355 { 00356 if (d->resolver.isRunning() || d->state > KServerSocketPrivate::LookupDone) 00357 return; 00358 00359 if (d->resolver.status() < 0) 00360 { 00361 setError(LookupFailure); 00362 emit gotError(LookupFailure); 00363 d->bindWhenFound = d->listenWhenBound = false; 00364 d->state = KServerSocketPrivate::None; 00365 return; 00366 } 00367 00368 // lookup succeeded 00369 d->resolverResults = d->resolver.results(); 00370 d->state = KServerSocketPrivate::LookupDone; 00371 emit hostFound(); 00372 00373 if (d->bindWhenFound) 00374 doBind(); 00375 } 00376 00377 void KServerSocket::copyError() 00378 { 00379 setError(socketDevice()->error()); 00380 } 00381 00382 bool KServerSocket::doBind() 00383 { 00384 d->bindWhenFound = false; 00385 // loop through the results and bind to the first that works 00386 00387 KResolverResults::ConstIterator it = d->resolverResults.constBegin(); 00388 for ( ; it != d->resolverResults.constEnd(); ++it) 00389 if (bind(*it)) 00390 { 00391 if (d->listenWhenBound) 00392 return doListen(); 00393 return true; 00394 } 00395 else 00396 socketDevice()->close(); // didn't work, try again 00397 00398 // failed to bind 00399 emit gotError(error()); 00400 return false; 00401 } 00402 00403 bool KServerSocket::doListen() 00404 { 00405 if (!socketDevice()->listen(d->backlog)) 00406 { 00407 copyError(); 00408 emit gotError(error()); 00409 return false; // failed to listen 00410 } 00411 00412 // set up ready accept signal 00413 QObject::connect(socketDevice()->readNotifier(), SIGNAL(activated(int)), 00414 this, SIGNAL(readyAccept())); 00415 d->state = KServerSocketPrivate::Listening; 00416 return true; 00417 } 00418 00419 00420 #include "k3serversocket.moc"
KDE 4.6 API Reference