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

Provided by KDAB

Privacy Policy
Learn to use CMake with our Intro Training
Find out more

source code of qtbase/src/network/socket/qnativesocketengine_unix.cpp