File indexing completed on 2023-09-24 04:04:39
0001 /* -*- C++ -*- 0002 * Copyright (C) 2003 Thiago Macieira <thiago@kde.org> 0003 * 0004 * 0005 * Permission is hereby granted, free of charge, to any person obtaining 0006 * a copy of this software and associated documentation files (the 0007 * "Software"), to deal in the Software without restriction, including 0008 * without limitation the rights to use, copy, modify, merge, publish, 0009 * distribute, sublicense, and/or sell copies of the Software, and to 0010 * permit persons to whom the Software is furnished to do so, subject to 0011 * the following conditions: 0012 * 0013 * The above copyright notice and this permission notice shall be included 0014 * in all copies or substantial portions of the Software. 0015 * 0016 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 0017 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 0018 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 0019 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 0020 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 0021 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 0022 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 0023 */ 0024 0025 #include "k3serversocket.h" 0026 0027 #include <config-network.h> 0028 0029 #include <QSocketNotifier> 0030 #include <QMutex> 0031 0032 #include "k3socketaddress.h" 0033 #include "k3resolver.h" 0034 #include "k3socketdevice.h" 0035 #include "k3bufferedsocket.h" 0036 0037 using namespace KNetwork; 0038 0039 class KNetwork::KServerSocketPrivate 0040 { 0041 public: 0042 KResolver resolver; 0043 KResolverResults resolverResults; 0044 0045 enum { None, LookupDone, Bound, Listening } state; 0046 int backlog; 0047 int timeout; 0048 0049 bool bindWhenFound : 1, listenWhenBound : 1, useKBufferedSocket : 1; 0050 0051 KServerSocketPrivate() 0052 : state(None), timeout(0), bindWhenFound(false), listenWhenBound(false), 0053 useKBufferedSocket(true) 0054 { 0055 resolver.setFlags(KResolver::Passive); 0056 resolver.setFamily(KResolver::KnownFamily); 0057 } 0058 }; 0059 0060 KServerSocket::KServerSocket(QObject *parent) 0061 : QObject(parent), d(new KServerSocketPrivate) 0062 { 0063 QObject::connect(&d->resolver, SIGNAL(finished(KNetwork::KResolverResults)), 0064 this, SLOT(lookupFinishedSlot())); 0065 } 0066 0067 KServerSocket::KServerSocket(const QString &service, QObject *parent) 0068 : QObject(parent), d(new KServerSocketPrivate) 0069 { 0070 QObject::connect(&d->resolver, SIGNAL(finished(KNetwork::KResolverResults)), 0071 this, SLOT(lookupFinishedSlot())); 0072 d->resolver.setServiceName(service); 0073 } 0074 0075 KServerSocket::KServerSocket(const QString &node, const QString &service, 0076 QObject *parent) 0077 : QObject(parent), d(new KServerSocketPrivate) 0078 { 0079 QObject::connect(&d->resolver, SIGNAL(finished(KNetwork::KResolverResults)), 0080 this, SLOT(lookupFinishedSlot())); 0081 setAddress(node, service); 0082 } 0083 0084 KServerSocket::~KServerSocket() 0085 { 0086 close(); 0087 delete d; 0088 } 0089 0090 bool KServerSocket::setSocketOptions(int opts) 0091 { 0092 QMutexLocker locker(mutex()); 0093 KSocketBase::setSocketOptions(opts); // call parent 0094 bool result = socketDevice()->setSocketOptions(opts); // and set the implementation 0095 copyError(); 0096 return result; 0097 } 0098 0099 KResolver &KServerSocket::resolver() const 0100 { 0101 return d->resolver; 0102 } 0103 0104 const KResolverResults &KServerSocket::resolverResults() const 0105 { 0106 return d->resolverResults; 0107 } 0108 0109 void KServerSocket::setResolutionEnabled(bool enable) 0110 { 0111 if (enable) { 0112 d->resolver.setFlags(d->resolver.flags() & ~KResolver::NoResolve); 0113 } else { 0114 d->resolver.setFlags(d->resolver.flags() | KResolver::NoResolve); 0115 } 0116 } 0117 0118 void KServerSocket::setFamily(int families) 0119 { 0120 d->resolver.setFamily(families); 0121 } 0122 0123 void KServerSocket::setAddress(const QString &service) 0124 { 0125 d->resolver.setNodeName(QString()); 0126 d->resolver.setServiceName(service); 0127 d->resolverResults.clear(); 0128 if (d->state <= KServerSocketPrivate::LookupDone) { 0129 d->state = KServerSocketPrivate::None; 0130 } 0131 } 0132 0133 void KServerSocket::setAddress(const QString &node, const QString &service) 0134 { 0135 d->resolver.setNodeName(node); 0136 d->resolver.setServiceName(service); 0137 d->resolverResults.clear(); 0138 if (d->state <= KServerSocketPrivate::LookupDone) { 0139 d->state = KServerSocketPrivate::None; 0140 } 0141 } 0142 0143 void KServerSocket::setTimeout(int msec) 0144 { 0145 d->timeout = msec; 0146 } 0147 0148 bool KServerSocket::lookup() 0149 { 0150 setError(NoError); 0151 if (d->resolver.isRunning() && !blocking()) { 0152 return true; // already doing lookup 0153 } 0154 0155 if (d->state >= KServerSocketPrivate::LookupDone) { 0156 return true; // results are already available 0157 } 0158 0159 // make sure we have at least one parameter for lookup 0160 if (d->resolver.serviceName().isNull() && 0161 !d->resolver.nodeName().isNull()) { 0162 d->resolver.setServiceName(QLatin1String("")); 0163 } 0164 0165 // don't restart the lookups if they had succeeded and 0166 // the input values weren't changed 0167 0168 // reset results 0169 d->resolverResults = KResolverResults(); 0170 0171 if (d->resolver.status() <= 0) 0172 // if it's already running, there's no harm in calling again 0173 { 0174 d->resolver.start(); // signal may emit 0175 } 0176 0177 if (blocking()) { 0178 // we're in blocking mode operation 0179 // wait for the results 0180 0181 d->resolver.wait(); // signal may be emitted again 0182 // lookupFinishedSlot has been called 0183 } 0184 0185 return true; 0186 } 0187 0188 bool KServerSocket::bind(const KResolverEntry &address) 0189 { 0190 if (socketDevice()->bind(address)) { 0191 setError(NoError); 0192 0193 d->state = KServerSocketPrivate::Bound; 0194 emit bound(address); 0195 return true; 0196 } 0197 copyError(); 0198 return false; 0199 } 0200 0201 bool KServerSocket::bind(const QString &node, const QString &service) 0202 { 0203 setAddress(node, service); 0204 return bind(); 0205 } 0206 0207 bool KServerSocket::bind(const QString &service) 0208 { 0209 setAddress(service); 0210 return bind(); 0211 } 0212 0213 bool KServerSocket::bind() 0214 { 0215 if (d->state >= KServerSocketPrivate::Bound) { 0216 return true; 0217 } 0218 0219 if (d->state < KServerSocketPrivate::LookupDone) { 0220 if (!blocking()) { 0221 d->bindWhenFound = true; 0222 bool ok = lookup(); // will call doBind 0223 if (d->state >= KServerSocketPrivate::Bound) { 0224 d->bindWhenFound = false; 0225 } 0226 return ok; 0227 } 0228 0229 // not blocking 0230 if (!lookup()) { 0231 return false; 0232 } 0233 } 0234 0235 return doBind(); 0236 } 0237 0238 bool KServerSocket::listen(int backlog) 0239 { 0240 // WARNING 0241 // this function has to be reentrant 0242 // due to the mechanisms used for binding, this function might 0243 // end up calling itself 0244 0245 if (d->state == KServerSocketPrivate::Listening) { 0246 return true; // already listening 0247 } 0248 0249 d->backlog = backlog; 0250 0251 if (d->state < KServerSocketPrivate::Bound) { 0252 // we must bind 0253 // note that we can end up calling ourselves here 0254 d->listenWhenBound = true; 0255 if (!bind()) { 0256 d->listenWhenBound = false; 0257 return false; 0258 } 0259 0260 if (d->state < KServerSocketPrivate::Bound) 0261 // asynchronous lookup in progress... 0262 // we can't be blocking here anyways 0263 { 0264 return true; 0265 } 0266 0267 d->listenWhenBound = false; 0268 } 0269 0270 if (d->state < KServerSocketPrivate::Listening) { 0271 return doListen(); 0272 } 0273 0274 return true; 0275 } 0276 0277 void KServerSocket::close() 0278 { 0279 socketDevice()->close(); 0280 if (d->resolver.isRunning()) { 0281 d->resolver.cancel(false); 0282 } 0283 d->state = KServerSocketPrivate::None; 0284 emit closed(); 0285 } 0286 0287 void KServerSocket::setAcceptBuffered(bool enable) 0288 { 0289 d->useKBufferedSocket = enable; 0290 } 0291 0292 KStreamSocket *KServerSocket::accept() 0293 { 0294 if (d->state < KServerSocketPrivate::Listening) { 0295 if (!blocking()) { 0296 listen(); 0297 setError(WouldBlock); 0298 return nullptr; 0299 } else if (!listen()) 0300 // error happened during listen 0301 { 0302 return nullptr; 0303 } 0304 } 0305 0306 // check to see if we're doing a timeout 0307 if (blocking() && d->timeout > 0) { 0308 bool timedout; 0309 if (!socketDevice()->poll(d->timeout, &timedout)) { 0310 copyError(); 0311 return nullptr; 0312 } 0313 0314 if (timedout) { 0315 return nullptr; 0316 } 0317 } 0318 0319 // we're listening here 0320 KSocketDevice *accepted = socketDevice()->accept(); 0321 if (!accepted) { 0322 // error happened during accept 0323 copyError(); 0324 return nullptr; 0325 } 0326 0327 KStreamSocket *streamsocket; 0328 if (d->useKBufferedSocket) { 0329 streamsocket = new KBufferedSocket(); 0330 streamsocket->setOpenMode(KStreamSocket::ReadWrite); 0331 } else { 0332 streamsocket = new KStreamSocket(); 0333 streamsocket->setOpenMode(KStreamSocket::ReadWrite | 0334 KStreamSocket::Unbuffered); 0335 } 0336 streamsocket->setSocketDevice(accepted); 0337 0338 // FIXME! 0339 // when KStreamSocket can find out the state of the socket passed through 0340 // setSocketDevice, this will probably be unnecessary: 0341 streamsocket->setState(KStreamSocket::Connected); 0342 0343 return streamsocket; 0344 } 0345 0346 KSocketAddress KServerSocket::localAddress() const 0347 { 0348 return socketDevice()->localAddress(); 0349 } 0350 0351 KSocketAddress KServerSocket::externalAddress() const 0352 { 0353 return socketDevice()->externalAddress(); 0354 } 0355 0356 void KServerSocket::lookupFinishedSlot() 0357 { 0358 if (d->resolver.isRunning() || d->state > KServerSocketPrivate::LookupDone) { 0359 return; 0360 } 0361 0362 if (d->resolver.status() < 0) { 0363 setError(LookupFailure); 0364 emit gotError(LookupFailure); 0365 d->bindWhenFound = d->listenWhenBound = false; 0366 d->state = KServerSocketPrivate::None; 0367 return; 0368 } 0369 0370 // lookup succeeded 0371 d->resolverResults = d->resolver.results(); 0372 d->state = KServerSocketPrivate::LookupDone; 0373 emit hostFound(); 0374 0375 if (d->bindWhenFound) { 0376 doBind(); 0377 } 0378 } 0379 0380 void KServerSocket::copyError() 0381 { 0382 setError(socketDevice()->error()); 0383 } 0384 0385 bool KServerSocket::doBind() 0386 { 0387 d->bindWhenFound = false; 0388 // loop through the results and bind to the first that works 0389 0390 KResolverResults::ConstIterator it = d->resolverResults.constBegin(); 0391 for (; it != d->resolverResults.constEnd(); ++it) 0392 if (bind(*it)) { 0393 if (d->listenWhenBound) { 0394 return doListen(); 0395 } 0396 return true; 0397 } else { 0398 socketDevice()->close(); // didn't work, try again 0399 } 0400 0401 // failed to bind 0402 emit gotError(error()); 0403 return false; 0404 } 0405 0406 bool KServerSocket::doListen() 0407 { 0408 if (!socketDevice()->listen(d->backlog)) { 0409 copyError(); 0410 emit gotError(error()); 0411 return false; // failed to listen 0412 } 0413 0414 // set up ready accept signal 0415 QObject::connect(socketDevice()->readNotifier(), SIGNAL(activated(int)), 0416 this, SIGNAL(readyAccept())); 0417 d->state = KServerSocketPrivate::Listening; 0418 return true; 0419 } 0420 0421 #include "moc_k3serversocket.cpp"