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