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