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"