diff options
Diffstat (limited to 'src/network/socket/qnativesocketengine_win.cpp')
-rw-r--r-- | src/network/socket/qnativesocketengine_win.cpp | 172 |
1 files changed, 41 insertions, 131 deletions
diff --git a/src/network/socket/qnativesocketengine_win.cpp b/src/network/socket/qnativesocketengine_win.cpp index 9fcf5fbf16..6525f46e30 100644 --- a/src/network/socket/qnativesocketengine_win.cpp +++ b/src/network/socket/qnativesocketengine_win.cpp @@ -1,50 +1,11 @@ -/**************************************************************************** -** -** Copyright (C) 2021 The Qt Company Ltd. -** Copyright (C) 2016 Intel Corporation. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtNetwork module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -// Prevent windows system header files from defining min/max as macros. -#define NOMINMAX 1 +// 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 #include <winsock2.h> #include <ws2tcpip.h> -#include "qnativesocketengine_p.h" +#include "qnativesocketengine_p_p.h" #include <qabstracteventdispatcher.h> #include <qsocketnotifier.h> @@ -52,13 +13,14 @@ #include <qdatetime.h> #include <qnetworkinterface.h> #include <qoperatingsystemversion.h> +#include <qvarlengtharray.h> #include <algorithm> +#include <chrono> //#define QNATIVESOCKETENGINE_DEBUG #if defined(QNATIVESOCKETENGINE_DEBUG) -# include <qstring.h> -# include <qbytearray.h> +#include <private/qdebug_p.h> #endif QT_BEGIN_NAMESPACE @@ -127,36 +89,6 @@ void verboseWSErrorDebug(int r) qErrnoWarning(r, "more details"); } -/* - Returns a human readable representation of the first \a len - characters in \a data. -*/ -static QByteArray qt_prettyDebug(const char *data, int len, int maxLength) -{ - if (!data) return "(null)"; - QByteArray out; - for (int i = 0; i < len; ++i) { - char c = data[i]; - if (isprint(int(uchar(c)))) { - out += c; - } else switch (c) { - case '\n': out += "\\n"; break; - case '\r': out += "\\r"; break; - case '\t': out += "\\t"; break; - default: - QString tmp; - tmp.sprintf("\\%o", c); - out += tmp.toLatin1().constData(); - } - } - - if (len < maxLength) - out += "..."; - - return out; -} - - #define WS_ERROR_DEBUG(x) verboseWSErrorDebug(x) #else @@ -325,15 +257,6 @@ static inline QAbstractSocket::SocketType qt_socket_getType(qintptr socketDescri bool QNativeSocketEnginePrivate::createNewSocket(QAbstractSocket::SocketType socketType, QAbstractSocket::NetworkLayerProtocol &socketProtocol) { - - //### no ip6 support on winsocket 1.1 but we will try not to use this !!!!!!!!!!!!1 - /* - if (winsockVersion < 0x20 && socketProtocol == QAbstractSocket::IPv6Protocol) { - //### no ip6 support - return -1; - } - */ - //### SCTP not implemented if (socketType == QAbstractSocket::SctpSocket) { setError(QAbstractSocket::UnsupportedSocketOperationError, @@ -346,34 +269,15 @@ bool QNativeSocketEnginePrivate::createNewSocket(QAbstractSocket::SocketType soc || (socketProtocol == QAbstractSocket::AnyIPProtocol)) ? AF_INET6 : AF_INET; int type = (socketType == QAbstractSocket::UdpSocket) ? SOCK_DGRAM : SOCK_STREAM; - // MSDN KB179942 states that on winnt 4 WSA_FLAG_OVERLAPPED is needed if socket is to be non blocking - // and recomends alwasy doing it for cross windows version comapablity. + // MSDN KB179942 states that on winnt 4 WSA_FLAG_OVERLAPPED is needed if socket is to be non + // blocking and recommends always doing it for cross-windows-version compatibility. - // WSA_FLAG_NO_HANDLE_INHERIT is atomic (like linux O_CLOEXEC), but requires windows 7 SP 1 or later - // SetHandleInformation is supported since W2K but isn't atomic + // WSA_FLAG_NO_HANDLE_INHERIT is atomic (like linux O_CLOEXEC) #ifndef WSA_FLAG_NO_HANDLE_INHERIT #define WSA_FLAG_NO_HANDLE_INHERIT 0x80 #endif SOCKET socket = ::WSASocket(protocol, type, 0, NULL, 0, WSA_FLAG_NO_HANDLE_INHERIT | WSA_FLAG_OVERLAPPED); - // previous call fails if the windows 7 service pack 1 or hot fix isn't installed. - - // Try the old API if the new one failed on Windows 7 - if (socket == INVALID_SOCKET && QOperatingSystemVersion::current() < QOperatingSystemVersion::Windows8) { - socket = ::WSASocket(protocol, type, 0, NULL, 0, WSA_FLAG_OVERLAPPED); -#ifdef HANDLE_FLAG_INHERIT - if (socket != INVALID_SOCKET) { - // make non inheritable the old way - BOOL handleFlags = SetHandleInformation(reinterpret_cast<HANDLE>(socket), HANDLE_FLAG_INHERIT, 0); -#ifdef QNATIVESOCKETENGINE_DEBUG - qDebug() << "QNativeSocketEnginePrivate::createNewSocket - set inheritable" << handleFlags; -#else - Q_UNUSED(handleFlags); -#endif - } -#endif - } - if (socket == INVALID_SOCKET) { int err = WSAGetLastError(); WS_ERROR_DEBUG(err); @@ -508,7 +412,6 @@ bool QNativeSocketEnginePrivate::setOption(QNativeSocketEngine::SocketOption opt return false; } return true; - break; } case QNativeSocketEngine::TypeOfServiceOption: case QNativeSocketEngine::MaxStreamsSocketOption: @@ -868,10 +771,10 @@ bool QNativeSocketEnginePrivate::nativeListen(int backlog) return true; } -int QNativeSocketEnginePrivate::nativeAccept() +qintptr QNativeSocketEnginePrivate::nativeAccept() { - int acceptedDescriptor = WSAAccept(socketDescriptor, 0,0,0,0); - if (acceptedDescriptor == -1) { + SOCKET acceptedDescriptor = WSAAccept(socketDescriptor, 0,0,0,0); + if (acceptedDescriptor == INVALID_SOCKET) { int err = WSAGetLastError(); switch (err) { case WSAEACCES: @@ -905,19 +808,19 @@ int QNativeSocketEnginePrivate::nativeAccept() setError(QAbstractSocket::UnknownSocketError, UnknownSocketErrorString); break; } - } else if (acceptedDescriptor != -1 && QAbstractEventDispatcher::instance()) { + } else if (acceptedDescriptor != INVALID_SOCKET && QAbstractEventDispatcher::instance()) { // Because of WSAAsyncSelect() WSAAccept returns a non blocking socket // with the same attributes as the listening socket including the current // WSAAsyncSelect(). To be able to change the socket to blocking mode the - // WSAAsyncSelect() call must be cancled. + // WSAAsyncSelect() call must be canceled. QSocketNotifier n(acceptedDescriptor, QSocketNotifier::Read); n.setEnabled(true); n.setEnabled(false); } #if defined (QNATIVESOCKETENGINE_DEBUG) - qDebug("QNativeSocketEnginePrivate::nativeAccept() == %i", acceptedDescriptor); + qDebug("QNativeSocketEnginePrivate::nativeAccept() == %lld", qint64(acceptedDescriptor)); #endif - return acceptedDescriptor; + return qintptr(acceptedDescriptor); } static bool multicastMembershipHelper(QNativeSocketEnginePrivate *d, @@ -1280,7 +1183,7 @@ qint64 QNativeSocketEnginePrivate::nativeReceiveDatagram(char *data, qint64 maxL #if defined (QNATIVESOCKETENGINE_DEBUG) bool printSender = (ret != -1 && (options & QNativeSocketEngine::WantDatagramSender) != 0); qDebug("QNativeSocketEnginePrivate::nativeReceiveDatagram(%p \"%s\", %lli, %s, %i) == %lli", - data, qt_prettyDebug(data, qMin<qint64>(ret, 16), ret).data(), maxLength, + data, QtDebugUtils::toPrintable(data, ret, 16).constData(), maxLength, printSender ? header->senderAddress.toString().toLatin1().constData() : "(unknown)", printSender ? header->senderPort : 0, ret); #endif @@ -1413,8 +1316,8 @@ qint64 QNativeSocketEnginePrivate::nativeSendDatagram(const char *data, qint64 l } #if defined (QNATIVESOCKETENGINE_DEBUG) - qDebug("QNativeSocketEnginePrivate::nativeSendDatagram(%p \"%s\", %lli, \"%s\", %i) == %lli", data, - qt_prettyDebug(data, qMin<qint64>(len, 16), len).data(), len, + qDebug("QNativeSocketEnginePrivate::nativeSendDatagram(%p \"%s\", %lli, \"%s\", %i) == %lli", + data, QtDebugUtils::toPrintable(data, len, 16).constData(), len, header.destinationAddress.toString().toLatin1().constData(), header.destinationPort, ret); #endif @@ -1473,7 +1376,7 @@ qint64 QNativeSocketEnginePrivate::nativeWrite(const char *data, qint64 len) #if defined (QNATIVESOCKETENGINE_DEBUG) qDebug("QNativeSocketEnginePrivate::nativeWrite(%p \"%s\", %lli) == %lli", - data, qt_prettyDebug(data, qMin(int(ret), 16), int(ret)).data(), len, ret); + data, QtDebugUtils::toPrintable(data, ret, 16).constData(), len, ret); #endif return ret; @@ -1515,8 +1418,8 @@ qint64 QNativeSocketEnginePrivate::nativeRead(char *data, qint64 maxLength) #if defined (QNATIVESOCKETENGINE_DEBUG) if (ret != -2) { - qDebug("QNativeSocketEnginePrivate::nativeRead(%p \"%s\", %lli) == %lli", - data, qt_prettyDebug(data, qMin(int(bytesRead), 16), int(bytesRead)).data(), maxLength, ret); + qDebug("QNativeSocketEnginePrivate::nativeRead(%p \"%s\", %lli) == %lli", data, + QtDebugUtils::toPrintable(data, bytesRead, 16).constData(), maxLength, ret); } else { qDebug("QNativeSocketEnginePrivate::nativeRead(%p, %lli) == -2 (WOULD BLOCK)", data, maxLength); @@ -1526,7 +1429,18 @@ qint64 QNativeSocketEnginePrivate::nativeRead(char *data, qint64 maxLength) return ret; } -int QNativeSocketEnginePrivate::nativeSelect(int timeout, bool selectForRead) const +inline timeval durationToTimeval(std::chrono::nanoseconds dur) noexcept +{ + using namespace std::chrono; + const auto secs = duration_cast<seconds>(dur); + const auto frac = duration_cast<microseconds>(dur - secs); + struct timeval tval; + tval.tv_sec = secs.count(); + tval.tv_usec = frac.count(); + return tval; +} + +int QNativeSocketEnginePrivate::nativeSelect(QDeadlineTimer deadline, bool selectForRead) const { bool readEnabled = selectForRead && readNotifier && readNotifier->isEnabled(); if (readEnabled) @@ -1540,12 +1454,10 @@ int QNativeSocketEnginePrivate::nativeSelect(int timeout, bool selectForRead) co fds.fd_count = 1; fds.fd_array[0] = (SOCKET)socketDescriptor; - struct timeval tv; - tv.tv_sec = timeout / 1000; - tv.tv_usec = (timeout % 1000) * 1000; + struct timeval tv = durationToTimeval(deadline.remainingTimeAsDuration()); if (selectForRead) { - ret = select(0, &fds, 0, 0, timeout < 0 ? 0 : &tv); + ret = select(0, &fds, 0, 0, &tv); } else { // select for write @@ -1554,7 +1466,7 @@ int QNativeSocketEnginePrivate::nativeSelect(int timeout, bool selectForRead) co FD_ZERO(&fdexception); FD_SET((SOCKET)socketDescriptor, &fdexception); - ret = select(0, 0, &fds, &fdexception, timeout < 0 ? 0 : &tv); + ret = select(0, 0, &fds, &fdexception, &tv); // ... but if it is actually set, pretend it did not happen if (ret > 0 && FD_ISSET((SOCKET)socketDescriptor, &fdexception)) @@ -1567,7 +1479,7 @@ int QNativeSocketEnginePrivate::nativeSelect(int timeout, bool selectForRead) co return ret; } -int QNativeSocketEnginePrivate::nativeSelect(int timeout, +int QNativeSocketEnginePrivate::nativeSelect(QDeadlineTimer deadline, bool checkRead, bool checkWrite, bool *selectForRead, bool *selectForWrite) const { @@ -1596,11 +1508,9 @@ int QNativeSocketEnginePrivate::nativeSelect(int timeout, FD_SET((SOCKET)socketDescriptor, &fdexception); } - struct timeval tv; - tv.tv_sec = timeout / 1000; - tv.tv_usec = (timeout % 1000) * 1000; + struct timeval tv = durationToTimeval(deadline.remainingTimeAsDuration()); - ret = select(socketDescriptor + 1, &fdread, &fdwrite, &fdexception, timeout < 0 ? 0 : &tv); + ret = select(socketDescriptor + 1, &fdread, &fdwrite, &fdexception, &tv); //... but if it is actually set, pretend it did not happen if (ret > 0 && FD_ISSET((SOCKET)socketDescriptor, &fdexception)) |