diff --git a/.gitignore b/.gitignore index 4acca4502..326a36379 100644 --- a/.gitignore +++ b/.gitignore @@ -95,3 +95,4 @@ Packages/*.pkgar local/cache/pkgar/ local/patches/base/redox.patch local/reference/ +local/recipes/qt/qtbase/source/ diff --git a/local/recipes/qt/qtbase/source/src/network/socket/qnativesocketengine_unix.cpp b/local/recipes/qt/qtbase/source/src/network/socket/qnativesocketengine_unix.cpp deleted file mode 100644 index a4ac293cd..000000000 --- a/local/recipes/qt/qtbase/source/src/network/socket/qnativesocketengine_unix.cpp +++ /dev/null @@ -1,1506 +0,0 @@ -// Copyright (C) 2021 The Qt Company Ltd. -// Copyright (C) 2016 Intel Corporation. -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only -// Qt-Security score:significant reason:default - -//#define QNATIVESOCKETENGINE_DEBUG -#include "qnativesocketengine_p_p.h" -#include "private/qnet_unix_p.h" -#include "qdeadlinetimer.h" -#include "qiodevice.h" -#include "qhostaddress.h" -#include "qvarlengtharray.h" -#include "qnetworkinterface.h" -#include "qnetworkinterface_p.h" -#include "qendian.h" -#ifdef Q_OS_WASM -#include -#endif -#include -#include -#include -#ifdef Q_OS_INTEGRITY -#include -#endif - -#if defined QNATIVESOCKETENGINE_DEBUG -#include -#endif - -#include -#ifndef QT_NO_SCTP -#include -#include -#include -#endif -#ifdef AF_LINK -# include -#endif - -QT_BEGIN_NAMESPACE - -/* - Extracts the port and address from a sockaddr, and stores them in - \a port and \a addr if they are non-null. -*/ -static inline void qt_socket_getPortAndAddress(const qt_sockaddr *s, quint16 *port, QHostAddress *addr) -{ - if (s->a.sa_family == AF_INET6) { - Q_IPV6ADDR tmp; - memcpy(&tmp, &s->a6.sin6_addr, sizeof(tmp)); - if (addr) { - QHostAddress tmpAddress; - tmpAddress.setAddress(tmp); - *addr = tmpAddress; -#if QT_CONFIG(networkinterface) - if (s->a6.sin6_scope_id) - addr->setScopeId(QNetworkInterface::interfaceNameFromIndex(s->a6.sin6_scope_id)); -#endif - } - if (port) - *port = ntohs(s->a6.sin6_port); - return; - } - - if (port) - *port = ntohs(s->a4.sin_port); - if (addr) { - QHostAddress tmpAddress; - tmpAddress.setAddress(ntohl(s->a4.sin_addr.s_addr)); - *addr = tmpAddress; - } -} - -static void convertToLevelAndOption(QNativeSocketEngine::SocketOption opt, - QAbstractSocket::NetworkLayerProtocol socketProtocol, int &level, int &n) -{ - n = -1; - level = SOL_SOCKET; // default - - switch (opt) { - case QNativeSocketEngine::NonBlockingSocketOption: // fcntl, not setsockopt - case QNativeSocketEngine::BindExclusively: // not handled on Unix - case QNativeSocketEngine::MaxStreamsSocketOption: - Q_UNREACHABLE(); - - case QNativeSocketEngine::BindInterfaceIndex: - Q_UNREACHABLE(); // handled directly in setOption() - - case QNativeSocketEngine::BroadcastSocketOption: - n = SO_BROADCAST; - break; - case QNativeSocketEngine::ReceiveBufferSocketOption: - n = SO_RCVBUF; - break; - case QNativeSocketEngine::SendBufferSocketOption: - n = SO_SNDBUF; - break; - case QNativeSocketEngine::AddressReusable: - n = SO_REUSEADDR; - break; - case QNativeSocketEngine::ReceiveOutOfBandData: - n = SO_OOBINLINE; - break; - case QNativeSocketEngine::LowDelayOption: - level = IPPROTO_TCP; - n = TCP_NODELAY; - break; - case QNativeSocketEngine::KeepAliveOption: - n = SO_KEEPALIVE; - break; - case QNativeSocketEngine::MulticastTtlOption: - if (socketProtocol == QAbstractSocket::IPv6Protocol || socketProtocol == QAbstractSocket::AnyIPProtocol) { - level = IPPROTO_IPV6; - n = IPV6_MULTICAST_HOPS; - } else - { - level = IPPROTO_IP; - n = IP_MULTICAST_TTL; - } - break; - case QNativeSocketEngine::MulticastLoopbackOption: - if (socketProtocol == QAbstractSocket::IPv6Protocol || socketProtocol == QAbstractSocket::AnyIPProtocol) { - level = IPPROTO_IPV6; - n = IPV6_MULTICAST_LOOP; - } else - { - level = IPPROTO_IP; - n = IP_MULTICAST_LOOP; - } - break; - case QNativeSocketEngine::TypeOfServiceOption: - if (socketProtocol == QAbstractSocket::IPv4Protocol) { - level = IPPROTO_IP; - n = IP_TOS; - } - break; - case QNativeSocketEngine::ReceivePacketInformation: - if (socketProtocol == QAbstractSocket::IPv6Protocol || socketProtocol == QAbstractSocket::AnyIPProtocol) { - level = IPPROTO_IPV6; - n = IPV6_RECVPKTINFO; - } else if (socketProtocol == QAbstractSocket::IPv4Protocol) { - level = IPPROTO_IP; -#ifdef IP_PKTINFO - n = IP_PKTINFO; -#endif - } - break; - case QNativeSocketEngine::ReceiveHopLimit: - if (socketProtocol == QAbstractSocket::IPv6Protocol || socketProtocol == QAbstractSocket::AnyIPProtocol) { - level = IPPROTO_IPV6; - n = IPV6_RECVHOPLIMIT; - } else if (socketProtocol == QAbstractSocket::IPv4Protocol) { -#ifdef IP_RECVTTL // IP_RECVTTL is a non-standard extension supported on some OS - level = IPPROTO_IP; - n = IP_RECVTTL; -#endif - } - break; - - case QNativeSocketEngine::PathMtuInformation: - if (socketProtocol == QAbstractSocket::IPv6Protocol || socketProtocol == QAbstractSocket::AnyIPProtocol) { -#ifdef IPV6_MTU - level = IPPROTO_IPV6; - n = IPV6_MTU; -#endif - } else { -#ifdef IP_MTU - level = IPPROTO_IP; - n = IP_MTU; -#endif - } - break; - case QNativeSocketEngine::KeepAliveIdleOption: - level = IPPROTO_TCP; -#ifdef TCP_KEEPALIVE - n = TCP_KEEPALIVE; -#else - n = TCP_KEEPIDLE; -#endif - break; - case QNativeSocketEngine::KeepAliveIntervalOption: -#ifdef TCP_KEEPINTVL - level = IPPROTO_TCP; - n = TCP_KEEPINTVL; -#endif - break; - case QNativeSocketEngine::KeepAliveCountOption: -#ifdef TCP_KEEPCNT - level = IPPROTO_TCP; - n = TCP_KEEPCNT; -#endif - break; - } -} - -/*! \internal - - Creates and returns a new socket descriptor of type \a socketType - and \a socketProtocol. Returns -1 on failure. -*/ -bool QNativeSocketEnginePrivate::createNewSocket(QAbstractSocket::SocketType socketType, - QAbstractSocket::NetworkLayerProtocol &socketProtocol) -{ -#ifndef QT_NO_SCTP - int protocol = (socketType == QAbstractSocket::SctpSocket) ? IPPROTO_SCTP : 0; -#else - if (socketType == QAbstractSocket::SctpSocket) { - setError(QAbstractSocket::UnsupportedSocketOperationError, - ProtocolUnsupportedErrorString); -#if defined (QNATIVESOCKETENGINE_DEBUG) - qDebug("QNativeSocketEnginePrivate::createNewSocket(%d, %d): unsupported protocol", - socketType, socketProtocol); -#endif - return false; - } - int protocol = 0; -#endif // QT_NO_SCTP - int domain = (socketProtocol == QAbstractSocket::IPv6Protocol - || socketProtocol == QAbstractSocket::AnyIPProtocol) ? AF_INET6 : AF_INET; - int type = (socketType == QAbstractSocket::UdpSocket) ? SOCK_DGRAM : SOCK_STREAM; - - int socket = qt_safe_socket(domain, type, protocol, O_NONBLOCK); - if (socket < 0 && socketProtocol == QAbstractSocket::AnyIPProtocol && (errno == EAFNOSUPPORT || errno == ENOTSUP )) { - domain = AF_INET; - socket = qt_safe_socket(domain, type, protocol, O_NONBLOCK); - socketProtocol = QAbstractSocket::IPv4Protocol; - } - - if (socket < 0) { - int ecopy = errno; - switch (ecopy) { - case EPROTONOSUPPORT: - case EAFNOSUPPORT: - case EINVAL: - setError(QAbstractSocket::UnsupportedSocketOperationError, ProtocolUnsupportedErrorString); - break; - case ENFILE: - case EMFILE: - case ENOBUFS: - case ENOMEM: - setError(QAbstractSocket::SocketResourceError, ResourceErrorString); - break; - case EACCES: - setError(QAbstractSocket::SocketAccessError, AccessErrorString); - break; - default: - break; - } - -#if defined (QNATIVESOCKETENGINE_DEBUG) - qDebug("QNativeSocketEnginePrivate::createNewSocket(%d, %d) == false (%s)", - socketType, socketProtocol, - strerror(ecopy)); -#endif - - return false; - } - - // Attempt to enable dual-stack - if (domain == AF_INET6) { - const int ipv6only = 0; - [[maybe_unused]] const int ret = ::setsockopt(socket, IPPROTO_IPV6, IPV6_V6ONLY, - &ipv6only, sizeof(ipv6only)); -#if defined (QNATIVESOCKETENGINE_DEBUG) - if (ret != 0) { - qDebug("QNativeSocketEnginePrivate::createNewSocket(%d, %d): " - "failed to set IPV6_V6ONLY to %d.", - socketType, socketProtocol, ipv6only); - } -#endif - } - -#if defined (QNATIVESOCKETENGINE_DEBUG) - qDebug("QNativeSocketEnginePrivate::createNewSocket(%d, %d) == true", - socketType, socketProtocol); -#endif - - socketDescriptor = socket; - this->socketProtocol = socketProtocol; - this->socketType = socketType; - return true; -} - -/* - Returns the value of the socket option \a opt. -*/ -int QNativeSocketEnginePrivate::option(QNativeSocketEngine::SocketOption opt) const -{ - Q_Q(const QNativeSocketEngine); - if (!q->isValid()) - return -1; - - // handle non-getsockopt and specific cases first - switch (opt) { - case QNativeSocketEngine::BindExclusively: - case QNativeSocketEngine::NonBlockingSocketOption: - case QNativeSocketEngine::BroadcastSocketOption: - return -1; - case QNativeSocketEngine::MaxStreamsSocketOption: { -#ifndef QT_NO_SCTP - sctp_initmsg sctpInitMsg; - QT_SOCKOPTLEN_T sctpInitMsgSize = sizeof(sctpInitMsg); - if (::getsockopt(socketDescriptor, SOL_SCTP, SCTP_INITMSG, &sctpInitMsg, - &sctpInitMsgSize) == 0) - return int(qMin(sctpInitMsg.sinit_num_ostreams, sctpInitMsg.sinit_max_instreams)); -#endif - return -1; - } - - case QNativeSocketEngine::PathMtuInformation: -#if defined(IPV6_PATHMTU) && !defined(IPV6_MTU) - // Prefer IPV6_MTU (handled by convertToLevelAndOption), if available - // (Linux); fall back to IPV6_PATHMTU otherwise (FreeBSD): - if (socketProtocol == QAbstractSocket::IPv6Protocol) { - ip6_mtuinfo mtuinfo; - QT_SOCKOPTLEN_T len = sizeof(mtuinfo); - if (::getsockopt(socketDescriptor, IPPROTO_IPV6, IPV6_PATHMTU, &mtuinfo, &len) == 0) - return int(mtuinfo.ip6m_mtu); - return -1; - } -#endif - break; - - default: - break; - } - - int n, level; - int v = 0; - QT_SOCKOPTLEN_T len = sizeof(v); - - convertToLevelAndOption(opt, socketProtocol, level, n); - if (n != -1 && ::getsockopt(socketDescriptor, level, n, (char *) &v, &len) != -1) - return len == 1 ? qFromUnaligned(&v) : v; - - return -1; -} - - -/* - Sets the socket option \a opt to \a v. -*/ -bool QNativeSocketEnginePrivate::setOption(QNativeSocketEngine::SocketOption opt, int v) -{ -#ifdef QNATIVESOCKETENGINE_DEBUG -# define perrorDebug(msg) perror("QNativeSocketEnginePrivate::setOption(): " msg) -#else -# define perrorDebug(msg) (void)0 -#endif - Q_Q(QNativeSocketEngine); - if (!q->isValid()) - return false; - - // handle non-setsockopt and specific cases first - switch (opt) { - case QNativeSocketEngine::NonBlockingSocketOption: { - // Make the socket nonblocking. -#if !defined(Q_OS_VXWORKS) - int flags = ::fcntl(socketDescriptor, F_GETFL, 0); - if (flags == -1) { - perrorDebug("fcntl(F_GETFL) failed"); - return false; - } - if (::fcntl(socketDescriptor, F_SETFL, flags | O_NONBLOCK) == -1) { - perrorDebug("fcntl(F_SETFL) failed"); - return false; - } -#else // Q_OS_VXWORKS - if (qt_safe_ioctl(socketDescriptor, FIONBIO, &v) < 0) { - perrorDebug("ioctl(FIONBIO, 1) failed"); - return false; - } -#endif // Q_OS_VXWORKS - return true; - } - case QNativeSocketEngine::BindExclusively: - return true; - - case QNativeSocketEngine::ReceivePacketInformation: - if (socketProtocol == QAbstractSocket::IPv4Protocol) { -#if !defined(IP_PKTINFO) && defined(IP_RECVDSTADDR) && defined(IP_RECVIF) - // Seen on FreeBSD and QNX. We need both to get the information we want. - int r = 0; - r += ::setsockopt(socketDescriptor, IPPROTO_IP, IP_RECVDSTADDR, &v, sizeof(v)); - r += ::setsockopt(socketDescriptor, IPPROTO_IP, IP_RECVIF, &v, sizeof(v)); - return r == 0; -#endif - } - break; - - case QNativeSocketEngine::MaxStreamsSocketOption: { -#ifndef QT_NO_SCTP - sctp_initmsg sctpInitMsg; - QT_SOCKOPTLEN_T sctpInitMsgSize = sizeof(sctpInitMsg); - if (::getsockopt(socketDescriptor, SOL_SCTP, SCTP_INITMSG, &sctpInitMsg, - &sctpInitMsgSize) == 0) { - sctpInitMsg.sinit_num_ostreams = sctpInitMsg.sinit_max_instreams = uint16_t(v); - return ::setsockopt(socketDescriptor, SOL_SCTP, SCTP_INITMSG, &sctpInitMsg, - sctpInitMsgSize) == 0; - } -#endif - return false; - } - case QNativeSocketEngine::BindInterfaceIndex: { -#if defined(SO_BINDTOIFINDEX) // seen on Linux - return ::setsockopt(socketDescriptor, SOL_SOCKET, SO_BINDTOIFINDEX, - &v, sizeof(v)) == 0; -#elif defined(IPV6_BOUND_IF) && defined(IP_BOUND_IF) // seen on Darwin - // note: on Darwin, this only limits sending the data, not receiving it - if (socketProtocol == QAbstractSocket::IPv6Protocol - || socketProtocol == QAbstractSocket::AnyIPProtocol) { - return ::setsockopt(socketDescriptor, IPPROTO_IPV6, IPV6_BOUND_IF, &v, sizeof(v)) == 0; - } else { - return ::setsockopt(socketDescriptor, IPPROTO_IP, IP_BOUND_IF, &v, sizeof(v)) == 0; - } -#elif defined(SO_BINDTODEVICE) && QT_CONFIG(networkinterface) - // need to convert to interface name - const QByteArray name = QNetworkInterfaceManager::interfaceNameFromIndex(v).toLatin1(); - return ::setsockopt(socketDescriptor, SOL_SOCKET, SO_BINDTODEVICE, - name.data(), socklen_t(name.size())) == 0; -#else - return false; -#endif - } - default: - break; - } - - int n, level; - convertToLevelAndOption(opt, socketProtocol, level, n); -#if defined(SO_REUSEPORT) && !defined(Q_OS_LINUX) - if (opt == QNativeSocketEngine::AddressReusable) { - // on OS X, SO_REUSEADDR isn't sufficient to allow multiple binds to the - // same port (which is useful for multicast UDP). SO_REUSEPORT is, but - // we most definitely do not want to use this for TCP. See QTBUG-6305. - if (socketType == QAbstractSocket::UdpSocket) - n = SO_REUSEPORT; - } -#endif - - if (n == -1) - return false; - return ::setsockopt(socketDescriptor, level, n, (char *) &v, sizeof(v)) == 0; -#undef perrorDebug -} - -bool QNativeSocketEnginePrivate::nativeConnect(const QHostAddress &addr, quint16 port) -{ -#ifdef QNATIVESOCKETENGINE_DEBUG - qDebug() << "QNativeSocketEnginePrivate::nativeConnect() " << socketDescriptor; -#endif - - int socketError = 0; - if (socketState == QAbstractSocket::ConnectingState) { - // We are already connecting, try to read out an error if any. - // This is to avoid calling connect() more than necessary, as the kernel may try to send - // us messages on poll/select of this socket whenever we do. - socklen_t len = sizeof(socketError); - if (getsockopt(int(socketDescriptor), SOL_SOCKET, SO_ERROR, &socketError, &len) != 0) { - // getsockopt failed - let's treat socketError as undefined to be safe. So, reset. - socketError = 0; - } - } - - int connectResult = -1; - if (socketError == 0) { - qt_sockaddr aa; - QT_SOCKLEN_T sockAddrSize; - setPortAndAddress(port, addr, &aa, &sockAddrSize); - - connectResult = qt_safe_connect(socketDescriptor, &aa.a, sockAddrSize); - socketError = errno; - } - if (connectResult == -1) { - switch (socketError) { - case EISCONN: - socketState = QAbstractSocket::ConnectedState; - break; - case ECONNREFUSED: - case EINVAL: - case ENOENT: - setError(QAbstractSocket::ConnectionRefusedError, ConnectionRefusedErrorString); - socketState = QAbstractSocket::UnconnectedState; - break; - case ETIMEDOUT: - setError(QAbstractSocket::NetworkError, ConnectionTimeOutErrorString); - break; - case EHOSTUNREACH: - setError(QAbstractSocket::NetworkError, HostUnreachableErrorString); - socketState = QAbstractSocket::UnconnectedState; - break; - case ENETUNREACH: - setError(QAbstractSocket::NetworkError, NetworkUnreachableErrorString); - socketState = QAbstractSocket::UnconnectedState; - break; - case EADDRINUSE: - setError(QAbstractSocket::NetworkError, AddressInuseErrorString); - break; - case EINPROGRESS: - case EALREADY: - setError(QAbstractSocket::UnfinishedSocketOperationError, InvalidSocketErrorString); - socketState = QAbstractSocket::ConnectingState; - break; - case EAGAIN: - setError(QAbstractSocket::UnfinishedSocketOperationError, InvalidSocketErrorString); - break; - case EACCES: - case EPERM: - setError(QAbstractSocket::SocketAccessError, AccessErrorString); - socketState = QAbstractSocket::UnconnectedState; - break; - case EAFNOSUPPORT: - case EBADF: - case EFAULT: - case ENOTSOCK: - socketState = QAbstractSocket::UnconnectedState; - break; - default: - break; - } - - if (socketState != QAbstractSocket::ConnectedState) { -#if defined (QNATIVESOCKETENGINE_DEBUG) - qDebug("QNativeSocketEnginePrivate::nativeConnect(%s, %i) == false (%s)", - addr.toString().toLatin1().constData(), port, - socketState == QAbstractSocket::ConnectingState - ? "Connection in progress" : strerror(socketError)); -#endif - return false; - } - } - -#if defined (QNATIVESOCKETENGINE_DEBUG) - qDebug("QNativeSocketEnginePrivate::nativeConnect(%s, %i) == true", - addr.toString().toLatin1().constData(), port); -#endif - - socketState = QAbstractSocket::ConnectedState; - return true; -} - -bool QNativeSocketEnginePrivate::nativeBind(const QHostAddress &address, quint16 port) -{ - qt_sockaddr aa; - QT_SOCKLEN_T sockAddrSize; - setPortAndAddress(port, address, &aa, &sockAddrSize); - -#ifdef IPV6_V6ONLY - if (aa.a.sa_family == AF_INET6) { - int ipv6only = 0; - if (address.protocol() == QAbstractSocket::IPv6Protocol) - ipv6only = 1; - //default value of this socket option varies depending on unix variant (or system configuration on BSD), so always set it explicitly - ::setsockopt(socketDescriptor, IPPROTO_IPV6, IPV6_V6ONLY, (char*)&ipv6only, sizeof(ipv6only) ); - } -#endif - - int bindResult = QT_SOCKET_BIND(socketDescriptor, &aa.a, sockAddrSize); - if (bindResult < 0 && errno == EAFNOSUPPORT && address.protocol() == QAbstractSocket::AnyIPProtocol) { - // retry with v4 - aa.a4.sin_family = AF_INET; - aa.a4.sin_port = htons(port); - aa.a4.sin_addr.s_addr = htonl(address.toIPv4Address()); - sockAddrSize = sizeof(aa.a4); - bindResult = QT_SOCKET_BIND(socketDescriptor, &aa.a, sockAddrSize); - } - - if (bindResult < 0) { -#if defined (QNATIVESOCKETENGINE_DEBUG) - int ecopy = errno; -#endif - switch(errno) { - case EADDRINUSE: - setError(QAbstractSocket::AddressInUseError, AddressInuseErrorString); - break; - case EACCES: - setError(QAbstractSocket::SocketAccessError, AddressProtectedErrorString); - break; - case EINVAL: - setError(QAbstractSocket::UnsupportedSocketOperationError, OperationUnsupportedErrorString); - break; - case EADDRNOTAVAIL: - setError(QAbstractSocket::SocketAddressNotAvailableError, AddressNotAvailableErrorString); - break; - default: - break; - } - -#if defined (QNATIVESOCKETENGINE_DEBUG) - qDebug("QNativeSocketEnginePrivate::nativeBind(%s, %i) == false (%s)", - address.toString().toLatin1().constData(), port, strerror(ecopy)); -#endif - - return false; - } - -#if defined (QNATIVESOCKETENGINE_DEBUG) - qDebug("QNativeSocketEnginePrivate::nativeBind(%s, %i) == true", - address.toString().toLatin1().constData(), port); -#endif - socketState = QAbstractSocket::BoundState; - return true; -} - -bool QNativeSocketEnginePrivate::nativeListen(int backlog) -{ - if (qt_safe_listen(socketDescriptor, backlog) < 0) { -#if defined (QNATIVESOCKETENGINE_DEBUG) - int ecopy = errno; -#endif - switch (errno) { - case EADDRINUSE: - setError(QAbstractSocket::AddressInUseError, - PortInuseErrorString); - break; - default: - break; - } - -#if defined (QNATIVESOCKETENGINE_DEBUG) - qDebug("QNativeSocketEnginePrivate::nativeListen(%i) == false (%s)", - backlog, strerror(ecopy)); -#endif - return false; - } - -#if defined (QNATIVESOCKETENGINE_DEBUG) - qDebug("QNativeSocketEnginePrivate::nativeListen(%i) == true", backlog); -#endif - - socketState = QAbstractSocket::ListeningState; - return true; -} - -qintptr QNativeSocketEnginePrivate::nativeAccept() -{ - int acceptedDescriptor = qt_safe_accept(socketDescriptor, nullptr, nullptr); - if (acceptedDescriptor == -1) { - switch (errno) { - case EBADF: - case EOPNOTSUPP: - setError(QAbstractSocket::UnsupportedSocketOperationError, InvalidSocketErrorString); - break; - case ECONNABORTED: - setError(QAbstractSocket::NetworkError, RemoteHostClosedErrorString); - break; - case EFAULT: - case ENOTSOCK: - setError(QAbstractSocket::SocketResourceError, NotSocketErrorString); - break; - case EPROTONOSUPPORT: -#if !defined(Q_OS_OPENBSD) - case EPROTO: -#endif - case EAFNOSUPPORT: - case EINVAL: - setError(QAbstractSocket::UnsupportedSocketOperationError, ProtocolUnsupportedErrorString); - break; - case ENFILE: - case EMFILE: - case ENOBUFS: - case ENOMEM: - setError(QAbstractSocket::SocketResourceError, ResourceErrorString); - break; - case EACCES: - case EPERM: - setError(QAbstractSocket::SocketAccessError, AccessErrorString); - break; -#if EAGAIN != EWOULDBLOCK - case EWOULDBLOCK: -#endif - case EAGAIN: - setError(QAbstractSocket::TemporaryError, TemporaryErrorString); - break; - default: - setError(QAbstractSocket::UnknownSocketError, UnknownSocketErrorString); - break; - } - } - - return qintptr(acceptedDescriptor); -} - -#ifndef QT_NO_NETWORKINTERFACE - -static bool multicastMembershipHelper(QNativeSocketEnginePrivate *d, - int how6, - int how4, - const QHostAddress &groupAddress, - const QNetworkInterface &interface) -{ - int level = 0; - int sockOpt = 0; - void *sockArg; - int sockArgSize; - - ip_mreq mreq4; - ipv6_mreq mreq6; - - if (groupAddress.protocol() == QAbstractSocket::IPv6Protocol) { - level = IPPROTO_IPV6; - sockOpt = how6; - sockArg = &mreq6; - sockArgSize = sizeof(mreq6); - memset(&mreq6, 0, sizeof(mreq6)); - Q_IPV6ADDR ip6 = groupAddress.toIPv6Address(); - memcpy(&mreq6.ipv6mr_multiaddr, &ip6, sizeof(ip6)); - mreq6.ipv6mr_interface = interface.index(); - } else if (groupAddress.protocol() == QAbstractSocket::IPv4Protocol) { - level = IPPROTO_IP; - sockOpt = how4; - sockArg = &mreq4; - sockArgSize = sizeof(mreq4); - memset(&mreq4, 0, sizeof(mreq4)); - mreq4.imr_multiaddr.s_addr = htonl(groupAddress.toIPv4Address()); - - if (interface.isValid()) { - const QList addressEntries = interface.addressEntries(); - bool found = false; - for (const QNetworkAddressEntry &entry : addressEntries) { - const QHostAddress ip = entry.ip(); - if (ip.protocol() == QAbstractSocket::IPv4Protocol) { - mreq4.imr_interface.s_addr = htonl(ip.toIPv4Address()); - found = true; - break; - } - } - if (!found) { - d->setError(QAbstractSocket::NetworkError, - QNativeSocketEnginePrivate::NetworkUnreachableErrorString); - return false; - } - } else { - mreq4.imr_interface.s_addr = INADDR_ANY; - } - } else { - // unreachable - d->setError(QAbstractSocket::UnsupportedSocketOperationError, - QNativeSocketEnginePrivate::ProtocolUnsupportedErrorString); - return false; - } - - int res = setsockopt(d->socketDescriptor, level, sockOpt, sockArg, sockArgSize); - if (res == -1) { - switch (errno) { - case ENOPROTOOPT: - d->setError(QAbstractSocket::UnsupportedSocketOperationError, - QNativeSocketEnginePrivate::OperationUnsupportedErrorString); - break; - case EADDRNOTAVAIL: - d->setError(QAbstractSocket::SocketAddressNotAvailableError, - QNativeSocketEnginePrivate::AddressNotAvailableErrorString); - break; - default: - d->setError(QAbstractSocket::UnknownSocketError, - QNativeSocketEnginePrivate::UnknownSocketErrorString); - break; - } - return false; - } - return true; -} - -bool QNativeSocketEnginePrivate::nativeJoinMulticastGroup(const QHostAddress &groupAddress, - const QNetworkInterface &interface) -{ - return multicastMembershipHelper(this, - IPV6_JOIN_GROUP, - IP_ADD_MEMBERSHIP, - groupAddress, - interface); -} - -bool QNativeSocketEnginePrivate::nativeLeaveMulticastGroup(const QHostAddress &groupAddress, - const QNetworkInterface &interface) -{ - return multicastMembershipHelper(this, - IPV6_LEAVE_GROUP, - IP_DROP_MEMBERSHIP, - groupAddress, - interface); -} - -QNetworkInterface QNativeSocketEnginePrivate::nativeMulticastInterface() const -{ - if (socketProtocol == QAbstractSocket::IPv6Protocol || socketProtocol == QAbstractSocket::AnyIPProtocol) { - uint v; - QT_SOCKOPTLEN_T sizeofv = sizeof(v); - if (::getsockopt(socketDescriptor, IPPROTO_IPV6, IPV6_MULTICAST_IF, &v, &sizeofv) == -1) - return QNetworkInterface(); - return QNetworkInterface::interfaceFromIndex(v); - } - -#if defined(Q_OS_SOLARIS) - struct in_addr v = { 0, 0, 0, 0}; -#else - struct in_addr v = { 0 }; -#endif - QT_SOCKOPTLEN_T sizeofv = sizeof(v); - if (::getsockopt(socketDescriptor, IPPROTO_IP, IP_MULTICAST_IF, &v, &sizeofv) == -1) - return QNetworkInterface(); - if (v.s_addr != 0 && sizeofv >= QT_SOCKOPTLEN_T(sizeof(v))) { - QHostAddress ipv4(ntohl(v.s_addr)); - QList ifaces = QNetworkInterface::allInterfaces(); - for (int i = 0; i < ifaces.size(); ++i) { - const QNetworkInterface &iface = ifaces.at(i); - QList entries = iface.addressEntries(); - for (int j = 0; j < entries.size(); ++j) { - const QNetworkAddressEntry &entry = entries.at(j); - if (entry.ip() == ipv4) - return iface; - } - } - } - return QNetworkInterface(); -} - -bool QNativeSocketEnginePrivate::nativeSetMulticastInterface(const QNetworkInterface &iface) -{ - if (socketProtocol == QAbstractSocket::IPv6Protocol || socketProtocol == QAbstractSocket::AnyIPProtocol) { - uint v = iface.index(); - return (::setsockopt(socketDescriptor, IPPROTO_IPV6, IPV6_MULTICAST_IF, &v, sizeof(v)) != -1); - } - - struct in_addr v; - if (iface.isValid()) { - QList entries = iface.addressEntries(); - for (int i = 0; i < entries.size(); ++i) { - const QNetworkAddressEntry &entry = entries.at(i); - const QHostAddress &ip = entry.ip(); - if (ip.protocol() == QAbstractSocket::IPv4Protocol) { - v.s_addr = htonl(ip.toIPv4Address()); - int r = ::setsockopt(socketDescriptor, IPPROTO_IP, IP_MULTICAST_IF, &v, sizeof(v)); - if (r != -1) - return true; - } - } - return false; - } - - v.s_addr = INADDR_ANY; - return (::setsockopt(socketDescriptor, IPPROTO_IP, IP_MULTICAST_IF, &v, sizeof(v)) != -1); -} - -#endif // QT_NO_NETWORKINTERFACE - -qint64 QNativeSocketEnginePrivate::nativeBytesAvailable() const -{ - int nbytes = 0; - // gives shorter than true amounts on Unix domain sockets. - qint64 available = -1; - -#if defined (SO_NREAD) - if (socketType == QAbstractSocket::UdpSocket) { - socklen_t sz = sizeof nbytes; - if (!::getsockopt(socketDescriptor, SOL_SOCKET, SO_NREAD, &nbytes, &sz)) - available = nbytes; - } -#endif - - if (available == -1 && qt_safe_ioctl(socketDescriptor, FIONREAD, (char *) &nbytes) >= 0) - available = nbytes; - -#if defined (QNATIVESOCKETENGINE_DEBUG) - qDebug("QNativeSocketEnginePrivate::nativeBytesAvailable() == %lli", available); -#endif - return available > 0 ? available : 0; -} - -bool QNativeSocketEnginePrivate::nativeHasPendingDatagrams() const -{ - // Peek 1 bytes into the next message. - ssize_t readBytes; - char c; - QT_EINTR_LOOP(readBytes, ::recv(socketDescriptor, &c, 1, MSG_PEEK)); - - // If there's no error, or if our buffer was too small, there must be a - // pending datagram. - bool result = (readBytes != -1) || errno == EMSGSIZE; - -#if defined (QNATIVESOCKETENGINE_DEBUG) - qDebug("QNativeSocketEnginePrivate::nativeHasPendingDatagrams() == %s", - result ? "true" : "false"); -#endif - return result; -} - -qint64 QNativeSocketEnginePrivate::nativePendingDatagramSize() const -{ - ssize_t recvResult = -1; -#ifdef Q_OS_LINUX - // Linux can return the actual datagram size if we use MSG_TRUNC - char c; - QT_EINTR_LOOP(recvResult, ::recv(socketDescriptor, &c, 1, MSG_PEEK | MSG_TRUNC)); -#elif defined(SO_NREAD) - // macOS can return the actual datagram size if we use SO_NREAD - int value; - socklen_t valuelen = sizeof(value); - recvResult = getsockopt(socketDescriptor, SOL_SOCKET, SO_NREAD, &value, &valuelen); - if (recvResult != -1) - recvResult = value; -#elif defined(Q_OS_VXWORKS) - // VxWorks: use ioctl(FIONREAD) to query the number of bytes available - int available = 0; - int ioctlResult = ::ioctl(socketDescriptor, FIONREAD, &available); - if (ioctlResult != -1) - recvResult = available; -#else - // We need to grow the buffer to fit the entire datagram. - // We start at 1500 bytes (the MTU for Ethernet V2), which should catch - // almost all uses (effective MTU for UDP under IPv4 is 1468), except - // for localhost datagrams and those reassembled by the IP layer. - char udpMessagePeekBuffer[1500]; - struct msghdr msg; - struct iovec vec; - - memset(&msg, 0, sizeof(msg)); - msg.msg_iov = &vec; - msg.msg_iovlen = 1; - vec.iov_base = udpMessagePeekBuffer; - vec.iov_len = sizeof(udpMessagePeekBuffer); - - for (;;) { - // the data written to udpMessagePeekBuffer is discarded, so - // this function is still reentrant although it might not look - // so. - recvResult = ::recvmsg(socketDescriptor, &msg, MSG_PEEK); - if (recvResult == -1 && errno == EINTR) - continue; - - // was the result truncated? - if ((msg.msg_flags & MSG_TRUNC) == 0) - break; - - // grow by 16 times - msg.msg_iovlen *= 16; - if (msg.msg_iov != &vec) - delete[] msg.msg_iov; - msg.msg_iov = new struct iovec[msg.msg_iovlen]; - std::fill_n(msg.msg_iov, msg.msg_iovlen, vec); - } - - if (msg.msg_iov != &vec) - delete[] msg.msg_iov; -#endif - -#if defined (QNATIVESOCKETENGINE_DEBUG) - qDebug("QNativeSocketEnginePrivate::nativePendingDatagramSize() == %zd", recvResult); -#endif - - return qint64(recvResult); -} - -qint64 QNativeSocketEnginePrivate::nativeReceiveDatagram(char *data, qint64 maxSize, QIpPacketHeader *header, - QAbstractSocketEngine::PacketHeaderOptions options) -{ - // we use quintptr to force the alignment - quintptr cbuf[(CMSG_SPACE(sizeof(struct in6_pktinfo)) + CMSG_SPACE(sizeof(int)) -#if !defined(IP_PKTINFO) && defined(IP_RECVIF) && defined(AF_LINK) - + CMSG_SPACE(sizeof(sockaddr_dl)) -#endif -#ifndef QT_NO_SCTP - + CMSG_SPACE(sizeof(struct sctp_sndrcvinfo)) -#endif - + sizeof(quintptr) - 1) / sizeof(quintptr)]; - - struct msghdr msg; - struct iovec vec; - qt_sockaddr aa; - char c; - memset(&msg, 0, sizeof(msg)); - memset(&aa, 0, sizeof(aa)); - - // we need to receive at least one byte, even if our user isn't interested in it - vec.iov_base = maxSize ? data : &c; - vec.iov_len = maxSize ? maxSize : 1; - msg.msg_iov = &vec; - msg.msg_iovlen = 1; - if (options & QAbstractSocketEngine::WantDatagramSender) { - msg.msg_name = &aa; - msg.msg_namelen = sizeof(aa); - } - if (options & (QAbstractSocketEngine::WantDatagramHopLimit | QAbstractSocketEngine::WantDatagramDestination - | QAbstractSocketEngine::WantStreamNumber)) { - msg.msg_control = cbuf; - msg.msg_controllen = sizeof(cbuf); - } - - ssize_t recvResult = 0; - do { - recvResult = ::recvmsg(socketDescriptor, &msg, 0); - } while (recvResult == -1 && errno == EINTR); - - if (recvResult == -1) { - switch (errno) { -#if defined(EWOULDBLOCK) && EWOULDBLOCK != EAGAIN - case EWOULDBLOCK: -#endif - case EAGAIN: - // No datagram was available for reading - recvResult = -2; - break; - case ECONNREFUSED: - setError(QAbstractSocket::ConnectionRefusedError, ConnectionRefusedErrorString); - break; - default: - setError(QAbstractSocket::NetworkError, ReceiveDatagramErrorString); - } - if (header) - header->clear(); - } else if (options != QAbstractSocketEngine::WantNone) { - Q_ASSERT(header); - qt_socket_getPortAndAddress(&aa, &header->senderPort, &header->senderAddress); - header->destinationPort = localPort; - header->endOfRecord = (msg.msg_flags & MSG_EOR) != 0; - - // parse the ancillary data - struct cmsghdr *cmsgptr; - QT_WARNING_PUSH - QT_WARNING_DISABLE_CLANG("-Wsign-compare") - for (cmsgptr = CMSG_FIRSTHDR(&msg); cmsgptr != nullptr; - cmsgptr = CMSG_NXTHDR(&msg, cmsgptr)) { - QT_WARNING_POP - if (cmsgptr->cmsg_level == IPPROTO_IPV6 && cmsgptr->cmsg_type == IPV6_PKTINFO - && cmsgptr->cmsg_len >= CMSG_LEN(sizeof(in6_pktinfo))) { - in6_pktinfo *info = reinterpret_cast(CMSG_DATA(cmsgptr)); - - header->destinationAddress.setAddress(reinterpret_cast(&info->ipi6_addr)); - header->ifindex = info->ipi6_ifindex; - if (header->ifindex) - header->destinationAddress.setScopeId(QString::number(info->ipi6_ifindex)); - } - -#ifdef IP_PKTINFO - if (cmsgptr->cmsg_level == IPPROTO_IP && cmsgptr->cmsg_type == IP_PKTINFO - && cmsgptr->cmsg_len >= CMSG_LEN(sizeof(in_pktinfo))) { - in_pktinfo *info = reinterpret_cast(CMSG_DATA(cmsgptr)); - - header->destinationAddress.setAddress(ntohl(info->ipi_addr.s_addr)); - header->ifindex = info->ipi_ifindex; - } -#else -# ifdef IP_RECVDSTADDR - if (cmsgptr->cmsg_level == IPPROTO_IP && cmsgptr->cmsg_type == IP_RECVDSTADDR - && cmsgptr->cmsg_len >= CMSG_LEN(sizeof(in_addr))) { - in_addr *addr = reinterpret_cast(CMSG_DATA(cmsgptr)); - - header->destinationAddress.setAddress(ntohl(addr->s_addr)); - } -# endif -# if defined(IP_RECVIF) && defined(AF_LINK) - if (cmsgptr->cmsg_level == IPPROTO_IP && cmsgptr->cmsg_type == IP_RECVIF - && cmsgptr->cmsg_len >= CMSG_LEN(sizeof(sockaddr_dl))) { - sockaddr_dl *sdl = reinterpret_cast(CMSG_DATA(cmsgptr)); - header->ifindex = sdl->sdl_index; - } -# endif -#endif - - if (cmsgptr->cmsg_len == CMSG_LEN(sizeof(int)) - && ((cmsgptr->cmsg_level == IPPROTO_IPV6 && cmsgptr->cmsg_type == IPV6_HOPLIMIT) - || (cmsgptr->cmsg_level == IPPROTO_IP && cmsgptr->cmsg_type == IP_TTL))) { - static_assert(sizeof(header->hopLimit) == sizeof(int)); - memcpy(&header->hopLimit, CMSG_DATA(cmsgptr), sizeof(header->hopLimit)); - } - -#ifndef QT_NO_SCTP - if (cmsgptr->cmsg_level == IPPROTO_SCTP && cmsgptr->cmsg_type == SCTP_SNDRCV - && cmsgptr->cmsg_len >= CMSG_LEN(sizeof(sctp_sndrcvinfo))) { - sctp_sndrcvinfo *rcvInfo = reinterpret_cast(CMSG_DATA(cmsgptr)); - - header->streamNumber = int(rcvInfo->sinfo_stream); - } -#endif - } - } - -#if defined (QNATIVESOCKETENGINE_DEBUG) - qDebug("QNativeSocketEnginePrivate::nativeReceiveDatagram(%p \"%s\", %lli, %s, %i) == %lli", - data, QtDebugUtils::toPrintable(data, recvResult, 16).constData(), maxSize, - (recvResult != -1 && options != QAbstractSocketEngine::WantNone) - ? header->senderAddress.toString().toLatin1().constData() : "(unknown)", - (recvResult != -1 && options != QAbstractSocketEngine::WantNone) - ? header->senderPort : 0, (qint64) recvResult); -#endif - - return qint64((maxSize || recvResult < 0) ? recvResult : Q_INT64_C(0)); -} - -qint64 QNativeSocketEnginePrivate::nativeSendDatagram(const char *data, qint64 len, const QIpPacketHeader &header) -{ - // we use quintptr to force the alignment - quintptr cbuf[(CMSG_SPACE(sizeof(struct in6_pktinfo)) + CMSG_SPACE(sizeof(int)) -#ifndef QT_NO_SCTP - + CMSG_SPACE(sizeof(struct sctp_sndrcvinfo)) -#endif - + sizeof(quintptr) - 1) / sizeof(quintptr)]; - - struct cmsghdr *cmsgptr = reinterpret_cast(cbuf); - struct msghdr msg; - struct iovec vec; - qt_sockaddr aa; - - memset(&msg, 0, sizeof(msg)); - memset(&aa, 0, sizeof(aa)); - vec.iov_base = const_cast(data); - vec.iov_len = len; - msg.msg_iov = &vec; - msg.msg_iovlen = 1; - msg.msg_control = &cbuf; - - if (header.destinationPort != 0) { - msg.msg_name = &aa.a; - setPortAndAddress(header.destinationPort, header.destinationAddress, - &aa, &msg.msg_namelen); - } - - if (msg.msg_namelen == sizeof(aa.a6)) { - if (header.hopLimit != -1) { - msg.msg_controllen += CMSG_SPACE(sizeof(int)); - cmsgptr->cmsg_len = CMSG_LEN(sizeof(int)); - cmsgptr->cmsg_level = IPPROTO_IPV6; - cmsgptr->cmsg_type = IPV6_HOPLIMIT; - memcpy(CMSG_DATA(cmsgptr), &header.hopLimit, sizeof(int)); - cmsgptr = reinterpret_cast(reinterpret_cast(cmsgptr) + CMSG_SPACE(sizeof(int))); - } - if (header.ifindex != 0 || !header.senderAddress.isNull()) { - struct in6_pktinfo *data = reinterpret_cast(CMSG_DATA(cmsgptr)); - memset(data, 0, sizeof(*data)); - msg.msg_controllen += CMSG_SPACE(sizeof(*data)); - cmsgptr->cmsg_len = CMSG_LEN(sizeof(*data)); - cmsgptr->cmsg_level = IPPROTO_IPV6; - cmsgptr->cmsg_type = IPV6_PKTINFO; - data->ipi6_ifindex = header.ifindex; - - QIPv6Address tmp = header.senderAddress.toIPv6Address(); - memcpy(&data->ipi6_addr, &tmp, sizeof(tmp)); - cmsgptr = reinterpret_cast(reinterpret_cast(cmsgptr) + CMSG_SPACE(sizeof(*data))); - } - } else { - if (header.hopLimit != -1) { - msg.msg_controllen += CMSG_SPACE(sizeof(int)); - cmsgptr->cmsg_len = CMSG_LEN(sizeof(int)); - cmsgptr->cmsg_level = IPPROTO_IP; - cmsgptr->cmsg_type = IP_TTL; - memcpy(CMSG_DATA(cmsgptr), &header.hopLimit, sizeof(int)); - cmsgptr = reinterpret_cast(reinterpret_cast(cmsgptr) + CMSG_SPACE(sizeof(int))); - } - -#if defined(IP_PKTINFO) || defined(IP_SENDSRCADDR) - if (header.ifindex != 0 || !header.senderAddress.isNull()) { -# ifdef IP_PKTINFO - struct in_pktinfo *data = reinterpret_cast(CMSG_DATA(cmsgptr)); - memset(data, 0, sizeof(*data)); - cmsgptr->cmsg_type = IP_PKTINFO; - data->ipi_ifindex = header.ifindex; - data->ipi_addr.s_addr = htonl(header.senderAddress.toIPv4Address()); -# elif defined(IP_SENDSRCADDR) - struct in_addr *data = reinterpret_cast(CMSG_DATA(cmsgptr)); - cmsgptr->cmsg_type = IP_SENDSRCADDR; - data->s_addr = htonl(header.senderAddress.toIPv4Address()); -# endif - cmsgptr->cmsg_level = IPPROTO_IP; - msg.msg_controllen += CMSG_SPACE(sizeof(*data)); - cmsgptr->cmsg_len = CMSG_LEN(sizeof(*data)); - cmsgptr = reinterpret_cast(reinterpret_cast(cmsgptr) + CMSG_SPACE(sizeof(*data))); - } -#endif - } - -#ifndef QT_NO_SCTP - if (header.streamNumber != -1) { - struct sctp_sndrcvinfo *data = reinterpret_cast(CMSG_DATA(cmsgptr)); - memset(data, 0, sizeof(*data)); - msg.msg_controllen += CMSG_SPACE(sizeof(sctp_sndrcvinfo)); - cmsgptr->cmsg_len = CMSG_LEN(sizeof(sctp_sndrcvinfo)); - cmsgptr->cmsg_level = IPPROTO_SCTP; - cmsgptr->cmsg_type = SCTP_SNDRCV; - data->sinfo_stream = uint16_t(header.streamNumber); - cmsgptr = reinterpret_cast(reinterpret_cast(cmsgptr) + CMSG_SPACE(sizeof(*data))); - } -#endif - - if (msg.msg_controllen == 0) - msg.msg_control = nullptr; - ssize_t sentBytes = qt_safe_sendmsg(socketDescriptor, &msg, 0); - - if (sentBytes < 0) { - switch (errno) { -#if defined(EWOULDBLOCK) && EWOULDBLOCK != EAGAIN - case EWOULDBLOCK: -#endif - case EAGAIN: - sentBytes = -2; - break; - case EMSGSIZE: - // seen on VxWorks - case ENOMEM: - setError(QAbstractSocket::DatagramTooLargeError, DatagramTooLargeErrorString); - break; - case ECONNRESET: - setError(QAbstractSocket::RemoteHostClosedError, RemoteHostClosedErrorString); - break; - default: - setError(QAbstractSocket::NetworkError, SendDatagramErrorString); - } - } - -#if defined (QNATIVESOCKETENGINE_DEBUG) - qDebug("QNativeSocketEngine::sendDatagram(%p \"%s\", %lli, \"%s\", %i) == %lli", data, - QtDebugUtils::toPrintable(data, len, 16).constData(), len, - header.destinationAddress.toString().toLatin1().constData(), - header.destinationPort, (qint64) sentBytes); -#endif - - return qint64(sentBytes); -} - -bool QNativeSocketEnginePrivate::fetchConnectionParameters() -{ - localPort = 0; - localAddress.clear(); - peerPort = 0; - peerAddress.clear(); - inboundStreamCount = outboundStreamCount = 0; - - if (socketDescriptor == -1) - return false; - - qt_sockaddr sa; - QT_SOCKLEN_T sockAddrSize = sizeof(sa); - - // Determine local address - memset(&sa, 0, sizeof(sa)); - if (::getsockname(socketDescriptor, &sa.a, &sockAddrSize) == 0) { - qt_socket_getPortAndAddress(&sa, &localPort, &localAddress); - - // Determine protocol family - switch (sa.a.sa_family) { - case AF_INET: - socketProtocol = QAbstractSocket::IPv4Protocol; - break; - case AF_INET6: - socketProtocol = QAbstractSocket::IPv6Protocol; - break; - default: - socketProtocol = QAbstractSocket::UnknownNetworkLayerProtocol; - break; - } - - } else if (errno == EBADF) { - setError(QAbstractSocket::UnsupportedSocketOperationError, InvalidSocketErrorString); - return false; - } - -#if defined (IPV6_V6ONLY) - // determine if local address is dual mode - // On linux, these are returned as "::" (==AnyIPv6) - // On OSX, these are returned as "::FFFF:0.0.0.0" (==AnyIPv4) - // in either case, the IPV6_V6ONLY option is cleared - int ipv6only = 0; - socklen_t optlen = sizeof(ipv6only); - if (socketProtocol == QAbstractSocket::IPv6Protocol - && (localAddress == QHostAddress::AnyIPv4 || localAddress == QHostAddress::AnyIPv6) - && !getsockopt(socketDescriptor, IPPROTO_IPV6, IPV6_V6ONLY, (char*)&ipv6only, &optlen )) { - if (optlen != sizeof(ipv6only)) - qWarning("unexpected size of IPV6_V6ONLY socket option"); - if (!ipv6only) { - socketProtocol = QAbstractSocket::AnyIPProtocol; - localAddress = QHostAddress::Any; - } - } -#endif - - // Determine the remote address - bool connected = ::getpeername(socketDescriptor, &sa.a, &sockAddrSize) == 0; - if (connected) { - qt_socket_getPortAndAddress(&sa, &peerPort, &peerAddress); - inboundStreamCount = outboundStreamCount = 1; - } - - // Determine the socket type (UDP/TCP/SCTP) - int value = 0; - QT_SOCKOPTLEN_T valueSize = sizeof(int); - if (::getsockopt(socketDescriptor, SOL_SOCKET, SO_TYPE, &value, &valueSize) == 0) { - if (value == SOCK_STREAM) { - socketType = QAbstractSocket::TcpSocket; -#ifndef QT_NO_SCTP - if (option(QNativeSocketEngine::MaxStreamsSocketOption) != -1) { - socketType = QAbstractSocket::SctpSocket; - if (connected) { - sctp_status sctpStatus; - QT_SOCKOPTLEN_T sctpStatusSize = sizeof(sctpStatus); - sctp_event_subscribe sctpEvents; - - memset(&sctpEvents, 0, sizeof(sctpEvents)); - sctpEvents.sctp_data_io_event = 1; - if (::getsockopt(socketDescriptor, SOL_SCTP, SCTP_STATUS, &sctpStatus, - &sctpStatusSize) == 0 && - ::setsockopt(socketDescriptor, SOL_SCTP, SCTP_EVENTS, &sctpEvents, - sizeof(sctpEvents)) == 0) { - inboundStreamCount = int(sctpStatus.sstat_instrms); - outboundStreamCount = int(sctpStatus.sstat_outstrms); - } else { - setError(QAbstractSocket::UnsupportedSocketOperationError, - InvalidSocketErrorString); - return false; - } - } - } -#endif - } else if (value == SOCK_DGRAM) { - socketType = QAbstractSocket::UdpSocket; -#ifdef SOCK_SEQPACKET - } else if (value == SOCK_SEQPACKET) { - // We approximate the SEQPACKET socket type to TCP, because - // this enum is actually used to determine if the socket type has - // a notion of connection. SOCK_DGRAM are connectionless, while - // SOCK_STREAM and SOCK_SEQPACKET are connection-orientired. - // This mapping is still suboptimal, because it is possible to send - // a 0-byte packet via SEQPACKET socket and Qt will treat it as - // a disconnect. - socketType = QAbstractSocket::TcpSocket; -#endif - } else { - socketType = QAbstractSocket::UnknownSocketType; - } - } -#if defined (QNATIVESOCKETENGINE_DEBUG) - QString socketProtocolStr = QStringLiteral("UnknownProtocol"); - if (socketProtocol == QAbstractSocket::IPv4Protocol) socketProtocolStr = QStringLiteral("IPv4Protocol"); - else if (socketProtocol == QAbstractSocket::IPv6Protocol || socketProtocol == QAbstractSocket::AnyIPProtocol) socketProtocolStr = QStringLiteral("IPv6Protocol"); - - QString socketTypeStr = QStringLiteral("UnknownSocketType"); - if (socketType == QAbstractSocket::TcpSocket) socketTypeStr = QStringLiteral("TcpSocket"); - else if (socketType == QAbstractSocket::UdpSocket) socketTypeStr = QStringLiteral("UdpSocket"); - else if (socketType == QAbstractSocket::SctpSocket) socketTypeStr = QStringLiteral("SctpSocket"); - - qDebug("QNativeSocketEnginePrivate::fetchConnectionParameters() local == %s:%i," - " peer == %s:%i, socket == %s - %s, inboundStreamCount == %i, outboundStreamCount == %i", - localAddress.toString().toLatin1().constData(), localPort, - peerAddress.toString().toLatin1().constData(), peerPort,socketTypeStr.toLatin1().constData(), - socketProtocolStr.toLatin1().constData(), inboundStreamCount, outboundStreamCount); -#endif - return true; -} - -void QNativeSocketEnginePrivate::nativeClose() -{ -#if defined (QNATIVESOCKETENGINE_DEBUG) - qDebug("QNativeSocketEngine::nativeClose()"); -#endif - - qt_safe_close(socketDescriptor); -} - -qint64 QNativeSocketEnginePrivate::nativeWrite(const char *data, qint64 len) -{ - Q_Q(QNativeSocketEngine); - - ssize_t writtenBytes; - writtenBytes = qt_safe_write_nosignal(socketDescriptor, data, len); - - if (writtenBytes < 0) { - switch (errno) { - case EPIPE: - case ECONNRESET: - writtenBytes = -1; - setError(QAbstractSocket::RemoteHostClosedError, RemoteHostClosedErrorString); - q->close(); - break; -#if EWOULDBLOCK != EAGAIN - case EWOULDBLOCK: -#endif - case EAGAIN: - writtenBytes = 0; - break; - case EMSGSIZE: - setError(QAbstractSocket::DatagramTooLargeError, DatagramTooLargeErrorString); - break; - default: - break; - } - } - -#if defined (QNATIVESOCKETENGINE_DEBUG) - qDebug("QNativeSocketEnginePrivate::nativeWrite(%p \"%s\", %llu) == %i", data, - QtDebugUtils::toPrintable(data, len, 16).constData(), len, (int) writtenBytes); -#endif - - return qint64(writtenBytes); -} -/* -*/ -qint64 QNativeSocketEnginePrivate::nativeRead(char *data, qint64 maxSize) -{ - Q_Q(QNativeSocketEngine); - if (!q->isValid()) { - qWarning("QNativeSocketEngine::nativeRead: Invalid socket"); - return -1; - } - - ssize_t r = 0; - r = qt_safe_read(socketDescriptor, data, maxSize); - - if (r < 0) { - r = -1; - switch (errno) { -#if EWOULDBLOCK-0 && EWOULDBLOCK != EAGAIN - case EWOULDBLOCK: -#endif - case EAGAIN: - // No data was available for reading - r = -2; - break; - case ECONNRESET: -#if defined(Q_OS_VXWORKS) - case ESHUTDOWN: -#endif - r = 0; - break; - case ETIMEDOUT: - socketError = QAbstractSocket::SocketTimeoutError; - break; - default: - socketError = QAbstractSocket::NetworkError; - break; - } - - if (r == -1) { - hasSetSocketError = true; - socketErrorString = qt_error_string(); - } - } - -#if defined (QNATIVESOCKETENGINE_DEBUG) - qDebug("QNativeSocketEnginePrivate::nativeRead(%p \"%s\", %llu) == %zd", data, - QtDebugUtils::toPrintable(data, r, 16).constData(), maxSize, r); -#endif - - return qint64(r); -} - -int QNativeSocketEnginePrivate::nativeSelect(QDeadlineTimer deadline, bool selectForRead) const -{ - bool dummy; - return nativeSelect(deadline, selectForRead, !selectForRead, &dummy, &dummy); -} - -#ifndef Q_OS_WASM - -int QNativeSocketEnginePrivate::nativeSelect(QDeadlineTimer deadline, bool checkRead, - bool checkWrite, bool *selectForRead, - bool *selectForWrite) const -{ - pollfd pfd = qt_make_pollfd(socketDescriptor, 0); - - if (checkRead) - pfd.events |= POLLIN; - - if (checkWrite) - pfd.events |= POLLOUT; - - const int ret = qt_safe_poll(&pfd, 1, deadline); - - if (ret <= 0) - return ret; - - if (pfd.revents & POLLNVAL) { - errno = EBADF; - return -1; - } - - static const short read_flags = POLLIN | POLLHUP | POLLERR; - static const short write_flags = POLLOUT | POLLHUP | POLLERR; - - *selectForRead = ((pfd.revents & read_flags) != 0); - *selectForWrite = ((pfd.revents & write_flags) != 0); - - return ret; -} - -#else - -int QNativeSocketEnginePrivate::nativeSelect(QDeadlineTimer deadline, bool checkRead, - bool checkWrite, bool *selectForRead, - bool *selectForWrite) const -{ - *selectForRead = checkRead; - *selectForWrite = checkWrite; - bool socketDisconnect = false; - QEventDispatcherWasm::socketSelect(deadline.remainingTime(), socketDescriptor, checkRead, - checkWrite, selectForRead, selectForWrite, - &socketDisconnect); - - // The disconnect/close handling code in QAbstractsScket::canReadNotification() - // does not detect remote disconnect properly; do that here as a workardound. - if (socketDisconnect) - receiver->closeNotification(); - - return 1; -} - -#endif // Q_OS_WASM - -QT_END_NAMESPACE