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