1// Copyright (C) 2016 The Qt Company Ltd.
2// Copyright (C) 2016 Intel Corporation.
3// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
4// Qt-Security score:significant reason:default
5
6//#define QNATIVESOCKETENGINE_DEBUG
7
8/*! \class QNativeSocketEngine
9 \internal
10
11 \brief The QNativeSocketEngine class provides low level access to a socket.
12
13 \reentrant
14 \ingroup network
15 \inmodule QtNetwork
16
17 QtSocketLayer provides basic socket functionality provided by the
18 operating system. It also keeps track of what state the socket is
19 in, and which errors that occur.
20
21 The classes QTcpSocket, QUdpSocket and QTcpServer provide a
22 higher level API, and are in general more useful for the common
23 application.
24
25 There are two main ways of initializing the a QNativeSocketEngine; either
26 create a new socket by passing the socket type (TcpSocket or
27 UdpSocket) and network layer protocol (IPv4Protocol or
28 IPv6Protocol) to initialize(), or pass an existing socket
29 descriptor and have QNativeSocketEngine determine the type and protocol
30 itself. The native socket descriptor can later be fetched by
31 calling socketDescriptor(). The socket is made non-blocking, but
32 blocking behavior can still be achieved by calling waitForRead()
33 and waitForWrite(). isValid() can be called to check if the socket
34 has been successfully initialized and is ready to use.
35
36 To connect to a host, determine its address and pass this and the
37 port number to connectToHost(). The socket can then be used as a
38 TCP or UDP client. Otherwise; bind(), listen() and accept() are
39 used to have the socket function as a TCP or UDP server. Call
40 close() to close the socket.
41
42 bytesAvailable() is called to determine how much data is available
43 for reading. read() and write() are used by both TCP and UDP
44 clients to exchange data with the connected peer. UDP clients can
45 also call hasMoreDatagrams(), nextDatagramSize(),
46 readDatagram(), and writeDatagram().
47
48 Call state() to determine the state of the socket, for
49 example, ListeningState or ConnectedState. socketType() tells
50 whether the socket is a TCP socket or a UDP socket, or if the
51 socket type is unknown. protocol() is used to determine the
52 socket's network layer protocol.
53
54 localAddress(), localPort() are called to find the address and
55 port that are currently bound to the socket. If the socket is
56 connected, peerAddress() and peerPort() determine the address and
57 port of the connected peer.
58
59 Finally, if any function should fail, error() and
60 errorString() can be called to determine the cause of the error.
61*/
62
63/*!
64 \enum QAbstractSocketEngine::PacketHeaderOption
65
66 Specifies which fields in the IP packet header are desired in the call to
67 readDatagram().
68
69 \value WantNone caller isn't interested in the packet metadata
70 \value WantDatagramSender caller wants the sender address and port number
71 \value WantDatagramDestination caller wants the packet's destination address and port number
72 (this option is useful to distinguish multicast packets from unicast)
73 \value WantDatagramHopLimit caller wants the packet's remaining hop limit or time to live
74 (this option is useful in IPv4 multicasting, where the TTL is used
75 to indicate the realm)
76 \value WantAll this is a catch-all value to indicate the caller is
77 interested in all the available information
78
79 \sa readDatagram(), QNetworkDatagram
80*/
81
82#include "qnativesocketengine_p_p.h"
83
84#include <qabstracteventdispatcher.h>
85#include <qsocketnotifier.h>
86#include <qnetworkinterface.h>
87
88#include <private/qthread_p.h>
89#include <private/qobject_p.h>
90
91#if !defined(QT_NO_NETWORKPROXY)
92# include "qnetworkproxy.h"
93# include "qabstractsocket.h"
94# include "qtcpserver.h"
95#endif
96
97#if !defined(QT_NO_SCTP)
98# include "qsctpserver.h"
99#endif
100
101QT_BEGIN_NAMESPACE
102
103using namespace Qt::StringLiterals;
104
105//#define QNATIVESOCKETENGINE_DEBUG
106
107#define Q_VOID
108
109// Common constructs
110#define Q_CHECK_VALID_SOCKETLAYER(function, returnValue) do { \
111 if (!isValid()) { \
112 qWarning(""#function" was called on an uninitialized socket device"); \
113 return returnValue; \
114 } } while (0)
115#define Q_CHECK_INVALID_SOCKETLAYER(function, returnValue) do { \
116 if (isValid()) { \
117 qWarning(""#function" was called on an already initialized socket device"); \
118 return returnValue; \
119 } } while (0)
120#define Q_CHECK_STATE(function, checkState, returnValue) do { \
121 if (d->socketState != (checkState)) { \
122 qWarning(""#function" was not called in "#checkState); \
123 return (returnValue); \
124 } } while (0)
125#define Q_CHECK_NOT_STATE(function, checkState, returnValue) do { \
126 if (d->socketState == (checkState)) { \
127 qWarning(""#function" was called in "#checkState); \
128 return (returnValue); \
129 } } while (0)
130#define Q_CHECK_STATES(function, state1, state2, returnValue) do { \
131 if (d->socketState != (state1) && d->socketState != (state2)) { \
132 qWarning(""#function" was called" \
133 " not in "#state1" or "#state2); \
134 return (returnValue); \
135 } } while (0)
136#define Q_CHECK_STATES3(function, state1, state2, state3, returnValue) do { \
137 if (d->socketState != (state1) && d->socketState != (state2) && d->socketState != (state3)) { \
138 qWarning(""#function" was called" \
139 " not in "#state1" or "#state2); \
140 return (returnValue); \
141 } } while (0)
142#define Q_CHECK_TYPE(function, type, returnValue) do { \
143 if (d->socketType != (type)) { \
144 qWarning(#function" was called by a" \
145 " socket other than "#type""); \
146 return (returnValue); \
147 } } while (0)
148#define Q_CHECK_TYPES(function, type1, type2, returnValue) do { \
149 if (d->socketType != (type1) && d->socketType != (type2)) { \
150 qWarning(#function" was called by a" \
151 " socket other than "#type1" or "#type2); \
152 return (returnValue); \
153 } } while (0)
154#define Q_TR(a) QT_TRANSLATE_NOOP(QNativeSocketEngine, a)
155
156/*! \internal
157 Constructs the private class and initializes all data members.
158*/
159QNativeSocketEnginePrivate::QNativeSocketEnginePrivate() :
160 socketDescriptor(-1),
161 readNotifier(nullptr),
162 writeNotifier(nullptr),
163 exceptNotifier(nullptr)
164{
165#if defined(Q_OS_WIN)
166 QSysInfo::machineHostName(); // this initializes ws2_32.dll
167#endif
168}
169
170/*! \internal
171 Destructs the private class.
172*/
173QNativeSocketEnginePrivate::~QNativeSocketEnginePrivate()
174{
175}
176
177/*! \internal
178
179 Sets the error and error string if not set already. The only
180 interesting error is the first one that occurred, and not the last
181 one.
182*/
183void QNativeSocketEnginePrivate::setError(QAbstractSocket::SocketError error, ErrorString errorString) const
184{
185 if (hasSetSocketError) {
186 // Only set socket errors once for one engine; expect the
187 // socket to recreate its engine after an error. Note: There's
188 // one exception: SocketError(11) bypasses this as it's purely
189 // a temporary internal error condition.
190 // Another exception is the way the waitFor*() functions set
191 // an error when a timeout occurs. After the call to setError()
192 // they reset the hasSetSocketError to false
193 return;
194 }
195 if (error != QAbstractSocket::SocketError(11))
196 hasSetSocketError = true;
197
198 socketError = error;
199
200 switch (errorString) {
201 case NonBlockingInitFailedErrorString:
202 socketErrorString = QNativeSocketEngine::tr(s: "Unable to initialize non-blocking socket");
203 break;
204 case BroadcastingInitFailedErrorString:
205 socketErrorString = QNativeSocketEngine::tr(s: "Unable to initialize broadcast socket");
206 break;
207 // should not happen anymore
208 case NoIpV6ErrorString:
209 socketErrorString = QNativeSocketEngine::tr(s: "Attempt to use IPv6 socket on a platform with no IPv6 support");
210 break;
211 case RemoteHostClosedErrorString:
212 socketErrorString = QNativeSocketEngine::tr(s: "The remote host closed the connection");
213 break;
214 case TimeOutErrorString:
215 socketErrorString = QNativeSocketEngine::tr(s: "Network operation timed out");
216 break;
217 case ResourceErrorString:
218 socketErrorString = QNativeSocketEngine::tr(s: "Out of resources");
219 break;
220 case OperationUnsupportedErrorString:
221 socketErrorString = QNativeSocketEngine::tr(s: "Unsupported socket operation");
222 break;
223 case ProtocolUnsupportedErrorString:
224 socketErrorString = QNativeSocketEngine::tr(s: "Protocol type not supported");
225 break;
226 case InvalidSocketErrorString:
227 socketErrorString = QNativeSocketEngine::tr(s: "Invalid socket descriptor");
228 break;
229 case HostUnreachableErrorString:
230 socketErrorString = QNativeSocketEngine::tr(s: "Host unreachable");
231 break;
232 case NetworkUnreachableErrorString:
233 socketErrorString = QNativeSocketEngine::tr(s: "Network unreachable");
234 break;
235 case AccessErrorString:
236 socketErrorString = QNativeSocketEngine::tr(s: "Permission denied");
237 break;
238 case ConnectionTimeOutErrorString:
239 socketErrorString = QNativeSocketEngine::tr(s: "Connection timed out");
240 break;
241 case ConnectionRefusedErrorString:
242 socketErrorString = QNativeSocketEngine::tr(s: "Connection refused");
243 break;
244 case AddressInuseErrorString:
245 socketErrorString = QNativeSocketEngine::tr(s: "The bound address is already in use");
246 break;
247 case AddressNotAvailableErrorString:
248 socketErrorString = QNativeSocketEngine::tr(s: "The address is not available");
249 break;
250 case AddressProtectedErrorString:
251 socketErrorString = QNativeSocketEngine::tr(s: "The address is protected");
252 break;
253 case DatagramTooLargeErrorString:
254 socketErrorString = QNativeSocketEngine::tr(s: "Datagram was too large to send");
255 break;
256 case SendDatagramErrorString:
257 socketErrorString = QNativeSocketEngine::tr(s: "Unable to send a message");
258 break;
259 case ReceiveDatagramErrorString:
260 socketErrorString = QNativeSocketEngine::tr(s: "Unable to receive a message");
261 break;
262 case WriteErrorString:
263 socketErrorString = QNativeSocketEngine::tr(s: "Unable to write");
264 break;
265 case ReadErrorString:
266 socketErrorString = QNativeSocketEngine::tr(s: "Network error");
267 break;
268 case PortInuseErrorString:
269 socketErrorString = QNativeSocketEngine::tr(s: "Another socket is already listening on the same port");
270 break;
271 case NotSocketErrorString:
272 socketErrorString = QNativeSocketEngine::tr(s: "Operation on non-socket");
273 break;
274 case InvalidProxyTypeString:
275 socketErrorString = QNativeSocketEngine::tr(s: "The proxy type is invalid for this operation");
276 break;
277 case TemporaryErrorString:
278 socketErrorString = QNativeSocketEngine::tr(s: "Temporary error");
279 break;
280 case NetworkDroppedConnectionErrorString:
281 socketErrorString = QNativeSocketEngine::tr(s: "Network dropped connection on reset");
282 break;
283 case ConnectionResetErrorString:
284 socketErrorString = QNativeSocketEngine::tr(s: "Connection reset by peer");
285 break;
286 case UnknownSocketErrorString:
287 socketErrorString = QNativeSocketEngine::tr(s: "Unknown error");
288 break;
289 }
290}
291
292/*!
293 \internal
294
295 Adjusts the incoming \a address family to match the currently bound address
296 (if any). This function will convert v4-mapped IPv6 addresses to IPv4 and
297 vice-versa. All other address types and values will be left unchanged.
298 */
299QHostAddress QNativeSocketEnginePrivate::adjustAddressProtocol(const QHostAddress &address) const
300{
301 QAbstractSocket::NetworkLayerProtocol targetProtocol = socketProtocol;
302 if (Q_LIKELY(targetProtocol == QAbstractSocket::UnknownNetworkLayerProtocol))
303 return address;
304
305 QAbstractSocket::NetworkLayerProtocol sourceProtocol = address.protocol();
306
307 if (targetProtocol == QAbstractSocket::AnyIPProtocol)
308 targetProtocol = QAbstractSocket::IPv6Protocol;
309 if (targetProtocol == QAbstractSocket::IPv6Protocol && sourceProtocol == QAbstractSocket::IPv4Protocol) {
310 // convert to IPv6 v4-mapped address. This always works
311 return QHostAddress(address.toIPv6Address());
312 }
313
314 if (targetProtocol == QAbstractSocket::IPv4Protocol && sourceProtocol == QAbstractSocket::IPv6Protocol) {
315 // convert to IPv4 if the source is a v4-mapped address
316 quint32 ip4 = address.toIPv4Address();
317 if (ip4)
318 return QHostAddress(ip4);
319 }
320
321 return address;
322}
323
324bool QNativeSocketEnginePrivate::checkProxy(const QHostAddress &address)
325{
326 if (address.isLoopback())
327 return true;
328
329#if !defined(QT_NO_NETWORKPROXY)
330 QObject *parent = q_func()->parent();
331 QNetworkProxy proxy;
332 QNetworkProxyQuery::QueryType queryType = QNetworkProxyQuery::TcpSocket;
333 if (QAbstractSocket *socket = qobject_cast<QAbstractSocket *>(object: parent)) {
334 proxy = socket->proxy();
335 switch (socket->socketType()) {
336 case QAbstractSocket::UdpSocket:
337 queryType = QNetworkProxyQuery::UdpSocket;
338 break;
339 case QAbstractSocket::SctpSocket:
340 queryType = QNetworkProxyQuery::SctpSocket;
341 break;
342 case QAbstractSocket::TcpSocket:
343 case QAbstractSocket::UnknownSocketType:
344 queryType = QNetworkProxyQuery::TcpSocket;
345 }
346 } else if (QTcpServer *server = qobject_cast<QTcpServer *>(object: parent)) {
347 proxy = server->proxy();
348 queryType = QNetworkProxyQuery::TcpServer;
349#ifndef QT_NO_SCTP
350 if (qobject_cast<QSctpServer *>(server))
351 queryType = QNetworkProxyQuery::SctpServer;
352#endif
353 } else {
354 // no parent -> no proxy
355 return true;
356 }
357
358 if (proxy.type() == QNetworkProxy::DefaultProxy) {
359 // This is similar to what we have in QNetworkProxy::applicationProxy,
360 // the only difference is that we provide the correct query type instead of
361 // always using TcpSocket unconditionally (this is the default type for
362 // QNetworkProxyQuery).
363 QNetworkProxyQuery query;
364 query.setQueryType(queryType);
365 proxy = QNetworkProxyFactory::proxyForQuery(query).constFirst();
366 }
367
368 if (proxy.type() != QNetworkProxy::DefaultProxy &&
369 proxy.type() != QNetworkProxy::NoProxy) {
370 // QNativeSocketEngine doesn't do proxies
371 setError(error: QAbstractSocket::UnsupportedSocketOperationError,
372 errorString: QNativeSocketEnginePrivate::InvalidProxyTypeString);
373 return false;
374 }
375#endif
376
377 return true;
378}
379
380/*!
381 Constructs a QNativeSocketEngine.
382
383 \sa initialize()
384*/
385QNativeSocketEngine::QNativeSocketEngine(QObject *parent)
386 : QAbstractSocketEngine(*new QNativeSocketEnginePrivate(), parent)
387{
388}
389
390/*!
391 Destructs a QNativeSocketEngine.
392*/
393QNativeSocketEngine::~QNativeSocketEngine()
394{
395 close();
396}
397
398/*!
399 Initializes a QNativeSocketEngine by creating a new socket of type \a
400 socketType and network layer protocol \a protocol. Returns \c true on
401 success; otherwise returns \c false.
402
403 If the socket was already initialized, this function closes the
404 socket before reeinitializing it.
405
406 The new socket is non-blocking, and for UDP sockets it's also
407 broadcast enabled.
408*/
409bool QNativeSocketEngine::initialize(QAbstractSocket::SocketType socketType, QAbstractSocket::NetworkLayerProtocol protocol)
410{
411 Q_D(QNativeSocketEngine);
412 if (isValid())
413 close();
414
415 // Create the socket
416 if (!d->createNewSocket(type: socketType, protocol)) {
417#if defined (QNATIVESOCKETENGINE_DEBUG)
418 QString typeStr = "UnknownSocketType"_L1;
419 if (socketType == QAbstractSocket::TcpSocket) typeStr = "TcpSocket"_L1;
420 else if (socketType == QAbstractSocket::UdpSocket) typeStr = "UdpSocket"_L1;
421 else if (socketType == QAbstractSocket::SctpSocket) typeStr = "SctpSocket"_L1;
422 QString protocolStr = "UnknownProtocol"_L1;
423 if (protocol == QAbstractSocket::IPv4Protocol) protocolStr = "IPv4Protocol"_L1;
424 else if (protocol == QAbstractSocket::IPv6Protocol) protocolStr = "IPv6Protocol"_L1;
425 qDebug("QNativeSocketEngine::initialize(type == %s, protocol == %s) failed: %s",
426 typeStr.toLatin1().constData(), protocolStr.toLatin1().constData(), d->socketErrorString.toLatin1().constData());
427#endif
428 return false;
429 }
430
431 if (socketType == QAbstractSocket::UdpSocket) {
432 // Set the broadcasting flag if it's a UDP socket.
433 // IPv6 does not support broadcast — only set option for IPv4
434 if (protocol != QAbstractSocket::IPv6Protocol) {
435 if (!setOption(option: BroadcastSocketOption, value: 1)) {
436 d->setError(error: QAbstractSocket::UnsupportedSocketOperationError,
437 errorString: QNativeSocketEnginePrivate::BroadcastingInitFailedErrorString);
438 close();
439 return false;
440 }
441 }
442
443 // Set some extra flags that are interesting to us, but accept failure
444 setOption(option: ReceivePacketInformation, value: 1);
445 setOption(option: ReceiveHopLimit, value: 1);
446 }
447
448
449#ifndef Q_OS_WASM
450 // Make sure we receive out-of-band data
451 if (socketType == QAbstractSocket::TcpSocket
452 && !setOption(option: ReceiveOutOfBandData, value: 1)) {
453 qWarning(msg: "QNativeSocketEngine::initialize unable to inline out-of-band data");
454 }
455#endif
456
457 // Before Qt 4.6, we always set the send and receive buffer size to 49152 as
458 // this was found to be an optimal value. However, modern OS
459 // all have some kind of auto tuning for this and we therefore don't set
460 // this explicitly anymore.
461 // If it introduces any performance regressions for Qt 4.6.x (x > 0) then
462 // it will be put back in.
463 //
464 // You can use tests/manual/qhttpnetworkconnection to test HTTP download speed
465 // with this.
466 //
467 // pre-4.6:
468 // setReceiveBufferSize(49152);
469 // setSendBufferSize(49152);
470
471 return true;
472}
473
474/*! \overload
475
476 Initializes the socket using \a socketDescriptor instead of
477 creating a new one. The socket type and network layer protocol are
478 determined automatically. The socket's state is set to \a
479 socketState.
480
481 If the socket type is either TCP or UDP, it is made non-blocking.
482 UDP sockets are also broadcast enabled.
483 */
484bool QNativeSocketEngine::initialize(qintptr socketDescriptor, QAbstractSocket::SocketState socketState)
485{
486 Q_D(QNativeSocketEngine);
487
488 if (isValid())
489 close();
490
491 d->socketDescriptor = socketDescriptor;
492
493 // determine socket type and protocol
494 if (!d->fetchConnectionParameters()) {
495#if defined (QNATIVESOCKETENGINE_DEBUG)
496 qDebug() << "QNativeSocketEngine::initialize(socketDescriptor) failed:"
497 << socketDescriptor << d->socketErrorString;
498#endif
499 d->socketDescriptor = -1;
500 return false;
501 }
502
503 if (d->socketType != QAbstractSocket::UnknownSocketType) {
504 // Make the socket nonblocking.
505 if (!setOption(option: NonBlockingSocketOption, value: 1)) {
506 d->setError(error: QAbstractSocket::UnsupportedSocketOperationError,
507 errorString: QNativeSocketEnginePrivate::NonBlockingInitFailedErrorString);
508 close();
509 return false;
510 }
511
512 // Set the broadcasting flag if it's a UDP socket.
513 if (d->socketType == QAbstractSocket::UdpSocket
514 && !setOption(option: BroadcastSocketOption, value: 1)) {
515 d->setError(error: QAbstractSocket::UnsupportedSocketOperationError,
516 errorString: QNativeSocketEnginePrivate::BroadcastingInitFailedErrorString);
517 close();
518 return false;
519 }
520 }
521
522 d->socketState = socketState;
523 return true;
524}
525
526/*!
527 Returns \c true if the socket is valid; otherwise returns \c false. A
528 socket is valid if it has not been successfully initialized, or if
529 it has been closed.
530*/
531bool QNativeSocketEngine::isValid() const
532{
533 Q_D(const QNativeSocketEngine);
534 return d->socketDescriptor != -1;
535}
536
537/*!
538 Returns the native socket descriptor. Any use of this descriptor
539 stands the risk of being non-portable.
540*/
541qintptr QNativeSocketEngine::socketDescriptor() const
542{
543 Q_D(const QNativeSocketEngine);
544 return d->socketDescriptor;
545}
546
547/*!
548 Connects to the IP address and port specified by \a address and \a
549 port. If the connection is established, this function returns \c true
550 and the socket enters ConnectedState. Otherwise, false is
551 returned.
552
553 If false is returned, state() should be called to see if the
554 socket is in ConnectingState. If so, a delayed TCP connection is
555 taking place, and connectToHost() must be called again later to
556 determine if the connection was established successfully or
557 not. The second connection attempt must be made when the socket is
558 ready for writing. This state can be determined either by
559 connecting a QSocketNotifier to the socket descriptor returned by
560 socketDescriptor(), or by calling the blocking function
561 waitForWrite().
562
563 Example:
564 \snippet code/src_network_socket_qnativesocketengine.cpp 0
565
566 Otherwise, error() should be called to determine the cause of the
567 error.
568*/
569bool QNativeSocketEngine::connectToHost(const QHostAddress &address, quint16 port)
570{
571 Q_D(QNativeSocketEngine);
572 Q_CHECK_VALID_SOCKETLAYER(QNativeSocketEngine::connectToHost(), false);
573
574 if (!d->checkProxy(address))
575 return false;
576
577 Q_CHECK_STATES3(QNativeSocketEngine::connectToHost(), QAbstractSocket::BoundState,
578 QAbstractSocket::UnconnectedState, QAbstractSocket::ConnectingState, false);
579
580 d->peerAddress = address;
581 d->peerPort = port;
582 bool connected = d->nativeConnect(address: d->adjustAddressProtocol(address), port);
583 if (connected)
584 d->fetchConnectionParameters();
585
586 return connected;
587}
588
589/*!
590 If there's a connection activity on the socket, process it. Then
591 notify our parent if there really was activity.
592*/
593void QNativeSocketEngine::connectionNotification()
594{
595 Q_D(QNativeSocketEngine);
596 Q_ASSERT(state() == QAbstractSocket::ConnectingState);
597
598 connectToHost(address: d->peerAddress, port: d->peerPort);
599 if (state() != QAbstractSocket::ConnectingState) {
600 // we changed states
601 QAbstractSocketEngine::connectionNotification();
602 }
603}
604
605/*!
606 Connects to the remote host name given by \a name on port \a
607 port. When this function is called, the upper-level will not
608 perform a hostname lookup.
609
610 The native socket engine does not support this operation,
611 but some other socket engines (notably proxy-based ones) do.
612*/
613bool QNativeSocketEngine::connectToHostByName(const QString &name, quint16 port)
614{
615 Q_UNUSED(name);
616 Q_UNUSED(port);
617 Q_D(QNativeSocketEngine);
618 d->setError(error: QAbstractSocket::UnsupportedSocketOperationError,
619 errorString: QNativeSocketEnginePrivate::OperationUnsupportedErrorString);
620 return false;
621}
622
623/*!
624 Binds the socket to the address \a address and port \a
625 port. Returns \c true on success; otherwise false is returned. The
626 port may be 0, in which case an arbitrary unused port is assigned
627 automatically by the operating system.
628
629 Servers call this function to set up the server's address and
630 port. TCP servers must in addition call listen() after bind().
631*/
632bool QNativeSocketEngine::bind(const QHostAddress &address, quint16 port)
633{
634 Q_D(QNativeSocketEngine);
635 Q_CHECK_VALID_SOCKETLAYER(QNativeSocketEngine::bind(), false);
636
637 if (!d->checkProxy(address))
638 return false;
639
640 Q_CHECK_STATE(QNativeSocketEngine::bind(), QAbstractSocket::UnconnectedState, false);
641
642 if (!d->nativeBind(address: d->adjustAddressProtocol(address), port))
643 return false;
644
645 d->fetchConnectionParameters();
646 return true;
647}
648
649/*!
650 Prepares a TCP server for accepting incoming connections. This
651 function must be called after bind(), and only by TCP sockets.
652
653 After this function has been called, pending client connections
654 are detected by checking if the socket is ready for reading. This
655 can be done by either creating a QSocketNotifier, passing the
656 socket descriptor returned by socketDescriptor(), or by calling
657 the blocking function waitForRead().
658
659 Example:
660 \snippet code/src_network_socket_qnativesocketengine.cpp 1
661
662 \sa bind(), accept()
663*/
664bool QNativeSocketEngine::listen(int backlog)
665{
666 Q_D(QNativeSocketEngine);
667 Q_CHECK_VALID_SOCKETLAYER(QNativeSocketEngine::listen(), false);
668 Q_CHECK_STATE(QNativeSocketEngine::listen(), QAbstractSocket::BoundState, false);
669#ifndef QT_NO_SCTP
670 Q_CHECK_TYPES(QNativeSocketEngine::listen(), QAbstractSocket::TcpSocket,
671 QAbstractSocket::SctpSocket, false);
672#else
673 Q_CHECK_TYPE(QNativeSocketEngine::listen(), QAbstractSocket::TcpSocket, false);
674#endif
675
676 return d->nativeListen(backlog);
677}
678
679/*!
680 Accepts a pending connection from the socket, which must be in
681 ListeningState, and returns its socket descriptor. If no pending
682 connections are available, -1 is returned.
683
684 \sa bind(), listen()
685*/
686qintptr QNativeSocketEngine::accept()
687{
688 Q_D(QNativeSocketEngine);
689 Q_CHECK_VALID_SOCKETLAYER(QNativeSocketEngine::accept(), -1);
690 Q_CHECK_STATE(QNativeSocketEngine::accept(), QAbstractSocket::ListeningState, -1);
691#ifndef QT_NO_SCTP
692 Q_CHECK_TYPES(QNativeSocketEngine::accept(), QAbstractSocket::TcpSocket,
693 QAbstractSocket::SctpSocket, -1);
694#else
695 Q_CHECK_TYPE(QNativeSocketEngine::accept(), QAbstractSocket::TcpSocket, -1);
696#endif
697
698 return d->nativeAccept();
699}
700
701/*!
702 Returns the number of bytes that are currently available for
703 reading. On error, -1 is returned.
704
705 For UDP sockets, this function returns the accumulated size of all
706 pending datagrams, and it is therefore more useful for UDP sockets
707 to call hasPendingDatagrams() and pendingDatagramSize().
708*/
709qint64 QNativeSocketEngine::bytesAvailable() const
710{
711 Q_D(const QNativeSocketEngine);
712 Q_CHECK_VALID_SOCKETLAYER(QNativeSocketEngine::bytesAvailable(), -1);
713 Q_CHECK_NOT_STATE(QNativeSocketEngine::bytesAvailable(), QAbstractSocket::UnconnectedState, -1);
714
715 return d->nativeBytesAvailable();
716}
717
718#ifndef QT_NO_UDPSOCKET
719#ifndef QT_NO_NETWORKINTERFACE
720
721/*!
722 \since 4.8
723*/
724bool QNativeSocketEngine::joinMulticastGroup(const QHostAddress &groupAddress,
725 const QNetworkInterface &iface)
726{
727 Q_D(QNativeSocketEngine);
728 Q_CHECK_VALID_SOCKETLAYER(QNativeSocketEngine::joinMulticastGroup(), false);
729 Q_CHECK_STATE(QNativeSocketEngine::joinMulticastGroup(), QAbstractSocket::BoundState, false);
730 Q_CHECK_TYPE(QNativeSocketEngine::joinMulticastGroup(), QAbstractSocket::UdpSocket, false);
731
732 // if the user binds a socket to an IPv6 address (or QHostAddress::Any) and
733 // then attempts to join an IPv4 multicast group, this won't work on
734 // Windows. In order to make this cross-platform, we warn & fail on all
735 // platforms.
736 if (groupAddress.protocol() == QAbstractSocket::IPv4Protocol &&
737 (d->socketProtocol == QAbstractSocket::IPv6Protocol ||
738 d->socketProtocol == QAbstractSocket::AnyIPProtocol)) {
739 qWarning(msg: "QAbstractSocket: cannot bind to QHostAddress::Any (or an IPv6 address) and join an IPv4 multicast group;"
740 " bind to QHostAddress::AnyIPv4 instead if you want to do this");
741 return false;
742 }
743
744 return d->nativeJoinMulticastGroup(groupAddress, iface);
745}
746
747/*!
748 \since 4.8
749*/
750bool QNativeSocketEngine::leaveMulticastGroup(const QHostAddress &groupAddress,
751 const QNetworkInterface &iface)
752{
753 Q_D(QNativeSocketEngine);
754 Q_CHECK_VALID_SOCKETLAYER(QNativeSocketEngine::leaveMulticastGroup(), false);
755 Q_CHECK_STATE(QNativeSocketEngine::leaveMulticastGroup(), QAbstractSocket::BoundState, false);
756 Q_CHECK_TYPE(QNativeSocketEngine::leaveMulticastGroup(), QAbstractSocket::UdpSocket, false);
757 return d->nativeLeaveMulticastGroup(groupAddress, iface);
758}
759
760/*!
761 \since 4.8
762*/
763QNetworkInterface QNativeSocketEngine::multicastInterface() const
764{
765 Q_D(const QNativeSocketEngine);
766 Q_CHECK_VALID_SOCKETLAYER(QNativeSocketEngine::multicastInterface(), QNetworkInterface());
767 Q_CHECK_TYPE(QNativeSocketEngine::multicastInterface(), QAbstractSocket::UdpSocket, QNetworkInterface());
768 return d->nativeMulticastInterface();
769}
770
771/*!
772 \since 4.8
773*/
774bool QNativeSocketEngine::setMulticastInterface(const QNetworkInterface &iface)
775{
776 Q_D(QNativeSocketEngine);
777 Q_CHECK_VALID_SOCKETLAYER(QNativeSocketEngine::setMulticastInterface(), false);
778 Q_CHECK_TYPE(QNativeSocketEngine::setMulticastInterface(), QAbstractSocket::UdpSocket, false);
779 return d->nativeSetMulticastInterface(iface);
780}
781
782#endif // QT_NO_NETWORKINTERFACE
783
784/*!
785 Returns \c true if there is at least one datagram pending. This
786 function is only called by UDP sockets, where a datagram can have
787 a size of 0. TCP sockets call bytesAvailable().
788*/
789bool QNativeSocketEngine::hasPendingDatagrams() const
790{
791 Q_D(const QNativeSocketEngine);
792 Q_CHECK_VALID_SOCKETLAYER(QNativeSocketEngine::hasPendingDatagrams(), false);
793 Q_CHECK_NOT_STATE(QNativeSocketEngine::hasPendingDatagrams(), QAbstractSocket::UnconnectedState, false);
794 Q_CHECK_TYPE(QNativeSocketEngine::hasPendingDatagrams(), QAbstractSocket::UdpSocket, false);
795
796 return d->nativeHasPendingDatagrams();
797}
798
799/*!
800 Returns the size of the pending datagram, or -1 if no datagram is
801 pending. A datagram size of 0 is perfectly valid. This function is
802 called by UDP sockets before receiveMessage(). For TCP sockets,
803 call bytesAvailable().
804*/
805qint64 QNativeSocketEngine::pendingDatagramSize() const
806{
807 Q_D(const QNativeSocketEngine);
808 Q_CHECK_VALID_SOCKETLAYER(QNativeSocketEngine::pendingDatagramSize(), -1);
809 Q_CHECK_TYPE(QNativeSocketEngine::pendingDatagramSize(), QAbstractSocket::UdpSocket, -1);
810
811 return d->nativePendingDatagramSize();
812}
813#endif // QT_NO_UDPSOCKET
814
815/*!
816 Reads up to \a maxSize bytes of a datagram from the socket,
817 stores it in \a data and returns the number of bytes read. The
818 address, port, and other IP header fields are stored in \a header
819 according to the request in \a options.
820
821 For UDP sockets, to avoid unnecessarily loss of data, call
822 pendingDatagramSize() to determine the size of the pending message
823 before reading it. If \a maxSize is too small, the rest of the
824 datagram will be lost.
825
826 Returns -1 if an error occurred.
827
828 \sa hasPendingDatagrams()
829*/
830qint64 QNativeSocketEngine::readDatagram(char *data, qint64 maxSize, QIpPacketHeader *header,
831 PacketHeaderOptions options)
832{
833 Q_D(QNativeSocketEngine);
834 Q_CHECK_VALID_SOCKETLAYER(QNativeSocketEngine::readDatagram(), -1);
835 Q_CHECK_STATES(QNativeSocketEngine::readDatagram(), QAbstractSocket::BoundState,
836 QAbstractSocket::ConnectedState, -1);
837
838 return d->nativeReceiveDatagram(data, maxLength: maxSize, header, options);
839}
840
841/*!
842 Writes a datagram of size \a size bytes to the socket from
843 \a data to the destination contained in \a header, and returns the
844 number of bytes written, or -1 if an error occurred. If \a header
845 contains other settings like hop limit or source address, this function
846 will try to pass them to the operating system too, but will not
847 indicate an error if it could not pass them.
848
849 Only one datagram is sent, and if there is too much data to fit
850 into a single datagram, the operation will fail and error()
851 will return QAbstractSocket::DatagramTooLargeError. Operating systems impose an
852 upper limit to the size of a datagram, but this size is different
853 on almost all platforms. Sending large datagrams is in general
854 disadvised, as even if they are sent successfully, they are likely
855 to be fragmented before arriving at their destination.
856
857 Experience has shown that it is in general safe to send IPv4 datagrams
858 no larger than 512 bytes or IPv6 datagrams no larger than 1280 (the
859 minimum MTU).
860
861 \sa readDatagram()
862*/
863qint64 QNativeSocketEngine::writeDatagram(const char *data, qint64 size, const QIpPacketHeader &header)
864{
865 Q_D(QNativeSocketEngine);
866 Q_CHECK_VALID_SOCKETLAYER(QNativeSocketEngine::writeDatagram(), -1);
867 Q_CHECK_STATES(QNativeSocketEngine::writeDatagram(), QAbstractSocket::BoundState,
868 QAbstractSocket::ConnectedState, -1);
869
870 return d->nativeSendDatagram(data, length: size, header);
871}
872
873/*!
874 Writes a block of \a size bytes from \a data to the socket.
875 Returns the number of bytes written, or -1 if an error occurred.
876
877 Passing zero as the \a size parameter on a connected UDP socket
878 will send an empty datagram. For other socket types results are
879 unspecified.
880*/
881qint64 QNativeSocketEngine::write(const char *data, qint64 size)
882{
883 Q_D(QNativeSocketEngine);
884 Q_CHECK_VALID_SOCKETLAYER(QNativeSocketEngine::write(), -1);
885 Q_CHECK_STATE(QNativeSocketEngine::write(), QAbstractSocket::ConnectedState, -1);
886 return d->nativeWrite(data, length: size);
887}
888
889
890qint64 QNativeSocketEngine::bytesToWrite() const
891{
892 return 0;
893}
894
895/*!
896 Reads up to \a maxSize bytes into \a data from the socket.
897 Returns the number of bytes read, or -1 if an error occurred.
898*/
899qint64 QNativeSocketEngine::read(char *data, qint64 maxSize)
900{
901 Q_D(QNativeSocketEngine);
902 Q_CHECK_VALID_SOCKETLAYER(QNativeSocketEngine::read(), -1);
903 Q_CHECK_STATES(QNativeSocketEngine::read(), QAbstractSocket::ConnectedState, QAbstractSocket::BoundState, -1);
904
905 qint64 readBytes = d->nativeRead(data, maxLength: maxSize);
906
907 // Handle remote close
908 if (readBytes == 0 && (d->socketType == QAbstractSocket::TcpSocket
909#ifndef QT_NO_SCTP
910 || d->socketType == QAbstractSocket::SctpSocket
911#endif
912 )) {
913 d->setError(error: QAbstractSocket::RemoteHostClosedError,
914 errorString: QNativeSocketEnginePrivate::RemoteHostClosedErrorString);
915 close();
916 return -1;
917 } else if (readBytes == -1) {
918 if (!d->hasSetSocketError) {
919 d->hasSetSocketError = true;
920 d->socketError = QAbstractSocket::NetworkError;
921 d->socketErrorString = qt_error_string();
922 }
923 close();
924 return -1;
925 }
926 return readBytes;
927}
928
929/*!
930 Closes the socket. In order to use the socket again, initialize()
931 must be called.
932*/
933void QNativeSocketEngine::close()
934{
935 Q_D(QNativeSocketEngine);
936 if (d->readNotifier)
937 d->readNotifier->setEnabled(false);
938 if (d->writeNotifier)
939 d->writeNotifier->setEnabled(false);
940 if (d->exceptNotifier)
941 d->exceptNotifier->setEnabled(false);
942
943 if (d->socketDescriptor != -1) {
944 d->nativeClose();
945 d->socketDescriptor = -1;
946 }
947 d->socketState = QAbstractSocket::UnconnectedState;
948 d->hasSetSocketError = false;
949 d->localPort = 0;
950 d->localAddress.clear();
951 d->peerPort = 0;
952 d->peerAddress.clear();
953 d->inboundStreamCount = d->outboundStreamCount = 0;
954 if (d->readNotifier) {
955 delete d->readNotifier;
956 d->readNotifier = nullptr;
957 }
958 if (d->writeNotifier) {
959 delete d->writeNotifier;
960 d->writeNotifier = nullptr;
961 }
962 if (d->exceptNotifier) {
963 delete d->exceptNotifier;
964 d->exceptNotifier = nullptr;
965 }
966}
967
968/*!
969 Waits until \a deadline has expired or until the socket is ready for
970 reading. If \a timedOut is not \nullptr and \a deadline has expired,
971 the value of \a timedOut is set to true.
972
973 Returns \c true if data is available for reading; otherwise returns
974 false.
975
976 This is a blocking function call; its use is disadvised in a
977 single threaded application, as the whole thread will stop
978 responding until the function returns. waitForRead() is most
979 useful when there is no event loop available. The general approach
980 is to create a QSocketNotifier, passing the socket descriptor
981 returned by socketDescriptor() to its constructor.
982*/
983bool QNativeSocketEngine::waitForRead(QDeadlineTimer deadline, bool *timedOut)
984{
985 Q_D(const QNativeSocketEngine);
986 Q_CHECK_VALID_SOCKETLAYER(QNativeSocketEngine::waitForRead(), false);
987 Q_CHECK_NOT_STATE(QNativeSocketEngine::waitForRead(),
988 QAbstractSocket::UnconnectedState, false);
989
990 if (timedOut)
991 *timedOut = false;
992
993 int ret = d->nativeSelect(deadline, selectForRead: true);
994 if (ret == 0) {
995 if (timedOut)
996 *timedOut = true;
997 d->setError(error: QAbstractSocket::SocketTimeoutError,
998 errorString: QNativeSocketEnginePrivate::TimeOutErrorString);
999 d->hasSetSocketError = false; // A timeout error is temporary in waitFor functions
1000 return false;
1001 } else if (state() == QAbstractSocket::ConnectingState) {
1002 connectToHost(address: d->peerAddress, port: d->peerPort);
1003 }
1004
1005 return ret > 0;
1006}
1007
1008/*!
1009 Waits until \a deadline has expired or until the socket is ready for
1010 writing. If \a timedOut is not \nullptr and \a deadline has expired,
1011 the value of \a timedOut is set to true.
1012
1013 Returns \c true if data is available for writing; otherwise returns
1014 false.
1015
1016 This is a blocking function call; its use is disadvised in a
1017 single threaded application, as the whole thread will stop
1018 responding until the function returns. waitForWrite() is most
1019 useful when there is no event loop available. The general approach
1020 is to create a QSocketNotifier, passing the socket descriptor
1021 returned by socketDescriptor() to its constructor.
1022*/
1023bool QNativeSocketEngine::waitForWrite(QDeadlineTimer deadline, bool *timedOut)
1024{
1025 Q_D(QNativeSocketEngine);
1026 Q_CHECK_VALID_SOCKETLAYER(QNativeSocketEngine::waitForWrite(), false);
1027 Q_CHECK_NOT_STATE(QNativeSocketEngine::waitForWrite(),
1028 QAbstractSocket::UnconnectedState, false);
1029
1030 if (timedOut)
1031 *timedOut = false;
1032
1033 int ret = d->nativeSelect(deadline, selectForRead: false);
1034 // On Windows, the socket is in connected state if a call to
1035 // select(writable) is successful. In this case we should not
1036 // issue a second call to WSAConnect()
1037#if defined (Q_OS_WIN)
1038 if (state() == QAbstractSocket::ConnectingState) {
1039 if (ret > 0) {
1040 setState(QAbstractSocket::ConnectedState);
1041 d_func()->fetchConnectionParameters();
1042 return true;
1043 } else {
1044 int value = 0;
1045 int valueSize = sizeof(value);
1046 if (::getsockopt(d->socketDescriptor, SOL_SOCKET, SO_ERROR, (char *) &value, &valueSize) == 0) {
1047 if (value == WSAECONNREFUSED) {
1048 d->setError(QAbstractSocket::ConnectionRefusedError, QNativeSocketEnginePrivate::ConnectionRefusedErrorString);
1049 d->socketState = QAbstractSocket::UnconnectedState;
1050 return false;
1051 } else if (value == WSAETIMEDOUT) {
1052 d->setError(QAbstractSocket::NetworkError, QNativeSocketEnginePrivate::ConnectionTimeOutErrorString);
1053 d->socketState = QAbstractSocket::UnconnectedState;
1054 return false;
1055 } else if (value == WSAEHOSTUNREACH) {
1056 d->setError(QAbstractSocket::NetworkError, QNativeSocketEnginePrivate::HostUnreachableErrorString);
1057 d->socketState = QAbstractSocket::UnconnectedState;
1058 return false;
1059 }
1060 }
1061 }
1062 }
1063#endif
1064
1065 if (ret == 0) {
1066 if (timedOut)
1067 *timedOut = true;
1068 d->setError(error: QAbstractSocket::SocketTimeoutError,
1069 errorString: QNativeSocketEnginePrivate::TimeOutErrorString);
1070 d->hasSetSocketError = false; // A timeout error is temporary in waitFor functions
1071 return false;
1072 } else if (state() == QAbstractSocket::ConnectingState || (state() == QAbstractSocket::BoundState && d->socketDescriptor != -1)) {
1073 connectToHost(address: d->peerAddress, port: d->peerPort);
1074 }
1075
1076 return ret > 0;
1077}
1078
1079bool QNativeSocketEngine::waitForReadOrWrite(bool *readyToRead, bool *readyToWrite,
1080 bool checkRead, bool checkWrite,
1081 QDeadlineTimer deadline, bool *timedOut)
1082{
1083 Q_D(QNativeSocketEngine);
1084 Q_CHECK_VALID_SOCKETLAYER(QNativeSocketEngine::waitForReadOrWrite(), false);
1085 Q_CHECK_NOT_STATE(QNativeSocketEngine::waitForReadOrWrite(),
1086 QAbstractSocket::UnconnectedState, false);
1087
1088 int ret = d->nativeSelect(deadline, checkRead, checkWrite, selectForRead: readyToRead, selectForWrite: readyToWrite);
1089 // On Windows, the socket is in connected state if a call to
1090 // select(writable) is successful. In this case we should not
1091 // issue a second call to WSAConnect()
1092#if defined (Q_OS_WIN)
1093 if (state() == QAbstractSocket::ConnectingState) {
1094 if (checkWrite && ((readyToWrite && *readyToWrite) || !readyToWrite) && ret > 0) {
1095 setState(QAbstractSocket::ConnectedState);
1096 d_func()->fetchConnectionParameters();
1097 return true;
1098 } else {
1099 int value = 0;
1100 int valueSize = sizeof(value);
1101 if (::getsockopt(d->socketDescriptor, SOL_SOCKET, SO_ERROR, (char *) &value, &valueSize) == 0) {
1102 if (value == WSAECONNREFUSED) {
1103 d->setError(QAbstractSocket::ConnectionRefusedError, QNativeSocketEnginePrivate::ConnectionRefusedErrorString);
1104 d->socketState = QAbstractSocket::UnconnectedState;
1105 return false;
1106 } else if (value == WSAETIMEDOUT) {
1107 d->setError(QAbstractSocket::NetworkError, QNativeSocketEnginePrivate::ConnectionTimeOutErrorString);
1108 d->socketState = QAbstractSocket::UnconnectedState;
1109 return false;
1110 } else if (value == WSAEHOSTUNREACH) {
1111 d->setError(QAbstractSocket::NetworkError, QNativeSocketEnginePrivate::HostUnreachableErrorString);
1112 d->socketState = QAbstractSocket::UnconnectedState;
1113 return false;
1114 }
1115 }
1116 }
1117 }
1118#endif
1119 if (ret == 0) {
1120 if (timedOut)
1121 *timedOut = true;
1122 d->setError(error: QAbstractSocket::SocketTimeoutError,
1123 errorString: QNativeSocketEnginePrivate::TimeOutErrorString);
1124 d->hasSetSocketError = false; // A timeout error is temporary in waitFor functions
1125 return false;
1126 } else if (state() == QAbstractSocket::ConnectingState) {
1127 connectToHost(address: d->peerAddress, port: d->peerPort);
1128 }
1129
1130 return ret > 0;
1131}
1132
1133#if 0 // currently unused
1134/*
1135 Returns the size of the operating system's socket receive
1136 buffer. Depending on the operating system, this size may be
1137 different from what has been set earlier with
1138 setReceiveBufferSize().
1139*/
1140qint64 QNativeSocketEngine::receiveBufferSize() const
1141{
1142 Q_CHECK_VALID_SOCKETLAYER(QNativeSocketEngine::receiveBufferSize(), -1);
1143 return option(ReceiveBufferSocketOption);
1144}
1145
1146/*
1147 Sets the size of the operating system receive buffer to \a size.
1148
1149 For clients, this should be set before connectToHost() is called;
1150 otherwise it will have no effect. For servers, it should be called
1151 before listen().
1152
1153 The operating system receive buffer size effectively limits two
1154 things: how much data can be in transit at any one moment, and how
1155 much data can be received in one iteration of the main event loop.
1156 Setting the size of the receive buffer may have an impact on the
1157 socket's performance.
1158
1159 The default value is operating system-dependent.
1160*/
1161void QNativeSocketEngine::setReceiveBufferSize(qint64 size)
1162{
1163 Q_CHECK_VALID_SOCKETLAYER(QNativeSocketEngine::setReceiveBufferSize(), Q_VOID);
1164 setOption(ReceiveBufferSocketOption, size);
1165}
1166
1167/*
1168 Returns the size of the operating system send buffer. Depending on
1169 the operating system, this size may be different from what has
1170 been set earlier with setSendBufferSize().
1171*/
1172qint64 QNativeSocketEngine::sendBufferSize() const
1173{
1174 Q_CHECK_VALID_SOCKETLAYER(QNativeSocketEngine::setSendBufferSize(), -1);
1175 return option(SendBufferSocketOption);
1176}
1177
1178/*
1179 Sets the size of the operating system send buffer to \a size.
1180
1181 The operating system send buffer size effectively limits how much
1182 data can be in transit at any one moment. Setting the size of the
1183 send buffer may have an impact on the socket's performance.
1184
1185 The default value is operating system-dependent.
1186*/
1187void QNativeSocketEngine::setSendBufferSize(qint64 size)
1188{
1189 Q_CHECK_VALID_SOCKETLAYER(QNativeSocketEngine::setSendBufferSize(), Q_VOID);
1190 setOption(SendBufferSocketOption, size);
1191}
1192#endif
1193
1194/*!
1195 Sets the option \a option to the value \a value.
1196*/
1197bool QNativeSocketEngine::setOption(SocketOption option, int value)
1198{
1199 Q_D(QNativeSocketEngine);
1200 return d->setOption(option, value);
1201}
1202
1203/*!
1204 Returns the value of the option \a socketOption.
1205*/
1206int QNativeSocketEngine::option(SocketOption socketOption) const
1207{
1208 Q_D(const QNativeSocketEngine);
1209 return d->option(option: socketOption);
1210}
1211
1212bool QNativeSocketEngine::isReadNotificationEnabled() const
1213{
1214 Q_D(const QNativeSocketEngine);
1215 return d->readNotifier && d->readNotifier->isEnabled();
1216}
1217
1218/*
1219 \internal
1220 \class QReadNotifier
1221 \brief The QReadNotifer class is used to improve performance.
1222
1223 QReadNotifier is a private class used for performance reasons vs
1224 connecting to the QSocketNotifier activated() signal.
1225 */
1226class QReadNotifier : public QSocketNotifier
1227{
1228public:
1229 QReadNotifier(qintptr fd, QNativeSocketEngine *parent)
1230 : QSocketNotifier(fd, QSocketNotifier::Read, parent)
1231 { engine = parent; }
1232
1233protected:
1234 bool event(QEvent *) override;
1235
1236 QNativeSocketEngine *engine;
1237};
1238
1239bool QReadNotifier::event(QEvent *e)
1240{
1241 if (e->type() == QEvent::SockAct) {
1242 engine->readNotification();
1243 return true;
1244 } else if (e->type() == QEvent::SockClose) {
1245 engine->closeNotification();
1246 return true;
1247 }
1248 return QSocketNotifier::event(e);
1249}
1250
1251/*
1252 \internal
1253 \class QWriteNotifier
1254 \brief The QWriteNotifer class is used to improve performance.
1255
1256 QWriteNotifier is a private class used for performance reasons vs
1257 connecting to the QSocketNotifier activated() signal.
1258 */
1259class QWriteNotifier : public QSocketNotifier
1260{
1261public:
1262 QWriteNotifier(qintptr fd, QNativeSocketEngine *parent)
1263 : QSocketNotifier(fd, QSocketNotifier::Write, parent) { engine = parent; }
1264
1265protected:
1266 bool event(QEvent *) override;
1267
1268 QNativeSocketEngine *engine;
1269};
1270
1271bool QWriteNotifier::event(QEvent *e)
1272{
1273 if (e->type() == QEvent::SockAct) {
1274 if (engine->state() == QAbstractSocket::ConnectingState)
1275 engine->connectionNotification();
1276 else
1277 engine->writeNotification();
1278 return true;
1279 }
1280 return QSocketNotifier::event(e);
1281}
1282
1283class QExceptionNotifier : public QSocketNotifier
1284{
1285public:
1286 QExceptionNotifier(qintptr fd, QNativeSocketEngine *parent)
1287 : QSocketNotifier(fd, QSocketNotifier::Exception, parent) { engine = parent; }
1288
1289protected:
1290 bool event(QEvent *) override;
1291
1292 QNativeSocketEngine *engine;
1293};
1294
1295bool QExceptionNotifier::event(QEvent *e)
1296{
1297 if (e->type() == QEvent::SockAct) {
1298 if (engine->state() == QAbstractSocket::ConnectingState)
1299 engine->connectionNotification();
1300 else
1301 engine->exceptionNotification();
1302 return true;
1303 }
1304 return QSocketNotifier::event(e);
1305}
1306
1307void QNativeSocketEngine::setReadNotificationEnabled(bool enable)
1308{
1309 Q_D(QNativeSocketEngine);
1310 if (d->readNotifier) {
1311 d->readNotifier->setEnabled(enable);
1312 } else if (enable && d->threadData.loadRelaxed()->hasEventDispatcher()) {
1313 d->readNotifier = new QReadNotifier(d->socketDescriptor, this);
1314 d->readNotifier->setEnabled(true);
1315 }
1316}
1317
1318bool QNativeSocketEngine::isWriteNotificationEnabled() const
1319{
1320 Q_D(const QNativeSocketEngine);
1321 return d->writeNotifier && d->writeNotifier->isEnabled();
1322}
1323
1324void QNativeSocketEngine::setWriteNotificationEnabled(bool enable)
1325{
1326 Q_D(QNativeSocketEngine);
1327 if (d->writeNotifier) {
1328 d->writeNotifier->setEnabled(enable);
1329 } else if (enable && d->threadData.loadRelaxed()->hasEventDispatcher()) {
1330 d->writeNotifier = new QWriteNotifier(d->socketDescriptor, this);
1331 d->writeNotifier->setEnabled(true);
1332 }
1333}
1334
1335bool QNativeSocketEngine::isExceptionNotificationEnabled() const
1336{
1337 Q_D(const QNativeSocketEngine);
1338 return d->exceptNotifier && d->exceptNotifier->isEnabled();
1339}
1340
1341void QNativeSocketEngine::setExceptionNotificationEnabled(bool enable)
1342{
1343 Q_D(QNativeSocketEngine);
1344 if (d->exceptNotifier) {
1345 d->exceptNotifier->setEnabled(enable);
1346 } else if (enable && d->threadData.loadRelaxed()->hasEventDispatcher()) {
1347 d->exceptNotifier = new QExceptionNotifier(d->socketDescriptor, this);
1348 d->exceptNotifier->setEnabled(true);
1349 }
1350}
1351
1352QT_END_NAMESPACE
1353
1354#include "moc_qnativesocketengine_p.cpp"
1355

source code of qtbase/src/network/socket/qnativesocketengine.cpp