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