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 "k3socketdevice.h"
35 #include "k3bufferedsocket.h"
36 
37 using namespace KNetwork;
38 
39 class KNetwork::KServerSocketPrivate
40 {
41 public:
42  KResolver resolver;
43  KResolverResults resolverResults;
44 
45  enum { None, LookupDone, Bound, Listening } state;
46  int backlog;
47  int timeout;
48 
49  bool bindWhenFound : 1, listenWhenBound : 1, useKBufferedSocket : 1;
50 
51  KServerSocketPrivate()
52  : state(None), timeout(0), bindWhenFound(false), listenWhenBound(false),
53  useKBufferedSocket(true)
54  {
55  resolver.setFlags(KResolver::Passive);
56  resolver.setFamily(KResolver::KnownFamily);
57  }
58 };
59 
61  : QObject(parent), d(new KServerSocketPrivate)
62 {
63  QObject::connect(&d->resolver, SIGNAL(finished(KNetwork::KResolverResults)),
64  this, SLOT(lookupFinishedSlot()));
65 }
66 
68  : QObject(parent), d(new KServerSocketPrivate)
69 {
70  QObject::connect(&d->resolver, SIGNAL(finished(KNetwork::KResolverResults)),
71  this, SLOT(lookupFinishedSlot()));
72  d->resolver.setServiceName(service);
73 }
74 
75 KServerSocket::KServerSocket(const QString &node, const QString &service,
76  QObject *parent)
77  : QObject(parent), d(new KServerSocketPrivate)
78 {
79  QObject::connect(&d->resolver, SIGNAL(finished(KNetwork::KResolverResults)),
80  this, SLOT(lookupFinishedSlot()));
81  setAddress(node, service);
82 }
83 
85 {
86  close();
87  delete d;
88 }
89 
91 {
92  QMutexLocker locker(mutex());
93  KSocketBase::setSocketOptions(opts); // call parent
94  bool result = socketDevice()->setSocketOptions(opts); // and set the implementation
95  copyError();
96  return result;
97 }
98 
100 {
101  return d->resolver;
102 }
103 
105 {
106  return d->resolverResults;
107 }
108 
110 {
111  if (enable) {
112  d->resolver.setFlags(d->resolver.flags() & ~KResolver::NoResolve);
113  } else {
114  d->resolver.setFlags(d->resolver.flags() | KResolver::NoResolve);
115  }
116 }
117 
118 void KServerSocket::setFamily(int families)
119 {
120  d->resolver.setFamily(families);
121 }
122 
123 void KServerSocket::setAddress(const QString &service)
124 {
125  d->resolver.setNodeName(QString());
126  d->resolver.setServiceName(service);
127  d->resolverResults.clear();
128  if (d->state <= KServerSocketPrivate::LookupDone) {
129  d->state = KServerSocketPrivate::None;
130  }
131 }
132 
133 void KServerSocket::setAddress(const QString &node, const QString &service)
134 {
135  d->resolver.setNodeName(node);
136  d->resolver.setServiceName(service);
137  d->resolverResults.clear();
138  if (d->state <= KServerSocketPrivate::LookupDone) {
139  d->state = KServerSocketPrivate::None;
140  }
141 }
142 
144 {
145  d->timeout = msec;
146 }
147 
149 {
150  setError(NoError);
151  if (d->resolver.isRunning() && !blocking()) {
152  return true; // already doing lookup
153  }
154 
155  if (d->state >= KServerSocketPrivate::LookupDone) {
156  return true; // results are already available
157  }
158 
159  // make sure we have at least one parameter for lookup
160  if (d->resolver.serviceName().isNull() &&
161  !d->resolver.nodeName().isNull()) {
162  d->resolver.setServiceName(QLatin1String(""));
163  }
164 
165  // don't restart the lookups if they had succeeded and
166  // the input values weren't changed
167 
168  // reset results
169  d->resolverResults = KResolverResults();
170 
171  if (d->resolver.status() <= 0)
172  // if it's already running, there's no harm in calling again
173  {
174  d->resolver.start(); // signal may emit
175  }
176 
177  if (blocking()) {
178  // we're in blocking mode operation
179  // wait for the results
180 
181  d->resolver.wait(); // signal may be emitted again
182  // lookupFinishedSlot has been called
183  }
184 
185  return true;
186 }
187 
189 {
190  if (socketDevice()->bind(address)) {
191  setError(NoError);
192 
193  d->state = KServerSocketPrivate::Bound;
194  emit bound(address);
195  return true;
196  }
197  copyError();
198  return false;
199 }
200 
201 bool KServerSocket::bind(const QString &node, const QString &service)
202 {
203  setAddress(node, service);
204  return bind();
205 }
206 
207 bool KServerSocket::bind(const QString &service)
208 {
209  setAddress(service);
210  return bind();
211 }
212 
214 {
215  if (d->state >= KServerSocketPrivate::Bound) {
216  return true;
217  }
218 
219  if (d->state < KServerSocketPrivate::LookupDone) {
220  if (!blocking()) {
221  d->bindWhenFound = true;
222  bool ok = lookup(); // will call doBind
223  if (d->state >= KServerSocketPrivate::Bound) {
224  d->bindWhenFound = false;
225  }
226  return ok;
227  }
228 
229  // not blocking
230  if (!lookup()) {
231  return false;
232  }
233  }
234 
235  return doBind();
236 }
237 
238 bool KServerSocket::listen(int backlog)
239 {
240  // WARNING
241  // this function has to be reentrant
242  // due to the mechanisms used for binding, this function might
243  // end up calling itself
244 
245  if (d->state == KServerSocketPrivate::Listening) {
246  return true; // already listening
247  }
248 
249  d->backlog = backlog;
250 
251  if (d->state < KServerSocketPrivate::Bound) {
252  // we must bind
253  // note that we can end up calling ourselves here
254  d->listenWhenBound = true;
255  if (!bind()) {
256  d->listenWhenBound = false;
257  return false;
258  }
259 
260  if (d->state < KServerSocketPrivate::Bound)
261  // asynchronous lookup in progress...
262  // we can't be blocking here anyways
263  {
264  return true;
265  }
266 
267  d->listenWhenBound = false;
268  }
269 
270  if (d->state < KServerSocketPrivate::Listening) {
271  return doListen();
272  }
273 
274  return true;
275 }
276 
278 {
279  socketDevice()->close();
280  if (d->resolver.isRunning()) {
281  d->resolver.cancel(false);
282  }
283  d->state = KServerSocketPrivate::None;
284  emit closed();
285 }
286 
288 {
289  d->useKBufferedSocket = enable;
290 }
291 
293 {
294  if (d->state < KServerSocketPrivate::Listening) {
295  if (!blocking()) {
296  listen();
297  setError(WouldBlock);
298  return nullptr;
299  } else if (!listen())
300  // error happened during listen
301  {
302  return nullptr;
303  }
304  }
305 
306  // check to see if we're doing a timeout
307  if (blocking() && d->timeout > 0) {
308  bool timedout;
309  if (!socketDevice()->poll(d->timeout, &timedout)) {
310  copyError();
311  return nullptr;
312  }
313 
314  if (timedout) {
315  return nullptr;
316  }
317  }
318 
319  // we're listening here
320  KSocketDevice *accepted = socketDevice()->accept();
321  if (!accepted) {
322  // error happened during accept
323  copyError();
324  return nullptr;
325  }
326 
327  KStreamSocket *streamsocket;
328  if (d->useKBufferedSocket) {
329  streamsocket = new KBufferedSocket();
330  streamsocket->setOpenMode(KStreamSocket::ReadWrite);
331  } else {
332  streamsocket = new KStreamSocket();
333  streamsocket->setOpenMode(KStreamSocket::ReadWrite |
335  }
336  streamsocket->setSocketDevice(accepted);
337 
338  // FIXME!
339  // when KStreamSocket can find out the state of the socket passed through
340  // setSocketDevice, this will probably be unnecessary:
341  streamsocket->setState(KStreamSocket::Connected);
342 
343  return streamsocket;
344 }
345 
347 {
348  return socketDevice()->localAddress();
349 }
350 
352 {
353  return socketDevice()->externalAddress();
354 }
355 
356 void KServerSocket::lookupFinishedSlot()
357 {
358  if (d->resolver.isRunning() || d->state > KServerSocketPrivate::LookupDone) {
359  return;
360  }
361 
362  if (d->resolver.status() < 0) {
363  setError(LookupFailure);
364  emit gotError(LookupFailure);
365  d->bindWhenFound = d->listenWhenBound = false;
366  d->state = KServerSocketPrivate::None;
367  return;
368  }
369 
370  // lookup succeeded
371  d->resolverResults = d->resolver.results();
372  d->state = KServerSocketPrivate::LookupDone;
373  emit hostFound();
374 
375  if (d->bindWhenFound) {
376  doBind();
377  }
378 }
379 
381 {
383 }
384 
385 bool KServerSocket::doBind()
386 {
387  d->bindWhenFound = false;
388  // loop through the results and bind to the first that works
389 
390  KResolverResults::ConstIterator it = d->resolverResults.constBegin();
391  for (; it != d->resolverResults.constEnd(); ++it)
392  if (bind(*it)) {
393  if (d->listenWhenBound) {
394  return doListen();
395  }
396  return true;
397  } else {
398  socketDevice()->close(); // didn't work, try again
399  }
400 
401  // failed to bind
402  emit gotError(error());
403  return false;
404 }
405 
406 bool KServerSocket::doListen()
407 {
408  if (!socketDevice()->listen(d->backlog)) {
409  copyError();
410  emit gotError(error());
411  return false; // failed to listen
412  }
413 
414  // set up ready accept signal
415  QObject::connect(socketDevice()->readNotifier(), SIGNAL(activated(int)),
416  this, SIGNAL(readyAccept()));
417  d->state = KServerSocketPrivate::Listening;
418  return true;
419 }
420 
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:380
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:369
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-2021 The KDE developers.
Generated on Sat Jan 23 2021 03:47:34 by doxygen 1.8.11 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.