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