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