kdecore Library API Documentation

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