Qt
Internal/Contributor docs for the Qt SDK. <b>Note:</b> These are NOT official API docs; those are found <a href='https://doc.qt.io/'>here</a>.
Loading...
Searching...
No Matches
qnativesocketengine_win.cpp
Go to the documentation of this file.
1// Copyright (C) 2021 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#include <winsock2.h>
6#include <ws2tcpip.h>
7
9
11#include <qsocketnotifier.h>
12#include <qdebug.h>
13#include <qdatetime.h>
14#include <qnetworkinterface.h>
16#include <qvarlengtharray.h>
17
18#include <algorithm>
19#include <chrono>
20
21//#define QNATIVESOCKETENGINE_DEBUG
22#if defined(QNATIVESOCKETENGINE_DEBUG)
23#include <private/qdebug_p.h>
24#endif
25
27
28//Some distributions of mingw (including 4.7.2 from mingw.org) are missing this from headers.
29//Also microsoft headers don't include it when building on XP and earlier.
30#ifndef IPV6_V6ONLY
31#define IPV6_V6ONLY 27
32#endif
33#ifndef IP_HOPLIMIT
34#define IP_HOPLIMIT 21 // Receive packet hop limit.
35#endif
36
37#if defined(QNATIVESOCKETENGINE_DEBUG)
38
39void verboseWSErrorDebug(int r)
40{
41 switch (r) {
42 case WSANOTINITIALISED : qDebug("WSA error : WSANOTINITIALISED"); break;
43 case WSAEINTR: qDebug("WSA error : WSAEINTR"); break;
44 case WSAEBADF: qDebug("WSA error : WSAEBADF"); break;
45 case WSAEACCES: qDebug("WSA error : WSAEACCES"); break;
46 case WSAEFAULT: qDebug("WSA error : WSAEFAULT"); break;
47 case WSAEINVAL: qDebug("WSA error : WSAEINVAL"); break;
48 case WSAEMFILE: qDebug("WSA error : WSAEMFILE"); break;
49 case WSAEWOULDBLOCK: qDebug("WSA error : WSAEWOULDBLOCK"); break;
50 case WSAEINPROGRESS: qDebug("WSA error : WSAEINPROGRESS"); break;
51 case WSAEALREADY: qDebug("WSA error : WSAEALREADY"); break;
52 case WSAENOTSOCK: qDebug("WSA error : WSAENOTSOCK"); break;
53 case WSAEDESTADDRREQ: qDebug("WSA error : WSAEDESTADDRREQ"); break;
54 case WSAEMSGSIZE: qDebug("WSA error : WSAEMSGSIZE"); break;
55 case WSAEPROTOTYPE: qDebug("WSA error : WSAEPROTOTYPE"); break;
56 case WSAENOPROTOOPT: qDebug("WSA error : WSAENOPROTOOPT"); break;
57 case WSAEPROTONOSUPPORT: qDebug("WSA error : WSAEPROTONOSUPPORT"); break;
58 case WSAESOCKTNOSUPPORT: qDebug("WSA error : WSAESOCKTNOSUPPORT"); break;
59 case WSAEOPNOTSUPP: qDebug("WSA error : WSAEOPNOTSUPP"); break;
60 case WSAEPFNOSUPPORT: qDebug("WSA error : WSAEPFNOSUPPORT"); break;
61 case WSAEAFNOSUPPORT: qDebug("WSA error : WSAEAFNOSUPPORT"); break;
62 case WSAEADDRINUSE: qDebug("WSA error : WSAEADDRINUSE"); break;
63 case WSAEADDRNOTAVAIL: qDebug("WSA error : WSAEADDRNOTAVAIL"); break;
64 case WSAENETDOWN: qDebug("WSA error : WSAENETDOWN"); break;
65 case WSAENETUNREACH: qDebug("WSA error : WSAENETUNREACH"); break;
66 case WSAENETRESET: qDebug("WSA error : WSAENETRESET"); break;
67 case WSAECONNABORTED: qDebug("WSA error : WSAECONNABORTED"); break;
68 case WSAECONNRESET: qDebug("WSA error : WSAECONNRESET"); break;
69 case WSAENOBUFS: qDebug("WSA error : WSAENOBUFS"); break;
70 case WSAEISCONN: qDebug("WSA error : WSAEISCONN"); break;
71 case WSAENOTCONN: qDebug("WSA error : WSAENOTCONN"); break;
72 case WSAESHUTDOWN: qDebug("WSA error : WSAESHUTDOWN"); break;
73 case WSAETOOMANYREFS: qDebug("WSA error : WSAETOOMANYREFS"); break;
74 case WSAETIMEDOUT: qDebug("WSA error : WSAETIMEDOUT"); break;
75 case WSAECONNREFUSED: qDebug("WSA error : WSAECONNREFUSED"); break;
76 case WSAELOOP: qDebug("WSA error : WSAELOOP"); break;
77 case WSAENAMETOOLONG: qDebug("WSA error : WSAENAMETOOLONG"); break;
78 case WSAEHOSTDOWN: qDebug("WSA error : WSAEHOSTDOWN"); break;
79 case WSAEHOSTUNREACH: qDebug("WSA error : WSAEHOSTUNREACH"); break;
80 case WSAENOTEMPTY: qDebug("WSA error : WSAENOTEMPTY"); break;
81 case WSAEPROCLIM: qDebug("WSA error : WSAEPROCLIM"); break;
82 case WSAEUSERS: qDebug("WSA error : WSAEUSERS"); break;
83 case WSAEDQUOT: qDebug("WSA error : WSAEDQUOT"); break;
84 case WSAESTALE: qDebug("WSA error : WSAESTALE"); break;
85 case WSAEREMOTE: qDebug("WSA error : WSAEREMOTE"); break;
86 case WSAEDISCON: qDebug("WSA error : WSAEDISCON"); break;
87 default: qDebug("WSA error : Unknown"); break;
88 }
89 qErrnoWarning(r, "more details");
90}
91
92#define WS_ERROR_DEBUG(x) verboseWSErrorDebug(x)
93
94#else
95
96#define WS_ERROR_DEBUG(x) Q_UNUSED(x)
97
98#endif
99
100#ifndef AF_INET6
101#define AF_INET6 23 /* Internetwork Version 6 */
102#endif
103
104#ifndef SO_EXCLUSIVEADDRUSE
105#define SO_EXCLUSIVEADDRUSE ((int)(~SO_REUSEADDR)) /* disallow local address reuse */
106#endif
107
108/*
109 Extracts the port and address from a sockaddr, and stores them in
110 \a port and \a addr if they are non-null.
111*/
112static inline void qt_socket_getPortAndAddress(SOCKET socketDescriptor, const qt_sockaddr *sa, quint16 *port, QHostAddress *address)
113{
114 if (sa->a.sa_family == AF_INET6) {
115 const sockaddr_in6 *sa6 = &sa->a6;
116 Q_IPV6ADDR tmp;
117 for (int i = 0; i < 16; ++i)
118 tmp.c[i] = sa6->sin6_addr.s6_addr[i];
119 if (address) {
121 a.setAddress(tmp);
122 if (sa6->sin6_scope_id)
123 a.setScopeId(QString::number(sa6->sin6_scope_id));
124 *address = a;
125 }
126 if (port)
127 WSANtohs(socketDescriptor, sa6->sin6_port, port);
128 } else
129
130 if (sa->a.sa_family == AF_INET) {
131 const sockaddr_in *sa4 = &sa->a4;
132 unsigned long addr;
133 WSANtohl(socketDescriptor, sa4->sin_addr.s_addr, &addr);
136 if (address)
137 *address = a;
138 if (port)
139 WSANtohs(socketDescriptor, sa4->sin_port, port);
140 }
141}
142
144 QAbstractSocket::NetworkLayerProtocol socketProtocol, int &level, int &n)
145{
146 n = -1;
147 level = SOL_SOCKET; // default
148
149 switch (opt) {
151 case QNativeSocketEngine::TypeOfServiceOption: // not supported
153 Q_UNREACHABLE();
154
156 n = SO_RCVBUF;
157 break;
159 n = SO_SNDBUF;
160 break;
162 n = SO_BROADCAST;
163 break;
165 n = SO_REUSEADDR;
166 break;
169 break;
171 n = SO_OOBINLINE;
172 break;
174 level = IPPROTO_TCP;
175 n = TCP_NODELAY;
176 break;
178 n = SO_KEEPALIVE;
179 break;
181 if (socketProtocol == QAbstractSocket::IPv6Protocol || socketProtocol == QAbstractSocket::AnyIPProtocol) {
182 level = IPPROTO_IPV6;
183 n = IPV6_MULTICAST_HOPS;
184 } else
185 {
186 level = IPPROTO_IP;
187 n = IP_MULTICAST_TTL;
188 }
189 break;
191 if (socketProtocol == QAbstractSocket::IPv6Protocol || socketProtocol == QAbstractSocket::AnyIPProtocol) {
192 level = IPPROTO_IPV6;
193 n = IPV6_MULTICAST_LOOP;
194 } else
195 {
196 level = IPPROTO_IP;
197 n = IP_MULTICAST_LOOP;
198 }
199 break;
201 if (socketProtocol == QAbstractSocket::IPv6Protocol || socketProtocol == QAbstractSocket::AnyIPProtocol) {
202 level = IPPROTO_IPV6;
203 n = IPV6_PKTINFO;
204 } else if (socketProtocol == QAbstractSocket::IPv4Protocol) {
205 level = IPPROTO_IP;
206 n = IP_PKTINFO;
207 }
208 break;
210 if (socketProtocol == QAbstractSocket::IPv6Protocol || socketProtocol == QAbstractSocket::AnyIPProtocol) {
211 level = IPPROTO_IPV6;
212 n = IPV6_HOPLIMIT;
213 } else if (socketProtocol == QAbstractSocket::IPv4Protocol) {
214 level = IPPROTO_IP;
215 n = IP_HOPLIMIT;
216 }
217 break;
218
220 break; // not supported on Windows
221 }
222}
223
228{
229 int value = 0;
230 QT_SOCKLEN_T valueSize = sizeof(value);
231 if (::getsockopt(socketDescriptor, SOL_SOCKET, SO_TYPE,
232 reinterpret_cast<char *>(&value), &valueSize) != 0) {
233 WS_ERROR_DEBUG(WSAGetLastError());
234 } else {
235 if (value == SOCK_STREAM)
237 else if (value == SOCK_DGRAM)
239 }
241}
242
243// MS Transport Provider IOCTL to control
244// reporting PORT_UNREACHABLE messages
245// on UDP sockets via recv/WSARecv/etc.
246// Path TRUE in input buffer to enable (default if supported),
247// FALSE to disable.
248#ifndef SIO_UDP_CONNRESET
249# ifndef IOC_VENDOR
250# define IOC_VENDOR 0x18000000
251# endif
252# ifndef _WSAIOW
253# define _WSAIOW(x,y) (IOC_IN|(x)|(y))
254# endif
255# define SIO_UDP_CONNRESET _WSAIOW(IOC_VENDOR,12)
256#endif
257
259{
260 //### SCTP not implemented
264 return false;
265 }
266
267 //Windows XP and 2003 support IPv6 but not dual stack sockets
270 int type = (socketType == QAbstractSocket::UdpSocket) ? SOCK_DGRAM : SOCK_STREAM;
271
272 // MSDN KB179942 states that on winnt 4 WSA_FLAG_OVERLAPPED is needed if socket is to be non
273 // blocking and recommends always doing it for cross-windows-version compatibility.
274
275 // WSA_FLAG_NO_HANDLE_INHERIT is atomic (like linux O_CLOEXEC)
276#ifndef WSA_FLAG_NO_HANDLE_INHERIT
277#define WSA_FLAG_NO_HANDLE_INHERIT 0x80
278#endif
279
280 SOCKET socket = ::WSASocket(protocol, type, 0, NULL, 0, WSA_FLAG_NO_HANDLE_INHERIT | WSA_FLAG_OVERLAPPED);
281 if (socket == INVALID_SOCKET) {
282 int err = WSAGetLastError();
283 WS_ERROR_DEBUG(err);
284 switch (err) {
285 case WSANOTINITIALISED:
286 //###
287 break;
288 case WSAEAFNOSUPPORT:
289 case WSAESOCKTNOSUPPORT:
290 case WSAEPROTOTYPE:
291 case WSAEINVAL:
293 break;
294 case WSAEMFILE:
295 case WSAENOBUFS:
297 break;
298 default:
299 break;
300 }
301
302 return false;
303 }
304
306 // enable new behavior using
307 // SIO_UDP_CONNRESET
308 DWORD dwBytesReturned = 0;
309 int bNewBehavior = 1;
310 if (::WSAIoctl(socket, SIO_UDP_CONNRESET, &bNewBehavior, sizeof(bNewBehavior),
311 NULL, 0, &dwBytesReturned, NULL, NULL) == SOCKET_ERROR) {
312 // not to worry isBogusUdpReadNotification() should handle this otherwise
313 int err = WSAGetLastError();
314 WS_ERROR_DEBUG(err);
315 }
316 }
317
318 // get the pointer to sendmsg and recvmsg
319 DWORD bytesReturned;
320 GUID recvmsgguid = WSAID_WSARECVMSG;
321 if (WSAIoctl(socket, SIO_GET_EXTENSION_FUNCTION_POINTER,
322 &recvmsgguid, sizeof(recvmsgguid),
323 &recvmsg, sizeof(recvmsg), &bytesReturned, NULL, NULL) == SOCKET_ERROR)
324 recvmsg = 0;
325
326 GUID sendmsgguid = WSAID_WSASENDMSG;
327 if (WSAIoctl(socket, SIO_GET_EXTENSION_FUNCTION_POINTER,
328 &sendmsgguid, sizeof(sendmsgguid),
329 &sendmsg, sizeof(sendmsg), &bytesReturned, NULL, NULL) == SOCKET_ERROR)
330 sendmsg = 0;
331
333 this->socketProtocol = socketProtocol;
334 this->socketType = socketType;
335
336 // Make the socket nonblocking.
339 q_func()->close();
340 return false;
341 }
342
343 return true;
344}
345
351{
352 Q_Q(const QNativeSocketEngine);
353 if (!q->isValid())
354 return -1;
355
356 // handle non-getsockopt
357 switch (opt) {
359 unsigned long buf = 0;
360 if (WSAIoctl(socketDescriptor, FIONBIO, 0,0, &buf, sizeof(buf), 0,0,0) == 0)
361 return buf;
362 else
363 return -1;
364 break;
365 }
368 return -1;
369
370 default:
371 break;
372 }
373
374#if Q_BYTE_ORDER != Q_LITTLE_ENDIAN
375#error code assumes windows is little endian
376#endif
377 int n, level;
378 int v = 0; //note: windows doesn't write to all bytes if the option type is smaller than int
379 QT_SOCKOPTLEN_T len = sizeof(v);
380
382 if (n != -1) {
383 if (getsockopt(socketDescriptor, level, n, (char *) &v, &len) == 0)
384 return v;
385 WS_ERROR_DEBUG(WSAGetLastError());
386 }
387 return -1;
388}
389
390
395{
396 Q_Q(const QNativeSocketEngine);
397 if (!q->isValid())
398 return false;
399
400 // handle non-setsockopt options
401 switch (opt) {
403 // see QTBUG-30478 SO_SNDBUF should not be used on Vista or later
404 return false;
406 {
407 unsigned long buf = v;
408 unsigned long outBuf;
409 DWORD sizeWritten = 0;
410 if (::WSAIoctl(socketDescriptor, FIONBIO, &buf, sizeof(unsigned long), &outBuf, sizeof(unsigned long), &sizeWritten, 0,0) == SOCKET_ERROR) {
411 WS_ERROR_DEBUG(WSAGetLastError());
412 return false;
413 }
414 return true;
415 }
418 return false;
419
420 default:
421 break;
422 }
423
424 int n, level;
426 if (n == -1)
427 return false;
428 if (::setsockopt(socketDescriptor, level, n, (char*)&v, sizeof(v)) != 0) {
429 WS_ERROR_DEBUG(WSAGetLastError());
430 return false;
431 }
432 return true;
433}
434
440{
441 localPort = 0;
443 peerPort = 0;
446
447 if (socketDescriptor == -1)
448 return false;
449
450 qt_sockaddr sa;
451 QT_SOCKLEN_T sockAddrSize = sizeof(sa);
452
453 // Determine local address
454 memset(&sa, 0, sizeof(sa));
455 if (::getsockname(socketDescriptor, &sa.a, &sockAddrSize) == 0) {
457 // Determine protocol family
458 switch (sa.a.sa_family) {
459 case AF_INET:
461 break;
462 case AF_INET6:
464 break;
465 default:
467 break;
468 }
469 } else {
470 int err = WSAGetLastError();
471 WS_ERROR_DEBUG(err);
472 if (err == WSAENOTSOCK) {
475 return false;
476 }
477 }
478
479 // determine if local address is dual mode
480 DWORD ipv6only = 0;
481 QT_SOCKOPTLEN_T optlen = sizeof(ipv6only);
483 && !getsockopt(socketDescriptor, IPPROTO_IPV6, IPV6_V6ONLY, (char*)&ipv6only, &optlen )) {
484 if (!ipv6only) {
487 }
488 }
489
490 // Some Windows kernels return a v4-mapped QHostAddress::AnyIPv4 as a
491 // local address of the socket which bound on both IPv4 and IPv6 interfaces.
492 // This address does not match to any special address and should not be used
493 // to send the data. So, replace it with QHostAddress::Any.
494 const uchar ipv6MappedNet[] = {0,0,0,0, 0,0,0,0, 0,0,0xff,0xff, 0,0,0,0};
495 if (localAddress.isInSubnet(QHostAddress(ipv6MappedNet), 128 - 32)) {
496 bool ok = false;
497 const quint32 localIPv4 = localAddress.toIPv4Address(&ok);
498 if (ok && localIPv4 == INADDR_ANY) {
501 }
502 }
503
504 memset(&sa, 0, sizeof(sa));
505 if (::getpeername(socketDescriptor, &sa.a, &sockAddrSize) == 0) {
508 } else {
509 WS_ERROR_DEBUG(WSAGetLastError());
510 }
511
513
514#if defined (QNATIVESOCKETENGINE_DEBUG)
515 QString socketProtocolStr = QStringLiteral("UnknownProtocol");
516 if (socketProtocol == QAbstractSocket::IPv4Protocol) socketProtocolStr = QStringLiteral("IPv4Protocol");
517 else if (socketProtocol == QAbstractSocket::IPv6Protocol) socketProtocolStr = QStringLiteral("IPv6Protocol");
518
519 QString socketTypeStr = QStringLiteral("UnknownSocketType");
520 if (socketType == QAbstractSocket::TcpSocket) socketTypeStr = QStringLiteral("TcpSocket");
521 else if (socketType == QAbstractSocket::UdpSocket) socketTypeStr = QStringLiteral("UdpSocket");
522
523 qDebug("QNativeSocketEnginePrivate::fetchConnectionParameters() localAddress == %s, localPort = %i, peerAddress == %s, peerPort = %i, socketProtocol == %s, socketType == %s", localAddress.toString().toLatin1().constData(), localPort, peerAddress.toString().toLatin1().constData(), peerPort, socketProtocolStr.toLatin1().constData(), socketTypeStr.toLatin1().constData());
524#endif
525
526 return true;
527}
528
529
531{
532 Q_ASSERT(d);
533 switch (error) {
534 case WSAEISCONN:
535 d->socketState = QAbstractSocket::ConnectedState;
536 break;
537 case WSAEHOSTUNREACH:
540 break;
541 case WSAEADDRNOTAVAIL:
544 break;
545 case WSAEINPROGRESS:
547 d->socketState = QAbstractSocket::ConnectingState;
548 break;
549 case WSAEADDRINUSE:
551 break;
552 case WSAECONNREFUSED:
555 break;
556 case WSAETIMEDOUT:
559 break;
560 case WSAEACCES:
563 break;
564 case WSAENETUNREACH:
567 break;
568 case WSAEINVAL:
569 case WSAEALREADY:
571 break;
572 default:
573 break;
574 }
575}
576
578{
579
580#if defined (QNATIVESOCKETENGINE_DEBUG)
581 qDebug("QNativeSocketEnginePrivate::nativeConnect() to %s :: %i", address.toString().toLatin1().constData(), port);
582#endif
583
584 qt_sockaddr aa;
585 QT_SOCKLEN_T sockAddrSize = 0;
586
587 setPortAndAddress(port, address, &aa, &sockAddrSize);
588
590 //IPV6_V6ONLY option must be cleared to connect to a V4 mapped address
591 DWORD ipv6only = 0;
592 ipv6only = ::setsockopt(socketDescriptor, IPPROTO_IPV6, IPV6_V6ONLY, (char*)&ipv6only, sizeof(ipv6only) );
593 }
594
595 forever {
596 int connectResult = ::WSAConnect(socketDescriptor, &aa.a, sockAddrSize, 0,0,0,0);
597 if (connectResult == SOCKET_ERROR) {
598 int err = WSAGetLastError();
599 WS_ERROR_DEBUG(err);
600
601 switch (err) {
602 case WSANOTINITIALISED:
603 //###
604 break;
605 case WSAEWOULDBLOCK: {
606 // If WSAConnect returns WSAEWOULDBLOCK on the second
607 // connection attempt, we have to check SO_ERROR's
608 // value to detect ECONNREFUSED. If we don't get
609 // ECONNREFUSED, we'll have to treat it as an
610 // unfinished operation.
611 int value = 0;
612 QT_SOCKLEN_T valueSize = sizeof(value);
613 bool tryAgain = false;
614 bool errorDetected = false;
615 int tries = 0;
616 do {
617 if (::getsockopt(socketDescriptor, SOL_SOCKET, SO_ERROR, (char *) &value, &valueSize) == 0) {
618 if (value != NOERROR) {
620 errorDetected = true;
621 // MSDN says getsockopt with SO_ERROR clears the error, but it's not actually cleared
622 // and this can affect all subsequent WSAConnect attempts, so clear it now.
623 const int val = NO_ERROR;
624 ::setsockopt(socketDescriptor, SOL_SOCKET, SO_ERROR, reinterpret_cast<const char*>(&val), sizeof val);
625 } else {
626 // When we get WSAEWOULDBLOCK the outcome was not known, so a
627 // NOERROR might indicate that the result of the operation
628 // is still unknown. We try again to increase the chance that we did
629 // get the correct result.
630 tryAgain = !tryAgain;
631 }
633 }
634 tries++;
635 } while (tryAgain && (tries < 2));
636
637 if (errorDetected)
638 break;
639 // fall through to unfinished operation error handling
640 err = WSAEINPROGRESS;
642 }
643
644 default:
645 setErrorFromWSAError(err, this);
646 break;
647 }
649#if defined (QNATIVESOCKETENGINE_DEBUG)
650 qDebug("QNativeSocketEnginePrivate::nativeConnect(%s, %i) == false (%s)",
651 address.toString().toLatin1().constData(), port,
653 ? "Connection in progress" : socketErrorString.toLatin1().constData());
654#endif
655 return false;
656 }
657 }
658 break;
659 }
660
661#if defined (QNATIVESOCKETENGINE_DEBUG)
662 qDebug("QNativeSocketEnginePrivate::nativeConnect(%s, %i) == true",
663 address.toString().toLatin1().constData(), port);
664#endif
665
667 return true;
668}
669
670
672{
674 if (address.protocol() == QAbstractSocket::IPv4Protocol) {
675 if ((address.toIPv4Address() & 0xffff0000) == 0xefff0000) {
676 // binding to a multicast address
678 }
679 }
680
681 qt_sockaddr aa;
682 QT_SOCKLEN_T sockAddrSize = 0;
683 setPortAndAddress(port, address, &aa, &sockAddrSize);
684
685 if (aa.a.sa_family == AF_INET6) {
686 // The default may change in future, so set it explicitly
687 int ipv6only = 0;
688 if (address.protocol() == QAbstractSocket::IPv6Protocol)
689 ipv6only = 1;
690 ::setsockopt(socketDescriptor, IPPROTO_IPV6, IPV6_V6ONLY, (char*)&ipv6only, sizeof(ipv6only) );
691 }
692
693
694 int bindResult = ::bind(socketDescriptor, &aa.a, sockAddrSize);
695 if (bindResult == SOCKET_ERROR && WSAGetLastError() == WSAEAFNOSUPPORT
696 && address.protocol() == QAbstractSocket::AnyIPProtocol) {
697 // retry with v4
698 aa.a4.sin_family = AF_INET;
699 aa.a4.sin_port = htons(port);
700 aa.a4.sin_addr.s_addr = htonl(address.toIPv4Address());
701 sockAddrSize = sizeof(aa.a4);
702 bindResult = ::bind(socketDescriptor, &aa.a, sockAddrSize);
703 }
704 if (bindResult == SOCKET_ERROR) {
705 int err = WSAGetLastError();
706 WS_ERROR_DEBUG(err);
707 switch (err) {
708 case WSANOTINITIALISED:
709 //###
710 break;
711 case WSAEADDRINUSE:
712 case WSAEINVAL:
714 break;
715 case WSAEACCES:
717 break;
718 case WSAEADDRNOTAVAIL:
720 break;
721 default:
722 break;
723 }
724
725#if defined (QNATIVESOCKETENGINE_DEBUG)
726 qDebug("QNativeSocketEnginePrivate::nativeBind(%s, %i) == false (%s)",
727 address.toString().toLatin1().constData(), port, socketErrorString.toLatin1().constData());
728#endif
729
730 return false;
731 }
732
733#if defined (QNATIVESOCKETENGINE_DEBUG)
734 qDebug("QNativeSocketEnginePrivate::nativeBind(%s, %i) == true",
735 address.toString().toLatin1().constData(), port);
736#endif
738 return true;
739}
740
741
743{
744 if (::listen(socketDescriptor, backlog) == SOCKET_ERROR) {
745 int err = WSAGetLastError();
746 WS_ERROR_DEBUG(err);
747 switch (err) {
748 case WSANOTINITIALISED:
749 //###
750 break;
751 case WSAEADDRINUSE:
754 break;
755 default:
756 break;
757 }
758
759#if defined (QNATIVESOCKETENGINE_DEBUG)
760 qDebug("QNativeSocketEnginePrivate::nativeListen(%i) == false (%s)",
762#endif
763 return false;
764 }
765
766#if defined (QNATIVESOCKETENGINE_DEBUG)
767 qDebug("QNativeSocketEnginePrivate::nativeListen(%i) == true", backlog);
768#endif
769
771 return true;
772}
773
775{
776 SOCKET acceptedDescriptor = WSAAccept(socketDescriptor, 0,0,0,0);
777 if (acceptedDescriptor == INVALID_SOCKET) {
778 int err = WSAGetLastError();
779 switch (err) {
780 case WSAEACCES:
782 break;
783 case WSAECONNREFUSED:
785 break;
786 case WSAECONNRESET:
788 break;
789 case WSAENETDOWN:
791 break;
792 case WSAENOTSOCK:
794 break;
795 case WSAEINVAL:
796 case WSAEOPNOTSUPP:
798 break;
799 case WSAEFAULT:
800 case WSAEMFILE:
801 case WSAENOBUFS:
803 break;
804 case WSAEWOULDBLOCK:
806 break;
807 default:
809 break;
810 }
811 } else if (acceptedDescriptor != INVALID_SOCKET && QAbstractEventDispatcher::instance()) {
812 // Because of WSAAsyncSelect() WSAAccept returns a non blocking socket
813 // with the same attributes as the listening socket including the current
814 // WSAAsyncSelect(). To be able to change the socket to blocking mode the
815 // WSAAsyncSelect() call must be canceled.
816 QSocketNotifier n(acceptedDescriptor, QSocketNotifier::Read);
817 n.setEnabled(true);
818 n.setEnabled(false);
819 }
820#if defined (QNATIVESOCKETENGINE_DEBUG)
821 qDebug("QNativeSocketEnginePrivate::nativeAccept() == %lld", qint64(acceptedDescriptor));
822#endif
823 return qintptr(acceptedDescriptor);
824}
825
827 int how6,
828 int how4,
829 const QHostAddress &groupAddress,
830 const QNetworkInterface &iface)
831{
832 int level = 0;
833 int sockOpt = 0;
834 char *sockArg;
835 int sockArgSize;
836
837 struct ip_mreq mreq4;
838 struct ipv6_mreq mreq6;
839
840 if (groupAddress.protocol() == QAbstractSocket::IPv6Protocol) {
841 level = IPPROTO_IPV6;
842 sockOpt = how6;
843 sockArg = reinterpret_cast<char *>(&mreq6);
844 sockArgSize = sizeof(mreq6);
845 memset(&mreq6, 0, sizeof(mreq6));
846 Q_IPV6ADDR ip6 = groupAddress.toIPv6Address();
847 memcpy(&mreq6.ipv6mr_multiaddr, &ip6, sizeof(ip6));
848 mreq6.ipv6mr_interface = iface.index();
849 } else if (groupAddress.protocol() == QAbstractSocket::IPv4Protocol) {
850 level = IPPROTO_IP;
851 sockOpt = how4;
852 sockArg = reinterpret_cast<char *>(&mreq4);
853 sockArgSize = sizeof(mreq4);
854 memset(&mreq4, 0, sizeof(mreq4));
855 mreq4.imr_multiaddr.s_addr = htonl(groupAddress.toIPv4Address());
856
857 if (iface.isValid()) {
858 const QList<QNetworkAddressEntry> addressEntries = iface.addressEntries();
859 bool found = false;
860 for (const QNetworkAddressEntry &entry : addressEntries) {
861 const QHostAddress ip = entry.ip();
863 mreq4.imr_interface.s_addr = htonl(ip.toIPv4Address());
864 found = true;
865 break;
866 }
867 }
868 if (!found) {
871 return false;
872 }
873 } else {
874 mreq4.imr_interface.s_addr = INADDR_ANY;
875 }
876 } else {
877 // unreachable
880 return false;
881 }
882
883 int res = setsockopt(d->socketDescriptor, level, sockOpt, sockArg, sockArgSize);
884 if (res == -1) {
887 return false;
888 }
889 return true;
890}
891
893 const QNetworkInterface &iface)
894{
895 return multicastMembershipHelper(this,
896 IPV6_JOIN_GROUP,
897 IP_ADD_MEMBERSHIP,
898 groupAddress,
899 iface);
900}
901
903 const QNetworkInterface &iface)
904{
905 return multicastMembershipHelper(this,
906 IPV6_LEAVE_GROUP,
907 IP_DROP_MEMBERSHIP,
908 groupAddress,
909 iface);
910}
911
913{
915 uint v;
916 QT_SOCKOPTLEN_T sizeofv = sizeof(v);
917 if (::getsockopt(socketDescriptor, IPPROTO_IPV6, IPV6_MULTICAST_IF, (char *) &v, &sizeofv) == -1)
918 return QNetworkInterface();
920 }
921
922 struct in_addr v;
923 v.s_addr = 0;
924 QT_SOCKOPTLEN_T sizeofv = sizeof(v);
925 if (::getsockopt(socketDescriptor, IPPROTO_IP, IP_MULTICAST_IF, (char *) &v, &sizeofv) == -1)
926 return QNetworkInterface();
927 if (v.s_addr != 0 && sizeofv >= QT_SOCKOPTLEN_T(sizeof(v))) {
928 QHostAddress ipv4(ntohl(v.s_addr));
929 QList<QNetworkInterface> ifaces = QNetworkInterface::allInterfaces();
930 for (int i = 0; i < ifaces.count(); ++i) {
931 const QNetworkInterface &iface = ifaces.at(i);
932 if (!(iface.flags() & QNetworkInterface::CanMulticast))
933 continue;
934 QList<QNetworkAddressEntry> entries = iface.addressEntries();
935 for (int j = 0; j < entries.count(); ++j) {
936 const QNetworkAddressEntry &entry = entries.at(j);
937 if (entry.ip() == ipv4)
938 return iface;
939 }
940 }
941 }
942 return QNetworkInterface();
943}
944
946{
947
949 uint v = iface.isValid() ? iface.index() : 0;
950 return (::setsockopt(socketDescriptor, IPPROTO_IPV6, IPV6_MULTICAST_IF, (char *) &v, sizeof(v)) != -1);
951 }
952
953 struct in_addr v;
954 if (iface.isValid()) {
955 QList<QNetworkAddressEntry> entries = iface.addressEntries();
956 for (int i = 0; i < entries.count(); ++i) {
957 const QNetworkAddressEntry &entry = entries.at(i);
958 const QHostAddress &ip = entry.ip();
960 v.s_addr = htonl(ip.toIPv4Address());
961 int r = ::setsockopt(socketDescriptor, IPPROTO_IP, IP_MULTICAST_IF, (char *) &v, sizeof(v));
962 if (r != -1)
963 return true;
964 }
965 }
966 return false;
967 }
968
969 v.s_addr = INADDR_ANY;
970 return (::setsockopt(socketDescriptor, IPPROTO_IP, IP_MULTICAST_IF, (char *) &v, sizeof(v)) != -1);
971}
972
974{
975 unsigned long nbytes = 0;
976 unsigned long dummy = 0;
977 DWORD sizeWritten = 0;
978 if (::WSAIoctl(socketDescriptor, FIONREAD, &dummy, sizeof(dummy), &nbytes, sizeof(nbytes), &sizeWritten, 0,0) == SOCKET_ERROR) {
979 WS_ERROR_DEBUG(WSAGetLastError());
980 return -1;
981 }
982
983 // ioctlsocket sometimes reports 1 byte available for datagrams
984 // while the following recvfrom returns -1 and claims connection
985 // was reset (udp is connectionless). so we peek one byte to
986 // catch this case and return 0 bytes available if recvfrom
987 // fails.
988 if (nbytes == 1 && socketType == QAbstractSocket::UdpSocket) {
989 char c;
990 WSABUF buf;
991 buf.buf = &c;
992 buf.len = sizeof(c);
993 DWORD bytesReceived;
994 DWORD flags = MSG_PEEK;
995 if (::WSARecvFrom(socketDescriptor, &buf, 1, &bytesReceived, &flags, 0,0,0,0) == SOCKET_ERROR) {
996 int err = WSAGetLastError();
997 if (err != WSAECONNRESET && err != WSAENETRESET)
998 return 0;
999 } else {
1000 return bytesReceived;
1001 }
1002 }
1003 return nbytes;
1004}
1005
1006
1008{
1009 // Create a sockaddr struct and reset its port number.
1011 QT_SOCKLEN_T storageSize = sizeof(storage);
1012 memset(&storage, 0, storageSize);
1013
1014 bool result = false;
1015
1016 // Peek 0 bytes into the next message. The size of the message may
1017 // well be 0, so we check if there was a sender.
1018 char c;
1019 WSABUF buf;
1020 buf.buf = &c;
1021 buf.len = sizeof(c);
1022 DWORD available = 0;
1023 DWORD flags = MSG_PEEK;
1024 int ret = ::WSARecvFrom(socketDescriptor, &buf, 1, &available, &flags, &storage.a, &storageSize,0,0);
1025 int err = WSAGetLastError();
1026 if (ret == SOCKET_ERROR && err != WSAEMSGSIZE) {
1027 WS_ERROR_DEBUG(err);
1028 result = (err == WSAECONNRESET || err == WSAENETRESET);
1029 } else {
1030 // If there's no error, or if our buffer was too small, there must be
1031 // a pending datagram.
1032 result = true;
1033 }
1034
1035#if defined (QNATIVESOCKETENGINE_DEBUG)
1036 qDebug("QNativeSocketEnginePrivate::nativeHasPendingDatagrams() == %s",
1037 result ? "true" : "false");
1038#endif
1039 return result;
1040}
1041
1042
1044{
1045 qint64 ret = -1;
1046 int recvResult = 0;
1047 DWORD flags;
1048 // We increase the amount we peek by 2048 * 5 on each iteration
1049 // Grabs most cases fast and early.
1050 char udpMessagePeekBuffer[2048];
1051 const int increments = 5;
1052 QVarLengthArray<WSABUF, 10> buf;
1053 for (;;) {
1054 buf.reserve(buf.size() + increments);
1055 std::fill_n(std::back_inserter(buf), increments, WSABUF{sizeof(udpMessagePeekBuffer), udpMessagePeekBuffer});
1056
1057 flags = MSG_PEEK;
1058 DWORD bytesRead = 0;
1059 recvResult = ::WSARecv(socketDescriptor, buf.data(), DWORD(buf.size()), &bytesRead, &flags, nullptr, nullptr);
1060 int err = WSAGetLastError();
1061 if (recvResult != SOCKET_ERROR) {
1062 ret = qint64(bytesRead);
1063 break;
1064 } else {
1065 switch (err) {
1066 case WSAEMSGSIZE:
1067 continue;
1068 case WSAECONNRESET:
1069 case WSAENETRESET:
1070 ret = 0;
1071 break;
1072 default:
1073 WS_ERROR_DEBUG(err);
1074 ret = -1;
1075 break;
1076 }
1077 break;
1078 }
1079 }
1080
1081#if defined (QNATIVESOCKETENGINE_DEBUG)
1082 qDebug("QNativeSocketEnginePrivate::nativePendingDatagramSize() == %lli", ret);
1083#endif
1084
1085 return ret;
1086}
1087
1089 QAbstractSocketEngine::PacketHeaderOptions options)
1090{
1091 union {
1092 char cbuf[WSA_CMSG_SPACE(sizeof(struct in6_pktinfo)) + WSA_CMSG_SPACE(sizeof(int))];
1093 WSACMSGHDR align; // only to ensure alignment
1094 };
1095 WSAMSG msg;
1096 WSABUF buf;
1097 qt_sockaddr aa;
1098 char c;
1099 memset(&msg, 0, sizeof(msg));
1100 memset(&aa, 0, sizeof(aa));
1101
1102 // we need to receive at least one byte, even if our user isn't interested in it
1103 buf.buf = maxLength ? data : &c;
1104 buf.len = maxLength ? maxLength : 1;
1105 msg.lpBuffers = &buf;
1106 msg.dwBufferCount = 1;
1107 msg.name = reinterpret_cast<LPSOCKADDR>(&aa);
1108 msg.namelen = sizeof(aa);
1109 msg.Control.buf = cbuf;
1110 msg.Control.len = sizeof(cbuf);
1111
1112 DWORD flags = 0;
1113 DWORD bytesRead = 0;
1114 qint64 ret;
1115
1116 if (recvmsg)
1117 ret = recvmsg(socketDescriptor, &msg, &bytesRead, 0,0);
1118 else
1119 ret = ::WSARecvFrom(socketDescriptor, &buf, 1, &bytesRead, &flags, msg.name, &msg.namelen,0,0);
1120 if (ret == SOCKET_ERROR) {
1121 int err = WSAGetLastError();
1122 if (err == WSAEMSGSIZE) {
1123 // it is ok the buffer was to small if bytesRead is larger than
1124 // maxLength then assume bytes read is really maxLenth
1125 ret = qint64(bytesRead) > maxLength ? maxLength : qint64(bytesRead);
1127 qt_socket_getPortAndAddress(socketDescriptor, &aa, &header->senderPort, &header->senderAddress);
1128 } else {
1129 WS_ERROR_DEBUG(err);
1130 switch (err) {
1131 case WSAENETRESET:
1133 break;
1134 case WSAECONNRESET:
1136 break;
1137 default:
1139 break;
1140 }
1141 ret = -1;
1142 if (header)
1143 header->clear();
1144 }
1145 } else {
1146 ret = qint64(bytesRead);
1148 qt_socket_getPortAndAddress(socketDescriptor, &aa, &header->senderPort, &header->senderAddress);
1149 }
1150
1151 if (ret != -1 && recvmsg && options != QAbstractSocketEngine::WantNone) {
1152 // get the ancillary data
1153 header->destinationPort = localPort;
1154 WSACMSGHDR *cmsgptr;
1155 for (cmsgptr = WSA_CMSG_FIRSTHDR(&msg); cmsgptr != NULL;
1156 cmsgptr = WSA_CMSG_NXTHDR(&msg, cmsgptr)) {
1157 if (cmsgptr->cmsg_level == IPPROTO_IPV6 && cmsgptr->cmsg_type == IPV6_PKTINFO
1158 && cmsgptr->cmsg_len >= WSA_CMSG_LEN(sizeof(in6_pktinfo))) {
1159 in6_pktinfo *info = reinterpret_cast<in6_pktinfo *>(WSA_CMSG_DATA(cmsgptr));
1160
1161 header->destinationAddress.setAddress(reinterpret_cast<quint8 *>(&info->ipi6_addr));
1162 header->ifindex = info->ipi6_ifindex;
1163 if (header->ifindex)
1164 header->destinationAddress.setScopeId(QString::number(info->ipi6_ifindex));
1165 }
1166 if (cmsgptr->cmsg_level == IPPROTO_IP && cmsgptr->cmsg_type == IP_PKTINFO
1167 && cmsgptr->cmsg_len >= WSA_CMSG_LEN(sizeof(in_pktinfo))) {
1168 in_pktinfo *info = reinterpret_cast<in_pktinfo *>(WSA_CMSG_DATA(cmsgptr));
1169 u_long addr;
1170 WSANtohl(socketDescriptor, info->ipi_addr.s_addr, &addr);
1171 header->destinationAddress.setAddress(addr);
1172 header->ifindex = info->ipi_ifindex;
1173 }
1174
1175 if (cmsgptr->cmsg_len == WSA_CMSG_LEN(sizeof(int))
1176 && ((cmsgptr->cmsg_level == IPPROTO_IPV6 && cmsgptr->cmsg_type == IPV6_HOPLIMIT)
1177 || (cmsgptr->cmsg_level == IPPROTO_IP && cmsgptr->cmsg_type == IP_TTL))) {
1178 header->hopLimit = *reinterpret_cast<int *>(WSA_CMSG_DATA(cmsgptr));
1179 }
1180 }
1181 }
1182
1183#if defined (QNATIVESOCKETENGINE_DEBUG)
1184 bool printSender = (ret != -1 && (options & QNativeSocketEngine::WantDatagramSender) != 0);
1185 qDebug("QNativeSocketEnginePrivate::nativeReceiveDatagram(%p \"%s\", %lli, %s, %i) == %lli",
1186 data, QtDebugUtils::toPrintable(data, ret, 16).constData(), maxLength,
1187 printSender ? header->senderAddress.toString().toLatin1().constData() : "(unknown)",
1188 printSender ? header->senderPort : 0, ret);
1189#endif
1190
1191 return ret;
1192}
1193
1194
1196 const QIpPacketHeader &header)
1197{
1198 union {
1199 char cbuf[WSA_CMSG_SPACE(sizeof(struct in6_pktinfo)) + WSA_CMSG_SPACE(sizeof(int))];
1200 WSACMSGHDR align; // ensures alignment
1201 };
1202 WSACMSGHDR *cmsgptr = &align;
1203 WSAMSG msg;
1204 WSABUF buf;
1205 qt_sockaddr aa;
1206
1207 memset(&msg, 0, sizeof(msg));
1208 memset(&aa, 0, sizeof(aa));
1209 buf.buf = len ? (char*)data : 0;
1210 msg.lpBuffers = &buf;
1211 msg.dwBufferCount = 1;
1212 msg.name = &aa.a;
1213 buf.len = len;
1214
1215 setPortAndAddress(header.destinationPort, header.destinationAddress, &aa, &msg.namelen);
1216
1217 uint oldIfIndex = 0;
1218 bool mustSetIpv6MulticastIf = false;
1219
1220 if (msg.namelen == sizeof(aa.a6)) {
1221 // sending IPv6
1222 if (header.hopLimit != -1) {
1223 msg.Control.len += WSA_CMSG_SPACE(sizeof(int));
1224 cmsgptr->cmsg_len = WSA_CMSG_LEN(sizeof(int));
1225 cmsgptr->cmsg_level = IPPROTO_IPV6;
1226 cmsgptr->cmsg_type = IPV6_HOPLIMIT;
1227 memcpy(WSA_CMSG_DATA(cmsgptr), &header.hopLimit, sizeof(int));
1228 cmsgptr = reinterpret_cast<WSACMSGHDR *>(reinterpret_cast<char *>(cmsgptr)
1229 + WSA_CMSG_SPACE(sizeof(int)));
1230 }
1231 if (!header.senderAddress.isNull()) {
1232 struct in6_pktinfo *data = reinterpret_cast<in6_pktinfo *>(WSA_CMSG_DATA(cmsgptr));
1233 memset(data, 0, sizeof(*data));
1234 msg.Control.len += WSA_CMSG_SPACE(sizeof(*data));
1235 cmsgptr->cmsg_len = WSA_CMSG_LEN(sizeof(*data));
1236 cmsgptr->cmsg_level = IPPROTO_IPV6;
1237 cmsgptr->cmsg_type = IPV6_PKTINFO;
1238 data->ipi6_ifindex = header.ifindex;
1239
1240 Q_IPV6ADDR tmp = header.senderAddress.toIPv6Address();
1241 memcpy(&data->ipi6_addr, &tmp, sizeof(tmp));
1242 cmsgptr = reinterpret_cast<WSACMSGHDR *>(reinterpret_cast<char *>(cmsgptr)
1243 + WSA_CMSG_SPACE(sizeof(*data)));
1244 } else if (header.ifindex != 0) {
1245 // Unlike other operating systems, setting the interface index in the in6_pktinfo
1246 // structure above and leaving the ipi6_addr set to :: will cause the packets to be
1247 // sent with source address ::. So we have to use IPV6_MULTICAST_IF, which MSDN is
1248 // quite clear that "This option does not change the default interface for receiving
1249 // IPv6 multicast traffic."
1250 QT_SOCKOPTLEN_T len = sizeof(oldIfIndex);
1251 if (::getsockopt(socketDescriptor, IPPROTO_IPV6, IPV6_MULTICAST_IF,
1252 reinterpret_cast<char *>(&oldIfIndex), &len) == -1
1253 || ::setsockopt(socketDescriptor, IPPROTO_IPV6, IPV6_MULTICAST_IF,
1254 reinterpret_cast<const char *>(&header.ifindex), sizeof(header.ifindex)) == -1) {
1256 return -1;
1257 }
1258 mustSetIpv6MulticastIf = true;
1259 }
1260 } else {
1261 // sending IPv4
1262 if (header.hopLimit != -1) {
1263 msg.Control.len += WSA_CMSG_SPACE(sizeof(int));
1264 cmsgptr->cmsg_len = WSA_CMSG_LEN(sizeof(int));
1265 cmsgptr->cmsg_level = IPPROTO_IP;
1266 cmsgptr->cmsg_type = IP_TTL;
1267 memcpy(WSA_CMSG_DATA(cmsgptr), &header.hopLimit, sizeof(int));
1268 cmsgptr = reinterpret_cast<WSACMSGHDR *>(reinterpret_cast<char *>(cmsgptr)
1269 + WSA_CMSG_SPACE(sizeof(int)));
1270 }
1271 if (header.ifindex != 0 || !header.senderAddress.isNull()) {
1272 struct in_pktinfo *data = reinterpret_cast<in_pktinfo *>(WSA_CMSG_DATA(cmsgptr));
1273 memset(data, 0, sizeof(*data));
1274 msg.Control.len += WSA_CMSG_SPACE(sizeof(*data));
1275 cmsgptr->cmsg_len = WSA_CMSG_LEN(sizeof(*data));
1276 cmsgptr->cmsg_level = IPPROTO_IP;
1277 cmsgptr->cmsg_type = IP_PKTINFO;
1278 data->ipi_ifindex = header.ifindex;
1279 WSAHtonl(socketDescriptor, header.senderAddress.toIPv4Address(), &data->ipi_addr.s_addr);
1280 cmsgptr = reinterpret_cast<WSACMSGHDR *>(reinterpret_cast<char *>(cmsgptr)
1281 + WSA_CMSG_SPACE(sizeof(*data)));
1282 }
1283 }
1284
1285 if (msg.Control.len != 0)
1286 msg.Control.buf = cbuf;
1287
1288 DWORD flags = 0;
1289 DWORD bytesSent = 0;
1290 qint64 ret = -1;
1291 if (sendmsg) {
1292 ret = sendmsg(socketDescriptor, &msg, flags, &bytesSent, 0,0);
1293 } else {
1294 ret = ::WSASendTo(socketDescriptor, &buf, 1, &bytesSent, flags, msg.name, msg.namelen, 0,0);
1295 }
1296 if (ret == SOCKET_ERROR) {
1297 int err = WSAGetLastError();
1298 WS_ERROR_DEBUG(err);
1299 switch (err) {
1300 case WSAEMSGSIZE:
1302 break;
1303 default:
1305 break;
1306 }
1307 ret = -1;
1308 } else {
1309 ret = qint64(bytesSent);
1310 }
1311
1312 if (mustSetIpv6MulticastIf) {
1313 // undo what we did above
1314 ::setsockopt(socketDescriptor, IPPROTO_IPV6, IPV6_MULTICAST_IF,
1315 reinterpret_cast<char *>(&oldIfIndex), sizeof(oldIfIndex));
1316 }
1317
1318#if defined (QNATIVESOCKETENGINE_DEBUG)
1319 qDebug("QNativeSocketEnginePrivate::nativeSendDatagram(%p \"%s\", %lli, \"%s\", %i) == %lli",
1320 data, QtDebugUtils::toPrintable(data, len, 16).constData(), len,
1321 header.destinationAddress.toString().toLatin1().constData(),
1322 header.destinationPort, ret);
1323#endif
1324
1325 return ret;
1326}
1327
1328
1330{
1332 qint64 ret = 0;
1333 qint64 bytesToSend = len;
1334
1335 for (;;) {
1336 WSABUF buf;
1337 buf.buf = const_cast<char*>(data) + ret;
1338 buf.len = bytesToSend;
1339 DWORD flags = 0;
1340 DWORD bytesWritten = 0;
1341
1342 int socketRet = ::WSASend(socketDescriptor, &buf, 1, &bytesWritten, flags, 0,0);
1343
1345
1346 int err;
1347 if (socketRet != SOCKET_ERROR) {
1348 if (ret == len || bytesToSend != qint64(bytesWritten))
1349 break;
1350 } else if ((err = WSAGetLastError()) == WSAEWOULDBLOCK) {
1351 break;
1352 } else if (err == WSAENOBUFS) {
1353 // this function used to not send more than 49152 per call to WSASendTo
1354 // to avoid getting a WSAENOBUFS. However this is a performance regression
1355 // and we think it only appears with old windows versions. We now handle the
1356 // WSAENOBUFS and hope it never appears anyway.
1357 // just go on, the next loop run we will try a smaller number
1358 } else {
1359 WS_ERROR_DEBUG(err);
1360 switch (err) {
1361 case WSAECONNRESET:
1362 case WSAECONNABORTED:
1363 ret = -1;
1365 q->close();
1366 break;
1367 default:
1368 break;
1369 }
1370 break;
1371 }
1372
1373 // for next send:
1374 bytesToSend = qMin<qint64>(49152, len - ret);
1375 }
1376
1377#if defined (QNATIVESOCKETENGINE_DEBUG)
1378 qDebug("QNativeSocketEnginePrivate::nativeWrite(%p \"%s\", %lli) == %lli",
1379 data, QtDebugUtils::toPrintable(data, ret, 16).constData(), len, ret);
1380#endif
1381
1382 return ret;
1383}
1384
1386{
1387 qint64 ret = -1;
1388 WSABUF buf;
1389 buf.buf = data;
1390 buf.len = maxLength;
1391 DWORD flags = 0;
1392 DWORD bytesRead = 0;
1393 if (::WSARecv(socketDescriptor, &buf, 1, &bytesRead, &flags, 0,0) == SOCKET_ERROR) {
1394 int err = WSAGetLastError();
1395 WS_ERROR_DEBUG(err);
1396 switch (err) {
1397 case WSAEWOULDBLOCK:
1398 ret = -2;
1399 break;
1400 case WSAEBADF:
1401 case WSAEINVAL:
1402 //error string is now set in read(), not here in nativeRead()
1403 break;
1404 case WSAECONNRESET:
1405 case WSAECONNABORTED:
1406 // for tcp sockets this will be handled in QNativeSocketEngine::read
1407 ret = 0;
1408 break;
1409 default:
1410 break;
1411 }
1412 } else {
1413 if (WSAGetLastError() == WSAEWOULDBLOCK)
1414 ret = -2;
1415 else
1416 ret = qint64(bytesRead);
1417 }
1418
1419#if defined (QNATIVESOCKETENGINE_DEBUG)
1420 if (ret != -2) {
1421 qDebug("QNativeSocketEnginePrivate::nativeRead(%p \"%s\", %lli) == %lli", data,
1422 QtDebugUtils::toPrintable(data, bytesRead, 16).constData(), maxLength, ret);
1423 } else {
1424 qDebug("QNativeSocketEnginePrivate::nativeRead(%p, %lli) == -2 (WOULD BLOCK)",
1425 data, maxLength);
1426 }
1427#endif
1428
1429 return ret;
1430}
1431
1432inline timeval durationToTimeval(std::chrono::nanoseconds dur) noexcept
1433{
1434 using namespace std::chrono;
1435 const auto secs = duration_cast<seconds>(dur);
1436 const auto frac = duration_cast<microseconds>(dur - secs);
1437 struct timeval tval;
1438 tval.tv_sec = secs.count();
1439 tval.tv_usec = frac.count();
1440 return tval;
1441}
1442
1444{
1445 bool readEnabled = selectForRead && readNotifier && readNotifier->isEnabled();
1446 if (readEnabled)
1447 readNotifier->setEnabled(false);
1448
1449 fd_set fds;
1450
1451 int ret = 0;
1452
1453 memset(&fds, 0, sizeof(fd_set));
1454 fds.fd_count = 1;
1455 fds.fd_array[0] = (SOCKET)socketDescriptor;
1456
1457 struct timeval tv = durationToTimeval(deadline.remainingTimeAsDuration());
1458
1459 if (selectForRead) {
1460 ret = select(0, &fds, 0, 0, &tv);
1461 } else {
1462 // select for write
1463
1464 // Windows needs this to report errors when connecting a socket ...
1465 fd_set fdexception;
1466 FD_ZERO(&fdexception);
1467 FD_SET((SOCKET)socketDescriptor, &fdexception);
1468
1469 ret = select(0, 0, &fds, &fdexception, &tv);
1470
1471 // ... but if it is actually set, pretend it did not happen
1472 if (ret > 0 && FD_ISSET((SOCKET)socketDescriptor, &fdexception))
1473 ret--;
1474 }
1475
1476 if (readEnabled)
1477 readNotifier->setEnabled(true);
1478
1479 return ret;
1480}
1481
1483 bool checkRead, bool checkWrite,
1484 bool *selectForRead, bool *selectForWrite) const
1485{
1486 bool readEnabled = checkRead && readNotifier && readNotifier->isEnabled();
1487 if (readEnabled)
1488 readNotifier->setEnabled(false);
1489
1490 fd_set fdread;
1491 fd_set fdwrite;
1492 fd_set fdexception;
1493
1494 int ret = 0;
1495
1496 memset(&fdread, 0, sizeof(fd_set));
1497 if (checkRead) {
1498 fdread.fd_count = 1;
1499 fdread.fd_array[0] = (SOCKET)socketDescriptor;
1500 }
1501 memset(&fdwrite, 0, sizeof(fd_set));
1502 FD_ZERO(&fdexception);
1503 if (checkWrite) {
1504 fdwrite.fd_count = 1;
1505 fdwrite.fd_array[0] = (SOCKET)socketDescriptor;
1506
1507 // Windows needs this to report errors when connecting a socket
1508 FD_SET((SOCKET)socketDescriptor, &fdexception);
1509 }
1510
1511 struct timeval tv = durationToTimeval(deadline.remainingTimeAsDuration());
1512
1513 ret = select(socketDescriptor + 1, &fdread, &fdwrite, &fdexception, &tv);
1514
1515 //... but if it is actually set, pretend it did not happen
1516 if (ret > 0 && FD_ISSET((SOCKET)socketDescriptor, &fdexception))
1517 ret--;
1518
1519 if (readEnabled)
1520 readNotifier->setEnabled(true);
1521
1522 if (ret <= 0)
1523 return ret;
1524
1525 *selectForRead = FD_ISSET((SOCKET)socketDescriptor, &fdread);
1526 *selectForWrite = FD_ISSET((SOCKET)socketDescriptor, &fdwrite);
1527
1528 return ret;
1529}
1530
1532{
1533#if defined (QTCPSOCKETENGINE_DEBUG)
1534 qDebug("QNativeSocketEnginePrivate::nativeClose()");
1535#endif
1536 // We were doing a setsockopt here before with SO_DONTLINGER. (However with kind of wrong
1537 // usage of parameters, it wants a BOOL but we used a struct and pretended it to be bool).
1538 // We don't think setting this option should be done here, if a user wants it she/he can
1539 // do it manually with socketDescriptor()/setSocketDescriptor();
1540 ::closesocket(socketDescriptor);
1541}
1542
static QAbstractEventDispatcher * instance(QThread *thread=nullptr)
Returns a pointer to the event dispatcher object for the specified thread.
QAbstractSocket::NetworkLayerProtocol socketProtocol
QAbstractSocket::SocketState socketState
QAbstractSocket::SocketType socketType
static constexpr auto IPv4Protocol
static constexpr auto UnknownNetworkLayerProtocol
static constexpr auto AnyIPProtocol
static constexpr auto IPv6Protocol
SocketType
This enum describes the transport layer protocol.
const char * constData() const noexcept
Returns a pointer to the const data stored in the byte array.
Definition qbytearray.h:124
\inmodule QtCore
std::chrono::nanoseconds remainingTimeAsDuration() const noexcept
Returns the time remaining before the deadline.
The QHostAddress class provides an IP address.
quint32 toIPv4Address(bool *ok=nullptr) const
Returns the IPv4 address as a number.
void clear()
Sets the host address to null and sets the protocol to QAbstractSocket::UnknownNetworkLayerProtocol.
bool isInSubnet(const QHostAddress &subnet, int netmask) const
void setAddress(quint32 ip4Addr)
Set the IPv4 address specified by ip4Addr.
QString toString() const
Returns the address as a string.
NetworkLayerProtocol protocol() const
Returns the network layer protocol of the host address.
bool createNewSocket(QAbstractSocket::SocketType type, QAbstractSocket::NetworkLayerProtocol &protocol)
QNetworkInterface nativeMulticastInterface() const
qint64 nativeWrite(const char *data, qint64 length)
int option(QNativeSocketEngine::SocketOption option) const
bool nativeJoinMulticastGroup(const QHostAddress &groupAddress, const QNetworkInterface &iface)
bool setOption(QNativeSocketEngine::SocketOption option, int value)
int nativeSelect(QDeadlineTimer deadline, bool selectForRead) const
void setError(QAbstractSocket::SocketError error, ErrorString errorString) const
bool nativeSetMulticastInterface(const QNetworkInterface &iface)
bool fetchConnectionParameters()
Fetches information about both ends of the connection: whatever is available.
bool nativeBind(const QHostAddress &address, quint16 port)
qint64 nativeSendDatagram(const char *data, qint64 length, const QIpPacketHeader &header)
bool nativeConnect(const QHostAddress &address, quint16 port)
void setPortAndAddress(quint16 port, const QHostAddress &address, qt_sockaddr *aa, QT_SOCKLEN_T *sockAddrSize)
bool nativeLeaveMulticastGroup(const QHostAddress &groupAddress, const QNetworkInterface &iface)
qint64 nativeRead(char *data, qint64 maxLength)
qint64 nativeReceiveDatagram(char *data, qint64 maxLength, QIpPacketHeader *header, QAbstractSocketEngine::PacketHeaderOptions options)
The QNativeSocketEngine class provides low level access to a socket.
The QNetworkAddressEntry class stores one IP address supported by a network interface,...
The QNetworkInterface class provides a listing of the host's IP addresses and network interfaces.
static QNetworkInterface interfaceFromIndex(int index)
Returns a QNetworkInterface object for the interface whose internal ID is index.
static QList< QNetworkInterface > allInterfaces()
Returns a listing of all the network interfaces found on the host machine.
\inmodule QtCore
bool isEnabled() const
Returns true if the notifier is enabled; otherwise returns false.
void setEnabled(bool)
If enable is true, the notifier is enabled; otherwise the notifier is disabled.
\macro QT_RESTRICTED_CAST_FROM_ASCII
Definition qstring.h:129
QByteArray toLatin1() const &
Definition qstring.h:630
static QString number(int, int base=10)
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition qstring.cpp:8084
EGLint EGLint EGLint EGLint int int int int * fds
QStyleOptionButton opt
void qErrnoWarning(const char *msg,...)
Combined button and popup list for selecting options.
Q_CORE_EXPORT QByteArray toPrintable(const char *data, qint64 len, qsizetype maxSize)
Definition qdebug.cpp:24
constexpr QBindableInterface iface
Definition qproperty.h:666
#define Q_FALLTHROUGH()
DBusConnection const char DBusError * error
static QString header(const QString &name)
EGLOutputLayerEXT EGLint EGLAttrib value
[5]
EGLOutputPortEXT port
static QT_BEGIN_NAMESPACE const char * socketType(QSocketNotifier::Type type)
#define forever
Definition qforeach.h:78
QIPv6Address Q_IPV6ADDR
#define qDebug
[1]
Definition qlogging.h:164
return ret
static void convertToLevelAndOption(QNativeSocketEngine::SocketOption opt, QAbstractSocket::NetworkLayerProtocol socketProtocol, int &level, int &n)
static QT_BEGIN_NAMESPACE void qt_socket_getPortAndAddress(const qt_sockaddr *s, quint16 *port, QHostAddress *addr)
static bool multicastMembershipHelper(QNativeSocketEnginePrivate *d, int how6, int how4, const QHostAddress &groupAddress, const QNetworkInterface &interface)
#define SO_EXCLUSIVEADDRUSE
static void qt_socket_getPortAndAddress(SOCKET socketDescriptor, const qt_sockaddr *sa, quint16 *port, QHostAddress *address)
static void convertToLevelAndOption(QNativeSocketEngine::SocketOption opt, QAbstractSocket::NetworkLayerProtocol socketProtocol, int &level, int &n)
static bool multicastMembershipHelper(QNativeSocketEnginePrivate *d, int how6, int how4, const QHostAddress &groupAddress, const QNetworkInterface &iface)
#define SIO_UDP_CONNRESET
#define IPV6_V6ONLY
static void setErrorFromWSAError(int error, QNativeSocketEnginePrivate *d)
#define WSA_FLAG_NO_HANDLE_INHERIT
timeval durationToTimeval(std::chrono::nanoseconds dur) noexcept
#define WS_ERROR_DEBUG(x)
static QAbstractSocket::SocketType qt_socket_getType(qintptr socketDescriptor)
#define IP_HOPLIMIT
#define AF_INET6
#define QT_SOCKOPTLEN_T
Definition qnet_unix_p.h:42
GLenum GLsizei GLuint GLint * bytesWritten
GLsizei const GLfloat * v
[13]
GLenum GLuint GLint level
GLboolean GLboolean GLboolean GLboolean a
[7]
GLboolean r
[2]
GLint GLsizei GLsizei GLenum GLenum GLsizei void * data
GLenum type
GLenum GLuint GLenum GLsizei const GLchar * buf
GLbitfield flags
GLfloat n
GLuint res
const GLubyte * c
GLuint GLfloat * val
GLuint entry
GLsizei maxLength
GLenum const void * addr
GLuint GLuint64EXT address
GLdouble GLdouble GLdouble GLdouble q
Definition qopenglext.h:259
GLuint64EXT * result
[6]
GLenum GLsizei len
#define Q_ASSERT(cond)
Definition qrandom.cpp:47
#define QStringLiteral(str)
const char SOCKET[]
Definition uistrings.cpp:29
unsigned int quint32
Definition qtypes.h:50
unsigned char uchar
Definition qtypes.h:32
unsigned short quint16
Definition qtypes.h:48
unsigned int uint
Definition qtypes.h:34
long long qint64
Definition qtypes.h:60
unsigned char quint8
Definition qtypes.h:46
ptrdiff_t qintptr
Definition qtypes.h:166
QStorageInfo storage
[1]
QDeadlineTimer deadline(30s)
QTcpSocket * socket
[1]
selection select(topLeft, bottomRight)
QHostInfo info
[0]
socketLayer bind(QHostAddress::Any, 4000)
socketLayer listen()