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

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