File indexing completed on 2024-12-08 12:17:38

0001 /*  -*- C++ -*-
0002  *  Copyright (C) 2003,2005 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 "k3clientsocketbase.h"
0026 
0027 #include <config-network.h>
0028 
0029 #include <QSocketNotifier>
0030 #include <QTimer>
0031 #include <QMutex>
0032 
0033 #include "k3socketaddress.h"
0034 #include "k3socketdevice.h"
0035 
0036 using namespace KNetwork;
0037 
0038 class KNetwork::KClientSocketBasePrivate
0039 {
0040 public:
0041     int state;
0042 
0043     KResolver localResolver, peerResolver;
0044     KResolverResults localResults, peerResults;
0045 
0046     bool enableRead : 1, enableWrite : 1;
0047 };
0048 
0049 KClientSocketBase::KClientSocketBase(QObject *parent)
0050     : KActiveSocketBase(parent), d(new KClientSocketBasePrivate)
0051 {
0052     d->state = Idle;
0053     d->enableRead = true;
0054     d->enableWrite = false;
0055 }
0056 
0057 KClientSocketBase::~KClientSocketBase()
0058 {
0059     close();
0060     delete d;
0061 }
0062 
0063 KClientSocketBase::SocketState KClientSocketBase::state() const
0064 {
0065     return static_cast<SocketState>(d->state);
0066 }
0067 
0068 void KClientSocketBase::setState(SocketState state)
0069 {
0070     d->state = state;
0071     stateChanging(state);
0072 }
0073 
0074 bool KClientSocketBase::setSocketOptions(int opts)
0075 {
0076     QMutexLocker locker(mutex());
0077     KSocketBase::setSocketOptions(opts); // call parent
0078 
0079     // don't create the device unnecessarily
0080     if (hasDevice()) {
0081         bool result = socketDevice()->setSocketOptions(opts); // and set the implementation
0082         copyError();
0083         return result;
0084     }
0085 
0086     return true;
0087 }
0088 
0089 KResolver &KClientSocketBase::peerResolver() const
0090 {
0091     return d->peerResolver;
0092 }
0093 
0094 const KResolverResults &KClientSocketBase::peerResults() const
0095 {
0096     return d->peerResults;
0097 }
0098 
0099 KResolver &KClientSocketBase::localResolver() const
0100 {
0101     return d->localResolver;
0102 }
0103 
0104 const KResolverResults &KClientSocketBase::localResults() const
0105 {
0106     return d->localResults;
0107 }
0108 
0109 void KClientSocketBase::setResolutionEnabled(bool enable)
0110 {
0111     if (enable) {
0112         d->localResolver.setFlags(d->localResolver.flags() & ~KResolver::NoResolve);
0113         d->peerResolver.setFlags(d->peerResolver.flags() & ~KResolver::NoResolve);
0114     } else {
0115         d->localResolver.setFlags(d->localResolver.flags() | KResolver::NoResolve);
0116         d->peerResolver.setFlags(d->peerResolver.flags() | KResolver::NoResolve);
0117     }
0118 }
0119 
0120 void KClientSocketBase::setFamily(int families)
0121 {
0122     d->localResolver.setFamily(families);
0123     d->peerResolver.setFamily(families);
0124 }
0125 
0126 bool KClientSocketBase::lookup()
0127 {
0128     if (state() == HostLookup && !blocking()) {
0129         return true;    // already doing lookup
0130     }
0131 
0132     if (state() > HostLookup) {
0133         return true;    // results are already available
0134     }
0135 
0136     if (state() < HostLookup) {
0137         if (d->localResolver.serviceName().isNull() &&
0138                 !d->localResolver.nodeName().isNull()) {
0139             d->localResolver.setServiceName(QLatin1String(""));
0140         }
0141 
0142         // don't restart the lookups if they had succeeded and
0143         // the input values weren't changed
0144         QObject::connect(&d->peerResolver,
0145                          SIGNAL(finished(KNetwork::KResolverResults)),
0146                          this, SLOT(lookupFinishedSlot()));
0147         QObject::connect(&d->localResolver,
0148                          SIGNAL(finished(KNetwork::KResolverResults)),
0149                          this, SLOT(lookupFinishedSlot()));
0150 
0151         if (d->localResolver.status() <= 0) {
0152             d->localResolver.start();
0153         }
0154         if (d->peerResolver.status() <= 0) {
0155             d->peerResolver.start();
0156         }
0157 
0158         setState(HostLookup);
0159         emit stateChanged(HostLookup);
0160 
0161         if (!d->localResolver.isRunning() && !d->peerResolver.isRunning()) {
0162             // if nothing is running, then the lookup results are still valid
0163             // pretend we had done lookup
0164             if (blocking()) {
0165                 lookupFinishedSlot();
0166             } else {
0167                 QTimer::singleShot(0, this, SLOT(lookupFinishedSlot()));
0168             }
0169         } else {
0170             d->localResults = d->peerResults = KResolverResults();
0171         }
0172     }
0173 
0174     if (blocking()) {
0175         // we're in blocking mode operation
0176         // wait for the results
0177 
0178         localResolver().wait();
0179         peerResolver().wait();
0180 
0181         // lookupFinishedSlot has been called
0182     }
0183 
0184     return true;
0185 }
0186 
0187 bool KClientSocketBase::bind(const KResolverEntry &address)
0188 {
0189     if (state() == HostLookup || state() > Connecting) {
0190         return false;
0191     }
0192 
0193     if (socketDevice()->bind(address)) {
0194         resetError();
0195 
0196         // don't set the state or emit signals if we are in a higher state
0197         if (state() < Bound) {
0198             setState(Bound);
0199             emit stateChanged(Bound);
0200             emit bound(address);
0201         }
0202         return true;
0203     }
0204     return false;
0205 }
0206 
0207 bool KClientSocketBase::connect(const KResolverEntry &address, OpenMode mode)
0208 {
0209     if (state() == Connected) {
0210         return true;    // to be compliant with the other classes
0211     }
0212     if (state() == HostLookup || state() > Connecting) {
0213         return false;
0214     }
0215 
0216     bool ok = socketDevice()->connect(address);
0217     copyError();
0218 
0219     if (ok) {
0220         SocketState newstate;
0221         if (error() == InProgress) {
0222             newstate = Connecting;
0223         } else {
0224             newstate = Connected;
0225         }
0226 
0227         if (state() < newstate) {
0228             setState(newstate);
0229             emit stateChanged(newstate);
0230             if (error() == NoError) {
0231                 KActiveSocketBase::open(mode | Unbuffered);
0232                 emit connected(address);
0233             }
0234         }
0235 
0236         return true;
0237     }
0238     return false;
0239 }
0240 
0241 bool KClientSocketBase::disconnect()
0242 {
0243     if (state() != Connected) {
0244         return false;
0245     }
0246 
0247     bool ok = socketDevice()->disconnect();
0248     copyError();
0249 
0250     if (ok) {
0251         setState(Unconnected);
0252         emit stateChanged(Unconnected);
0253         return true;
0254     }
0255     return false;
0256 }
0257 
0258 bool KClientSocketBase::open(OpenMode mode)
0259 {
0260     return connect(QString(), QString(), mode);
0261 }
0262 
0263 void KClientSocketBase::close()
0264 {
0265     if (state() == Idle) {
0266         return;    // nothing to do
0267     }
0268 
0269     if (state() == HostLookup) {
0270         d->peerResolver.cancel(false);
0271         d->localResolver.cancel(false);
0272     }
0273 
0274     d->localResults = d->peerResults = KResolverResults();
0275 
0276     socketDevice()->close();
0277     KActiveSocketBase::close();
0278     setState(Idle);
0279     emit stateChanged(Idle);
0280     emit closed();
0281 }
0282 
0283 bool KClientSocketBase::flush()
0284 {
0285     return false;
0286 }
0287 
0288 // This function is unlike all the others because it is const
0289 qint64 KClientSocketBase::bytesAvailable() const
0290 {
0291     return socketDevice()->bytesAvailable();
0292 }
0293 
0294 // All the functions below look really alike
0295 // Should I use a macro to define them?
0296 
0297 qint64 KClientSocketBase::waitForMore(int msecs, bool *timeout)
0298 {
0299     resetError();
0300     qint64 retval = socketDevice()->waitForMore(msecs, timeout);
0301     if (retval == -1) {
0302         copyError();
0303         emit gotError(error());
0304     }
0305     return retval;
0306 }
0307 
0308 qint64 KClientSocketBase::readData(char *data, qint64 maxlen, KSocketAddress *from)
0309 {
0310     resetError();
0311     qint64 retval = socketDevice()->readData(data, maxlen, from);
0312     if (retval == -1) {
0313         copyError();
0314         emit gotError(error());
0315     }
0316     return retval;
0317 }
0318 
0319 qint64 KClientSocketBase::peekData(char *data, qint64 maxlen, KSocketAddress *from)
0320 {
0321     resetError();
0322     qint64 retval = socketDevice()->peekData(data, maxlen, from);
0323     if (retval == -1) {
0324         copyError();
0325         emit gotError(error());
0326     }
0327     return retval;
0328 }
0329 
0330 qint64 KClientSocketBase::writeData(const char *data, qint64 len, const KSocketAddress *to)
0331 {
0332     resetError();
0333     qint64 retval = socketDevice()->writeData(data, len, to);
0334     if (retval == -1) {
0335         copyError();
0336         emit gotError(error());
0337     } else {
0338         emit bytesWritten(retval);
0339     }
0340     return retval;
0341 }
0342 
0343 KSocketAddress KClientSocketBase::localAddress() const
0344 {
0345     return socketDevice()->localAddress();
0346 }
0347 
0348 KSocketAddress KClientSocketBase::peerAddress() const
0349 {
0350     return socketDevice()->peerAddress();
0351 }
0352 
0353 bool KClientSocketBase::emitsReadyRead() const
0354 {
0355     return d->enableRead;
0356 }
0357 
0358 void KClientSocketBase::enableRead(bool enable)
0359 {
0360     QMutexLocker locker(mutex());
0361 
0362     d->enableRead = enable;
0363     QSocketNotifier *n = socketDevice()->readNotifier();
0364     if (n) {
0365         n->setEnabled(enable);
0366     }
0367 }
0368 
0369 bool KClientSocketBase::emitsReadyWrite() const
0370 {
0371     return d->enableWrite;
0372 }
0373 
0374 void KClientSocketBase::enableWrite(bool enable)
0375 {
0376     QMutexLocker locker(mutex());
0377 
0378     d->enableWrite = enable;
0379     QSocketNotifier *n = socketDevice()->writeNotifier();
0380     if (n) {
0381         n->setEnabled(enable);
0382     }
0383 }
0384 
0385 void KClientSocketBase::slotReadActivity()
0386 {
0387     if (d->enableRead) {
0388         emit readyRead();
0389     }
0390 }
0391 
0392 void KClientSocketBase::slotWriteActivity()
0393 {
0394     if (d->enableWrite) {
0395         emit readyWrite();
0396     }
0397 }
0398 
0399 void KClientSocketBase::lookupFinishedSlot()
0400 {
0401     if (d->peerResolver.isRunning() || d->localResolver.isRunning() || state() != HostLookup) {
0402         return;
0403     }
0404 
0405     QObject::disconnect(&d->peerResolver, nullptr, this, SLOT(lookupFinishedSlot()));
0406     QObject::disconnect(&d->localResolver, nullptr, this, SLOT(lookupFinishedSlot()));
0407     if (d->peerResolver.status() < 0 || d->localResolver.status() < 0) {
0408         setState(Idle);       // backtrack
0409         setError(LookupFailure);
0410         emit stateChanged(Idle);
0411         emit gotError(LookupFailure);
0412         return;
0413     }
0414 
0415     d->localResults = d->localResolver.results();
0416     d->peerResults = d->peerResolver.results();
0417     setState(HostFound);
0418     emit stateChanged(HostFound);
0419     emit hostFound();
0420 }
0421 
0422 void KClientSocketBase::stateChanging(SocketState newState)
0423 {
0424     if (newState == Connected && socketDevice()) {
0425         QSocketNotifier *n = socketDevice()->readNotifier();
0426         if (n) {
0427             n->setEnabled(d->enableRead);
0428             QObject::connect(n, SIGNAL(activated(int)), this, SLOT(slotReadActivity()));
0429         } else {
0430             return;
0431         }
0432 
0433         n = socketDevice()->writeNotifier();
0434         if (n) {
0435             n->setEnabled(d->enableWrite);
0436             QObject::connect(n, SIGNAL(activated(int)), this, SLOT(slotWriteActivity()));
0437         } else {
0438             return;
0439         }
0440     }
0441 }
0442 
0443 void KClientSocketBase::copyError()
0444 {
0445     setError(socketDevice()->error());
0446 }
0447 
0448 #include "moc_k3clientsocketbase.cpp"