KDELibs4Support

k3serversocket.cpp
1 /* -*- C++ -*-
2  * Copyright (C) 2003 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 "k3serversocket.h"
26 
27 #include <config-network.h>
28 
29 #include <QSocketNotifier>
30 #include <QMutex>
31 
32 #include "k3socketaddress.h"
33 #include "k3resolver.h"
34 #include "k3socketbase.h"
35 #include "k3socketdevice.h"
36 #include "k3bufferedsocket.h"
37 
38 using namespace KNetwork;
39 
40 class KNetwork::KServerSocketPrivate
41 {
42 public:
43  KResolver resolver;
44  KResolverResults resolverResults;
45 
46  enum { None, LookupDone, Bound, Listening } state;
47  int backlog;
48  int timeout;
49 
50  bool bindWhenFound : 1, listenWhenBound : 1, useKBufferedSocket : 1;
51 
52  KServerSocketPrivate()
53  : state(None), timeout(0), bindWhenFound(false), listenWhenBound(false),
54  useKBufferedSocket(true)
55  {
56  resolver.setFlags(KResolver::Passive);
57  resolver.setFamily(KResolver::KnownFamily);
58  }
59 };
60 
62  : QObject(parent), d(new KServerSocketPrivate)
63 {
64  QObject::connect(&d->resolver, SIGNAL(finished(KNetwork::KResolverResults)),
65  this, SLOT(lookupFinishedSlot()));
66 }
67 
69  : QObject(parent), d(new KServerSocketPrivate)
70 {
71  QObject::connect(&d->resolver, SIGNAL(finished(KNetwork::KResolverResults)),
72  this, SLOT(lookupFinishedSlot()));
73  d->resolver.setServiceName(service);
74 }
75 
76 KServerSocket::KServerSocket(const QString &node, const QString &service,
77  QObject *parent)
78  : QObject(parent), d(new KServerSocketPrivate)
79 {
80  QObject::connect(&d->resolver, SIGNAL(finished(KNetwork::KResolverResults)),
81  this, SLOT(lookupFinishedSlot()));
82  setAddress(node, service);
83 }
84 
86 {
87  close();
88  delete d;
89 }
90 
92 {
93  QMutexLocker locker(mutex());
94  KSocketBase::setSocketOptions(opts); // call parent
95  bool result = socketDevice()->setSocketOptions(opts); // and set the implementation
96  copyError();
97  return result;
98 }
99 
101 {
102  return d->resolver;
103 }
104 
106 {
107  return d->resolverResults;
108 }
109 
111 {
112  if (enable) {
113  d->resolver.setFlags(d->resolver.flags() & ~KResolver::NoResolve);
114  } else {
115  d->resolver.setFlags(d->resolver.flags() | KResolver::NoResolve);
116  }
117 }
118 
119 void KServerSocket::setFamily(int families)
120 {
121  d->resolver.setFamily(families);
122 }
123 
124 void KServerSocket::setAddress(const QString &service)
125 {
126  d->resolver.setNodeName(QString());
127  d->resolver.setServiceName(service);
128  d->resolverResults.clear();
129  if (d->state <= KServerSocketPrivate::LookupDone) {
130  d->state = KServerSocketPrivate::None;
131  }
132 }
133 
134 void KServerSocket::setAddress(const QString &node, const QString &service)
135 {
136  d->resolver.setNodeName(node);
137  d->resolver.setServiceName(service);
138  d->resolverResults.clear();
139  if (d->state <= KServerSocketPrivate::LookupDone) {
140  d->state = KServerSocketPrivate::None;
141  }
142 }
143 
145 {
146  d->timeout = msec;
147 }
148 
150 {
151  setError(NoError);
152  if (d->resolver.isRunning() && !blocking()) {
153  return true; // already doing lookup
154  }
155 
156  if (d->state >= KServerSocketPrivate::LookupDone) {
157  return true; // results are already available
158  }
159 
160  // make sure we have at least one parameter for lookup
161  if (d->resolver.serviceName().isNull() &&
162  !d->resolver.nodeName().isNull()) {
163  d->resolver.setServiceName(QLatin1String(""));
164  }
165 
166  // don't restart the lookups if they had succeeded and
167  // the input values weren't changed
168 
169  // reset results
170  d->resolverResults = KResolverResults();
171 
172  if (d->resolver.status() <= 0)
173  // if it's already running, there's no harm in calling again
174  {
175  d->resolver.start(); // signal may emit
176  }
177 
178  if (blocking()) {
179  // we're in blocking mode operation
180  // wait for the results
181 
182  d->resolver.wait(); // signal may be emitted again
183  // lookupFinishedSlot has been called
184  }
185 
186  return true;
187 }
188 
190 {
191  if (socketDevice()->bind(address)) {
192  setError(NoError);
193 
194  d->state = KServerSocketPrivate::Bound;
195  emit bound(address);
196  return true;
197  }
198  copyError();
199  return false;
200 }
201 
202 bool KServerSocket::bind(const QString &node, const QString &service)
203 {
204  setAddress(node, service);
205  return bind();
206 }
207 
208 bool KServerSocket::bind(const QString &service)
209 {
210  setAddress(service);
211  return bind();
212 }
213 
215 {
216  if (d->state >= KServerSocketPrivate::Bound) {
217  return true;
218  }
219 
220  if (d->state < KServerSocketPrivate::LookupDone) {
221  if (!blocking()) {
222  d->bindWhenFound = true;
223  bool ok = lookup(); // will call doBind
224  if (d->state >= KServerSocketPrivate::Bound) {
225  d->bindWhenFound = false;
226  }
227  return ok;
228  }
229 
230  // not blocking
231  if (!lookup()) {
232  return false;
233  }
234  }
235 
236  return doBind();
237 }
238 
239 bool KServerSocket::listen(int backlog)
240 {
241  // WARNING
242  // this function has to be reentrant
243  // due to the mechanisms used for binding, this function might
244  // end up calling itself
245 
246  if (d->state == KServerSocketPrivate::Listening) {
247  return true; // already listening
248  }
249 
250  d->backlog = backlog;
251 
252  if (d->state < KServerSocketPrivate::Bound) {
253  // we must bind
254  // note that we can end up calling ourselves here
255  d->listenWhenBound = true;
256  if (!bind()) {
257  d->listenWhenBound = false;
258  return false;
259  }
260 
261  if (d->state < KServerSocketPrivate::Bound)
262  // asynchronous lookup in progress...
263  // we can't be blocking here anyways
264  {
265  return true;
266  }
267 
268  d->listenWhenBound = false;
269  }
270 
271  if (d->state < KServerSocketPrivate::Listening) {
272  return doListen();
273  }
274 
275  return true;
276 }
277 
279 {
280  socketDevice()->close();
281  if (d->resolver.isRunning()) {
282  d->resolver.cancel(false);
283  }
284  d->state = KServerSocketPrivate::None;
285  emit closed();
286 }
287 
289 {
290  d->useKBufferedSocket = enable;
291 }
292 
294 {
295  if (d->state < KServerSocketPrivate::Listening) {
296  if (!blocking()) {
297  listen();
298  setError(WouldBlock);
299  return nullptr;
300  } else if (!listen())
301  // error happened during listen
302  {
303  return nullptr;
304  }
305  }
306 
307  // check to see if we're doing a timeout
308  if (blocking() && d->timeout > 0) {
309  bool timedout;
310  if (!socketDevice()->poll(d->timeout, &timedout)) {
311  copyError();
312  return nullptr;
313  }
314 
315  if (timedout) {
316  return nullptr;
317  }
318  }
319 
320  // we're listening here
321  KSocketDevice *accepted = socketDevice()->accept();
322  if (!accepted) {
323  // error happened during accept
324  copyError();
325  return nullptr;
326  }
327 
328  KStreamSocket *streamsocket;
329  if (d->useKBufferedSocket) {
330  streamsocket = new KBufferedSocket();
331  streamsocket->setOpenMode(KStreamSocket::ReadWrite);
332  } else {
333  streamsocket = new KStreamSocket();
334  streamsocket->setOpenMode(KStreamSocket::ReadWrite |
336  }
337  streamsocket->setSocketDevice(accepted);
338 
339  // FIXME!
340  // when KStreamSocket can find out the state of the socket passed through
341  // setSocketDevice, this will probably be unnecessary:
342  streamsocket->setState(KStreamSocket::Connected);
343 
344  return streamsocket;
345 }
346 
348 {
349  return socketDevice()->localAddress();
350 }
351 
353 {
354  return socketDevice()->externalAddress();
355 }
356 
357 void KServerSocket::lookupFinishedSlot()
358 {
359  if (d->resolver.isRunning() || d->state > KServerSocketPrivate::LookupDone) {
360  return;
361  }
362 
363  if (d->resolver.status() < 0) {
364  setError(LookupFailure);
365  emit gotError(LookupFailure);
366  d->bindWhenFound = d->listenWhenBound = false;
367  d->state = KServerSocketPrivate::None;
368  return;
369  }
370 
371  // lookup succeeded
372  d->resolverResults = d->resolver.results();
373  d->state = KServerSocketPrivate::LookupDone;
374  emit hostFound();
375 
376  if (d->bindWhenFound) {
377  doBind();
378  }
379 }
380 
382 {
384 }
385 
386 bool KServerSocket::doBind()
387 {
388  d->bindWhenFound = false;
389  // loop through the results and bind to the first that works
390 
391  KResolverResults::ConstIterator it = d->resolverResults.constBegin();
392  for (; it != d->resolverResults.constEnd(); ++it)
393  if (bind(*it)) {
394  if (d->listenWhenBound) {
395  return doListen();
396  }
397  return true;
398  } else {
399  socketDevice()->close(); // didn't work, try again
400  }
401 
402  // failed to bind
403  emit gotError(error());
404  return false;
405 }
406 
407 bool KServerSocket::doListen()
408 {
409  if (!socketDevice()->listen(d->backlog)) {
410  copyError();
411  emit gotError(error());
412  return false; // failed to listen
413  }
414 
415  // set up ready accept signal
416  QObject::connect(socketDevice()->readNotifier(), SIGNAL(activated(int)),
417  this, SIGNAL(readyAccept()));
418  d->state = KServerSocketPrivate::Listening;
419  return true;
420 }
421 
bool blocking() const
Retrieves this socket&#39;s blocking mode.
KStreamSocket * accept() override
Accepts one incoming connection and return the associated, open socket.
KSocketDevice * socketDevice() const
Retrieves the socket implementation used on this socket.
Simple stream socket.
const KResolverResults & resolverResults() const
Returns the internal list of resolved results for the binding address.
KSocketAddress externalAddress() const override
Returns this socket&#39;s externally visible local address.
One resolution entry.
Definition: k3resolver.h:72
void setFamily(int families)
Sets the allowed socket families.
Definition: k3resolver.cpp:381
Name and service resolution class.
Definition: k3resolver.h:312
void bound(const KNetwork::KResolverEntry &local)
This signal is emitted when the socket successfully binds to an address.
void close() override
Closes this socket.
SocketError error() const
Retrieves the socket error code.
A generic socket address.
void setAddress(const QString &service)
Sets the address on which we will listen.
Name and service resolution results.
Definition: k3resolver.h:212
~KServerSocket()
Destructor.
A namespace to store all networking-related (socket) classes.
void gotError(int code)
This signal is emitted when this object finds an error.
void close() override
Closes the socket.
KSocketAddress localAddress() const override
Returns this socket&#39;s local address.
void setSocketDevice(KSocketDevice *device) override
QMutex * mutex() const
Returns the internal mutex for this class.
void setError(SocketError error)
Sets the socket&#39;s error code.
bool setSocketOptions(int opts) override
This implementation sets the options on the socket.
Buffered stream sockets.
void setResolutionEnabled(bool enable)
Enables or disables name resolution.
void setTimeout(int msecs)
Sets the timeout for accepting.
void setState(SocketState state)
Sets the socket state to state.
virtual bool setSocketOptions(int opts)
Set the given socket options.
bool listen(int backlog=5) override
Puts this socket into listening mode.
void closed()
This signal is emitted when the socket completes the closing/shut down process.
void hostFound()
This signal is emitted when the lookup is successfully completed.
virtual bool bind()
Binds the socket to the addresses previously set with setAddress().
KSocketDevice * accept() override
Accepts a new incoming connection.
bool setSocketOptions(int opts) override
Sets the socket options.
KServerSocket(QObject *parent=nullptr)
Default constructor.
void readyAccept()
This signal is emitted whenever the socket is ready for accepting – i.e., there is at least one conn...
void copyError()
Convenience function to set this object&#39;s error code to match that of the socket device.
Low-level socket functionality.
void setAcceptBuffered(bool enable)
Toggles whether the accepted socket will be buffered or not.
KSocketAddress externalAddress() const override
Returns this socket&#39;s externally-visible address if know.
void setFamily(int families)
Sets the allowed families for the resolutions.
int setFlags(int flags)
Sets the flags.
Definition: k3resolver.cpp:370
QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type)
void setOpenMode(QIODevice::OpenMode openMode)
QObject * parent() const const
KResolver & resolver() const
Returns the internal KResolver object used for looking up the host name and service.
virtual bool lookup()
Starts the lookup for peer and local hostnames as well as their services.
KSocketAddress localAddress() const override
Returns this socket&#39;s local address.
This file is part of the KDE documentation.
Documentation copyright © 1996-2020 The KDE developers.
Generated on Tue Aug 4 2020 22:57:32 by doxygen 1.8.11 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.