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