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