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 int socketError = 0;
454 if (socketState == QAbstractSocket::ConnectingState) {
455 // We are already connecting, try to read out an error if any.
456 // This is to avoid calling connect() more than necessary, as the kernel may try to send
457 // us messages on poll/select of this socket whenever we do.
458 socklen_t len = sizeof(socketError);
459 if (getsockopt(int(socketDescriptor), SOL_SOCKET, SO_ERROR, &socketError, &len) != 0) {
460 // getsockopt failed - let's treat socketError as undefined to be safe. So, reset.
461 socketError = 0;
462 }
463 }
464
465 int connectResult = -1;
466 if (socketError == 0) {
467 qt_sockaddr aa;
468 QT_SOCKLEN_T sockAddrSize;
469 setPortAndAddress(port, addr, &aa, &sockAddrSize);
470
471 connectResult = qt_safe_connect(socketDescriptor, &aa.a, sockAddrSize);
472 socketError = errno;
473 }
474 if (connectResult == -1) {
475 switch (socketError) {
476 case EISCONN:
477 socketState = QAbstractSocket::ConnectedState;
478 break;
479 case ECONNREFUSED:
480 case EINVAL:
481 case ENOENT:
482 setError(QAbstractSocket::ConnectionRefusedError, ConnectionRefusedErrorString);
483 socketState = QAbstractSocket::UnconnectedState;
484 break;
485 case ETIMEDOUT:
486 setError(QAbstractSocket::NetworkError, ConnectionTimeOutErrorString);
487 break;
488 case EHOSTUNREACH:
489 setError(QAbstractSocket::NetworkError, HostUnreachableErrorString);
490 socketState = QAbstractSocket::UnconnectedState;
491 break;
492 case ENETUNREACH:
493 setError(QAbstractSocket::NetworkError, NetworkUnreachableErrorString);
494 socketState = QAbstractSocket::UnconnectedState;
495 break;
496 case EADDRINUSE:
497 setError(QAbstractSocket::NetworkError, AddressInuseErrorString);
498 break;
499 case EINPROGRESS:
500 case EALREADY:
501 setError(QAbstractSocket::UnfinishedSocketOperationError, InvalidSocketErrorString);
502 socketState = QAbstractSocket::ConnectingState;
503 break;
504 case EAGAIN:
505 setError(QAbstractSocket::UnfinishedSocketOperationError, InvalidSocketErrorString);
506 break;
507 case EACCES:
508 case EPERM:
509 setError(QAbstractSocket::SocketAccessError, AccessErrorString);
510 socketState = QAbstractSocket::UnconnectedState;
511 break;
512 case EAFNOSUPPORT:
513 case EBADF:
514 case EFAULT:
515 case ENOTSOCK:
516 socketState = QAbstractSocket::UnconnectedState;
517 break;
518 default:
519 break;
520 }
521
522 if (socketState != QAbstractSocket::ConnectedState) {
523#if defined (QNATIVESOCKETENGINE_DEBUG)
524 qDebug("QNativeSocketEnginePrivate::nativeConnect(%s, %i) == false (%s)",
525 addr.toString().toLatin1().constData(), port,
526 socketState == QAbstractSocket::ConnectingState
527 ? "Connection in progress" : strerror(socketError));
528#endif
529 return false;
530 }
531 }
532
533#if defined (QNATIVESOCKETENGINE_DEBUG)
534 qDebug("QNativeSocketEnginePrivate::nativeConnect(%s, %i) == true",
535 addr.toString().toLatin1().constData(), port);
536#endif
537
538 socketState = QAbstractSocket::ConnectedState;
539 return true;
540}
541
542bool QNativeSocketEnginePrivate::nativeBind(const QHostAddress &address, quint16 port)
543{
544 qt_sockaddr aa;
545 QT_SOCKLEN_T sockAddrSize;
546 setPortAndAddress(port, address, &aa, &sockAddrSize);
547
548#ifdef IPV6_V6ONLY
549 if (aa.a.sa_family == AF_INET6) {
550 int ipv6only = 0;
551 if (address.protocol() == QAbstractSocket::IPv6Protocol)
552 ipv6only = 1;
553 //default value of this socket option varies depending on unix variant (or system configuration on BSD), so always set it explicitly
554 ::setsockopt(socketDescriptor, IPPROTO_IPV6, IPV6_V6ONLY, (char*)&ipv6only, sizeof(ipv6only) );
555 }
556#endif
557
558 int bindResult = QT_SOCKET_BIND(socketDescriptor, &aa.a, sockAddrSize);
559 if (bindResult < 0 && errno == EAFNOSUPPORT && address.protocol() == QAbstractSocket::AnyIPProtocol) {
560 // retry with v4
561 aa.a4.sin_family = AF_INET;
562 aa.a4.sin_port = htons(port);
563 aa.a4.sin_addr.s_addr = htonl(address.toIPv4Address());
564 sockAddrSize = sizeof(aa.a4);
565 bindResult = QT_SOCKET_BIND(socketDescriptor, &aa.a, sockAddrSize);
566 }
567
568 if (bindResult < 0) {
569#if defined (QNATIVESOCKETENGINE_DEBUG)
570 int ecopy = errno;
571#endif
572 switch(errno) {
573 case EADDRINUSE:
574 setError(QAbstractSocket::AddressInUseError, AddressInuseErrorString);
575 break;
576 case EACCES:
577 setError(QAbstractSocket::SocketAccessError, AddressProtectedErrorString);
578 break;
579 case EINVAL:
580 setError(QAbstractSocket::UnsupportedSocketOperationError, OperationUnsupportedErrorString);
581 break;
582 case EADDRNOTAVAIL:
583 setError(QAbstractSocket::SocketAddressNotAvailableError, AddressNotAvailableErrorString);
584 break;
585 default:
586 break;
587 }
588
589#if defined (QNATIVESOCKETENGINE_DEBUG)
590 qDebug("QNativeSocketEnginePrivate::nativeBind(%s, %i) == false (%s)",
591 address.toString().toLatin1().constData(), port, strerror(ecopy));
592#endif
593
594 return false;
595 }
596
597#if defined (QNATIVESOCKETENGINE_DEBUG)
598 qDebug("QNativeSocketEnginePrivate::nativeBind(%s, %i) == true",
599 address.toString().toLatin1().constData(), port);
600#endif
601 socketState = QAbstractSocket::BoundState;
602 return true;
603}
604
606{
607 if (qt_safe_listen(socketDescriptor, backlog) < 0) {
608#if defined (QNATIVESOCKETENGINE_DEBUG)
609 int ecopy = errno;
610#endif
611 switch (errno) {
612 case EADDRINUSE:
613 setError(QAbstractSocket::AddressInUseError,
614 PortInuseErrorString);
615 break;
616 default:
617 break;
618 }
619
620#if defined (QNATIVESOCKETENGINE_DEBUG)
621 qDebug("QNativeSocketEnginePrivate::nativeListen(%i) == false (%s)",
622 backlog, strerror(ecopy));
623#endif
624 return false;
625 }
626
627#if defined (QNATIVESOCKETENGINE_DEBUG)
628 qDebug("QNativeSocketEnginePrivate::nativeListen(%i) == true", backlog);
629#endif
630
631 socketState = QAbstractSocket::ListeningState;
632 return true;
633}
634
636{
637 int acceptedDescriptor = qt_safe_accept(socketDescriptor, nullptr, nullptr);
638 if (acceptedDescriptor == -1) {
639 switch (errno) {
640 case EBADF:
641 case EOPNOTSUPP:
642 setError(QAbstractSocket::UnsupportedSocketOperationError, InvalidSocketErrorString);
643 break;
644 case ECONNABORTED:
645 setError(QAbstractSocket::NetworkError, RemoteHostClosedErrorString);
646 break;
647 case EFAULT:
648 case ENOTSOCK:
649 setError(QAbstractSocket::SocketResourceError, NotSocketErrorString);
650 break;
651 case EPROTONOSUPPORT:
652#if !defined(Q_OS_OPENBSD)
653 case EPROTO:
654#endif
655 case EAFNOSUPPORT:
656 case EINVAL:
657 setError(QAbstractSocket::UnsupportedSocketOperationError, ProtocolUnsupportedErrorString);
658 break;
659 case ENFILE:
660 case EMFILE:
661 case ENOBUFS:
662 case ENOMEM:
663 setError(QAbstractSocket::SocketResourceError, ResourceErrorString);
664 break;
665 case EACCES:
666 case EPERM:
667 setError(QAbstractSocket::SocketAccessError, AccessErrorString);
668 break;
669#if EAGAIN != EWOULDBLOCK
670 case EWOULDBLOCK:
671#endif
672 case EAGAIN:
673 setError(QAbstractSocket::TemporaryError, TemporaryErrorString);
674 break;
675 default:
676 setError(QAbstractSocket::UnknownSocketError, UnknownSocketErrorString);
677 break;
678 }
679 }
680
681 return qintptr(acceptedDescriptor);
682}
683
684#ifndef QT_NO_NETWORKINTERFACE
685
687 int how6,
688 int how4,
689 const QHostAddress &groupAddress,
690 const QNetworkInterface &interface)
691{
692 int level = 0;
693 int sockOpt = 0;
694 void *sockArg;
695 int sockArgSize;
696
697 ip_mreq mreq4;
698 ipv6_mreq mreq6;
699
700 if (groupAddress.protocol() == QAbstractSocket::IPv6Protocol) {
701 level = IPPROTO_IPV6;
702 sockOpt = how6;
703 sockArg = &mreq6;
704 sockArgSize = sizeof(mreq6);
705 memset(&mreq6, 0, sizeof(mreq6));
706 Q_IPV6ADDR ip6 = groupAddress.toIPv6Address();
707 memcpy(&mreq6.ipv6mr_multiaddr, &ip6, sizeof(ip6));
708 mreq6.ipv6mr_interface = interface.index();
709 } else if (groupAddress.protocol() == QAbstractSocket::IPv4Protocol) {
710 level = IPPROTO_IP;
711 sockOpt = how4;
712 sockArg = &mreq4;
713 sockArgSize = sizeof(mreq4);
714 memset(&mreq4, 0, sizeof(mreq4));
715 mreq4.imr_multiaddr.s_addr = htonl(groupAddress.toIPv4Address());
716
717 if (interface.isValid()) {
718 const QList<QNetworkAddressEntry> addressEntries = interface.addressEntries();
719 bool found = false;
720 for (const QNetworkAddressEntry &entry : addressEntries) {
721 const QHostAddress ip = entry.ip();
722 if (ip.protocol() == QAbstractSocket::IPv4Protocol) {
723 mreq4.imr_interface.s_addr = htonl(ip.toIPv4Address());
724 found = true;
725 break;
726 }
727 }
728 if (!found) {
729 d->setError(QAbstractSocket::NetworkError,
731 return false;
732 }
733 } else {
734 mreq4.imr_interface.s_addr = INADDR_ANY;
735 }
736 } else {
737 // unreachable
738 d->setError(QAbstractSocket::UnsupportedSocketOperationError,
740 return false;
741 }
742
743 int res = setsockopt(d->socketDescriptor, level, sockOpt, sockArg, sockArgSize);
744 if (res == -1) {
745 switch (errno) {
746 case ENOPROTOOPT:
747 d->setError(QAbstractSocket::UnsupportedSocketOperationError,
749 break;
750 case EADDRNOTAVAIL:
751 d->setError(QAbstractSocket::SocketAddressNotAvailableError,
753 break;
754 default:
755 d->setError(QAbstractSocket::UnknownSocketError,
757 break;
758 }
759 return false;
760 }
761 return true;
762}
763
764bool QNativeSocketEnginePrivate::nativeJoinMulticastGroup(const QHostAddress &groupAddress,
765 const QNetworkInterface &interface)
766{
767 return multicastMembershipHelper(this,
768 IPV6_JOIN_GROUP,
769 IP_ADD_MEMBERSHIP,
770 groupAddress,
771 interface);
772}
773
774bool QNativeSocketEnginePrivate::nativeLeaveMulticastGroup(const QHostAddress &groupAddress,
775 const QNetworkInterface &interface)
776{
777 return multicastMembershipHelper(this,
778 IPV6_LEAVE_GROUP,
779 IP_DROP_MEMBERSHIP,
780 groupAddress,
781 interface);
782}
783
785{
786 if (socketProtocol == QAbstractSocket::IPv6Protocol || socketProtocol == QAbstractSocket::AnyIPProtocol) {
787 uint v;
788 QT_SOCKOPTLEN_T sizeofv = sizeof(v);
789 if (::getsockopt(socketDescriptor, IPPROTO_IPV6, IPV6_MULTICAST_IF, &v, &sizeofv) == -1)
790 return QNetworkInterface();
791 return QNetworkInterface::interfaceFromIndex(v);
792 }
793
794#if defined(Q_OS_SOLARIS)
795 struct in_addr v = { 0, 0, 0, 0};
796#else
797 struct in_addr v = { 0 };
798#endif
799 QT_SOCKOPTLEN_T sizeofv = sizeof(v);
800 if (::getsockopt(socketDescriptor, IPPROTO_IP, IP_MULTICAST_IF, &v, &sizeofv) == -1)
801 return QNetworkInterface();
802 if (v.s_addr != 0 && sizeofv >= QT_SOCKOPTLEN_T(sizeof(v))) {
803 QHostAddress ipv4(ntohl(v.s_addr));
804 QList<QNetworkInterface> ifaces = QNetworkInterface::allInterfaces();
805 for (int i = 0; i < ifaces.size(); ++i) {
806 const QNetworkInterface &iface = ifaces.at(i);
807 QList<QNetworkAddressEntry> entries = iface.addressEntries();
808 for (int j = 0; j < entries.size(); ++j) {
809 const QNetworkAddressEntry &entry = entries.at(j);
810 if (entry.ip() == ipv4)
811 return iface;
812 }
813 }
814 }
815 return QNetworkInterface();
816}
817
818bool QNativeSocketEnginePrivate::nativeSetMulticastInterface(const QNetworkInterface &iface)
819{
820 if (socketProtocol == QAbstractSocket::IPv6Protocol || socketProtocol == QAbstractSocket::AnyIPProtocol) {
821 uint v = iface.index();
822 return (::setsockopt(socketDescriptor, IPPROTO_IPV6, IPV6_MULTICAST_IF, &v, sizeof(v)) != -1);
823 }
824
825 struct in_addr v;
826 if (iface.isValid()) {
827 QList<QNetworkAddressEntry> entries = iface.addressEntries();
828 for (int i = 0; i < entries.size(); ++i) {
829 const QNetworkAddressEntry &entry = entries.at(i);
830 const QHostAddress &ip = entry.ip();
831 if (ip.protocol() == QAbstractSocket::IPv4Protocol) {
832 v.s_addr = htonl(ip.toIPv4Address());
833 int r = ::setsockopt(socketDescriptor, IPPROTO_IP, IP_MULTICAST_IF, &v, sizeof(v));
834 if (r != -1)
835 return true;
836 }
837 }
838 return false;
839 }
840
841 v.s_addr = INADDR_ANY;
842 return (::setsockopt(socketDescriptor, IPPROTO_IP, IP_MULTICAST_IF, &v, sizeof(v)) != -1);
843}
844
845#endif // QT_NO_NETWORKINTERFACE
846
848{
849 int nbytes = 0;
850 // gives shorter than true amounts on Unix domain sockets.
851 qint64 available = -1;
852
853#if defined (SO_NREAD)
854 if (socketType == QAbstractSocket::UdpSocket) {
855 socklen_t sz = sizeof nbytes;
856 if (!::getsockopt(socketDescriptor, SOL_SOCKET, SO_NREAD, &nbytes, &sz))
857 available = nbytes;
858 }
859#endif
860
861 if (available == -1 && qt_safe_ioctl(socketDescriptor, FIONREAD, (char *) &nbytes) >= 0)
862 available = nbytes;
863
864#if defined (QNATIVESOCKETENGINE_DEBUG)
865 qDebug("QNativeSocketEnginePrivate::nativeBytesAvailable() == %lli", available);
866#endif
867 return available > 0 ? available : 0;
868}
869
871{
872 // Peek 1 bytes into the next message.
873 ssize_t readBytes;
874 char c;
875 QT_EINTR_LOOP(readBytes, ::recv(socketDescriptor, &c, 1, MSG_PEEK));
876
877 // If there's no error, or if our buffer was too small, there must be a
878 // pending datagram.
879 bool result = (readBytes != -1) || errno == EMSGSIZE;
880
881#if defined (QNATIVESOCKETENGINE_DEBUG)
882 qDebug("QNativeSocketEnginePrivate::nativeHasPendingDatagrams() == %s",
883 result ? "true" : "false");
884#endif
885 return result;
886}
887
889{
890 ssize_t recvResult = -1;
891#ifdef Q_OS_LINUX
892 // Linux can return the actual datagram size if we use MSG_TRUNC
893 char c;
894 QT_EINTR_LOOP(recvResult, ::recv(socketDescriptor, &c, 1, MSG_PEEK | MSG_TRUNC));
895#elif defined(SO_NREAD)
896 // macOS can return the actual datagram size if we use SO_NREAD
897 int value;
898 socklen_t valuelen = sizeof(value);
899 recvResult = getsockopt(socketDescriptor, SOL_SOCKET, SO_NREAD, &value, &valuelen);
900 if (recvResult != -1)
901 recvResult = value;
902#elif defined(Q_OS_VXWORKS)
903 // VxWorks: use ioctl(FIONREAD) to query the number of bytes available
904 int available = 0;
905 int ioctlResult = ::ioctl(socketDescriptor, FIONREAD, &available);
906 if (ioctlResult != -1)
907 recvResult = available;
908#else
909 // We need to grow the buffer to fit the entire datagram.
910 // We start at 1500 bytes (the MTU for Ethernet V2), which should catch
911 // almost all uses (effective MTU for UDP under IPv4 is 1468), except
912 // for localhost datagrams and those reassembled by the IP layer.
913 char udpMessagePeekBuffer[1500];
914 struct msghdr msg;
915 struct iovec vec;
916
917 memset(&msg, 0, sizeof(msg));
918 msg.msg_iov = &vec;
919 msg.msg_iovlen = 1;
920 vec.iov_base = udpMessagePeekBuffer;
921 vec.iov_len = sizeof(udpMessagePeekBuffer);
922
923 for (;;) {
924 // the data written to udpMessagePeekBuffer is discarded, so
925 // this function is still reentrant although it might not look
926 // so.
927 recvResult = ::recvmsg(socketDescriptor, &msg, MSG_PEEK);
928 if (recvResult == -1 && errno == EINTR)
929 continue;
930
931 // was the result truncated?
932 if ((msg.msg_flags & MSG_TRUNC) == 0)
933 break;
934
935 // grow by 16 times
936 msg.msg_iovlen *= 16;
937 if (msg.msg_iov != &vec)
938 delete[] msg.msg_iov;
939 msg.msg_iov = new struct iovec[msg.msg_iovlen];
940 std::fill_n(msg.msg_iov, msg.msg_iovlen, vec);
941 }
942
943 if (msg.msg_iov != &vec)
944 delete[] msg.msg_iov;
945#endif
946
947#if defined (QNATIVESOCKETENGINE_DEBUG)
948 qDebug("QNativeSocketEnginePrivate::nativePendingDatagramSize() == %zd", recvResult);
949#endif
950
951 return qint64(recvResult);
952}
953
954qint64 QNativeSocketEnginePrivate::nativeReceiveDatagram(char *data, qint64 maxSize, QIpPacketHeader *header,
955 QAbstractSocketEngine::PacketHeaderOptions options)
956{
957 // we use quintptr to force the alignment
958 quintptr cbuf[(CMSG_SPACE(sizeof(struct in6_pktinfo)) + CMSG_SPACE(sizeof(int))
959#if !defined(IP_PKTINFO) && defined(IP_RECVIF) && defined(AF_LINK)
960 + CMSG_SPACE(sizeof(sockaddr_dl))
961#endif
962#ifndef QT_NO_SCTP
963 + CMSG_SPACE(sizeof(struct sctp_sndrcvinfo))
964#endif
965 + sizeof(quintptr) - 1) / sizeof(quintptr)];
966
967 struct msghdr msg;
968 struct iovec vec;
969 qt_sockaddr aa;
970 char c;
971 memset(&msg, 0, sizeof(msg));
972 memset(&aa, 0, sizeof(aa));
973
974 // we need to receive at least one byte, even if our user isn't interested in it
975 vec.iov_base = maxSize ? data : &c;
976 vec.iov_len = maxSize ? maxSize : 1;
977 msg.msg_iov = &vec;
978 msg.msg_iovlen = 1;
979 if (options & QAbstractSocketEngine::WantDatagramSender) {
980 msg.msg_name = &aa;
981 msg.msg_namelen = sizeof(aa);
982 }
983 if (options & (QAbstractSocketEngine::WantDatagramHopLimit | QAbstractSocketEngine::WantDatagramDestination
984 | QAbstractSocketEngine::WantStreamNumber)) {
985 msg.msg_control = cbuf;
986 msg.msg_controllen = sizeof(cbuf);
987 }
988
989 ssize_t recvResult = 0;
990 do {
991 recvResult = ::recvmsg(socketDescriptor, &msg, 0);
992 } while (recvResult == -1 && errno == EINTR);
993
994 if (recvResult == -1) {
995 switch (errno) {
996#if defined(EWOULDBLOCK) && EWOULDBLOCK != EAGAIN
997 case EWOULDBLOCK:
998#endif
999 case EAGAIN:
1000 // No datagram was available for reading
1001 recvResult = -2;
1002 break;
1003 case ECONNREFUSED:
1004 setError(QAbstractSocket::ConnectionRefusedError, ConnectionRefusedErrorString);
1005 break;
1006 default:
1007 setError(QAbstractSocket::NetworkError, ReceiveDatagramErrorString);
1008 }
1009 if (header)
1010 header->clear();
1011 } else if (options != QAbstractSocketEngine::WantNone) {
1012 Q_ASSERT(header);
1013 qt_socket_getPortAndAddress(&aa, &header->senderPort, &header->senderAddress);
1014 header->destinationPort = localPort;
1015 header->endOfRecord = (msg.msg_flags & MSG_EOR) != 0;
1016
1017 // parse the ancillary data
1018 struct cmsghdr *cmsgptr;
1019 QT_WARNING_PUSH
1020 QT_WARNING_DISABLE_CLANG("-Wsign-compare")
1021 for (cmsgptr = CMSG_FIRSTHDR(&msg); cmsgptr != nullptr;
1022 cmsgptr = CMSG_NXTHDR(&msg, cmsgptr)) {
1023 QT_WARNING_POP
1024 if (cmsgptr->cmsg_level == IPPROTO_IPV6 && cmsgptr->cmsg_type == IPV6_PKTINFO
1025 && cmsgptr->cmsg_len >= CMSG_LEN(sizeof(in6_pktinfo))) {
1026 in6_pktinfo *info = reinterpret_cast<in6_pktinfo *>(CMSG_DATA(cmsgptr));
1027
1028 header->destinationAddress.setAddress(reinterpret_cast<quint8 *>(&info->ipi6_addr));
1029 header->ifindex = info->ipi6_ifindex;
1030 if (header->ifindex)
1031 header->destinationAddress.setScopeId(QString::number(info->ipi6_ifindex));
1032 }
1033
1034#ifdef IP_PKTINFO
1035 if (cmsgptr->cmsg_level == IPPROTO_IP && cmsgptr->cmsg_type == IP_PKTINFO
1036 && cmsgptr->cmsg_len >= CMSG_LEN(sizeof(in_pktinfo))) {
1037 in_pktinfo *info = reinterpret_cast<in_pktinfo *>(CMSG_DATA(cmsgptr));
1038
1039 header->destinationAddress.setAddress(ntohl(info->ipi_addr.s_addr));
1040 header->ifindex = info->ipi_ifindex;
1041 }
1042#else
1043# ifdef IP_RECVDSTADDR
1044 if (cmsgptr->cmsg_level == IPPROTO_IP && cmsgptr->cmsg_type == IP_RECVDSTADDR
1045 && cmsgptr->cmsg_len >= CMSG_LEN(sizeof(in_addr))) {
1046 in_addr *addr = reinterpret_cast<in_addr *>(CMSG_DATA(cmsgptr));
1047
1048 header->destinationAddress.setAddress(ntohl(addr->s_addr));
1049 }
1050# endif
1051# if defined(IP_RECVIF) && defined(AF_LINK)
1052 if (cmsgptr->cmsg_level == IPPROTO_IP && cmsgptr->cmsg_type == IP_RECVIF
1053 && cmsgptr->cmsg_len >= CMSG_LEN(sizeof(sockaddr_dl))) {
1054 sockaddr_dl *sdl = reinterpret_cast<sockaddr_dl *>(CMSG_DATA(cmsgptr));
1055 header->ifindex = sdl->sdl_index;
1056 }
1057# endif
1058#endif
1059
1060 if (cmsgptr->cmsg_len == CMSG_LEN(sizeof(int))
1061 && ((cmsgptr->cmsg_level == IPPROTO_IPV6 && cmsgptr->cmsg_type == IPV6_HOPLIMIT)
1062 || (cmsgptr->cmsg_level == IPPROTO_IP && cmsgptr->cmsg_type == IP_TTL))) {
1063 static_assert(sizeof(header->hopLimit) == sizeof(int));
1064 memcpy(&header->hopLimit, CMSG_DATA(cmsgptr), sizeof(header->hopLimit));
1065 }
1066
1067#ifndef QT_NO_SCTP
1068 if (cmsgptr->cmsg_level == IPPROTO_SCTP && cmsgptr->cmsg_type == SCTP_SNDRCV
1069 && cmsgptr->cmsg_len >= CMSG_LEN(sizeof(sctp_sndrcvinfo))) {
1070 sctp_sndrcvinfo *rcvInfo = reinterpret_cast<sctp_sndrcvinfo *>(CMSG_DATA(cmsgptr));
1071
1072 header->streamNumber = int(rcvInfo->sinfo_stream);
1073 }
1074#endif
1075 }
1076 }
1077
1078#if defined (QNATIVESOCKETENGINE_DEBUG)
1079 qDebug("QNativeSocketEnginePrivate::nativeReceiveDatagram(%p \"%s\", %lli, %s, %i) == %lli",
1080 data, QtDebugUtils::toPrintable(data, recvResult, 16).constData(), maxSize,
1081 (recvResult != -1 && options != QAbstractSocketEngine::WantNone)
1082 ? header->senderAddress.toString().toLatin1().constData() : "(unknown)",
1083 (recvResult != -1 && options != QAbstractSocketEngine::WantNone)
1084 ? header->senderPort : 0, (qint64) recvResult);
1085#endif
1086
1087 return qint64((maxSize || recvResult < 0) ? recvResult : Q_INT64_C(0));
1088}
1089
1090qint64 QNativeSocketEnginePrivate::nativeSendDatagram(const char *data, qint64 len, const QIpPacketHeader &header)
1091{
1092 // we use quintptr to force the alignment
1093 quintptr cbuf[(CMSG_SPACE(sizeof(struct in6_pktinfo)) + CMSG_SPACE(sizeof(int))
1094#ifndef QT_NO_SCTP
1095 + CMSG_SPACE(sizeof(struct sctp_sndrcvinfo))
1096#endif
1097 + sizeof(quintptr) - 1) / sizeof(quintptr)];
1098
1099 struct cmsghdr *cmsgptr = reinterpret_cast<struct cmsghdr *>(cbuf);
1100 struct msghdr msg;
1101 struct iovec vec;
1102 qt_sockaddr aa;
1103
1104 memset(&msg, 0, sizeof(msg));
1105 memset(&aa, 0, sizeof(aa));
1106 vec.iov_base = const_cast<char *>(data);
1107 vec.iov_len = len;
1108 msg.msg_iov = &vec;
1109 msg.msg_iovlen = 1;
1110 msg.msg_control = &cbuf;
1111
1112 if (header.destinationPort != 0) {
1113 msg.msg_name = &aa.a;
1114 setPortAndAddress(header.destinationPort, header.destinationAddress,
1115 &aa, &msg.msg_namelen);
1116 }
1117
1118 if (msg.msg_namelen == sizeof(aa.a6)) {
1119 if (header.hopLimit != -1) {
1120 msg.msg_controllen += CMSG_SPACE(sizeof(int));
1121 cmsgptr->cmsg_len = CMSG_LEN(sizeof(int));
1122 cmsgptr->cmsg_level = IPPROTO_IPV6;
1123 cmsgptr->cmsg_type = IPV6_HOPLIMIT;
1124 memcpy(CMSG_DATA(cmsgptr), &header.hopLimit, sizeof(int));
1125 cmsgptr = reinterpret_cast<cmsghdr *>(reinterpret_cast<char *>(cmsgptr) + CMSG_SPACE(sizeof(int)));
1126 }
1127 if (header.ifindex != 0 || !header.senderAddress.isNull()) {
1128 struct in6_pktinfo *data = reinterpret_cast<in6_pktinfo *>(CMSG_DATA(cmsgptr));
1129 memset(data, 0, sizeof(*data));
1130 msg.msg_controllen += CMSG_SPACE(sizeof(*data));
1131 cmsgptr->cmsg_len = CMSG_LEN(sizeof(*data));
1132 cmsgptr->cmsg_level = IPPROTO_IPV6;
1133 cmsgptr->cmsg_type = IPV6_PKTINFO;
1134 data->ipi6_ifindex = header.ifindex;
1135
1136 QIPv6Address tmp = header.senderAddress.toIPv6Address();
1137 memcpy(&data->ipi6_addr, &tmp, sizeof(tmp));
1138 cmsgptr = reinterpret_cast<cmsghdr *>(reinterpret_cast<char *>(cmsgptr) + CMSG_SPACE(sizeof(*data)));
1139 }
1140 } else {
1141 if (header.hopLimit != -1) {
1142 msg.msg_controllen += CMSG_SPACE(sizeof(int));
1143 cmsgptr->cmsg_len = CMSG_LEN(sizeof(int));
1144 cmsgptr->cmsg_level = IPPROTO_IP;
1145 cmsgptr->cmsg_type = IP_TTL;
1146 memcpy(CMSG_DATA(cmsgptr), &header.hopLimit, sizeof(int));
1147 cmsgptr = reinterpret_cast<cmsghdr *>(reinterpret_cast<char *>(cmsgptr) + CMSG_SPACE(sizeof(int)));
1148 }
1149
1150#if defined(IP_PKTINFO) || defined(IP_SENDSRCADDR)
1151 if (header.ifindex != 0 || !header.senderAddress.isNull()) {
1152# ifdef IP_PKTINFO
1153 struct in_pktinfo *data = reinterpret_cast<in_pktinfo *>(CMSG_DATA(cmsgptr));
1154 memset(data, 0, sizeof(*data));
1155 cmsgptr->cmsg_type = IP_PKTINFO;
1156 data->ipi_ifindex = header.ifindex;
1157 data->ipi_addr.s_addr = htonl(header.senderAddress.toIPv4Address());
1158# elif defined(IP_SENDSRCADDR)
1159 struct in_addr *data = reinterpret_cast<in_addr *>(CMSG_DATA(cmsgptr));
1160 cmsgptr->cmsg_type = IP_SENDSRCADDR;
1161 data->s_addr = htonl(header.senderAddress.toIPv4Address());
1162# endif
1163 cmsgptr->cmsg_level = IPPROTO_IP;
1164 msg.msg_controllen += CMSG_SPACE(sizeof(*data));
1165 cmsgptr->cmsg_len = CMSG_LEN(sizeof(*data));
1166 cmsgptr = reinterpret_cast<cmsghdr *>(reinterpret_cast<char *>(cmsgptr) + CMSG_SPACE(sizeof(*data)));
1167 }
1168#endif
1169 }
1170
1171#ifndef QT_NO_SCTP
1172 if (header.streamNumber != -1) {
1173 struct sctp_sndrcvinfo *data = reinterpret_cast<sctp_sndrcvinfo *>(CMSG_DATA(cmsgptr));
1174 memset(data, 0, sizeof(*data));
1175 msg.msg_controllen += CMSG_SPACE(sizeof(sctp_sndrcvinfo));
1176 cmsgptr->cmsg_len = CMSG_LEN(sizeof(sctp_sndrcvinfo));
1177 cmsgptr->cmsg_level = IPPROTO_SCTP;
1178 cmsgptr->cmsg_type = SCTP_SNDRCV;
1179 data->sinfo_stream = uint16_t(header.streamNumber);
1180 cmsgptr = reinterpret_cast<cmsghdr *>(reinterpret_cast<char *>(cmsgptr) + CMSG_SPACE(sizeof(*data)));
1181 }
1182#endif
1183
1184 if (msg.msg_controllen == 0)
1185 msg.msg_control = nullptr;
1186 ssize_t sentBytes = qt_safe_sendmsg(socketDescriptor, &msg, 0);
1187
1188 if (sentBytes < 0) {
1189 switch (errno) {
1190#if defined(EWOULDBLOCK) && EWOULDBLOCK != EAGAIN
1191 case EWOULDBLOCK:
1192#endif
1193 case EAGAIN:
1194 sentBytes = -2;
1195 break;
1196 case EMSGSIZE:
1197 // seen on VxWorks
1198 case ENOMEM:
1199 setError(QAbstractSocket::DatagramTooLargeError, DatagramTooLargeErrorString);
1200 break;
1201 case ECONNRESET:
1202 setError(QAbstractSocket::RemoteHostClosedError, RemoteHostClosedErrorString);
1203 break;
1204 default:
1205 setError(QAbstractSocket::NetworkError, SendDatagramErrorString);
1206 }
1207 }
1208
1209#if defined (QNATIVESOCKETENGINE_DEBUG)
1210 qDebug("QNativeSocketEngine::sendDatagram(%p \"%s\", %lli, \"%s\", %i) == %lli", data,
1211 QtDebugUtils::toPrintable(data, len, 16).constData(), len,
1212 header.destinationAddress.toString().toLatin1().constData(),
1213 header.destinationPort, (qint64) sentBytes);
1214#endif
1215
1216 return qint64(sentBytes);
1217}
1218
1220{
1221 localPort = 0;
1222 localAddress.clear();
1223 peerPort = 0;
1224 peerAddress.clear();
1225 inboundStreamCount = outboundStreamCount = 0;
1226
1227 if (socketDescriptor == -1)
1228 return false;
1229
1230 qt_sockaddr sa;
1231 QT_SOCKLEN_T sockAddrSize = sizeof(sa);
1232
1233 // Determine local address
1234 memset(&sa, 0, sizeof(sa));
1235 if (::getsockname(socketDescriptor, &sa.a, &sockAddrSize) == 0) {
1236 qt_socket_getPortAndAddress(&sa, &localPort, &localAddress);
1237
1238 // Determine protocol family
1239 switch (sa.a.sa_family) {
1240 case AF_INET:
1241 socketProtocol = QAbstractSocket::IPv4Protocol;
1242 break;
1243 case AF_INET6:
1244 socketProtocol = QAbstractSocket::IPv6Protocol;
1245 break;
1246 default:
1247 socketProtocol = QAbstractSocket::UnknownNetworkLayerProtocol;
1248 break;
1249 }
1250
1251 } else if (errno == EBADF) {
1252 setError(QAbstractSocket::UnsupportedSocketOperationError, InvalidSocketErrorString);
1253 return false;
1254 }
1255
1256#if defined (IPV6_V6ONLY)
1257 // determine if local address is dual mode
1258 // On linux, these are returned as "::" (==AnyIPv6)
1259 // On OSX, these are returned as "::FFFF:0.0.0.0" (==AnyIPv4)
1260 // in either case, the IPV6_V6ONLY option is cleared
1261 int ipv6only = 0;
1262 socklen_t optlen = sizeof(ipv6only);
1263 if (socketProtocol == QAbstractSocket::IPv6Protocol
1264 && (localAddress == QHostAddress::AnyIPv4 || localAddress == QHostAddress::AnyIPv6)
1265 && !getsockopt(socketDescriptor, IPPROTO_IPV6, IPV6_V6ONLY, (char*)&ipv6only, &optlen )) {
1266 if (optlen != sizeof(ipv6only))
1267 qWarning("unexpected size of IPV6_V6ONLY socket option");
1268 if (!ipv6only) {
1269 socketProtocol = QAbstractSocket::AnyIPProtocol;
1270 localAddress = QHostAddress::Any;
1271 }
1272 }
1273#endif
1274
1275 // Determine the remote address
1276 bool connected = ::getpeername(socketDescriptor, &sa.a, &sockAddrSize) == 0;
1277 if (connected) {
1278 qt_socket_getPortAndAddress(&sa, &peerPort, &peerAddress);
1279 inboundStreamCount = outboundStreamCount = 1;
1280 }
1281
1282 // Determine the socket type (UDP/TCP/SCTP)
1283 int value = 0;
1284 QT_SOCKOPTLEN_T valueSize = sizeof(int);
1285 if (::getsockopt(socketDescriptor, SOL_SOCKET, SO_TYPE, &value, &valueSize) == 0) {
1286 if (value == SOCK_STREAM) {
1287 socketType = QAbstractSocket::TcpSocket;
1288#ifndef QT_NO_SCTP
1289 if (option(QNativeSocketEngine::MaxStreamsSocketOption) != -1) {
1290 socketType = QAbstractSocket::SctpSocket;
1291 if (connected) {
1292 sctp_status sctpStatus;
1293 QT_SOCKOPTLEN_T sctpStatusSize = sizeof(sctpStatus);
1294 sctp_event_subscribe sctpEvents;
1295
1296 memset(&sctpEvents, 0, sizeof(sctpEvents));
1297 sctpEvents.sctp_data_io_event = 1;
1298 if (::getsockopt(socketDescriptor, SOL_SCTP, SCTP_STATUS, &sctpStatus,
1299 &sctpStatusSize) == 0 &&
1300 ::setsockopt(socketDescriptor, SOL_SCTP, SCTP_EVENTS, &sctpEvents,
1301 sizeof(sctpEvents)) == 0) {
1302 inboundStreamCount = int(sctpStatus.sstat_instrms);
1303 outboundStreamCount = int(sctpStatus.sstat_outstrms);
1304 } else {
1305 setError(QAbstractSocket::UnsupportedSocketOperationError,
1306 InvalidSocketErrorString);
1307 return false;
1308 }
1309 }
1310 }
1311#endif
1312 } else if (value == SOCK_DGRAM) {
1313 socketType = QAbstractSocket::UdpSocket;
1314#ifdef SOCK_SEQPACKET
1315 } else if (value == SOCK_SEQPACKET) {
1316 // We approximate the SEQPACKET socket type to TCP, because
1317 // this enum is actually used to determine if the socket type has
1318 // a notion of connection. SOCK_DGRAM are connectionless, while
1319 // SOCK_STREAM and SOCK_SEQPACKET are connection-orientired.
1320 // This mapping is still suboptimal, because it is possible to send
1321 // a 0-byte packet via SEQPACKET socket and Qt will treat it as
1322 // a disconnect.
1323 socketType = QAbstractSocket::TcpSocket;
1324#endif
1325 } else {
1326 socketType = QAbstractSocket::UnknownSocketType;
1327 }
1328 }
1329#if defined (QNATIVESOCKETENGINE_DEBUG)
1330 QString socketProtocolStr = QStringLiteral("UnknownProtocol");
1331 if (socketProtocol == QAbstractSocket::IPv4Protocol) socketProtocolStr = QStringLiteral("IPv4Protocol");
1332 else if (socketProtocol == QAbstractSocket::IPv6Protocol || socketProtocol == QAbstractSocket::AnyIPProtocol) socketProtocolStr = QStringLiteral("IPv6Protocol");
1333
1334 QString socketTypeStr = QStringLiteral("UnknownSocketType");
1335 if (socketType == QAbstractSocket::TcpSocket) socketTypeStr = QStringLiteral("TcpSocket");
1336 else if (socketType == QAbstractSocket::UdpSocket) socketTypeStr = QStringLiteral("UdpSocket");
1337 else if (socketType == QAbstractSocket::SctpSocket) socketTypeStr = QStringLiteral("SctpSocket");
1338
1339 qDebug("QNativeSocketEnginePrivate::fetchConnectionParameters() local == %s:%i,"
1340 " peer == %s:%i, socket == %s - %s, inboundStreamCount == %i, outboundStreamCount == %i",
1341 localAddress.toString().toLatin1().constData(), localPort,
1342 peerAddress.toString().toLatin1().constData(), peerPort,socketTypeStr.toLatin1().constData(),
1343 socketProtocolStr.toLatin1().constData(), inboundStreamCount, outboundStreamCount);
1344#endif
1345 return true;
1346}
1347
1349{
1350#if defined (QNATIVESOCKETENGINE_DEBUG)
1351 qDebug("QNativeSocketEngine::nativeClose()");
1352#endif
1353
1354 qt_safe_close(socketDescriptor);
1355}
1356
1357qint64 QNativeSocketEnginePrivate::nativeWrite(const char *data, qint64 len)
1358{
1359 Q_Q(QNativeSocketEngine);
1360
1361 ssize_t writtenBytes;
1362 writtenBytes = qt_safe_write_nosignal(socketDescriptor, data, len);
1363
1364 if (writtenBytes < 0) {
1365 switch (errno) {
1366 case EPIPE:
1367 case ECONNRESET:
1368 writtenBytes = -1;
1369 setError(QAbstractSocket::RemoteHostClosedError, RemoteHostClosedErrorString);
1370 q->close();
1371 break;
1372#if EWOULDBLOCK != EAGAIN
1373 case EWOULDBLOCK:
1374#endif
1375 case EAGAIN:
1376 writtenBytes = 0;
1377 break;
1378 case EMSGSIZE:
1379 setError(QAbstractSocket::DatagramTooLargeError, DatagramTooLargeErrorString);
1380 break;
1381 default:
1382 break;
1383 }
1384 }
1385
1386#if defined (QNATIVESOCKETENGINE_DEBUG)
1387 qDebug("QNativeSocketEnginePrivate::nativeWrite(%p \"%s\", %llu) == %i", data,
1388 QtDebugUtils::toPrintable(data, len, 16).constData(), len, (int) writtenBytes);
1389#endif
1390
1391 return qint64(writtenBytes);
1392}
1393/*
1394*/
1396{
1397 Q_Q(QNativeSocketEngine);
1398 if (!q->isValid()) {
1399 qWarning("QNativeSocketEngine::nativeRead: Invalid socket");
1400 return -1;
1401 }
1402
1403 ssize_t r = 0;
1404 r = qt_safe_read(socketDescriptor, data, maxSize);
1405
1406 if (r < 0) {
1407 r = -1;
1408 switch (errno) {
1409#if EWOULDBLOCK-0 && EWOULDBLOCK != EAGAIN
1410 case EWOULDBLOCK:
1411#endif
1412 case EAGAIN:
1413 // No data was available for reading
1414 r = -2;
1415 break;
1416 case ECONNRESET:
1417#if defined(Q_OS_VXWORKS)
1418 case ESHUTDOWN:
1419#endif
1420 r = 0;
1421 break;
1422 case ETIMEDOUT:
1423 socketError = QAbstractSocket::SocketTimeoutError;
1424 break;
1425 default:
1426 socketError = QAbstractSocket::NetworkError;
1427 break;
1428 }
1429
1430 if (r == -1) {
1431 hasSetSocketError = true;
1432 socketErrorString = qt_error_string();
1433 }
1434 }
1435
1436#if defined (QNATIVESOCKETENGINE_DEBUG)
1437 qDebug("QNativeSocketEnginePrivate::nativeRead(%p \"%s\", %llu) == %zd", data,
1438 QtDebugUtils::toPrintable(data, r, 16).constData(), maxSize, r);
1439#endif
1440
1441 return qint64(r);
1442}
1443
1444int QNativeSocketEnginePrivate::nativeSelect(QDeadlineTimer deadline, bool selectForRead) const
1445{
1446 bool dummy;
1447 return nativeSelect(deadline, selectForRead, !selectForRead, &dummy, &dummy);
1448}
1449
1450#ifndef Q_OS_WASM
1451
1452int QNativeSocketEnginePrivate::nativeSelect(QDeadlineTimer deadline, bool checkRead,
1453 bool checkWrite, bool *selectForRead,
1454 bool *selectForWrite) const
1455{
1456 pollfd pfd = qt_make_pollfd(socketDescriptor, 0);
1457
1458 if (checkRead)
1459 pfd.events |= POLLIN;
1460
1461 if (checkWrite)
1462 pfd.events |= POLLOUT;
1463
1464 const int ret = qt_safe_poll(&pfd, 1, deadline);
1465
1466 if (ret <= 0)
1467 return ret;
1468
1469 if (pfd.revents & POLLNVAL) {
1470 errno = EBADF;
1471 return -1;
1472 }
1473
1474 static const short read_flags = POLLIN | POLLHUP | POLLERR;
1475 static const short write_flags = POLLOUT | POLLHUP | POLLERR;
1476
1477 *selectForRead = ((pfd.revents & read_flags) != 0);
1478 *selectForWrite = ((pfd.revents & write_flags) != 0);
1479
1480 return ret;
1481}
1482
1483#else
1484
1485int QNativeSocketEnginePrivate::nativeSelect(QDeadlineTimer deadline, bool checkRead,
1486 bool checkWrite, bool *selectForRead,
1487 bool *selectForWrite) const
1488{
1489 *selectForRead = checkRead;
1490 *selectForWrite = checkWrite;
1491 bool socketDisconnect = false;
1492 QEventDispatcherWasm::socketSelect(deadline.remainingTime(), socketDescriptor, checkRead,
1493 checkWrite, selectForRead, selectForWrite,
1494 &socketDisconnect);
1495
1496 // The disconnect/close handling code in QAbstractsScket::canReadNotification()
1497 // does not detect remote disconnect properly; do that here as a workardound.
1498 if (socketDisconnect)
1499 receiver->closeNotification();
1500
1501 return 1;
1502}
1503
1504#endif // Q_OS_WASM
1505
1506QT_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