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