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 | */ |
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 | */ |
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 | |
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 | */ |
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 | */ |
325 | 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 | */ |
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 | |
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 | |
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 | |
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 | |
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 | |
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 | |
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 | |
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 | |
778 | 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 | |
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 | |
837 | 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 | |
860 | 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 | |
878 | 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 | |
938 | qint64 QNativeSocketEnginePrivate::(char *data, qint64 maxSize, QIpPacketHeader *, |
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 | 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 | |
1074 | qint64 QNativeSocketEnginePrivate::(const char *data, qint64 len, const QIpPacketHeader &) |
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 | |
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 | |
1323 | void QNativeSocketEnginePrivate::nativeClose() |
1324 | { |
1325 | #if defined (QNATIVESOCKETENGINE_DEBUG) |
1326 | qDebug("QNativeSocketEngine::nativeClose()" ); |
1327 | #endif |
1328 | |
1329 | qt_safe_close(socketDescriptor); |
1330 | } |
1331 | |
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 | */ |
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 | |
1418 | int QNativeSocketEnginePrivate::nativeSelect(int timeout, bool selectForRead) const |
1419 | { |
1420 | bool dummy; |
1421 | return nativeSelect(timeout, selectForRead, !selectForRead, &dummy, &dummy); |
1422 | } |
1423 | |
1424 | 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 | |