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//#define QNATIVESOCKETENGINE_DEBUG
7#include "qnativesocketengine_p_p.h"
8#include "private/qnet_unix_p.h"
9#include "qdeadlinetimer.h"
10#include "qiodevice.h"
11#include "qhostaddress.h"
12#include "qvarlengtharray.h"
13#include "qnetworkinterface.h"
14#include "qendian.h"
15#ifdef Q_OS_WASM
16#include <private/qeventdispatcher_wasm_p.h>
17#endif
18#include <time.h>
19#include <errno.h>
20#include <fcntl.h>
21#ifdef Q_OS_INTEGRITY
22#include <sys/uio.h>
23#endif
24
25#if defined QNATIVESOCKETENGINE_DEBUG
26#include <private/qdebug_p.h>
27#endif
28
29#include <netinet/tcp.h>
30#ifndef QT_NO_SCTP
31#include <sys/types.h>
32#include <sys/socket.h>
33#include <netinet/sctp.h>
34#endif
35#ifdef Q_OS_BSD4
36# include <net/if_dl.h>
37#endif
38
39QT_BEGIN_NAMESPACE
40
41/*
42 Extracts the port and address from a sockaddr, and stores them in
43 \a port and \a addr if they are non-null.
44*/
45static inline void qt_socket_getPortAndAddress(const qt_sockaddr *s, quint16 *port, QHostAddress *addr)
46{
47 if (s->a.sa_family == AF_INET6) {
48 Q_IPV6ADDR tmp;
49 memcpy(dest: &tmp, src: &s->a6.sin6_addr, n: sizeof(tmp));
50 if (addr) {
51 QHostAddress tmpAddress;
52 tmpAddress.setAddress(tmp);
53 *addr = tmpAddress;
54#if QT_CONFIG(networkinterface)
55 if (s->a6.sin6_scope_id)
56 addr->setScopeId(QNetworkInterface::interfaceNameFromIndex(index: s->a6.sin6_scope_id));
57#endif
58 }
59 if (port)
60 *port = ntohs(netshort: s->a6.sin6_port);
61 return;
62 }
63
64 if (port)
65 *port = ntohs(netshort: s->a4.sin_port);
66 if (addr) {
67 QHostAddress tmpAddress;
68 tmpAddress.setAddress(ntohl(netlong: s->a4.sin_addr.s_addr));
69 *addr = tmpAddress;
70 }
71}
72
73static void convertToLevelAndOption(QNativeSocketEngine::SocketOption opt,
74 QAbstractSocket::NetworkLayerProtocol socketProtocol, int &level, int &n)
75{
76 n = -1;
77 level = SOL_SOCKET; // default
78
79 switch (opt) {
80 case QNativeSocketEngine::NonBlockingSocketOption: // fcntl, not setsockopt
81 case QNativeSocketEngine::BindExclusively: // not handled on Unix
82 case QNativeSocketEngine::MaxStreamsSocketOption:
83 Q_UNREACHABLE();
84
85 case QNativeSocketEngine::BroadcastSocketOption:
86 n = SO_BROADCAST;
87 break;
88 case QNativeSocketEngine::ReceiveBufferSocketOption:
89 n = SO_RCVBUF;
90 break;
91 case QNativeSocketEngine::SendBufferSocketOption:
92 n = SO_SNDBUF;
93 break;
94 case QNativeSocketEngine::AddressReusable:
95 n = SO_REUSEADDR;
96 break;
97 case QNativeSocketEngine::ReceiveOutOfBandData:
98 n = SO_OOBINLINE;
99 break;
100 case QNativeSocketEngine::LowDelayOption:
101 level = IPPROTO_TCP;
102 n = TCP_NODELAY;
103 break;
104 case QNativeSocketEngine::KeepAliveOption:
105 n = SO_KEEPALIVE;
106 break;
107 case QNativeSocketEngine::MulticastTtlOption:
108 if (socketProtocol == QAbstractSocket::IPv6Protocol || socketProtocol == QAbstractSocket::AnyIPProtocol) {
109 level = IPPROTO_IPV6;
110 n = IPV6_MULTICAST_HOPS;
111 } else
112 {
113 level = IPPROTO_IP;
114 n = IP_MULTICAST_TTL;
115 }
116 break;
117 case QNativeSocketEngine::MulticastLoopbackOption:
118 if (socketProtocol == QAbstractSocket::IPv6Protocol || socketProtocol == QAbstractSocket::AnyIPProtocol) {
119 level = IPPROTO_IPV6;
120 n = IPV6_MULTICAST_LOOP;
121 } else
122 {
123 level = IPPROTO_IP;
124 n = IP_MULTICAST_LOOP;
125 }
126 break;
127 case QNativeSocketEngine::TypeOfServiceOption:
128 if (socketProtocol == QAbstractSocket::IPv4Protocol) {
129 level = IPPROTO_IP;
130 n = IP_TOS;
131 }
132 break;
133 case QNativeSocketEngine::ReceivePacketInformation:
134 if (socketProtocol == QAbstractSocket::IPv6Protocol || socketProtocol == QAbstractSocket::AnyIPProtocol) {
135 level = IPPROTO_IPV6;
136 n = IPV6_RECVPKTINFO;
137 } else if (socketProtocol == QAbstractSocket::IPv4Protocol) {
138 level = IPPROTO_IP;
139#ifdef IP_PKTINFO
140 n = IP_PKTINFO;
141#elif defined(IP_RECVDSTADDR)
142 // variant found in QNX and FreeBSD; it will get us only the
143 // destination address, not the interface; we need IP_RECVIF for that.
144 n = IP_RECVDSTADDR;
145#endif
146 }
147 break;
148 case QNativeSocketEngine::ReceiveHopLimit:
149 if (socketProtocol == QAbstractSocket::IPv6Protocol || socketProtocol == QAbstractSocket::AnyIPProtocol) {
150 level = IPPROTO_IPV6;
151 n = IPV6_RECVHOPLIMIT;
152 } else if (socketProtocol == QAbstractSocket::IPv4Protocol) {
153#ifdef IP_RECVTTL // IP_RECVTTL is a non-standard extension supported on some OS
154 level = IPPROTO_IP;
155 n = IP_RECVTTL;
156#endif
157 }
158 break;
159
160 case QNativeSocketEngine::PathMtuInformation:
161 if (socketProtocol == QAbstractSocket::IPv6Protocol || socketProtocol == QAbstractSocket::AnyIPProtocol) {
162#ifdef IPV6_MTU
163 level = IPPROTO_IPV6;
164 n = IPV6_MTU;
165#endif
166 } else {
167#ifdef IP_MTU
168 level = IPPROTO_IP;
169 n = IP_MTU;
170#endif
171 }
172 break;
173 }
174}
175
176/*! \internal
177
178 Creates and returns a new socket descriptor of type \a socketType
179 and \a socketProtocol. Returns -1 on failure.
180*/
181bool QNativeSocketEnginePrivate::createNewSocket(QAbstractSocket::SocketType socketType,
182 QAbstractSocket::NetworkLayerProtocol &socketProtocol)
183{
184#ifndef QT_NO_SCTP
185 int protocol = (socketType == QAbstractSocket::SctpSocket) ? IPPROTO_SCTP : 0;
186#else
187 if (socketType == QAbstractSocket::SctpSocket) {
188 setError(error: QAbstractSocket::UnsupportedSocketOperationError,
189 errorString: ProtocolUnsupportedErrorString);
190#if defined (QNATIVESOCKETENGINE_DEBUG)
191 qDebug("QNativeSocketEnginePrivate::createNewSocket(%d, %d): unsupported protocol",
192 socketType, socketProtocol);
193#endif
194 return false;
195 }
196 int protocol = 0;
197#endif // QT_NO_SCTP
198 int domain = (socketProtocol == QAbstractSocket::IPv6Protocol
199 || socketProtocol == QAbstractSocket::AnyIPProtocol) ? AF_INET6 : AF_INET;
200 int type = (socketType == QAbstractSocket::UdpSocket) ? SOCK_DGRAM : SOCK_STREAM;
201
202 int socket = qt_safe_socket(domain, type, protocol, O_NONBLOCK);
203 if (socket < 0 && socketProtocol == QAbstractSocket::AnyIPProtocol && errno == EAFNOSUPPORT) {
204 domain = AF_INET;
205 socket = qt_safe_socket(domain, type, protocol, O_NONBLOCK);
206 socketProtocol = QAbstractSocket::IPv4Protocol;
207 }
208
209 if (socket < 0) {
210 int ecopy = errno;
211 switch (ecopy) {
212 case EPROTONOSUPPORT:
213 case EAFNOSUPPORT:
214 case EINVAL:
215 setError(error: QAbstractSocket::UnsupportedSocketOperationError, errorString: ProtocolUnsupportedErrorString);
216 break;
217 case ENFILE:
218 case EMFILE:
219 case ENOBUFS:
220 case ENOMEM:
221 setError(error: QAbstractSocket::SocketResourceError, errorString: ResourceErrorString);
222 break;
223 case EACCES:
224 setError(error: QAbstractSocket::SocketAccessError, errorString: AccessErrorString);
225 break;
226 default:
227 break;
228 }
229
230#if defined (QNATIVESOCKETENGINE_DEBUG)
231 qDebug("QNativeSocketEnginePrivate::createNewSocket(%d, %d) == false (%s)",
232 socketType, socketProtocol,
233 strerror(ecopy));
234#endif
235
236 return false;
237 }
238
239#if defined (QNATIVESOCKETENGINE_DEBUG)
240 qDebug("QNativeSocketEnginePrivate::createNewSocket(%d, %d) == true",
241 socketType, socketProtocol);
242#endif
243
244 socketDescriptor = socket;
245 this->socketProtocol = socketProtocol;
246 this->socketType = socketType;
247 return true;
248}
249
250/*
251 Returns the value of the socket option \a opt.
252*/
253int QNativeSocketEnginePrivate::option(QNativeSocketEngine::SocketOption opt) const
254{
255 Q_Q(const QNativeSocketEngine);
256 if (!q->isValid())
257 return -1;
258
259 // handle non-getsockopt and specific cases first
260 switch (opt) {
261 case QNativeSocketEngine::BindExclusively:
262 case QNativeSocketEngine::NonBlockingSocketOption:
263 case QNativeSocketEngine::BroadcastSocketOption:
264 return -1;
265 case QNativeSocketEngine::MaxStreamsSocketOption: {
266#ifndef QT_NO_SCTP
267 sctp_initmsg sctpInitMsg;
268 QT_SOCKOPTLEN_T sctpInitMsgSize = sizeof(sctpInitMsg);
269 if (::getsockopt(socketDescriptor, SOL_SCTP, SCTP_INITMSG, &sctpInitMsg,
270 &sctpInitMsgSize) == 0)
271 return int(qMin(sctpInitMsg.sinit_num_ostreams, sctpInitMsg.sinit_max_instreams));
272#endif
273 return -1;
274 }
275
276 case QNativeSocketEngine::PathMtuInformation:
277#if defined(IPV6_PATHMTU) && !defined(IPV6_MTU)
278 // Prefer IPV6_MTU (handled by convertToLevelAndOption), if available
279 // (Linux); fall back to IPV6_PATHMTU otherwise (FreeBSD):
280 if (socketProtocol == QAbstractSocket::IPv6Protocol) {
281 ip6_mtuinfo mtuinfo;
282 QT_SOCKOPTLEN_T len = sizeof(mtuinfo);
283 if (::getsockopt(socketDescriptor, IPPROTO_IPV6, IPV6_PATHMTU, &mtuinfo, &len) == 0)
284 return int(mtuinfo.ip6m_mtu);
285 return -1;
286 }
287#endif
288 break;
289
290 default:
291 break;
292 }
293
294 int n, level;
295 int v = 0;
296 QT_SOCKOPTLEN_T len = sizeof(v);
297
298 convertToLevelAndOption(opt, socketProtocol, level, n);
299 if (n != -1 && ::getsockopt(fd: socketDescriptor, level: level, optname: n, optval: (char *) &v, optlen: &len) != -1)
300 return len == 1 ? qFromUnaligned<quint8>(src: &v) : v;
301
302 return -1;
303}
304
305
306/*
307 Sets the socket option \a opt to \a v.
308*/
309bool QNativeSocketEnginePrivate::setOption(QNativeSocketEngine::SocketOption opt, int v)
310{
311 Q_Q(QNativeSocketEngine);
312 if (!q->isValid())
313 return false;
314
315 // handle non-setsockopt and specific cases first
316 switch (opt) {
317 case QNativeSocketEngine::NonBlockingSocketOption: {
318 // Make the socket nonblocking.
319#if !defined(Q_OS_VXWORKS)
320 int flags = ::fcntl(fd: socketDescriptor, F_GETFL, 0);
321 if (flags == -1) {
322#ifdef QNATIVESOCKETENGINE_DEBUG
323 perror("QNativeSocketEnginePrivate::setOption(): fcntl(F_GETFL) failed");
324#endif
325 return false;
326 }
327 if (::fcntl(fd: socketDescriptor, F_SETFL, flags | O_NONBLOCK) == -1) {
328#ifdef QNATIVESOCKETENGINE_DEBUG
329 perror("QNativeSocketEnginePrivate::setOption(): fcntl(F_SETFL) failed");
330#endif
331 return false;
332 }
333#else // Q_OS_VXWORKS
334 int onoff = 1;
335
336 if (qt_safe_ioctl(socketDescriptor, FIONBIO, &onoff) < 0) {
337
338#ifdef QNATIVESOCKETENGINE_DEBUG
339 perror("QNativeSocketEnginePrivate::setOption(): ioctl(FIONBIO, 1) failed");
340#endif
341 return false;
342 }
343#endif // Q_OS_VXWORKS
344 return true;
345 }
346 case QNativeSocketEngine::BindExclusively:
347 return true;
348
349 case QNativeSocketEngine::MaxStreamsSocketOption: {
350#ifndef QT_NO_SCTP
351 sctp_initmsg sctpInitMsg;
352 QT_SOCKOPTLEN_T sctpInitMsgSize = sizeof(sctpInitMsg);
353 if (::getsockopt(socketDescriptor, SOL_SCTP, SCTP_INITMSG, &sctpInitMsg,
354 &sctpInitMsgSize) == 0) {
355 sctpInitMsg.sinit_num_ostreams = sctpInitMsg.sinit_max_instreams = uint16_t(v);
356 return ::setsockopt(socketDescriptor, SOL_SCTP, SCTP_INITMSG, &sctpInitMsg,
357 sctpInitMsgSize) == 0;
358 }
359#endif
360 return false;
361 }
362
363 default:
364 break;
365 }
366
367 int n, level;
368 convertToLevelAndOption(opt, socketProtocol, level, n);
369#if defined(SO_REUSEPORT) && !defined(Q_OS_LINUX)
370 if (opt == QNativeSocketEngine::AddressReusable) {
371 // on OS X, SO_REUSEADDR isn't sufficient to allow multiple binds to the
372 // same port (which is useful for multicast UDP). SO_REUSEPORT is, but
373 // we most definitely do not want to use this for TCP. See QTBUG-6305.
374 if (socketType == QAbstractSocket::UdpSocket)
375 n = SO_REUSEPORT;
376 }
377#endif
378
379 if (n == -1)
380 return false;
381 return ::setsockopt(fd: socketDescriptor, level: level, optname: n, optval: (char *) &v, optlen: sizeof(v)) == 0;
382}
383
384bool QNativeSocketEnginePrivate::nativeConnect(const QHostAddress &addr, quint16 port)
385{
386#ifdef QNATIVESOCKETENGINE_DEBUG
387 qDebug() << "QNativeSocketEnginePrivate::nativeConnect() " << socketDescriptor;
388#endif
389
390 qt_sockaddr aa;
391 QT_SOCKLEN_T sockAddrSize;
392 setPortAndAddress(port, address: addr, aa: &aa, sockAddrSize: &sockAddrSize);
393
394 int connectResult = qt_safe_connect(sockfd: socketDescriptor, addr: &aa.a, addrlen: sockAddrSize);
395#if defined (QNATIVESOCKETENGINE_DEBUG)
396 int ecopy = errno;
397#endif
398 if (connectResult == -1) {
399 switch (errno) {
400 case EISCONN:
401 socketState = QAbstractSocket::ConnectedState;
402 break;
403 case ECONNREFUSED:
404 case EINVAL:
405 case ENOENT:
406 setError(error: QAbstractSocket::ConnectionRefusedError, errorString: ConnectionRefusedErrorString);
407 socketState = QAbstractSocket::UnconnectedState;
408 break;
409 case ETIMEDOUT:
410 setError(error: QAbstractSocket::NetworkError, errorString: ConnectionTimeOutErrorString);
411 break;
412 case EHOSTUNREACH:
413 setError(error: QAbstractSocket::NetworkError, errorString: HostUnreachableErrorString);
414 socketState = QAbstractSocket::UnconnectedState;
415 break;
416 case ENETUNREACH:
417 setError(error: QAbstractSocket::NetworkError, errorString: NetworkUnreachableErrorString);
418 socketState = QAbstractSocket::UnconnectedState;
419 break;
420 case EADDRINUSE:
421 setError(error: QAbstractSocket::NetworkError, errorString: AddressInuseErrorString);
422 break;
423 case EINPROGRESS:
424 case EALREADY:
425 setError(error: QAbstractSocket::UnfinishedSocketOperationError, errorString: InvalidSocketErrorString);
426 socketState = QAbstractSocket::ConnectingState;
427 break;
428 case EAGAIN:
429 setError(error: QAbstractSocket::UnfinishedSocketOperationError, errorString: InvalidSocketErrorString);
430 break;
431 case EACCES:
432 case EPERM:
433 setError(error: QAbstractSocket::SocketAccessError, errorString: AccessErrorString);
434 socketState = QAbstractSocket::UnconnectedState;
435 break;
436 case EAFNOSUPPORT:
437 case EBADF:
438 case EFAULT:
439 case ENOTSOCK:
440 socketState = QAbstractSocket::UnconnectedState;
441 break;
442 default:
443 break;
444 }
445
446 if (socketState != QAbstractSocket::ConnectedState) {
447#if defined (QNATIVESOCKETENGINE_DEBUG)
448 qDebug("QNativeSocketEnginePrivate::nativeConnect(%s, %i) == false (%s)",
449 addr.toString().toLatin1().constData(), port,
450 socketState == QAbstractSocket::ConnectingState
451 ? "Connection in progress" : strerror(ecopy));
452#endif
453 return false;
454 }
455 }
456
457#if defined (QNATIVESOCKETENGINE_DEBUG)
458 qDebug("QNativeSocketEnginePrivate::nativeConnect(%s, %i) == true",
459 addr.toString().toLatin1().constData(), port);
460#endif
461
462 socketState = QAbstractSocket::ConnectedState;
463 return true;
464}
465
466bool QNativeSocketEnginePrivate::nativeBind(const QHostAddress &address, quint16 port)
467{
468 qt_sockaddr aa;
469 QT_SOCKLEN_T sockAddrSize;
470 setPortAndAddress(port, address, aa: &aa, sockAddrSize: &sockAddrSize);
471
472#ifdef IPV6_V6ONLY
473 if (aa.a.sa_family == AF_INET6) {
474 int ipv6only = 0;
475 if (address.protocol() == QAbstractSocket::IPv6Protocol)
476 ipv6only = 1;
477 //default value of this socket option varies depending on unix variant (or system configuration on BSD), so always set it explicitly
478 ::setsockopt(fd: socketDescriptor, IPPROTO_IPV6, IPV6_V6ONLY, optval: (char*)&ipv6only, optlen: sizeof(ipv6only) );
479 }
480#endif
481
482 int bindResult = QT_SOCKET_BIND(fd: socketDescriptor, addr: &aa.a, len: sockAddrSize);
483 if (bindResult < 0 && errno == EAFNOSUPPORT && address.protocol() == QAbstractSocket::AnyIPProtocol) {
484 // retry with v4
485 aa.a4.sin_family = AF_INET;
486 aa.a4.sin_port = htons(hostshort: port);
487 aa.a4.sin_addr.s_addr = htonl(hostlong: address.toIPv4Address());
488 sockAddrSize = sizeof(aa.a4);
489 bindResult = QT_SOCKET_BIND(fd: socketDescriptor, addr: &aa.a, len: sockAddrSize);
490 }
491
492 if (bindResult < 0) {
493#if defined (QNATIVESOCKETENGINE_DEBUG)
494 int ecopy = errno;
495#endif
496 switch(errno) {
497 case EADDRINUSE:
498 setError(error: QAbstractSocket::AddressInUseError, errorString: AddressInuseErrorString);
499 break;
500 case EACCES:
501 setError(error: QAbstractSocket::SocketAccessError, errorString: AddressProtectedErrorString);
502 break;
503 case EINVAL:
504 setError(error: QAbstractSocket::UnsupportedSocketOperationError, errorString: OperationUnsupportedErrorString);
505 break;
506 case EADDRNOTAVAIL:
507 setError(error: QAbstractSocket::SocketAddressNotAvailableError, errorString: AddressNotAvailableErrorString);
508 break;
509 default:
510 break;
511 }
512
513#if defined (QNATIVESOCKETENGINE_DEBUG)
514 qDebug("QNativeSocketEnginePrivate::nativeBind(%s, %i) == false (%s)",
515 address.toString().toLatin1().constData(), port, strerror(ecopy));
516#endif
517
518 return false;
519 }
520
521#if defined (QNATIVESOCKETENGINE_DEBUG)
522 qDebug("QNativeSocketEnginePrivate::nativeBind(%s, %i) == true",
523 address.toString().toLatin1().constData(), port);
524#endif
525 socketState = QAbstractSocket::BoundState;
526 return true;
527}
528
529bool QNativeSocketEnginePrivate::nativeListen(int backlog)
530{
531 if (qt_safe_listen(s: socketDescriptor, backlog) < 0) {
532#if defined (QNATIVESOCKETENGINE_DEBUG)
533 int ecopy = errno;
534#endif
535 switch (errno) {
536 case EADDRINUSE:
537 setError(error: QAbstractSocket::AddressInUseError,
538 errorString: PortInuseErrorString);
539 break;
540 default:
541 break;
542 }
543
544#if defined (QNATIVESOCKETENGINE_DEBUG)
545 qDebug("QNativeSocketEnginePrivate::nativeListen(%i) == false (%s)",
546 backlog, strerror(ecopy));
547#endif
548 return false;
549 }
550
551#if defined (QNATIVESOCKETENGINE_DEBUG)
552 qDebug("QNativeSocketEnginePrivate::nativeListen(%i) == true", backlog);
553#endif
554
555 socketState = QAbstractSocket::ListeningState;
556 return true;
557}
558
559qintptr QNativeSocketEnginePrivate::nativeAccept()
560{
561 int acceptedDescriptor = qt_safe_accept(s: socketDescriptor, addr: nullptr, addrlen: nullptr);
562 if (acceptedDescriptor == -1) {
563 switch (errno) {
564 case EBADF:
565 case EOPNOTSUPP:
566 setError(error: QAbstractSocket::UnsupportedSocketOperationError, errorString: InvalidSocketErrorString);
567 break;
568 case ECONNABORTED:
569 setError(error: QAbstractSocket::NetworkError, errorString: RemoteHostClosedErrorString);
570 break;
571 case EFAULT:
572 case ENOTSOCK:
573 setError(error: QAbstractSocket::SocketResourceError, errorString: NotSocketErrorString);
574 break;
575 case EPROTONOSUPPORT:
576#if !defined(Q_OS_OPENBSD)
577 case EPROTO:
578#endif
579 case EAFNOSUPPORT:
580 case EINVAL:
581 setError(error: QAbstractSocket::UnsupportedSocketOperationError, errorString: ProtocolUnsupportedErrorString);
582 break;
583 case ENFILE:
584 case EMFILE:
585 case ENOBUFS:
586 case ENOMEM:
587 setError(error: QAbstractSocket::SocketResourceError, errorString: ResourceErrorString);
588 break;
589 case EACCES:
590 case EPERM:
591 setError(error: QAbstractSocket::SocketAccessError, errorString: AccessErrorString);
592 break;
593#if EAGAIN != EWOULDBLOCK
594 case EWOULDBLOCK:
595#endif
596 case EAGAIN:
597 setError(error: QAbstractSocket::TemporaryError, errorString: TemporaryErrorString);
598 break;
599 default:
600 setError(error: QAbstractSocket::UnknownSocketError, errorString: UnknownSocketErrorString);
601 break;
602 }
603 }
604
605 return qintptr(acceptedDescriptor);
606}
607
608#ifndef QT_NO_NETWORKINTERFACE
609
610static bool multicastMembershipHelper(QNativeSocketEnginePrivate *d,
611 int how6,
612 int how4,
613 const QHostAddress &groupAddress,
614 const QNetworkInterface &interface)
615{
616 int level = 0;
617 int sockOpt = 0;
618 void *sockArg;
619 int sockArgSize;
620
621 ip_mreq mreq4;
622 ipv6_mreq mreq6;
623
624 if (groupAddress.protocol() == QAbstractSocket::IPv6Protocol) {
625 level = IPPROTO_IPV6;
626 sockOpt = how6;
627 sockArg = &mreq6;
628 sockArgSize = sizeof(mreq6);
629 memset(s: &mreq6, c: 0, n: sizeof(mreq6));
630 Q_IPV6ADDR ip6 = groupAddress.toIPv6Address();
631 memcpy(dest: &mreq6.ipv6mr_multiaddr, src: &ip6, n: sizeof(ip6));
632 mreq6.ipv6mr_interface = interface.index();
633 } else if (groupAddress.protocol() == QAbstractSocket::IPv4Protocol) {
634 level = IPPROTO_IP;
635 sockOpt = how4;
636 sockArg = &mreq4;
637 sockArgSize = sizeof(mreq4);
638 memset(s: &mreq4, c: 0, n: sizeof(mreq4));
639 mreq4.imr_multiaddr.s_addr = htonl(hostlong: groupAddress.toIPv4Address());
640
641 if (interface.isValid()) {
642 const QList<QNetworkAddressEntry> addressEntries = interface.addressEntries();
643 bool found = false;
644 for (const QNetworkAddressEntry &entry : addressEntries) {
645 const QHostAddress ip = entry.ip();
646 if (ip.protocol() == QAbstractSocket::IPv4Protocol) {
647 mreq4.imr_interface.s_addr = htonl(hostlong: ip.toIPv4Address());
648 found = true;
649 break;
650 }
651 }
652 if (!found) {
653 d->setError(error: QAbstractSocket::NetworkError,
654 errorString: QNativeSocketEnginePrivate::NetworkUnreachableErrorString);
655 return false;
656 }
657 } else {
658 mreq4.imr_interface.s_addr = INADDR_ANY;
659 }
660 } else {
661 // unreachable
662 d->setError(error: QAbstractSocket::UnsupportedSocketOperationError,
663 errorString: QNativeSocketEnginePrivate::ProtocolUnsupportedErrorString);
664 return false;
665 }
666
667 int res = setsockopt(fd: d->socketDescriptor, level: level, optname: sockOpt, optval: sockArg, optlen: sockArgSize);
668 if (res == -1) {
669 switch (errno) {
670 case ENOPROTOOPT:
671 d->setError(error: QAbstractSocket::UnsupportedSocketOperationError,
672 errorString: QNativeSocketEnginePrivate::OperationUnsupportedErrorString);
673 break;
674 case EADDRNOTAVAIL:
675 d->setError(error: QAbstractSocket::SocketAddressNotAvailableError,
676 errorString: QNativeSocketEnginePrivate::AddressNotAvailableErrorString);
677 break;
678 default:
679 d->setError(error: QAbstractSocket::UnknownSocketError,
680 errorString: QNativeSocketEnginePrivate::UnknownSocketErrorString);
681 break;
682 }
683 return false;
684 }
685 return true;
686}
687
688bool QNativeSocketEnginePrivate::nativeJoinMulticastGroup(const QHostAddress &groupAddress,
689 const QNetworkInterface &interface)
690{
691 return multicastMembershipHelper(d: this,
692 IPV6_JOIN_GROUP,
693 IP_ADD_MEMBERSHIP,
694 groupAddress,
695 interface);
696}
697
698bool QNativeSocketEnginePrivate::nativeLeaveMulticastGroup(const QHostAddress &groupAddress,
699 const QNetworkInterface &interface)
700{
701 return multicastMembershipHelper(d: this,
702 IPV6_LEAVE_GROUP,
703 IP_DROP_MEMBERSHIP,
704 groupAddress,
705 interface);
706}
707
708QNetworkInterface QNativeSocketEnginePrivate::nativeMulticastInterface() const
709{
710 if (socketProtocol == QAbstractSocket::IPv6Protocol || socketProtocol == QAbstractSocket::AnyIPProtocol) {
711 uint v;
712 QT_SOCKOPTLEN_T sizeofv = sizeof(v);
713 if (::getsockopt(fd: socketDescriptor, IPPROTO_IPV6, IPV6_MULTICAST_IF, optval: &v, optlen: &sizeofv) == -1)
714 return QNetworkInterface();
715 return QNetworkInterface::interfaceFromIndex(index: v);
716 }
717
718#if defined(Q_OS_SOLARIS)
719 struct in_addr v = { 0, 0, 0, 0};
720#else
721 struct in_addr v = { .s_addr: 0 };
722#endif
723 QT_SOCKOPTLEN_T sizeofv = sizeof(v);
724 if (::getsockopt(fd: socketDescriptor, IPPROTO_IP, IP_MULTICAST_IF, optval: &v, optlen: &sizeofv) == -1)
725 return QNetworkInterface();
726 if (v.s_addr != 0 && sizeofv >= QT_SOCKOPTLEN_T(sizeof(v))) {
727 QHostAddress ipv4(ntohl(netlong: v.s_addr));
728 QList<QNetworkInterface> ifaces = QNetworkInterface::allInterfaces();
729 for (int i = 0; i < ifaces.size(); ++i) {
730 const QNetworkInterface &iface = ifaces.at(i);
731 QList<QNetworkAddressEntry> entries = iface.addressEntries();
732 for (int j = 0; j < entries.size(); ++j) {
733 const QNetworkAddressEntry &entry = entries.at(i: j);
734 if (entry.ip() == ipv4)
735 return iface;
736 }
737 }
738 }
739 return QNetworkInterface();
740}
741
742bool QNativeSocketEnginePrivate::nativeSetMulticastInterface(const QNetworkInterface &iface)
743{
744 if (socketProtocol == QAbstractSocket::IPv6Protocol || socketProtocol == QAbstractSocket::AnyIPProtocol) {
745 uint v = iface.index();
746 return (::setsockopt(fd: socketDescriptor, IPPROTO_IPV6, IPV6_MULTICAST_IF, optval: &v, optlen: sizeof(v)) != -1);
747 }
748
749 struct in_addr v;
750 if (iface.isValid()) {
751 QList<QNetworkAddressEntry> entries = iface.addressEntries();
752 for (int i = 0; i < entries.size(); ++i) {
753 const QNetworkAddressEntry &entry = entries.at(i);
754 const QHostAddress &ip = entry.ip();
755 if (ip.protocol() == QAbstractSocket::IPv4Protocol) {
756 v.s_addr = htonl(hostlong: ip.toIPv4Address());
757 int r = ::setsockopt(fd: socketDescriptor, IPPROTO_IP, IP_MULTICAST_IF, optval: &v, optlen: sizeof(v));
758 if (r != -1)
759 return true;
760 }
761 }
762 return false;
763 }
764
765 v.s_addr = INADDR_ANY;
766 return (::setsockopt(fd: socketDescriptor, IPPROTO_IP, IP_MULTICAST_IF, optval: &v, optlen: sizeof(v)) != -1);
767}
768
769#endif // QT_NO_NETWORKINTERFACE
770
771qint64 QNativeSocketEnginePrivate::nativeBytesAvailable() const
772{
773 int nbytes = 0;
774 // gives shorter than true amounts on Unix domain sockets.
775 qint64 available = -1;
776
777#if defined (SO_NREAD)
778 if (socketType == QAbstractSocket::UdpSocket) {
779 socklen_t sz = sizeof nbytes;
780 if (!::getsockopt(socketDescriptor, SOL_SOCKET, SO_NREAD, &nbytes, &sz))
781 available = nbytes;
782 }
783#endif
784
785 if (available == -1 && qt_safe_ioctl(sockfd: socketDescriptor, FIONREAD, arg: (char *) &nbytes) >= 0)
786 available = nbytes;
787
788#if defined (QNATIVESOCKETENGINE_DEBUG)
789 qDebug("QNativeSocketEnginePrivate::nativeBytesAvailable() == %lli", available);
790#endif
791 return available > 0 ? available : 0;
792}
793
794bool QNativeSocketEnginePrivate::nativeHasPendingDatagrams() const
795{
796 // Peek 1 bytes into the next message.
797 ssize_t readBytes;
798 char c;
799 QT_EINTR_LOOP(readBytes, ::recv(socketDescriptor, &c, 1, MSG_PEEK));
800
801 // If there's no error, or if our buffer was too small, there must be a
802 // pending datagram.
803 bool result = (readBytes != -1) || errno == EMSGSIZE;
804
805#if defined (QNATIVESOCKETENGINE_DEBUG)
806 qDebug("QNativeSocketEnginePrivate::nativeHasPendingDatagrams() == %s",
807 result ? "true" : "false");
808#endif
809 return result;
810}
811
812qint64 QNativeSocketEnginePrivate::nativePendingDatagramSize() const
813{
814 ssize_t recvResult = -1;
815#ifdef Q_OS_LINUX
816 // Linux can return the actual datagram size if we use MSG_TRUNC
817 char c;
818 QT_EINTR_LOOP(recvResult, ::recv(socketDescriptor, &c, 1, MSG_PEEK | MSG_TRUNC));
819#elif defined(SO_NREAD)
820 // macOS can return the actual datagram size if we use SO_NREAD
821 int value;
822 socklen_t valuelen = sizeof(value);
823 recvResult = getsockopt(socketDescriptor, SOL_SOCKET, SO_NREAD, &value, &valuelen);
824 if (recvResult != -1)
825 recvResult = value;
826#elif defined(Q_OS_VXWORKS)
827 // VxWorks: use ioctl(FIONREAD) to query the number of bytes available
828 int available = 0;
829 int ioctlResult = ::ioctl(socketDescriptor, FIONREAD, &available);
830 if (ioctlResult != -1)
831 recvResult = available;
832#else
833 // We need to grow the buffer to fit the entire datagram.
834 // We start at 1500 bytes (the MTU for Ethernet V2), which should catch
835 // almost all uses (effective MTU for UDP under IPv4 is 1468), except
836 // for localhost datagrams and those reassembled by the IP layer.
837 char udpMessagePeekBuffer[1500];
838 struct msghdr msg;
839 struct iovec vec;
840
841 memset(&msg, 0, sizeof(msg));
842 msg.msg_iov = &vec;
843 msg.msg_iovlen = 1;
844 vec.iov_base = udpMessagePeekBuffer;
845 vec.iov_len = sizeof(udpMessagePeekBuffer);
846
847 for (;;) {
848 // the data written to udpMessagePeekBuffer is discarded, so
849 // this function is still reentrant although it might not look
850 // so.
851 recvResult = ::recvmsg(socketDescriptor, &msg, MSG_PEEK);
852 if (recvResult == -1 && errno == EINTR)
853 continue;
854
855 // was the result truncated?
856 if ((msg.msg_flags & MSG_TRUNC) == 0)
857 break;
858
859 // grow by 16 times
860 msg.msg_iovlen *= 16;
861 if (msg.msg_iov != &vec)
862 delete[] msg.msg_iov;
863 msg.msg_iov = new struct iovec[msg.msg_iovlen];
864 std::fill_n(msg.msg_iov, msg.msg_iovlen, vec);
865 }
866
867 if (msg.msg_iov != &vec)
868 delete[] msg.msg_iov;
869#endif
870
871#if defined (QNATIVESOCKETENGINE_DEBUG)
872 qDebug("QNativeSocketEnginePrivate::nativePendingDatagramSize() == %zd", recvResult);
873#endif
874
875 return qint64(recvResult);
876}
877
878qint64 QNativeSocketEnginePrivate::nativeReceiveDatagram(char *data, qint64 maxSize, QIpPacketHeader *header,
879 QAbstractSocketEngine::PacketHeaderOptions options)
880{
881 // we use quintptr to force the alignment
882 quintptr cbuf[(CMSG_SPACE(sizeof(struct in6_pktinfo)) + CMSG_SPACE(sizeof(int))
883#if !defined(IP_PKTINFO) && defined(IP_RECVIF) && defined(Q_OS_BSD4)
884 + CMSG_SPACE(sizeof(sockaddr_dl))
885#endif
886#ifndef QT_NO_SCTP
887 + CMSG_SPACE(sizeof(struct sctp_sndrcvinfo))
888#endif
889 + sizeof(quintptr) - 1) / sizeof(quintptr)];
890
891 struct msghdr msg;
892 struct iovec vec;
893 qt_sockaddr aa;
894 char c;
895 memset(s: &msg, c: 0, n: sizeof(msg));
896 memset(s: &aa, c: 0, n: sizeof(aa));
897
898 // we need to receive at least one byte, even if our user isn't interested in it
899 vec.iov_base = maxSize ? data : &c;
900 vec.iov_len = maxSize ? maxSize : 1;
901 msg.msg_iov = &vec;
902 msg.msg_iovlen = 1;
903 if (options & QAbstractSocketEngine::WantDatagramSender) {
904 msg.msg_name = &aa;
905 msg.msg_namelen = sizeof(aa);
906 }
907 if (options & (QAbstractSocketEngine::WantDatagramHopLimit | QAbstractSocketEngine::WantDatagramDestination
908 | QAbstractSocketEngine::WantStreamNumber)) {
909 msg.msg_control = cbuf;
910 msg.msg_controllen = sizeof(cbuf);
911 }
912
913 ssize_t recvResult = 0;
914 do {
915 recvResult = ::recvmsg(fd: socketDescriptor, message: &msg, flags: 0);
916 } while (recvResult == -1 && errno == EINTR);
917
918 if (recvResult == -1) {
919 switch (errno) {
920#if defined(EWOULDBLOCK) && EWOULDBLOCK != EAGAIN
921 case EWOULDBLOCK:
922#endif
923 case EAGAIN:
924 // No datagram was available for reading
925 recvResult = -2;
926 break;
927 case ECONNREFUSED:
928 setError(error: QAbstractSocket::ConnectionRefusedError, errorString: ConnectionRefusedErrorString);
929 break;
930 default:
931 setError(error: QAbstractSocket::NetworkError, errorString: ReceiveDatagramErrorString);
932 }
933 if (header)
934 header->clear();
935 } else if (options != QAbstractSocketEngine::WantNone) {
936 Q_ASSERT(header);
937 qt_socket_getPortAndAddress(s: &aa, port: &header->senderPort, addr: &header->senderAddress);
938 header->destinationPort = localPort;
939 header->endOfRecord = (msg.msg_flags & MSG_EOR) != 0;
940
941 // parse the ancillary data
942 struct cmsghdr *cmsgptr;
943 QT_WARNING_PUSH
944 QT_WARNING_DISABLE_CLANG("-Wsign-compare")
945 for (cmsgptr = CMSG_FIRSTHDR(&msg); cmsgptr != nullptr;
946 cmsgptr = CMSG_NXTHDR(&msg, cmsgptr)) {
947 QT_WARNING_POP
948 if (cmsgptr->cmsg_level == IPPROTO_IPV6 && cmsgptr->cmsg_type == IPV6_PKTINFO
949 && cmsgptr->cmsg_len >= CMSG_LEN(sizeof(in6_pktinfo))) {
950 in6_pktinfo *info = reinterpret_cast<in6_pktinfo *>(CMSG_DATA(cmsgptr));
951
952 header->destinationAddress.setAddress(reinterpret_cast<quint8 *>(&info->ipi6_addr));
953 header->ifindex = info->ipi6_ifindex;
954 if (header->ifindex)
955 header->destinationAddress.setScopeId(QString::number(info->ipi6_ifindex));
956 }
957
958#ifdef IP_PKTINFO
959 if (cmsgptr->cmsg_level == IPPROTO_IP && cmsgptr->cmsg_type == IP_PKTINFO
960 && cmsgptr->cmsg_len >= CMSG_LEN(sizeof(in_pktinfo))) {
961 in_pktinfo *info = reinterpret_cast<in_pktinfo *>(CMSG_DATA(cmsgptr));
962
963 header->destinationAddress.setAddress(ntohl(netlong: info->ipi_addr.s_addr));
964 header->ifindex = info->ipi_ifindex;
965 }
966#else
967# ifdef IP_RECVDSTADDR
968 if (cmsgptr->cmsg_level == IPPROTO_IP && cmsgptr->cmsg_type == IP_RECVDSTADDR
969 && cmsgptr->cmsg_len >= CMSG_LEN(sizeof(in_addr))) {
970 in_addr *addr = reinterpret_cast<in_addr *>(CMSG_DATA(cmsgptr));
971
972 header->destinationAddress.setAddress(ntohl(addr->s_addr));
973 }
974# endif
975# if defined(IP_RECVIF) && defined(Q_OS_BSD4)
976 if (cmsgptr->cmsg_level == IPPROTO_IP && cmsgptr->cmsg_type == IP_RECVIF
977 && cmsgptr->cmsg_len >= CMSG_LEN(sizeof(sockaddr_dl))) {
978 sockaddr_dl *sdl = reinterpret_cast<sockaddr_dl *>(CMSG_DATA(cmsgptr));
979 header->ifindex = sdl->sdl_index;
980 }
981# endif
982#endif
983
984 if (cmsgptr->cmsg_len == CMSG_LEN(sizeof(int))
985 && ((cmsgptr->cmsg_level == IPPROTO_IPV6 && cmsgptr->cmsg_type == IPV6_HOPLIMIT)
986 || (cmsgptr->cmsg_level == IPPROTO_IP && cmsgptr->cmsg_type == IP_TTL))) {
987 static_assert(sizeof(header->hopLimit) == sizeof(int));
988 memcpy(dest: &header->hopLimit, CMSG_DATA(cmsgptr), n: sizeof(header->hopLimit));
989 }
990
991#ifndef QT_NO_SCTP
992 if (cmsgptr->cmsg_level == IPPROTO_SCTP && cmsgptr->cmsg_type == SCTP_SNDRCV
993 && cmsgptr->cmsg_len >= CMSG_LEN(sizeof(sctp_sndrcvinfo))) {
994 sctp_sndrcvinfo *rcvInfo = reinterpret_cast<sctp_sndrcvinfo *>(CMSG_DATA(cmsgptr));
995
996 header->streamNumber = int(rcvInfo->sinfo_stream);
997 }
998#endif
999 }
1000 }
1001
1002#if defined (QNATIVESOCKETENGINE_DEBUG)
1003 qDebug("QNativeSocketEnginePrivate::nativeReceiveDatagram(%p \"%s\", %lli, %s, %i) == %lli",
1004 data, QtDebugUtils::toPrintable(data, recvResult, 16).constData(), maxSize,
1005 (recvResult != -1 && options != QAbstractSocketEngine::WantNone)
1006 ? header->senderAddress.toString().toLatin1().constData() : "(unknown)",
1007 (recvResult != -1 && options != QAbstractSocketEngine::WantNone)
1008 ? header->senderPort : 0, (qint64) recvResult);
1009#endif
1010
1011 return qint64((maxSize || recvResult < 0) ? recvResult : Q_INT64_C(0));
1012}
1013
1014qint64 QNativeSocketEnginePrivate::nativeSendDatagram(const char *data, qint64 len, const QIpPacketHeader &header)
1015{
1016 // we use quintptr to force the alignment
1017 quintptr cbuf[(CMSG_SPACE(sizeof(struct in6_pktinfo)) + CMSG_SPACE(sizeof(int))
1018#ifndef QT_NO_SCTP
1019 + CMSG_SPACE(sizeof(struct sctp_sndrcvinfo))
1020#endif
1021 + sizeof(quintptr) - 1) / sizeof(quintptr)];
1022
1023 struct cmsghdr *cmsgptr = reinterpret_cast<struct cmsghdr *>(cbuf);
1024 struct msghdr msg;
1025 struct iovec vec;
1026 qt_sockaddr aa;
1027
1028 memset(s: &msg, c: 0, n: sizeof(msg));
1029 memset(s: &aa, c: 0, n: sizeof(aa));
1030 vec.iov_base = const_cast<char *>(data);
1031 vec.iov_len = len;
1032 msg.msg_iov = &vec;
1033 msg.msg_iovlen = 1;
1034 msg.msg_control = &cbuf;
1035
1036 if (header.destinationPort != 0) {
1037 msg.msg_name = &aa.a;
1038 setPortAndAddress(port: header.destinationPort, address: header.destinationAddress,
1039 aa: &aa, sockAddrSize: &msg.msg_namelen);
1040 }
1041
1042 if (msg.msg_namelen == sizeof(aa.a6)) {
1043 if (header.hopLimit != -1) {
1044 msg.msg_controllen += CMSG_SPACE(sizeof(int));
1045 cmsgptr->cmsg_len = CMSG_LEN(sizeof(int));
1046 cmsgptr->cmsg_level = IPPROTO_IPV6;
1047 cmsgptr->cmsg_type = IPV6_HOPLIMIT;
1048 memcpy(CMSG_DATA(cmsgptr), src: &header.hopLimit, n: sizeof(int));
1049 cmsgptr = reinterpret_cast<cmsghdr *>(reinterpret_cast<char *>(cmsgptr) + CMSG_SPACE(sizeof(int)));
1050 }
1051 if (header.ifindex != 0 || !header.senderAddress.isNull()) {
1052 struct in6_pktinfo *data = reinterpret_cast<in6_pktinfo *>(CMSG_DATA(cmsgptr));
1053 memset(s: data, c: 0, n: sizeof(*data));
1054 msg.msg_controllen += CMSG_SPACE(sizeof(*data));
1055 cmsgptr->cmsg_len = CMSG_LEN(sizeof(*data));
1056 cmsgptr->cmsg_level = IPPROTO_IPV6;
1057 cmsgptr->cmsg_type = IPV6_PKTINFO;
1058 data->ipi6_ifindex = header.ifindex;
1059
1060 QIPv6Address tmp = header.senderAddress.toIPv6Address();
1061 memcpy(dest: &data->ipi6_addr, src: &tmp, n: sizeof(tmp));
1062 cmsgptr = reinterpret_cast<cmsghdr *>(reinterpret_cast<char *>(cmsgptr) + CMSG_SPACE(sizeof(*data)));
1063 }
1064 } else {
1065 if (header.hopLimit != -1) {
1066 msg.msg_controllen += CMSG_SPACE(sizeof(int));
1067 cmsgptr->cmsg_len = CMSG_LEN(sizeof(int));
1068 cmsgptr->cmsg_level = IPPROTO_IP;
1069 cmsgptr->cmsg_type = IP_TTL;
1070 memcpy(CMSG_DATA(cmsgptr), src: &header.hopLimit, n: sizeof(int));
1071 cmsgptr = reinterpret_cast<cmsghdr *>(reinterpret_cast<char *>(cmsgptr) + CMSG_SPACE(sizeof(int)));
1072 }
1073
1074#if defined(IP_PKTINFO) || defined(IP_SENDSRCADDR)
1075 if (header.ifindex != 0 || !header.senderAddress.isNull()) {
1076# ifdef IP_PKTINFO
1077 struct in_pktinfo *data = reinterpret_cast<in_pktinfo *>(CMSG_DATA(cmsgptr));
1078 memset(s: data, c: 0, n: sizeof(*data));
1079 cmsgptr->cmsg_type = IP_PKTINFO;
1080 data->ipi_ifindex = header.ifindex;
1081 data->ipi_addr.s_addr = htonl(hostlong: header.senderAddress.toIPv4Address());
1082# elif defined(IP_SENDSRCADDR)
1083 struct in_addr *data = reinterpret_cast<in_addr *>(CMSG_DATA(cmsgptr));
1084 cmsgptr->cmsg_type = IP_SENDSRCADDR;
1085 data->s_addr = htonl(header.senderAddress.toIPv4Address());
1086# endif
1087 cmsgptr->cmsg_level = IPPROTO_IP;
1088 msg.msg_controllen += CMSG_SPACE(sizeof(*data));
1089 cmsgptr->cmsg_len = CMSG_LEN(sizeof(*data));
1090 cmsgptr = reinterpret_cast<cmsghdr *>(reinterpret_cast<char *>(cmsgptr) + CMSG_SPACE(sizeof(*data)));
1091 }
1092#endif
1093 }
1094
1095#ifndef QT_NO_SCTP
1096 if (header.streamNumber != -1) {
1097 struct sctp_sndrcvinfo *data = reinterpret_cast<sctp_sndrcvinfo *>(CMSG_DATA(cmsgptr));
1098 memset(data, 0, sizeof(*data));
1099 msg.msg_controllen += CMSG_SPACE(sizeof(sctp_sndrcvinfo));
1100 cmsgptr->cmsg_len = CMSG_LEN(sizeof(sctp_sndrcvinfo));
1101 cmsgptr->cmsg_level = IPPROTO_SCTP;
1102 cmsgptr->cmsg_type = SCTP_SNDRCV;
1103 data->sinfo_stream = uint16_t(header.streamNumber);
1104 cmsgptr = reinterpret_cast<cmsghdr *>(reinterpret_cast<char *>(cmsgptr) + CMSG_SPACE(sizeof(*data)));
1105 }
1106#endif
1107
1108 if (msg.msg_controllen == 0)
1109 msg.msg_control = nullptr;
1110 ssize_t sentBytes = qt_safe_sendmsg(sockfd: socketDescriptor, msg: &msg, flags: 0);
1111
1112 if (sentBytes < 0) {
1113 switch (errno) {
1114#if defined(EWOULDBLOCK) && EWOULDBLOCK != EAGAIN
1115 case EWOULDBLOCK:
1116#endif
1117 case EAGAIN:
1118 sentBytes = -2;
1119 break;
1120 case EMSGSIZE:
1121 setError(error: QAbstractSocket::DatagramTooLargeError, errorString: DatagramTooLargeErrorString);
1122 break;
1123 case ECONNRESET:
1124 setError(error: QAbstractSocket::RemoteHostClosedError, errorString: RemoteHostClosedErrorString);
1125 break;
1126 default:
1127 setError(error: QAbstractSocket::NetworkError, errorString: SendDatagramErrorString);
1128 }
1129 }
1130
1131#if defined (QNATIVESOCKETENGINE_DEBUG)
1132 qDebug("QNativeSocketEngine::sendDatagram(%p \"%s\", %lli, \"%s\", %i) == %lli", data,
1133 QtDebugUtils::toPrintable(data, len, 16).constData(), len,
1134 header.destinationAddress.toString().toLatin1().constData(),
1135 header.destinationPort, (qint64) sentBytes);
1136#endif
1137
1138 return qint64(sentBytes);
1139}
1140
1141bool QNativeSocketEnginePrivate::fetchConnectionParameters()
1142{
1143 localPort = 0;
1144 localAddress.clear();
1145 peerPort = 0;
1146 peerAddress.clear();
1147 inboundStreamCount = outboundStreamCount = 0;
1148
1149 if (socketDescriptor == -1)
1150 return false;
1151
1152 qt_sockaddr sa;
1153 QT_SOCKLEN_T sockAddrSize = sizeof(sa);
1154
1155 // Determine local address
1156 memset(s: &sa, c: 0, n: sizeof(sa));
1157 if (::getsockname(fd: socketDescriptor, addr: &sa.a, len: &sockAddrSize) == 0) {
1158 qt_socket_getPortAndAddress(s: &sa, port: &localPort, addr: &localAddress);
1159
1160 // Determine protocol family
1161 switch (sa.a.sa_family) {
1162 case AF_INET:
1163 socketProtocol = QAbstractSocket::IPv4Protocol;
1164 break;
1165 case AF_INET6:
1166 socketProtocol = QAbstractSocket::IPv6Protocol;
1167 break;
1168 default:
1169 socketProtocol = QAbstractSocket::UnknownNetworkLayerProtocol;
1170 break;
1171 }
1172
1173 } else if (errno == EBADF) {
1174 setError(error: QAbstractSocket::UnsupportedSocketOperationError, errorString: InvalidSocketErrorString);
1175 return false;
1176 }
1177
1178#if defined (IPV6_V6ONLY)
1179 // determine if local address is dual mode
1180 // On linux, these are returned as "::" (==AnyIPv6)
1181 // On OSX, these are returned as "::FFFF:0.0.0.0" (==AnyIPv4)
1182 // in either case, the IPV6_V6ONLY option is cleared
1183 int ipv6only = 0;
1184 socklen_t optlen = sizeof(ipv6only);
1185 if (socketProtocol == QAbstractSocket::IPv6Protocol
1186 && (localAddress == QHostAddress::AnyIPv4 || localAddress == QHostAddress::AnyIPv6)
1187 && !getsockopt(fd: socketDescriptor, IPPROTO_IPV6, IPV6_V6ONLY, optval: (char*)&ipv6only, optlen: &optlen )) {
1188 if (optlen != sizeof(ipv6only))
1189 qWarning(msg: "unexpected size of IPV6_V6ONLY socket option");
1190 if (!ipv6only) {
1191 socketProtocol = QAbstractSocket::AnyIPProtocol;
1192 localAddress = QHostAddress::Any;
1193 }
1194 }
1195#endif
1196
1197 // Determine the remote address
1198 bool connected = ::getpeername(fd: socketDescriptor, addr: &sa.a, len: &sockAddrSize) == 0;
1199 if (connected) {
1200 qt_socket_getPortAndAddress(s: &sa, port: &peerPort, addr: &peerAddress);
1201 inboundStreamCount = outboundStreamCount = 1;
1202 }
1203
1204 // Determine the socket type (UDP/TCP/SCTP)
1205 int value = 0;
1206 QT_SOCKOPTLEN_T valueSize = sizeof(int);
1207 if (::getsockopt(fd: socketDescriptor, SOL_SOCKET, SO_TYPE, optval: &value, optlen: &valueSize) == 0) {
1208 if (value == SOCK_STREAM) {
1209#ifndef QT_NO_SCTP
1210 if (option(QNativeSocketEngine::MaxStreamsSocketOption) != -1) {
1211 socketType = QAbstractSocket::SctpSocket;
1212 if (connected) {
1213 sctp_status sctpStatus;
1214 QT_SOCKOPTLEN_T sctpStatusSize = sizeof(sctpStatus);
1215 sctp_event_subscribe sctpEvents;
1216
1217 memset(&sctpEvents, 0, sizeof(sctpEvents));
1218 sctpEvents.sctp_data_io_event = 1;
1219 if (::getsockopt(socketDescriptor, SOL_SCTP, SCTP_STATUS, &sctpStatus,
1220 &sctpStatusSize) == 0 &&
1221 ::setsockopt(socketDescriptor, SOL_SCTP, SCTP_EVENTS, &sctpEvents,
1222 sizeof(sctpEvents)) == 0) {
1223 inboundStreamCount = int(sctpStatus.sstat_instrms);
1224 outboundStreamCount = int(sctpStatus.sstat_outstrms);
1225 } else {
1226 setError(QAbstractSocket::UnsupportedSocketOperationError,
1227 InvalidSocketErrorString);
1228 return false;
1229 }
1230 }
1231 } else {
1232 socketType = QAbstractSocket::TcpSocket;
1233 }
1234#else
1235 socketType = QAbstractSocket::TcpSocket;
1236#endif
1237 } else {
1238 if (value == SOCK_DGRAM)
1239 socketType = QAbstractSocket::UdpSocket;
1240 else
1241 socketType = QAbstractSocket::UnknownSocketType;
1242 }
1243 }
1244#if defined (QNATIVESOCKETENGINE_DEBUG)
1245 QString socketProtocolStr = QStringLiteral("UnknownProtocol");
1246 if (socketProtocol == QAbstractSocket::IPv4Protocol) socketProtocolStr = QStringLiteral("IPv4Protocol");
1247 else if (socketProtocol == QAbstractSocket::IPv6Protocol || socketProtocol == QAbstractSocket::AnyIPProtocol) socketProtocolStr = QStringLiteral("IPv6Protocol");
1248
1249 QString socketTypeStr = QStringLiteral("UnknownSocketType");
1250 if (socketType == QAbstractSocket::TcpSocket) socketTypeStr = QStringLiteral("TcpSocket");
1251 else if (socketType == QAbstractSocket::UdpSocket) socketTypeStr = QStringLiteral("UdpSocket");
1252 else if (socketType == QAbstractSocket::SctpSocket) socketTypeStr = QStringLiteral("SctpSocket");
1253
1254 qDebug("QNativeSocketEnginePrivate::fetchConnectionParameters() local == %s:%i,"
1255 " peer == %s:%i, socket == %s - %s, inboundStreamCount == %i, outboundStreamCount == %i",
1256 localAddress.toString().toLatin1().constData(), localPort,
1257 peerAddress.toString().toLatin1().constData(), peerPort,socketTypeStr.toLatin1().constData(),
1258 socketProtocolStr.toLatin1().constData(), inboundStreamCount, outboundStreamCount);
1259#endif
1260 return true;
1261}
1262
1263void QNativeSocketEnginePrivate::nativeClose()
1264{
1265#if defined (QNATIVESOCKETENGINE_DEBUG)
1266 qDebug("QNativeSocketEngine::nativeClose()");
1267#endif
1268
1269 qt_safe_close(fd: socketDescriptor);
1270}
1271
1272qint64 QNativeSocketEnginePrivate::nativeWrite(const char *data, qint64 len)
1273{
1274 Q_Q(QNativeSocketEngine);
1275
1276 ssize_t writtenBytes;
1277 writtenBytes = qt_safe_write_nosignal(fd: socketDescriptor, data, len);
1278
1279 if (writtenBytes < 0) {
1280 switch (errno) {
1281 case EPIPE:
1282 case ECONNRESET:
1283 writtenBytes = -1;
1284 setError(error: QAbstractSocket::RemoteHostClosedError, errorString: RemoteHostClosedErrorString);
1285 q->close();
1286 break;
1287#if EWOULDBLOCK != EAGAIN
1288 case EWOULDBLOCK:
1289#endif
1290 case EAGAIN:
1291 writtenBytes = 0;
1292 break;
1293 case EMSGSIZE:
1294 setError(error: QAbstractSocket::DatagramTooLargeError, errorString: DatagramTooLargeErrorString);
1295 break;
1296 default:
1297 break;
1298 }
1299 }
1300
1301#if defined (QNATIVESOCKETENGINE_DEBUG)
1302 qDebug("QNativeSocketEnginePrivate::nativeWrite(%p \"%s\", %llu) == %i", data,
1303 QtDebugUtils::toPrintable(data, len, 16).constData(), len, (int) writtenBytes);
1304#endif
1305
1306 return qint64(writtenBytes);
1307}
1308/*
1309*/
1310qint64 QNativeSocketEnginePrivate::nativeRead(char *data, qint64 maxSize)
1311{
1312 Q_Q(QNativeSocketEngine);
1313 if (!q->isValid()) {
1314 qWarning(msg: "QNativeSocketEngine::nativeRead: Invalid socket");
1315 return -1;
1316 }
1317
1318 ssize_t r = 0;
1319 r = qt_safe_read(fd: socketDescriptor, data, maxlen: maxSize);
1320
1321 if (r < 0) {
1322 r = -1;
1323 switch (errno) {
1324#if EWOULDBLOCK-0 && EWOULDBLOCK != EAGAIN
1325 case EWOULDBLOCK:
1326#endif
1327 case EAGAIN:
1328 // No data was available for reading
1329 r = -2;
1330 break;
1331 case ECONNRESET:
1332#if defined(Q_OS_VXWORKS)
1333 case ESHUTDOWN:
1334#endif
1335 r = 0;
1336 break;
1337 case ETIMEDOUT:
1338 socketError = QAbstractSocket::SocketTimeoutError;
1339 break;
1340 default:
1341 socketError = QAbstractSocket::NetworkError;
1342 break;
1343 }
1344
1345 if (r == -1) {
1346 hasSetSocketError = true;
1347 socketErrorString = qt_error_string();
1348 }
1349 }
1350
1351#if defined (QNATIVESOCKETENGINE_DEBUG)
1352 qDebug("QNativeSocketEnginePrivate::nativeRead(%p \"%s\", %llu) == %zd", data,
1353 QtDebugUtils::toPrintable(data, r, 16).constData(), maxSize, r);
1354#endif
1355
1356 return qint64(r);
1357}
1358
1359int QNativeSocketEnginePrivate::nativeSelect(QDeadlineTimer deadline, bool selectForRead) const
1360{
1361 bool dummy;
1362 return nativeSelect(deadline, checkRead: selectForRead, checkWrite: !selectForRead, selectForRead: &dummy, selectForWrite: &dummy);
1363}
1364
1365#ifndef Q_OS_WASM
1366
1367int QNativeSocketEnginePrivate::nativeSelect(QDeadlineTimer deadline, bool checkRead,
1368 bool checkWrite, bool *selectForRead,
1369 bool *selectForWrite) const
1370{
1371 pollfd pfd = qt_make_pollfd(fd: socketDescriptor, events: 0);
1372
1373 if (checkRead)
1374 pfd.events |= POLLIN;
1375
1376 if (checkWrite)
1377 pfd.events |= POLLOUT;
1378
1379 const int ret = qt_safe_poll(fds: &pfd, nfds: 1, deadline);
1380
1381 if (ret <= 0)
1382 return ret;
1383
1384 if (pfd.revents & POLLNVAL) {
1385 errno = EBADF;
1386 return -1;
1387 }
1388
1389 static const short read_flags = POLLIN | POLLHUP | POLLERR;
1390 static const short write_flags = POLLOUT | POLLERR;
1391
1392 *selectForRead = ((pfd.revents & read_flags) != 0);
1393 *selectForWrite = ((pfd.revents & write_flags) != 0);
1394
1395 return ret;
1396}
1397
1398#else
1399
1400int QNativeSocketEnginePrivate::nativeSelect(QDeadlineTimer deadline, bool checkRead,
1401 bool checkWrite, bool *selectForRead,
1402 bool *selectForWrite) const
1403{
1404 *selectForRead = checkRead;
1405 *selectForWrite = checkWrite;
1406 bool socketDisconnect = false;
1407 QEventDispatcherWasm::socketSelect(deadline.remainingTime(), socketDescriptor, checkRead,
1408 checkWrite, selectForRead, selectForWrite,
1409 &socketDisconnect);
1410
1411 // The disconnect/close handling code in QAbstractsScket::canReadNotification()
1412 // does not detect remote disconnect properly; do that here as a workardound.
1413 if (socketDisconnect)
1414 receiver->closeNotification();
1415
1416 return 1;
1417}
1418
1419#endif // Q_OS_WASM
1420
1421QT_END_NAMESPACE
1422

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