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 "k3resolver.h"
35 #include "k3socketbase.h"
36 #include "k3socketdevice.h"
37 
38 using namespace KNetwork;
39 
40 class KNetwork::KClientSocketBasePrivate
41 {
42 public:
43  int state;
44 
45  KResolver localResolver, peerResolver;
46  KResolverResults localResults, peerResults;
47 
48  bool enableRead : 1, enableWrite : 1;
49 };
50 
52  : KActiveSocketBase(parent), d(new KClientSocketBasePrivate)
53 {
54  d->state = Idle;
55  d->enableRead = true;
56  d->enableWrite = false;
57 }
58 
60 {
61  close();
62  delete d;
63 }
64 
66 {
67  return static_cast<SocketState>(d->state);
68 }
69 
71 {
72  d->state = state;
73  stateChanging(state);
74 }
75 
77 {
78  QMutexLocker locker(mutex());
79  KSocketBase::setSocketOptions(opts); // call parent
80 
81  // don't create the device unnecessarily
82  if (hasDevice()) {
83  bool result = socketDevice()->setSocketOptions(opts); // and set the implementation
84  copyError();
85  return result;
86  }
87 
88  return true;
89 }
90 
92 {
93  return d->peerResolver;
94 }
95 
97 {
98  return d->peerResults;
99 }
100 
102 {
103  return d->localResolver;
104 }
105 
107 {
108  return d->localResults;
109 }
110 
112 {
113  if (enable) {
114  d->localResolver.setFlags(d->localResolver.flags() & ~KResolver::NoResolve);
115  d->peerResolver.setFlags(d->peerResolver.flags() & ~KResolver::NoResolve);
116  } else {
117  d->localResolver.setFlags(d->localResolver.flags() | KResolver::NoResolve);
118  d->peerResolver.setFlags(d->peerResolver.flags() | KResolver::NoResolve);
119  }
120 }
121 
123 {
124  d->localResolver.setFamily(families);
125  d->peerResolver.setFamily(families);
126 }
127 
129 {
130  if (state() == HostLookup && !blocking()) {
131  return true; // already doing lookup
132  }
133 
134  if (state() > HostLookup) {
135  return true; // results are already available
136  }
137 
138  if (state() < HostLookup) {
139  if (d->localResolver.serviceName().isNull() &&
140  !d->localResolver.nodeName().isNull()) {
141  d->localResolver.setServiceName(QLatin1String(""));
142  }
143 
144  // don't restart the lookups if they had succeeded and
145  // the input values weren't changed
146  QObject::connect(&d->peerResolver,
147  SIGNAL(finished(KNetwork::KResolverResults)),
148  this, SLOT(lookupFinishedSlot()));
149  QObject::connect(&d->localResolver,
150  SIGNAL(finished(KNetwork::KResolverResults)),
151  this, SLOT(lookupFinishedSlot()));
152 
153  if (d->localResolver.status() <= 0) {
154  d->localResolver.start();
155  }
156  if (d->peerResolver.status() <= 0) {
157  d->peerResolver.start();
158  }
159 
160  setState(HostLookup);
161  emit stateChanged(HostLookup);
162 
163  if (!d->localResolver.isRunning() && !d->peerResolver.isRunning()) {
164  // if nothing is running, then the lookup results are still valid
165  // pretend we had done lookup
166  if (blocking()) {
167  lookupFinishedSlot();
168  } else {
169  QTimer::singleShot(0, this, SLOT(lookupFinishedSlot()));
170  }
171  } else {
172  d->localResults = d->peerResults = KResolverResults();
173  }
174  }
175 
176  if (blocking()) {
177  // we're in blocking mode operation
178  // wait for the results
179 
180  localResolver().wait();
181  peerResolver().wait();
182 
183  // lookupFinishedSlot has been called
184  }
185 
186  return true;
187 }
188 
190 {
191  if (state() == HostLookup || state() > Connecting) {
192  return false;
193  }
194 
195  if (socketDevice()->bind(address)) {
196  resetError();
197 
198  // don't set the state or emit signals if we are in a higher state
199  if (state() < Bound) {
200  setState(Bound);
201  emit stateChanged(Bound);
202  emit bound(address);
203  }
204  return true;
205  }
206  return false;
207 }
208 
210 {
211  if (state() == Connected) {
212  return true; // to be compliant with the other classes
213  }
214  if (state() == HostLookup || state() > Connecting) {
215  return false;
216  }
217 
218  bool ok = socketDevice()->connect(address);
219  copyError();
220 
221  if (ok) {
222  SocketState newstate;
223  if (error() == InProgress) {
224  newstate = Connecting;
225  } else {
226  newstate = Connected;
227  }
228 
229  if (state() < newstate) {
230  setState(newstate);
231  emit stateChanged(newstate);
232  if (error() == NoError) {
234  emit connected(address);
235  }
236  }
237 
238  return true;
239  }
240  return false;
241 }
242 
244 {
245  if (state() != Connected) {
246  return false;
247  }
248 
249  bool ok = socketDevice()->disconnect();
250  copyError();
251 
252  if (ok) {
253  setState(Unconnected);
254  emit stateChanged(Unconnected);
255  return true;
256  }
257  return false;
258 }
259 
261 {
262  return connect(QString(), QString(), mode);
263 }
264 
266 {
267  if (state() == Idle) {
268  return; // nothing to do
269  }
270 
271  if (state() == HostLookup) {
272  d->peerResolver.cancel(false);
273  d->localResolver.cancel(false);
274  }
275 
276  d->localResults = d->peerResults = KResolverResults();
277 
278  socketDevice()->close();
280  setState(Idle);
281  emit stateChanged(Idle);
282  emit closed();
283 }
284 
286 {
287  return false;
288 }
289 
290 // This function is unlike all the others because it is const
292 {
293  return socketDevice()->bytesAvailable();
294 }
295 
296 // All the functions below look really alike
297 // Should I use a macro to define them?
298 
299 qint64 KClientSocketBase::waitForMore(int msecs, bool *timeout)
300 {
301  resetError();
302  qint64 retval = socketDevice()->waitForMore(msecs, timeout);
303  if (retval == -1) {
304  copyError();
305  emit gotError(error());
306  }
307  return retval;
308 }
309 
310 qint64 KClientSocketBase::readData(char *data, qint64 maxlen, KSocketAddress *from)
311 {
312  resetError();
313  qint64 retval = socketDevice()->readData(data, maxlen, from);
314  if (retval == -1) {
315  copyError();
316  emit gotError(error());
317  }
318  return retval;
319 }
320 
321 qint64 KClientSocketBase::peekData(char *data, qint64 maxlen, KSocketAddress *from)
322 {
323  resetError();
324  qint64 retval = socketDevice()->peekData(data, maxlen, from);
325  if (retval == -1) {
326  copyError();
327  emit gotError(error());
328  }
329  return retval;
330 }
331 
332 qint64 KClientSocketBase::writeData(const char *data, qint64 len, const KSocketAddress *to)
333 {
334  resetError();
335  qint64 retval = socketDevice()->writeData(data, len, to);
336  if (retval == -1) {
337  copyError();
338  emit gotError(error());
339  } else {
340  emit bytesWritten(retval);
341  }
342  return retval;
343 }
344 
346 {
347  return socketDevice()->localAddress();
348 }
349 
351 {
352  return socketDevice()->peerAddress();
353 }
354 
356 {
357  return d->enableRead;
358 }
359 
361 {
362  QMutexLocker locker(mutex());
363 
364  d->enableRead = enable;
366  if (n) {
367  n->setEnabled(enable);
368  }
369 }
370 
372 {
373  return d->enableWrite;
374 }
375 
377 {
378  QMutexLocker locker(mutex());
379 
380  d->enableWrite = enable;
382  if (n) {
383  n->setEnabled(enable);
384  }
385 }
386 
388 {
389  if (d->enableRead) {
390  emit readyRead();
391  }
392 }
393 
395 {
396  if (d->enableWrite) {
397  emit readyWrite();
398  }
399 }
400 
401 void KClientSocketBase::lookupFinishedSlot()
402 {
403  if (d->peerResolver.isRunning() || d->localResolver.isRunning() || state() != HostLookup) {
404  return;
405  }
406 
407  QObject::disconnect(&d->peerResolver, nullptr, this, SLOT(lookupFinishedSlot()));
408  QObject::disconnect(&d->localResolver, nullptr, this, SLOT(lookupFinishedSlot()));
409  if (d->peerResolver.status() < 0 || d->localResolver.status() < 0) {
410  setState(Idle); // backtrack
411  setError(LookupFailure);
412  emit stateChanged(Idle);
413  emit gotError(LookupFailure);
414  return;
415  }
416 
417  d->localResults = d->localResolver.results();
418  d->peerResults = d->peerResolver.results();
419  setState(HostFound);
420  emit stateChanged(HostFound);
421  emit hostFound();
422 }
423 
425 {
426  if (newState == Connected && socketDevice()) {
428  if (n) {
429  n->setEnabled(d->enableRead);
430  QObject::connect(n, SIGNAL(activated(int)), this, SLOT(slotReadActivity()));
431  } else {
432  return;
433  }
434 
435  n = socketDevice()->writeNotifier();
436  if (n) {
437  n->setEnabled(d->enableWrite);
438  QObject::connect(n, SIGNAL(activated(int)), this, SLOT(slotWriteActivity()));
439  } else {
440  return;
441  }
442  }
443 }
444 
446 {
448 }
449 
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.
virtual 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:437
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.
virtual ~KClientSocketBase()
Destructor.
virtual 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.
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-2020 The KDE developers.
Generated on Tue Aug 11 2020 23:00:55 by doxygen 1.8.11 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.