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