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

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