kstreamsocket.cpp00001
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"
|