File indexing completed on 2024-04-21 14:55:23

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"