KDECore
k3streamsocket.cpp
Go to the documentation of this file.00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025 #include "k3streamsocket.h"
00026
00027 #include <config.h>
00028 #include <config-network.h>
00029
00030 #include <QSocketNotifier>
00031 #include <QDateTime>
00032 #include <QTimer>
00033 #include <QPointer>
00034
00035 #include "k3socketaddress.h"
00036 #include "k3resolver.h"
00037 #include "k3socketdevice.h"
00038
00039 using namespace KNetwork;
00040
00041 class KNetwork::KStreamSocketPrivate
00042 {
00043 public:
00044 KResolverResults::ConstIterator local, peer;
00045 QTime startTime;
00046 QTimer timer;
00047
00048 int timeout;
00049
00050 inline KStreamSocketPrivate()
00051 : timeout(0)
00052 { }
00053 };
00054
00055 KStreamSocket::KStreamSocket(const QString& node, const QString& service,
00056 QObject* parent)
00057 : KClientSocketBase(parent), d(new KStreamSocketPrivate)
00058 {
00059 peerResolver().setNodeName(node);
00060 peerResolver().setServiceName(service);
00061 peerResolver().setFamily(KResolver::KnownFamily);
00062 localResolver().setFamily(KResolver::KnownFamily);
00063
00064 setSocketOptions(socketOptions() & ~Blocking);
00065
00066 QObject::connect(&d->timer, SIGNAL(timeout()), this, SLOT(timeoutSlot()));
00067 }
00068
00069 KStreamSocket::~KStreamSocket()
00070 {
00071 delete d;
00072
00073 }
00074
00075 int KStreamSocket::timeout() const
00076 {
00077 return d->timeout;
00078 }
00079
00080 int KStreamSocket::remainingTimeout() const
00081 {
00082 if (state() != Connecting)
00083 return timeout();
00084 if (timeout() <= 0)
00085 return 0;
00086
00087 return timeout() - d->startTime.elapsed();
00088 }
00089
00090 void KStreamSocket::setTimeout(int msecs)
00091 {
00092 d->timeout = msecs;
00093
00094 if (state() == Connecting)
00095 d->timer.start(msecs);
00096 }
00097
00098 bool KStreamSocket::bind(const QString& node, const QString& service)
00099 {
00100 if (state() != Idle)
00101 return false;
00102
00103 if (!node.isNull())
00104 localResolver().setNodeName(node);
00105 if (!service.isNull())
00106 localResolver().setServiceName(service);
00107 return true;
00108 }
00109
00110 bool KStreamSocket::bind(const KResolverEntry& entry)
00111 {
00112 return KClientSocketBase::bind(entry);
00113 }
00114
00115 bool KStreamSocket::connect(const QString& node, const QString& service,
00116 OpenMode mode)
00117 {
00118 Q_UNUSED(mode);
00119 if (state() == Connected)
00120 return true;
00121
00122 if (state() > Connected)
00123 return false;
00124
00125 if (!node.isNull())
00126 peerResolver().setNodeName(node);
00127 if (!service.isNull())
00128 peerResolver().setServiceName(service);
00129
00130 if (state() == Connecting && !blocking())
00131 {
00132 setError(InProgress);
00133 emit gotError(InProgress);
00134 return true;
00135 }
00136
00137 if (state() < HostFound)
00138 {
00139
00140 if (!blocking())
00141 {
00142 QObject::connect(this, SIGNAL(hostFound()), SLOT(hostFoundSlot()));
00143 return lookup();
00144 }
00145
00146
00147 if (!lookup())
00148 return false;
00149 }
00150
00151
00152
00153
00154
00155 if (timeout() > 0)
00156 {
00157 if (!blocking() && !d->timer.isActive())
00158 {
00159 d->timer.setSingleShot(true);
00160 d->timer.start(timeout());
00161 }
00162 else
00163 {
00164
00165
00166
00167
00168 d->timer.stop();
00169
00170 socketDevice()->setBlocking(false);
00171 while (true)
00172 {
00173 connectionEvent();
00174 if (state() < Connecting)
00175 return false;
00176 if (state() == Connected)
00177 return true;
00178
00179 if (remainingTimeout() <= 0)
00180 {
00181
00182 timeoutSlot();
00183 return false;
00184 }
00185
00186 if (socketDevice()->error() == InProgress)
00187 {
00188 bool timedout;
00189 socketDevice()->poll(remainingTimeout(), &timedout);
00190 if (timedout)
00191 {
00192 timeoutSlot();
00193 return false;
00194 }
00195 }
00196 }
00197 }
00198 }
00199
00200 connectionEvent();
00201 return error() == NoError;
00202 }
00203
00204 bool KStreamSocket::connect(const KResolverEntry& entry, OpenMode mode)
00205 {
00206 return KClientSocketBase::connect(entry, mode);
00207 }
00208
00209 void KStreamSocket::hostFoundSlot()
00210 {
00211 QObject::disconnect(this, SLOT(hostFoundSlot()));
00212 if (timeout() > 0)
00213 {
00214 d->timer.setSingleShot(true);
00215 d->timer.start(timeout());
00216 }
00217 QTimer::singleShot(0, this, SLOT(connectionEvent()));
00218 }
00219
00220 void KStreamSocket::connectionEvent()
00221 {
00222 if (state() != HostFound && state() != Connecting)
00223 return;
00224
00225 const KResolverResults& peer = peerResults();
00226 if (state() == HostFound)
00227 {
00228 d->startTime.start();
00229
00230 setState(Connecting);
00231 emit stateChanged(Connecting);
00232 d->peer = peer.begin();
00233 d->local = localResults().begin();
00234 }
00235
00236 while (d->peer != peer.end())
00237 {
00238 const KResolverEntry &r = *d->peer;
00239
00240 if (socketDevice()->socket() != -1)
00241 {
00242
00243
00244 if (socketDevice()->connect(r) && socketDevice()->error() == NoError)
00245 {
00246
00247 connectionSucceeded(r);
00248 return;
00249 }
00250 else if (socketDevice()->error() == InProgress)
00251
00252 return;
00253
00254
00255 copyError();
00256 socketDevice()->close();
00257 ++d->peer;
00258 continue;
00259 }
00260
00261
00262 if (!bindLocallyFor(r))
00263 {
00264
00265 ++d->peer;
00266 continue;
00267 }
00268
00269 {
00270 bool skip = false;
00271 emit aboutToConnect(r, skip);
00272 if (skip)
00273 {
00274 ++d->peer;
00275 continue;
00276 }
00277 }
00278
00279 if (socketDevice()->connect(r) || socketDevice()->error() == InProgress)
00280 {
00281
00282 if (socketDevice()->error() == InProgress)
00283 {
00284 QSocketNotifier *n = socketDevice()->readNotifier();
00285 QObject::connect(n, SIGNAL(activated(int)),
00286 this, SLOT(connectionEvent()));
00287 n->setEnabled(true);
00288
00289 n = socketDevice()->writeNotifier();
00290 QObject::connect(n, SIGNAL(activated(int)),
00291 this, SLOT(connectionEvent()));
00292 n->setEnabled(true);
00293
00294 return;
00295 }
00296
00297
00298 connectionSucceeded(r);
00299 return;
00300 }
00301
00302
00303
00304 copyError();
00305 socketDevice()->close();
00306 ++d->peer;
00307 }
00308
00309
00310 socketDevice()->setSocketOptions(socketOptions());
00311 setState(Idle);
00312 emit stateChanged(Idle);
00313 emit gotError(error());
00314 return;
00315 }
00316
00317 void KStreamSocket::timeoutSlot()
00318 {
00319 if (state() != Connecting)
00320 return;
00321
00322
00323 socketDevice()->close();
00324
00325 setError(Timeout);
00326 setState(HostFound);
00327 emit stateChanged(HostFound);
00328
00329 QPointer<KStreamSocket> that = this;
00330 emit gotError(Timeout);
00331
00332 if (!that.isNull())
00333 emit timedOut();
00334 }
00335
00336 bool KStreamSocket::bindLocallyFor(const KResolverEntry& peer)
00337 {
00338 const KResolverResults& local = localResults();
00339
00340 if (local.isEmpty())
00341
00342 return true;
00343
00344 bool foundone = false;
00345
00346 for (d->local = local.begin(); d->local != local.end(); ++d->local)
00347 if ((*d->local).family() == peer.family())
00348 {
00349
00350 foundone = true;
00351
00352 if (socketDevice()->bind(*d->local))
00353 return true;
00354 }
00355
00356 if (!foundone)
00357 {
00358
00359 setError(NotSupported);
00360 emit gotError(NotSupported);
00361 }
00362 else
00363 copyError();
00364 return false;
00365 }
00366
00367 void KStreamSocket::connectionSucceeded(const KResolverEntry& peer)
00368 {
00369 QObject::disconnect(socketDevice()->readNotifier(), 0, this, SLOT(connectionEvent()));
00370 QObject::disconnect(socketDevice()->writeNotifier(), 0, this, SLOT(connectionEvent()));
00371
00372 resetError();
00373 KActiveSocketBase::open(ReadWrite | Unbuffered);
00374 setState(Connected);
00375 socketDevice()->setSocketOptions(socketOptions());
00376 d->timer.stop();
00377 emit stateChanged(Connected);
00378
00379 if (!localResults().isEmpty())
00380 emit bound(*d->local);
00381 emit connected(peer);
00382 }
00383
00384 #include "k3streamsocket.moc"