diff options
Diffstat (limited to 'src/network/socket/qabstractsocket.cpp')
-rw-r--r-- | src/network/socket/qabstractsocket.cpp | 200 |
1 files changed, 91 insertions, 109 deletions
diff --git a/src/network/socket/qabstractsocket.cpp b/src/network/socket/qabstractsocket.cpp index 08e6b8c77d..e456d00713 100644 --- a/src/network/socket/qabstractsocket.cpp +++ b/src/network/socket/qabstractsocket.cpp @@ -1,42 +1,6 @@ -/**************************************************************************** -** -** Copyright (C) 2016 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$ -** -****************************************************************************/ +// Copyright (C) 2022 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 //#define QABSTRACTSOCKET_DEBUG @@ -209,8 +173,9 @@ parameter describes the type of error that occurred. When this signal is emitted, the socket may not be ready for a reconnect - attempt. In that case, attempts to reconnect should be done from the event - loop. For example, use a QTimer::singleShot() with 0 as the timeout. + attempt. In that case, attempts to reconnect should be done from the + event loop. For example, use QChronoTimer::singleShot() with 0ns as + the timeout. QAbstractSocket::SocketError is not a registered metatype, so for queued connections, you will have to register it with Q_DECLARE_METATYPE() and @@ -475,7 +440,7 @@ #include <qmetaobject.h> #include <qpointer.h> #include <qtimer.h> -#include <qelapsedtimer.h> +#include <qdeadlinetimer.h> #include <qscopedvaluerollback.h> #include <qvarlengtharray.h> @@ -500,7 +465,13 @@ QT_BEGIN_NAMESPACE -static const int DefaultConnectTimeout = 30000; +using namespace Qt::StringLiterals; +using namespace std::chrono_literals; + +QT_IMPL_METATYPE_EXTERN_TAGGED(QAbstractSocket::SocketState, QAbstractSocket__SocketState) +QT_IMPL_METATYPE_EXTERN_TAGGED(QAbstractSocket::SocketError, QAbstractSocket__SocketError) + +static constexpr auto DefaultConnectTimeout = 30s; static bool isProxyError(QAbstractSocket::SocketError error) { @@ -522,25 +493,6 @@ static bool isProxyError(QAbstractSocket::SocketError error) Constructs a QAbstractSocketPrivate. Initializes all members. */ QAbstractSocketPrivate::QAbstractSocketPrivate() - : emittedReadyRead(false), - emittedBytesWritten(false), - abortCalled(false), - pendingClose(false), - pauseMode(QAbstractSocket::PauseNever), - port(0), - localPort(0), - peerPort(0), - socketEngine(nullptr), - cachedSocketDescriptor(-1), - readBufferMaxSize(0), - isBuffered(false), - hasPendingData(false), - connectTimer(nullptr), - hostLookupId(-1), - socketType(QAbstractSocket::UnknownSocketType), - state(QAbstractSocket::UnconnectedState), - socketError(QAbstractSocket::UnknownSocketError), - preferredNetworkLayerProtocol(QAbstractSocket::UnknownNetworkLayerProtocol) { writeBufferChunkSize = QABSTRACTSOCKET_BUFFERSIZE; } @@ -592,14 +544,14 @@ bool QAbstractSocketPrivate::initSocketLayer(QAbstractSocket::NetworkLayerProtoc Q_Q(QAbstractSocket); #if defined (QABSTRACTSOCKET_DEBUG) QString typeStr; - if (q->socketType() == QAbstractSocket::TcpSocket) typeStr = QLatin1String("TcpSocket"); - else if (q->socketType() == QAbstractSocket::UdpSocket) typeStr = QLatin1String("UdpSocket"); - else if (q->socketType() == QAbstractSocket::SctpSocket) typeStr = QLatin1String("SctpSocket"); - else typeStr = QLatin1String("UnknownSocketType"); + if (q->socketType() == QAbstractSocket::TcpSocket) typeStr = "TcpSocket"_L1; + else if (q->socketType() == QAbstractSocket::UdpSocket) typeStr = "UdpSocket"_L1; + else if (q->socketType() == QAbstractSocket::SctpSocket) typeStr = "SctpSocket"_L1; + else typeStr = "UnknownSocketType"_L1; QString protocolStr; - if (protocol == QAbstractSocket::IPv4Protocol) protocolStr = QLatin1String("IPv4Protocol"); - else if (protocol == QAbstractSocket::IPv6Protocol) protocolStr = QLatin1String("IPv6Protocol"); - else protocolStr = QLatin1String("UnknownNetworkLayerProtocol"); + if (protocol == QAbstractSocket::IPv4Protocol) protocolStr = "IPv4Protocol"_L1; + else if (protocol == QAbstractSocket::IPv6Protocol) protocolStr = "IPv6Protocol"_L1; + else protocolStr = "UnknownNetworkLayerProtocol"_L1; #endif resetSocketLayer(); @@ -686,11 +638,19 @@ bool QAbstractSocketPrivate::canReadNotification() return !q->isReadable(); } } else { - if (hasPendingData) { + const bool isUdpSocket = (socketType == QAbstractSocket::UdpSocket); + if (hasPendingData && (!isUdpSocket || hasPendingDatagram)) { socketEngine->setReadNotificationEnabled(false); return true; } - hasPendingData = true; + if (!isUdpSocket +#if QT_CONFIG(udpsocket) + || socketEngine->hasPendingDatagrams() +#endif + ) { + hasPendingData = true; + hasPendingDatagram = isUdpSocket; + } } emitReadyRead(); @@ -886,7 +846,7 @@ void QAbstractSocketPrivate::resolveProxy(const QString &hostname, quint16 port) } // return the first that we can use - for (const QNetworkProxy &p : qAsConst(proxies)) { + for (const QNetworkProxy &p : std::as_const(proxies)) { if (socketType == QAbstractSocket::UdpSocket && (p.capabilities() & QNetworkProxy::UdpTunnelingCapability) == 0) continue; @@ -985,12 +945,12 @@ void QAbstractSocketPrivate::_q_startConnecting(const QHostInfo &hostInfo) #if defined(QABSTRACTSOCKET_DEBUG) - QString s = QLatin1String("{"); + QString s = "{"_L1; for (int i = 0; i < addresses.count(); ++i) { - if (i != 0) s += QLatin1String(", "); + if (i != 0) s += ", "_L1; s += addresses.at(i).toString(); } - s += QLatin1Char('}'); + s += u'}'; qDebug("QAbstractSocketPrivate::_q_startConnecting(hostInfo == %s)", s.toLatin1().constData()); #endif @@ -1107,8 +1067,7 @@ void QAbstractSocketPrivate::_q_connectToNextAddress() q, SLOT(_q_abortConnectionAttempt()), Qt::DirectConnection); } - int connectTimeout = DefaultConnectTimeout; - connectTimer->start(connectTimeout); + connectTimer->start(DefaultConnectTimeout); } // Wait for a write notification that will eventually call @@ -1346,12 +1305,29 @@ void QAbstractSocketPrivate::pauseSocketNotifiers(QAbstractSocket *socket) QAbstractSocketEngine *socketEngine = socket->d_func()->socketEngine; if (!socketEngine) return; - socket->d_func()->prePauseReadSocketNotifierState = socketEngine->isReadNotificationEnabled(); - socket->d_func()->prePauseWriteSocketNotifierState = socketEngine->isWriteNotificationEnabled(); - socket->d_func()->prePauseExceptionSocketNotifierState = socketEngine->isExceptionNotificationEnabled(); - socketEngine->setReadNotificationEnabled(false); - socketEngine->setWriteNotificationEnabled(false); - socketEngine->setExceptionNotificationEnabled(false); + bool read = socketEngine->isReadNotificationEnabled(); + bool write = socketEngine->isWriteNotificationEnabled(); + bool except = socketEngine->isExceptionNotificationEnabled(); + +#ifdef QABSTRACTSOCKET_DEBUG + qDebug() << socketEngine->socketDescriptor() + << "pause notifiers, storing 'true' states, currently read:" << read + << "write:" << write << "except:" << except; +#endif + // We do this if-check to avoid accidentally overwriting any previously stored state + // It will reset to false once the socket is re-enabled. + if (read) { + socket->d_func()->prePauseReadSocketNotifierState = true; + socketEngine->setReadNotificationEnabled(false); + } + if (write) { + socket->d_func()->prePauseWriteSocketNotifierState = true; + socketEngine->setWriteNotificationEnabled(false); + } + if (except) { + socket->d_func()->prePauseExceptionSocketNotifierState = true; + socketEngine->setExceptionNotificationEnabled(false); + } } void QAbstractSocketPrivate::resumeSocketNotifiers(QAbstractSocket *socket) @@ -1359,9 +1335,19 @@ void QAbstractSocketPrivate::resumeSocketNotifiers(QAbstractSocket *socket) QAbstractSocketEngine *socketEngine = socket->d_func()->socketEngine; if (!socketEngine) return; - socketEngine->setReadNotificationEnabled(socket->d_func()->prePauseReadSocketNotifierState); - socketEngine->setWriteNotificationEnabled(socket->d_func()->prePauseWriteSocketNotifierState); - socketEngine->setExceptionNotificationEnabled(socket->d_func()->prePauseExceptionSocketNotifierState); + QAbstractSocketPrivate *priv = socket->d_func(); +#ifdef QABSTRACTSOCKET_DEBUG + qDebug() << socketEngine->socketDescriptor() + << "Maybe resume notifiers, read:" << priv->prePauseReadSocketNotifierState + << "write:" << priv->prePauseWriteSocketNotifierState + << "exception:" << priv->prePauseExceptionSocketNotifierState; +#endif + if (std::exchange(priv->prePauseReadSocketNotifierState, false)) + socketEngine->setReadNotificationEnabled(true); + if (std::exchange(priv->prePauseWriteSocketNotifierState, false)) + socketEngine->setWriteNotificationEnabled(true); + if (std::exchange(priv->prePauseExceptionSocketNotifierState, false)) + socketEngine->setExceptionNotificationEnabled(true); } QAbstractSocketEngine* QAbstractSocketPrivate::getSocketEngine(QAbstractSocket *socket) @@ -1938,8 +1924,9 @@ bool QAbstractSocket::setSocketDescriptor(qintptr socketDescriptor, SocketState \since 4.6 Sets the given \a option to the value described by \a value. - \note On Windows Runtime, QAbstractSocket::KeepAliveOption must be set - before the socket is connected. + \note Since the options are set on an internal socket the options + only apply if the socket has been created. This is only guaranteed to + have happened after a call to bind(), or when connected() has been emitted. \sa socketOption() */ @@ -2074,8 +2061,7 @@ bool QAbstractSocket::waitForConnected(int msecs) bool wasPendingClose = d->pendingClose; d->pendingClose = false; - QElapsedTimer stopWatch; - stopWatch.start(); + QDeadlineTimer deadline{msecs}; if (d->state == HostLookupState) { #if defined (QABSTRACTSOCKET_DEBUG) @@ -2095,22 +2081,21 @@ bool QAbstractSocket::waitForConnected(int msecs) if (state() == UnconnectedState) return false; // connect not im progress anymore! - int connectTimeout = DefaultConnectTimeout; bool timedOut = true; #if defined (QABSTRACTSOCKET_DEBUG) int attempt = 1; #endif - while (state() == ConnectingState && (msecs == -1 || stopWatch.elapsed() < msecs)) { - int timeout = qt_subtract_from_timeout(msecs, stopWatch.elapsed()); - if (msecs != -1 && timeout > connectTimeout) - timeout = connectTimeout; + while (state() == ConnectingState && !deadline.hasExpired()) { + QDeadlineTimer timer = deadline; + if (!deadline.isForever() && deadline.remainingTimeAsDuration() > DefaultConnectTimeout) + timer = QDeadlineTimer(DefaultConnectTimeout); #if defined (QABSTRACTSOCKET_DEBUG) qDebug("QAbstractSocket::waitForConnected(%i) waiting %.2f secs for connection attempt #%i", - msecs, timeout / 1000.0, attempt++); + msecs, timer.remainingTime() / 1000.0, attempt++); #endif timedOut = false; - if (d->socketEngine && d->socketEngine->waitForWrite(timeout, &timedOut) && !timedOut) { + if (d->socketEngine && d->socketEngine->waitForWrite(timer, &timedOut) && !timedOut) { d->_q_testConnection(); } else { d->_q_connectToNextAddress(); @@ -2165,8 +2150,7 @@ bool QAbstractSocket::waitForReadyRead(int msecs) return false; } - QElapsedTimer stopWatch; - stopWatch.start(); + QDeadlineTimer deadline{msecs}; // handle a socket in connecting state if (state() == HostLookupState || state() == ConnectingState) { @@ -2182,7 +2166,7 @@ bool QAbstractSocket::waitForReadyRead(int msecs) bool readyToRead = false; bool readyToWrite = false; if (!d->socketEngine->waitForReadOrWrite(&readyToRead, &readyToWrite, true, !d->writeBuffer.isEmpty(), - qt_subtract_from_timeout(msecs, stopWatch.elapsed()))) { + deadline)) { #if defined (QABSTRACTSOCKET_DEBUG) qDebug("QAbstractSocket::waitForReadyRead(%i) failed (%i, %s)", msecs, d->socketEngine->error(), d->socketEngine->errorString().toLatin1().constData()); @@ -2200,7 +2184,7 @@ bool QAbstractSocket::waitForReadyRead(int msecs) if (readyToWrite) d->canWriteNotification(); - } while (msecs == -1 || qt_subtract_from_timeout(msecs, stopWatch.elapsed()) > 0); + } while (!deadline.hasExpired()); return false; } @@ -2236,8 +2220,7 @@ bool QAbstractSocket::waitForBytesWritten(int msecs) if (d->writeBuffer.isEmpty()) return false; - QElapsedTimer stopWatch; - stopWatch.start(); + QDeadlineTimer deadline{msecs}; // handle a socket in connecting state if (state() == HostLookupState || state() == ConnectingState) { @@ -2245,13 +2228,13 @@ bool QAbstractSocket::waitForBytesWritten(int msecs) return false; } - forever { + for (;;) { bool readyToRead = false; bool readyToWrite = false; if (!d->socketEngine->waitForReadOrWrite(&readyToRead, &readyToWrite, !d->readBufferMaxSize || d->buffer.size() < d->readBufferMaxSize, !d->writeBuffer.isEmpty(), - qt_subtract_from_timeout(msecs, stopWatch.elapsed()))) { + deadline)) { #if defined (QABSTRACTSOCKET_DEBUG) qDebug("QAbstractSocket::waitForBytesWritten(%i) failed (%i, %s)", msecs, d->socketEngine->error(), d->socketEngine->errorString().toLatin1().constData()); @@ -2315,8 +2298,7 @@ bool QAbstractSocket::waitForDisconnected(int msecs) return false; } - QElapsedTimer stopWatch; - stopWatch.start(); + QDeadlineTimer deadline{msecs}; // handle a socket in connecting state if (state() == HostLookupState || state() == ConnectingState) { @@ -2326,12 +2308,12 @@ bool QAbstractSocket::waitForDisconnected(int msecs) return true; } - forever { + for (;;) { bool readyToRead = false; bool readyToWrite = false; if (!d->socketEngine->waitForReadOrWrite(&readyToRead, &readyToWrite, state() == ConnectedState, !d->writeBuffer.isEmpty(), - qt_subtract_from_timeout(msecs, stopWatch.elapsed()))) { + deadline)) { #if defined (QABSTRACTSOCKET_DEBUG) qDebug("QAbstractSocket::waitForReadyRead(%i) failed (%i, %s)", msecs, d->socketEngine->error(), d->socketEngine->errorString().toLatin1().constData()); |