KDELibs4Support

k3clientsocketbase.cpp
1 /* -*- C++ -*-
2  * Copyright (C) 2003,2005 Thiago Macieira <[email protected]>
3  *
4  *
5  * Permission is hereby granted, free of charge, to any person obtaining
6  * a copy of this software and associated documentation files (the
7  * "Software"), to deal in the Software without restriction, including
8  * without limitation the rights to use, copy, modify, merge, publish,
9  * distribute, sublicense, and/or sell copies of the Software, and to
10  * permit persons to whom the Software is furnished to do so, subject to
11  * the following conditions:
12  *
13  * The above copyright notice and this permission notice shall be included
14  * in all copies or substantial portions of the Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20  * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21  * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22  * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23  */
24 
25 #include "k3clientsocketbase.h"
26 
27 #include <config-network.h>
28 
29 #include <QSocketNotifier>
30 #include <QTimer>
31 #include <QMutex>
32 
33 #include "k3socketaddress.h"
34 #include "k3socketdevice.h"
35 
36 using namespace KNetwork;
37 
38 class KNetwork::KClientSocketBasePrivate
39 {
40 public:
41  int state;
42 
43  KResolver localResolver, peerResolver;
44  KResolverResults localResults, peerResults;
45 
46  bool enableRead : 1, enableWrite : 1;
47 };
48 
50  : KActiveSocketBase(parent), d(new KClientSocketBasePrivate)
51 {
52  d->state = Idle;
53  d->enableRead = true;
54  d->enableWrite = false;
55 }
56 
58 {
59  close();
60  delete d;
61 }
62 
64 {
65  return static_cast<SocketState>(d->state);
66 }
67 
69 {
70  d->state = state;
71  stateChanging(state);
72 }
73 
75 {
76  QMutexLocker locker(mutex());
77  KSocketBase::setSocketOptions(opts); // call parent
78 
79  // don't create the device unnecessarily
80  if (hasDevice()) {
81  bool result = socketDevice()->setSocketOptions(opts); // and set the implementation
82  copyError();
83  return result;
84  }
85 
86  return true;
87 }
88 
90 {
91  return d->peerResolver;
92 }
93 
95 {
96  return d->peerResults;
97 }
98 
100 {
101  return d->localResolver;
102 }
103 
105 {
106  return d->localResults;
107 }
108 
110 {
111  if (enable) {
112  d->localResolver.setFlags(d->localResolver.flags() & ~KResolver::NoResolve);
113  d->peerResolver.setFlags(d->peerResolver.flags() & ~KResolver::NoResolve);
114  } else {
115  d->localResolver.setFlags(d->localResolver.flags() | KResolver::NoResolve);
116  d->peerResolver.setFlags(d->peerResolver.flags() | KResolver::NoResolve);
117  }
118 }
119 
121 {
122  d->localResolver.setFamily(families);
123  d->peerResolver.setFamily(families);
124 }
125 
127 {
128  if (state() == HostLookup && !blocking()) {
129  return true; // already doing lookup
130  }
131 
132  if (state() > HostLookup) {
133  return true; // results are already available
134  }
135 
136  if (state() < HostLookup) {
137  if (d->localResolver.serviceName().isNull() &&
138  !d->localResolver.nodeName().isNull()) {
139  d->localResolver.setServiceName(QLatin1String(""));
140  }
141 
142  // don't restart the lookups if they had succeeded and
143  // the input values weren't changed
144  QObject::connect(&d->peerResolver,
145  SIGNAL(finished(KNetwork::KResolverResults)),
146  this, SLOT(lookupFinishedSlot()));
147  QObject::connect(&d->localResolver,
148  SIGNAL(finished(KNetwork::KResolverResults)),
149  this, SLOT(lookupFinishedSlot()));
150 
151  if (d->localResolver.status() <= 0) {
152  d->localResolver.start();
153  }
154  if (d->peerResolver.status() <= 0) {
155  d->peerResolver.start();
156  }
157 
158  setState(HostLookup);
159  emit stateChanged(HostLookup);
160 
161  if (!d->localResolver.isRunning() && !d->peerResolver.isRunning()) {
162  // if nothing is running, then the lookup results are still valid
163  // pretend we had done lookup
164  if (blocking()) {
165  lookupFinishedSlot();
166  } else {
167  QTimer::singleShot(0, this, SLOT(lookupFinishedSlot()));
168  }
169  } else {
170  d->localResults = d->peerResults = KResolverResults();
171  }
172  }
173 
174  if (blocking()) {
175  // we're in blocking mode operation
176  // wait for the results
177 
178  localResolver().wait();
179  peerResolver().wait();
180 
181  // lookupFinishedSlot has been called
182  }
183 
184  return true;
185 }
186 
188 {
189  if (state() == HostLookup || state() > Connecting) {
190  return false;
191  }
192 
193  if (socketDevice()->bind(address)) {
194  resetError();
195 
196  // don't set the state or emit signals if we are in a higher state
197  if (state() < Bound) {
198  setState(Bound);
199  emit stateChanged(Bound);
200  emit bound(address);
201  }
202  return true;
203  }
204  return false;
205 }
206 
208 {
209  if (state() == Connected) {
210  return true; // to be compliant with the other classes
211  }
212  if (state() == HostLookup || state() > Connecting) {
213  return false;
214  }
215 
216  bool ok = socketDevice()->connect(address);
217  copyError();
218 
219  if (ok) {
220  SocketState newstate;
221  if (error() == InProgress) {
222  newstate = Connecting;
223  } else {
224  newstate = Connected;
225  }
226 
227  if (state() < newstate) {
228  setState(newstate);
229  emit stateChanged(newstate);
230  if (error() == NoError) {
232  emit connected(address);
233  }
234  }
235 
236  return true;
237  }
238  return false;
239 }
240 
242 {
243  if (state() != Connected) {
244  return false;
245  }
246 
247  bool ok = socketDevice()->disconnect();
248  copyError();
249 
250  if (ok) {
251  setState(Unconnected);
252  emit stateChanged(Unconnected);
253  return true;
254  }
255  return false;
256 }
257 
259 {
260  return connect(QString(), QString(), mode);
261 }
262 
264 {
265  if (state() == Idle) {
266  return; // nothing to do
267  }
268 
269  if (state() == HostLookup) {
270  d->peerResolver.cancel(false);
271  d->localResolver.cancel(false);
272  }
273 
274  d->localResults = d->peerResults = KResolverResults();
275 
276  socketDevice()->close();
278  setState(Idle);
279  emit stateChanged(Idle);
280  emit closed();
281 }
282 
284 {
285  return false;
286 }
287 
288 // This function is unlike all the others because it is const
290 {
291  return socketDevice()->bytesAvailable();
292 }
293 
294 // All the functions below look really alike
295 // Should I use a macro to define them?
296 
297 qint64 KClientSocketBase::waitForMore(int msecs, bool *timeout)
298 {
299  resetError();
300  qint64 retval = socketDevice()->waitForMore(msecs, timeout);
301  if (retval == -1) {
302  copyError();
303  emit gotError(error());
304  }
305  return retval;
306 }
307 
308 qint64 KClientSocketBase::readData(char *data, qint64 maxlen, KSocketAddress *from)
309 {
310  resetError();
311  qint64 retval = socketDevice()->readData(data, maxlen, from);
312  if (retval == -1) {
313  copyError();
314  emit gotError(error());
315  }
316  return retval;
317 }
318 
319 qint64 KClientSocketBase::peekData(char *data, qint64 maxlen, KSocketAddress *from)
320 {
321  resetError();
322  qint64 retval = socketDevice()->peekData(data, maxlen, from);
323  if (retval == -1) {
324  copyError();
325  emit gotError(error());
326  }
327  return retval;
328 }
329 
330 qint64 KClientSocketBase::writeData(const char *data, qint64 len, const KSocketAddress *to)
331 {
332  resetError();
333  qint64 retval = socketDevice()->writeData(data, len, to);
334  if (retval == -1) {
335  copyError();
336  emit gotError(error());
337  } else {
338  emit bytesWritten(retval);
339  }
340  return retval;
341 }
342 
344 {
345  return socketDevice()->localAddress();
346 }
347 
349 {
350  return socketDevice()->peerAddress();
351 }
352 
354 {
355  return d->enableRead;
356 }
357 
359 {
360  QMutexLocker locker(mutex());
361 
362  d->enableRead = enable;
364  if (n) {
365  n->setEnabled(enable);
366  }
367 }
368 
370 {
371  return d->enableWrite;
372 }
373 
375 {
376  QMutexLocker locker(mutex());
377 
378  d->enableWrite = enable;
380  if (n) {
381  n->setEnabled(enable);
382  }
383 }
384 
386 {
387  if (d->enableRead) {
388  emit readyRead();
389  }
390 }
391 
393 {
394  if (d->enableWrite) {
395  emit readyWrite();
396  }
397 }
398 
399 void KClientSocketBase::lookupFinishedSlot()
400 {
401  if (d->peerResolver.isRunning() || d->localResolver.isRunning() || state() != HostLookup) {
402  return;
403  }
404 
405  QObject::disconnect(&d->peerResolver, nullptr, this, SLOT(lookupFinishedSlot()));
406  QObject::disconnect(&d->localResolver, nullptr, this, SLOT(lookupFinishedSlot()));
407  if (d->peerResolver.status() < 0 || d->localResolver.status() < 0) {
408  setState(Idle); // backtrack
409  setError(LookupFailure);
410  emit stateChanged(Idle);
411  emit gotError(LookupFailure);
412  return;
413  }
414 
415  d->localResults = d->localResolver.results();
416  d->peerResults = d->peerResolver.results();
417  setState(HostFound);
418  emit stateChanged(HostFound);
419  emit hostFound();
420 }
421 
423 {
424  if (newState == Connected && socketDevice()) {
426  if (n) {
427  n->setEnabled(d->enableRead);
428  QObject::connect(n, SIGNAL(activated(int)), this, SLOT(slotReadActivity()));
429  } else {
430  return;
431  }
432 
433  n = socketDevice()->writeNotifier();
434  if (n) {
435  n->setEnabled(d->enableWrite);
436  QObject::connect(n, SIGNAL(activated(int)), this, SLOT(slotWriteActivity()));
437  } else {
438  return;
439  }
440  }
441 }
442 
444 {
446 }
447 
bool open(OpenMode mode) override
Opens the socket.
virtual bool connect(const QString &node=QString(), const QString &service=QString(), OpenMode mode=ReadWrite)=0
Attempts to connect to a given hostname and service, or use the default ones if none are given...
bool blocking() const
Retrieves this socket&#39;s blocking mode.
KSocketDevice * socketDevice() const
Retrieves the socket implementation used on this socket.
virtual bool flush()
This call is not supported on unbuffered sockets.
SocketState state() const
Returns the current state for this socket.
Abstract class for active sockets.
Definition: k3socketbase.h:460
KSocketAddress peerAddress() const override
Returns this socket&#39;s peer address.
qint64 readData(char *data, qint64 maxlen, KSocketAddress *from) override
Reads data from a socket.
One resolution entry.
Definition: k3resolver.h:72
void resetError()
Resets the socket error code and the I/O Device&#39;s status.
QSocketNotifier * writeNotifier() const
Returns a socket notifier for output on this socket.
virtual bool bind(const QString &node=QString(), const QString &service=QString())=0
Binds this socket to the given nodename and service, or use the default ones if none are given...
qint64 waitForMore(int msecs, bool *timeout=nullptr) override
Waits up to msecs for more data to be available on this socket.
qint64 writeData(const char *data, qint64 len, const KSocketAddress *to) override
This is an overloaded member function, provided for convenience. It differs from the above function o...
Name and service resolution class.
Definition: k3resolver.h:312
virtual bool lookup()
Starts the lookup for peer and local hostnames as well as their services.
bool connect(const KResolverEntry &address, OpenMode mode=ReadWrite) override
Connect to a remote host.
typedef OpenMode
KResolver & localResolver() const
Returns the internal KResolver object used for looking up the local host name and service...
virtual void slotReadActivity()
This slot is connected to the read notifier&#39;s signal meaning the socket can read more data...
SocketError error() const
Retrieves the socket error code.
A generic socket address.
void gotError(int code)
This signal is emitted when this object finds an error.
KSocketAddress peerAddress() const override
Returns the peer socket address.
virtual void close()
void hostFound()
This signal is emitted when the lookup is successfully completed.
bool disconnect(const QObject *sender, const char *signal, const QObject *receiver, const char *method)
Name and service resolution results.
Definition: k3resolver.h:212
qint64 readData(char *data, qint64 maxlen, KSocketAddress *from=nullptr) override
Reads data and the source address from this socket.
KClientSocketBase(QObject *parent)
Default constructor.
qint64 peekData(char *data, qint64 maxlen, KSocketAddress *from=nullptr) override
Peeks the data in the socket and the source address.
A namespace to store all networking-related (socket) classes.
QSocketNotifier * readNotifier() const
Returns a socket notifier for input on this socket.
void copyError()
Convenience function to set this object&#39;s error code to match that of the socket device.
void close() override
Closes the socket.
KSocketAddress localAddress() const override
Returns this socket&#39;s local address.
void setResolutionEnabled(bool enable)
Enables or disables name resolution.
bool wait(int msec=0)
Waits for a request to finish resolving.
Definition: k3resolver.cpp:436
QMutex * mutex() const
Returns the internal mutex for this class.
const KResolverResults & peerResults() const
Returns the internal list of resolved results for the peer address.
bool setSocketOptions(int opts) override
This implementation sets the options on the socket.
void bytesWritten(qint64 bytes)
void setState(SocketState state)
Sets the socket state to state.
virtual bool setSocketOptions(int opts)
Set the given socket options.
bool disconnect() override
Disconnects the socket.
void stateChanged(int newstate)
This signal is emitted whenever the socket state changes.
void readyWrite()
This signal is emitted whenever the socket is ready for writing – i.e., whenever there&#39;s space avail...
void setError(SocketError error)
Sets the socket&#39;s error code.
void bound(const KNetwork::KResolverEntry &local)
This signal is emitted when the socket successfully binds to an address.
qint64 waitForMore(int msecs, bool *timeout=nullptr) override
Waits for more data.
void setEnabled(bool enable)
virtual void enableRead(bool enable)
Enables the emission of the readyRead signal.
qint64 writeData(const char *data, qint64 len, const KSocketAddress *to=nullptr) override
Writes the given data to the given destination address.
virtual void stateChanging(SocketState newState)
This function is called by setState() whenever the state changes.
qint64 bytesAvailable() const override
Returns the number of bytes available on this socket.
void setFamily(int families)
Sets the allowed families for the resolutions.
bool hasDevice() const
Returns true if the socket device has been initialised in this object, either by calling socketDevice...
bool setSocketOptions(int opts) override
Sets the socket options.
bool disconnect() override
Disconnects this socket.
bool emitsReadyRead() const
Returns true if the readyRead signal is set to be emitted.
qint64 peekData(char *data, qint64 maxlen, KSocketAddress *from) override
Peeks data from the socket.
const KResolverResults & localResults() const
Returns the internal list of resolved results for the local address.
bool emitsReadyWrite() const
Returns true if the readyWrite signal is set to be emitted.
void readyRead()
QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type)
KResolver & peerResolver() const
Returns the internal KResolver object used for looking up the peer host name and service.
void close() override
Closes the socket.
virtual void enableWrite(bool enable)
Enables the emission of the readyWrite signal.
void connected(const KNetwork::KResolverEntry &remote)
This socket is emitted when the socket successfully connects to a remote address. ...
void closed()
This signal is emitted when the socket completes the closing/shut down process.
~KClientSocketBase() override
Destructor.
virtual void slotWriteActivity()
This slot is connected to the write notifier&#39;s signal meaning the socket can write more data...
bool open(OpenMode mode) override
Reimplemented from QIODevice.
qint64 bytesAvailable() const override
Returns the number of bytes available for reading without blocking.
KSocketAddress localAddress() const override
Returns the local socket address.
This file is part of the KDE documentation.
Documentation copyright © 1996-2021 The KDE developers.
Generated on Thu May 13 2021 22:58:12 by doxygen 1.8.11 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.