Coverage Report

Created: 2026-04-29 07:00

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