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