diff options
author | Ahmad Samir <[email protected]> | 2023-07-31 20:05:05 +0300 |
---|---|---|
committer | Ahmad Samir <[email protected]> | 2023-10-07 02:28:12 +0300 |
commit | 032ffb70a829184fb620cf14fa146580b742e0e8 (patch) | |
tree | 6994fa22f63b186007c9eb0b79afa4e71f8eeec9 | |
parent | 51c812af0747573ccf07fc232d860170c4ba2877 (diff) |
QAbstractSocketEngine: port to QDeadlineTimer
qnativesocketengine_win.cpp: don't check if timeout is < 0, because
remainingTimeAsDuration() doesn't return negative values.
All the changes done in one go, not function by function, as that causes
the least churn. You can think of them as a couple of very similar
changes repeated various times.
Drive-by change: replace `forever {` with `for (;;)`
Task-number: QTBUG-113518
Change-Id: Ie9f20031bf0d4ff19e5b2da5034822ba61f9cbc3
Reviewed-by: Qt CI Bot <[email protected]>
Reviewed-by: MÃ¥rten Nordheim <[email protected]>
-rw-r--r-- | src/network/socket/qabstractsocket.cpp | 41 | ||||
-rw-r--r-- | src/network/socket/qabstractsocketengine_p.h | 14 | ||||
-rw-r--r-- | src/network/socket/qhttpsocketengine.cpp | 26 | ||||
-rw-r--r-- | src/network/socket/qhttpsocketengine_p.h | 9 | ||||
-rw-r--r-- | src/network/socket/qnativesocketengine.cpp | 24 | ||||
-rw-r--r-- | src/network/socket/qnativesocketengine_p.h | 9 | ||||
-rw-r--r-- | src/network/socket/qnativesocketengine_p_p.h | 4 | ||||
-rw-r--r-- | src/network/socket/qnativesocketengine_unix.cpp | 22 | ||||
-rw-r--r-- | src/network/socket/qnativesocketengine_win.cpp | 30 | ||||
-rw-r--r-- | src/network/socket/qsocks5socketengine.cpp | 66 | ||||
-rw-r--r-- | src/network/socket/qsocks5socketengine_p.h | 11 | ||||
-rw-r--r-- | src/network/socket/qtcpserver.cpp | 2 | ||||
-rw-r--r-- | tests/auto/corelib/kernel/qsocketnotifier/tst_qsocketnotifier.cpp | 4 | ||||
-rw-r--r-- | tests/auto/network/socket/qhttpsocketengine/tst_qhttpsocketengine.cpp | 4 | ||||
-rw-r--r-- | tests/auto/network/socket/qsocks5socketengine/tst_qsocks5socketengine.cpp | 4 | ||||
-rw-r--r-- | tests/manual/socketengine/main.cpp | 6 |
16 files changed, 146 insertions, 130 deletions
diff --git a/src/network/socket/qabstractsocket.cpp b/src/network/socket/qabstractsocket.cpp index 0768b1ff7cd..e74f448987f 100644 --- a/src/network/socket/qabstractsocket.cpp +++ b/src/network/socket/qabstractsocket.cpp @@ -439,7 +439,7 @@ #include <qmetaobject.h> #include <qpointer.h> #include <qtimer.h> -#include <qelapsedtimer.h> +#include <qdeadlinetimer.h> #include <qscopedvaluerollback.h> #include <qvarlengtharray.h> @@ -465,11 +465,12 @@ QT_BEGIN_NAMESPACE 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 const int DefaultConnectTimeout = 30000; +static constexpr auto DefaultConnectTimeout = 30s; static bool isProxyError(QAbstractSocket::SocketError error) { @@ -2051,8 +2052,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) @@ -2076,17 +2076,17 @@ bool QAbstractSocket::waitForConnected(int msecs) #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 > DefaultConnectTimeout) - timeout = DefaultConnectTimeout; + 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(); @@ -2141,8 +2141,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) { @@ -2158,7 +2157,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()); @@ -2176,7 +2175,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; } @@ -2212,8 +2211,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) { @@ -2221,13 +2219,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()); @@ -2291,8 +2289,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) { @@ -2302,12 +2299,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()); diff --git a/src/network/socket/qabstractsocketengine_p.h b/src/network/socket/qabstractsocketengine_p.h index 7b1ec858020..9ee79cebc18 100644 --- a/src/network/socket/qabstractsocketengine_p.h +++ b/src/network/socket/qabstractsocketengine_p.h @@ -19,8 +19,9 @@ #include <QtNetwork/private/qtnetworkglobal_p.h> #include "QtNetwork/qhostaddress.h" #include "QtNetwork/qabstractsocket.h" -#include "private/qobject_p.h" +#include <QtCore/qdeadlinetimer.h> #include "private/qnetworkdatagram_p.h" +#include "private/qobject_p.h" QT_BEGIN_NAMESPACE @@ -44,6 +45,8 @@ public: #endif }; +static constexpr std::chrono::seconds DefaultTimeout{30}; + class Q_AUTOTEST_EXPORT QAbstractSocketEngine : public QObject { Q_OBJECT @@ -128,11 +131,14 @@ public: virtual int option(SocketOption option) const = 0; virtual bool setOption(SocketOption option, int value) = 0; - virtual bool waitForRead(int msecs = 30000, bool *timedOut = nullptr) = 0; - virtual bool waitForWrite(int msecs = 30000, bool *timedOut = nullptr) = 0; + virtual bool waitForRead(QDeadlineTimer deadline = QDeadlineTimer{DefaultTimeout}, + bool *timedOut = nullptr) = 0; + virtual bool waitForWrite(QDeadlineTimer deadline = QDeadlineTimer{DefaultTimeout}, + bool *timedOut = nullptr) = 0; virtual bool waitForReadOrWrite(bool *readyToRead, bool *readyToWrite, bool checkRead, bool checkWrite, - int msecs = 30000, bool *timedOut = nullptr) = 0; + QDeadlineTimer deadline = QDeadlineTimer{DefaultTimeout}, + bool *timedOut = nullptr) = 0; QAbstractSocket::SocketError error() const; QString errorString() const; diff --git a/src/network/socket/qhttpsocketengine.cpp b/src/network/socket/qhttpsocketengine.cpp index ba24460066b..07d24dd91b9 100644 --- a/src/network/socket/qhttpsocketengine.cpp +++ b/src/network/socket/qhttpsocketengine.cpp @@ -7,7 +7,7 @@ #include "qurl.h" #include "private/qhttpnetworkreply_p.h" #include "private/qiodevice_p.h" -#include "qelapsedtimer.h" +#include "qdeadlinetimer.h" #include "qnetworkinterface.h" #if !defined(QT_NO_NETWORKPROXY) @@ -310,19 +310,16 @@ bool QHttpSocketEngine::setOption(SocketOption option, int value) return false; } -bool QHttpSocketEngine::waitForRead(int msecs, bool *timedOut) +bool QHttpSocketEngine::waitForRead(QDeadlineTimer deadline, bool *timedOut) { Q_D(const QHttpSocketEngine); if (!d->socket || d->socket->state() == QAbstractSocket::UnconnectedState) return false; - QElapsedTimer stopWatch; - stopWatch.start(); - // Wait for more data if nothing is available. if (!d->socket->bytesAvailable()) { - if (!d->socket->waitForReadyRead(qt_subtract_from_timeout(msecs, stopWatch.elapsed()))) { + if (!d->socket->waitForReadyRead(deadline.remainingTime())) { if (d->socket->state() == QAbstractSocket::UnconnectedState) return true; setError(d->socket->error(), d->socket->errorString()); @@ -334,7 +331,7 @@ bool QHttpSocketEngine::waitForRead(int msecs, bool *timedOut) // If we're not connected yet, wait until we are, or until an error // occurs. - while (d->state != Connected && d->socket->waitForReadyRead(qt_subtract_from_timeout(msecs, stopWatch.elapsed()))) { + while (d->state != Connected && d->socket->waitForReadyRead(deadline.remainingTime())) { // Loop while the protocol handshake is taking place. } @@ -348,14 +345,14 @@ bool QHttpSocketEngine::waitForRead(int msecs, bool *timedOut) return true; } -bool QHttpSocketEngine::waitForWrite(int msecs, bool *timedOut) +bool QHttpSocketEngine::waitForWrite(QDeadlineTimer deadline, bool *timedOut) { Q_D(const QHttpSocketEngine); // If we're connected, just forward the call. if (d->state == Connected) { if (d->socket->bytesToWrite()) { - if (!d->socket->waitForBytesWritten(msecs)) { + if (!d->socket->waitForBytesWritten(deadline.remainingTime())) { if (d->socket->error() == QAbstractSocket::SocketTimeoutError && timedOut) *timedOut = true; return false; @@ -364,13 +361,10 @@ bool QHttpSocketEngine::waitForWrite(int msecs, bool *timedOut) return true; } - QElapsedTimer stopWatch; - stopWatch.start(); - // If we're not connected yet, wait until we are, and until bytes have // been received (i.e., the socket has connected, we have sent the // greeting, and then received the response). - while (d->state != Connected && d->socket->waitForReadyRead(qt_subtract_from_timeout(msecs, stopWatch.elapsed()))) { + while (d->state != Connected && d->socket->waitForReadyRead(deadline.remainingTime())) { // Loop while the protocol handshake is taking place. } @@ -386,20 +380,20 @@ bool QHttpSocketEngine::waitForWrite(int msecs, bool *timedOut) bool QHttpSocketEngine::waitForReadOrWrite(bool *readyToRead, bool *readyToWrite, bool checkRead, bool checkWrite, - int msecs, bool *timedOut) + QDeadlineTimer deadline, bool *timedOut) { Q_UNUSED(checkRead); if (!checkWrite) { // Not interested in writing? Then we wait for read notifications. - bool canRead = waitForRead(msecs, timedOut); + bool canRead = waitForRead(deadline, timedOut); if (readyToRead) *readyToRead = canRead; return canRead; } // Interested in writing? Then we wait for write notifications. - bool canWrite = waitForWrite(msecs, timedOut); + bool canWrite = waitForWrite(deadline, timedOut); if (readyToWrite) *readyToWrite = canWrite; return canWrite; diff --git a/src/network/socket/qhttpsocketengine_p.h b/src/network/socket/qhttpsocketengine_p.h index 242f11122fb..70ffd06b6ba 100644 --- a/src/network/socket/qhttpsocketengine_p.h +++ b/src/network/socket/qhttpsocketengine_p.h @@ -92,11 +92,14 @@ public: int option(SocketOption option) const override; bool setOption(SocketOption option, int value) override; - bool waitForRead(int msecs = 30000, bool *timedOut = nullptr) override; - bool waitForWrite(int msecs = 30000, bool *timedOut = nullptr) override; + bool waitForRead(QDeadlineTimer deadline = QDeadlineTimer{DefaultTimeout}, + bool *timedOut = nullptr) override; + bool waitForWrite(QDeadlineTimer deadline = QDeadlineTimer{DefaultTimeout}, + bool *timedOut = nullptr) override; bool waitForReadOrWrite(bool *readyToRead, bool *readyToWrite, bool checkRead, bool checkWrite, - int msecs = 30000, bool *timedOut = nullptr) override; + QDeadlineTimer deadline = QDeadlineTimer{DefaultTimeout}, + bool *timedOut = nullptr) override; bool isReadNotificationEnabled() const override; void setReadNotificationEnabled(bool enable) override; diff --git a/src/network/socket/qnativesocketengine.cpp b/src/network/socket/qnativesocketengine.cpp index e2726be7817..6d0d22deadd 100644 --- a/src/network/socket/qnativesocketengine.cpp +++ b/src/network/socket/qnativesocketengine.cpp @@ -962,9 +962,9 @@ void QNativeSocketEngine::close() } /*! - Waits for \a msecs milliseconds or until the socket is ready for - reading. If \a timedOut is not \nullptr and \a msecs milliseconds - have passed, the value of \a timedOut is set to true. + Waits until \a deadline has expired or until the socket is ready for + reading. If \a timedOut is not \nullptr and \a deadline has expired, + the value of \a timedOut is set to true. Returns \c true if data is available for reading; otherwise returns false. @@ -976,7 +976,7 @@ void QNativeSocketEngine::close() is to create a QSocketNotifier, passing the socket descriptor returned by socketDescriptor() to its constructor. */ -bool QNativeSocketEngine::waitForRead(int msecs, bool *timedOut) +bool QNativeSocketEngine::waitForRead(QDeadlineTimer deadline, bool *timedOut) { Q_D(const QNativeSocketEngine); Q_CHECK_VALID_SOCKETLAYER(QNativeSocketEngine::waitForRead(), false); @@ -986,7 +986,7 @@ bool QNativeSocketEngine::waitForRead(int msecs, bool *timedOut) if (timedOut) *timedOut = false; - int ret = d->nativeSelect(msecs, true); + int ret = d->nativeSelect(deadline, true); if (ret == 0) { if (timedOut) *timedOut = true; @@ -1002,9 +1002,9 @@ bool QNativeSocketEngine::waitForRead(int msecs, bool *timedOut) } /*! - Waits for \a msecs milliseconds or until the socket is ready for - writing. If \a timedOut is not \nullptr and \a msecs milliseconds - have passed, the value of \a timedOut is set to true. + Waits until \a deadline has expired or until the socket is ready for + writing. If \a timedOut is not \nullptr and \a deadline has expired, + the value of \a timedOut is set to true. Returns \c true if data is available for writing; otherwise returns false. @@ -1016,7 +1016,7 @@ bool QNativeSocketEngine::waitForRead(int msecs, bool *timedOut) is to create a QSocketNotifier, passing the socket descriptor returned by socketDescriptor() to its constructor. */ -bool QNativeSocketEngine::waitForWrite(int msecs, bool *timedOut) +bool QNativeSocketEngine::waitForWrite(QDeadlineTimer deadline, bool *timedOut) { Q_D(QNativeSocketEngine); Q_CHECK_VALID_SOCKETLAYER(QNativeSocketEngine::waitForWrite(), false); @@ -1026,7 +1026,7 @@ bool QNativeSocketEngine::waitForWrite(int msecs, bool *timedOut) if (timedOut) *timedOut = false; - int ret = d->nativeSelect(msecs, false); + int ret = d->nativeSelect(deadline, false); // On Windows, the socket is in connected state if a call to // select(writable) is successful. In this case we should not // issue a second call to WSAConnect() @@ -1074,14 +1074,14 @@ bool QNativeSocketEngine::waitForWrite(int msecs, bool *timedOut) bool QNativeSocketEngine::waitForReadOrWrite(bool *readyToRead, bool *readyToWrite, bool checkRead, bool checkWrite, - int msecs, bool *timedOut) + QDeadlineTimer deadline, bool *timedOut) { Q_D(QNativeSocketEngine); Q_CHECK_VALID_SOCKETLAYER(QNativeSocketEngine::waitForReadOrWrite(), false); Q_CHECK_NOT_STATE(QNativeSocketEngine::waitForReadOrWrite(), QAbstractSocket::UnconnectedState, false); - int ret = d->nativeSelect(msecs, checkRead, checkWrite, readyToRead, readyToWrite); + int ret = d->nativeSelect(deadline, checkRead, checkWrite, readyToRead, readyToWrite); // On Windows, the socket is in connected state if a call to // select(writable) is successful. In this case we should not // issue a second call to WSAConnect() diff --git a/src/network/socket/qnativesocketengine_p.h b/src/network/socket/qnativesocketengine_p.h index 4ee9764e425..4c185b7a4a1 100644 --- a/src/network/socket/qnativesocketengine_p.h +++ b/src/network/socket/qnativesocketengine_p.h @@ -154,11 +154,14 @@ public: int option(SocketOption option) const override; bool setOption(SocketOption option, int value) override; - bool waitForRead(int msecs = 30000, bool *timedOut = nullptr) override; - bool waitForWrite(int msecs = 30000, bool *timedOut = nullptr) override; + bool waitForRead(QDeadlineTimer deadline = QDeadlineTimer{DefaultTimeout}, + bool *timedOut = nullptr) override; + bool waitForWrite(QDeadlineTimer deadline = QDeadlineTimer{DefaultTimeout}, + bool *timedOut = nullptr) override; bool waitForReadOrWrite(bool *readyToRead, bool *readyToWrite, bool checkRead, bool checkWrite, - int msecs = 30000, bool *timedOut = nullptr) override; + QDeadlineTimer deadline = QDeadlineTimer{DefaultTimeout}, + bool *timedOut = nullptr) override; bool isReadNotificationEnabled() const override; void setReadNotificationEnabled(bool enable) override; diff --git a/src/network/socket/qnativesocketengine_p_p.h b/src/network/socket/qnativesocketengine_p_p.h index d52a30b1534..189a4327fd3 100644 --- a/src/network/socket/qnativesocketengine_p_p.h +++ b/src/network/socket/qnativesocketengine_p_p.h @@ -146,8 +146,8 @@ public: qint64 nativeSendDatagram(const char *data, qint64 length, const QIpPacketHeader &header); qint64 nativeRead(char *data, qint64 maxLength); qint64 nativeWrite(const char *data, qint64 length); - int nativeSelect(int timeout, bool selectForRead) const; - int nativeSelect(int timeout, bool checkRead, bool checkWrite, + int nativeSelect(QDeadlineTimer deadline, bool selectForRead) const; + int nativeSelect(QDeadlineTimer deadline, bool checkRead, bool checkWrite, bool *selectForRead, bool *selectForWrite) const; void nativeClose(); diff --git a/src/network/socket/qnativesocketengine_unix.cpp b/src/network/socket/qnativesocketengine_unix.cpp index 023a0dbc2c1..87c74f7f854 100644 --- a/src/network/socket/qnativesocketengine_unix.cpp +++ b/src/network/socket/qnativesocketengine_unix.cpp @@ -5,9 +5,9 @@ //#define QNATIVESOCKETENGINE_DEBUG #include "qnativesocketengine_p_p.h" #include "private/qnet_unix_p.h" +#include "qdeadlinetimer.h" #include "qiodevice.h" #include "qhostaddress.h" -#include "qelapsedtimer.h" #include "qvarlengtharray.h" #include "qnetworkinterface.h" #include "qendian.h" @@ -1344,16 +1344,17 @@ qint64 QNativeSocketEnginePrivate::nativeRead(char *data, qint64 maxSize) return qint64(r); } -int QNativeSocketEnginePrivate::nativeSelect(int timeout, bool selectForRead) const +int QNativeSocketEnginePrivate::nativeSelect(QDeadlineTimer deadline, bool selectForRead) const { bool dummy; - return nativeSelect(timeout, selectForRead, !selectForRead, &dummy, &dummy); + return nativeSelect(deadline, selectForRead, !selectForRead, &dummy, &dummy); } #ifndef Q_OS_WASM -int QNativeSocketEnginePrivate::nativeSelect(int timeout, bool checkRead, bool checkWrite, - bool *selectForRead, bool *selectForWrite) const +int QNativeSocketEnginePrivate::nativeSelect(QDeadlineTimer deadline, bool checkRead, + bool checkWrite, bool *selectForRead, + bool *selectForWrite) const { pollfd pfd = qt_make_pollfd(socketDescriptor, 0); @@ -1363,7 +1364,7 @@ int QNativeSocketEnginePrivate::nativeSelect(int timeout, bool checkRead, bool c if (checkWrite) pfd.events |= POLLOUT; - const int ret = qt_poll_msecs(&pfd, 1, timeout); + const int ret = qt_poll_msecs(&pfd, 1, deadline.remainingTime()); if (ret <= 0) return ret; @@ -1384,13 +1385,16 @@ int QNativeSocketEnginePrivate::nativeSelect(int timeout, bool checkRead, bool c #else -int QNativeSocketEnginePrivate::nativeSelect(int timeout, bool checkRead, bool checkWrite, - bool *selectForRead, bool *selectForWrite) const +int QNativeSocketEnginePrivate::nativeSelect(QDeadlineTimer deadline, bool checkRead, + bool checkWrite, bool *selectForRead, + bool *selectForWrite) const { *selectForRead = checkRead; *selectForWrite = checkWrite; bool socketDisconnect = false; - QEventDispatcherWasm::socketSelect(timeout, socketDescriptor, checkRead, checkWrite,selectForRead, selectForWrite, &socketDisconnect); + 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. diff --git a/src/network/socket/qnativesocketengine_win.cpp b/src/network/socket/qnativesocketengine_win.cpp index 16d974a68be..6525f46e308 100644 --- a/src/network/socket/qnativesocketengine_win.cpp +++ b/src/network/socket/qnativesocketengine_win.cpp @@ -16,6 +16,7 @@ #include <qvarlengtharray.h> #include <algorithm> +#include <chrono> //#define QNATIVESOCKETENGINE_DEBUG #if defined(QNATIVESOCKETENGINE_DEBUG) @@ -1428,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) @@ -1442,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 @@ -1456,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)) @@ -1469,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 { @@ -1498,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)) diff --git a/src/network/socket/qsocks5socketengine.cpp b/src/network/socket/qsocks5socketengine.cpp index a36b5d3b708..00f586562ce 100644 --- a/src/network/socket/qsocks5socketengine.cpp +++ b/src/network/socket/qsocks5socketengine.cpp @@ -9,6 +9,7 @@ #include "qdebug.h" #include "qhash.h" #include "qqueue.h" +#include "qdeadlinetimer.h" #include "qelapsedtimer.h" #include "qmutex.h" #include "qthread.h" @@ -25,13 +26,14 @@ QT_BEGIN_NAMESPACE using namespace Qt::StringLiterals; +using namespace std::chrono_literals; static const int MaxWriteBufferSize = 128*1024; //#define QSOCKS5SOCKETLAYER_DEBUG #define MAX_DATA_DUMP 256 -#define SOCKS5_BLOCKING_BIND_TIMEOUT 5000 +static constexpr auto Socks5BlockingBindTimeout = 5s; #define Q_INIT_CHECK(returnValue) do { \ if (!d->data) { \ @@ -318,7 +320,6 @@ void QSocks5BindStore::add(qintptr socketDescriptor, QSocks5BindData *bindData) bindData->timeStamp.start(); store.insert(socketDescriptor, bindData); - using namespace std::chrono_literals; // start sweep timer if not started if (sweepTimerId == -1) sweepTimerId = startTimer(1min); @@ -1327,11 +1328,8 @@ bool QSocks5SocketEngine::bind(const QHostAddress &addr, quint16 port) return false; } - int msecs = SOCKS5_BLOCKING_BIND_TIMEOUT; - QElapsedTimer stopWatch; - stopWatch.start(); d->data->controlSocket->connectToHost(d->proxyInfo.hostName(), d->proxyInfo.port()); - if (!d->waitForConnected(msecs, nullptr) || + if (!d->waitForConnected(QDeadlineTimer{Socks5BlockingBindTimeout}, nullptr) || d->data->controlSocket->state() == QAbstractSocket::UnconnectedState) { // waitForConnected sets the error state and closes the socket QSOCKS5_Q_DEBUG << "waitForConnected to proxy server" << d->data->controlSocket->errorString(); @@ -1422,11 +1420,9 @@ void QSocks5SocketEngine::close() Q_D(QSocks5SocketEngine); if (d->data && d->data->controlSocket) { if (d->data->controlSocket->state() == QAbstractSocket::ConnectedState) { - int msecs = 100; - QElapsedTimer stopWatch; - stopWatch.start(); + QDeadlineTimer deadline(100ms); while (!d->data->controlSocket->bytesToWrite()) { - if (!d->data->controlSocket->waitForBytesWritten(qt_subtract_from_timeout(msecs, stopWatch.elapsed()))) + if (!d->data->controlSocket->waitForBytesWritten(deadline.remainingTime())) break; } } @@ -1679,7 +1675,7 @@ bool QSocks5SocketEngine::setOption(SocketOption option, int value) return false; } -bool QSocks5SocketEnginePrivate::waitForConnected(int msecs, bool *timedOut) +bool QSocks5SocketEnginePrivate::waitForConnected(QDeadlineTimer deadline, bool *timedOut) { if (data->controlSocket->state() == QAbstractSocket::UnconnectedState) return false; @@ -1689,11 +1685,8 @@ bool QSocks5SocketEnginePrivate::waitForConnected(int msecs, bool *timedOut) mode == BindMode ? BindSuccess : UdpAssociateSuccess; - QElapsedTimer stopWatch; - stopWatch.start(); - while (socks5State != wantedState) { - if (!data->controlSocket->waitForReadyRead(qt_subtract_from_timeout(msecs, stopWatch.elapsed()))) { + if (!data->controlSocket->waitForReadyRead(deadline.remainingTime())) { if (data->controlSocket->state() == QAbstractSocket::UnconnectedState) return true; @@ -1707,18 +1700,15 @@ bool QSocks5SocketEnginePrivate::waitForConnected(int msecs, bool *timedOut) return true; } -bool QSocks5SocketEngine::waitForRead(int msecs, bool *timedOut) +bool QSocks5SocketEngine::waitForRead(QDeadlineTimer deadline, bool *timedOut) { Q_D(QSocks5SocketEngine); - QSOCKS5_DEBUG << "waitForRead" << msecs; + QSOCKS5_DEBUG << "waitForRead" << deadline.remainingTimeAsDuration(); d->readNotificationActivated = false; - QElapsedTimer stopWatch; - stopWatch.start(); - // are we connected yet? - if (!d->waitForConnected(msecs, timedOut)) + if (!d->waitForConnected(deadline, timedOut)) return false; if (d->data->controlSocket->state() == QAbstractSocket::UnconnectedState) return true; @@ -1732,7 +1722,7 @@ bool QSocks5SocketEngine::waitForRead(int msecs, bool *timedOut) if (d->mode == QSocks5SocketEnginePrivate::ConnectMode || d->mode == QSocks5SocketEnginePrivate::BindMode) { while (!d->readNotificationActivated) { - if (!d->data->controlSocket->waitForReadyRead(qt_subtract_from_timeout(msecs, stopWatch.elapsed()))) { + if (!d->data->controlSocket->waitForReadyRead(deadline.remainingTime())) { if (d->data->controlSocket->state() == QAbstractSocket::UnconnectedState) return true; @@ -1745,7 +1735,7 @@ bool QSocks5SocketEngine::waitForRead(int msecs, bool *timedOut) #ifndef QT_NO_UDPSOCKET } else { while (!d->readNotificationActivated) { - if (!d->udpData->udpSocket->waitForReadyRead(qt_subtract_from_timeout(msecs, stopWatch.elapsed()))) { + if (!d->udpData->udpSocket->waitForReadyRead(deadline.remainingTime())) { setError(d->udpData->udpSocket->error(), d->udpData->udpSocket->errorString()); if (timedOut && d->udpData->udpSocket->error() == QAbstractSocket::SocketTimeoutError) *timedOut = true; @@ -1764,16 +1754,13 @@ bool QSocks5SocketEngine::waitForRead(int msecs, bool *timedOut) } -bool QSocks5SocketEngine::waitForWrite(int msecs, bool *timedOut) +bool QSocks5SocketEngine::waitForWrite(QDeadlineTimer deadline, bool *timedOut) { Q_D(QSocks5SocketEngine); - QSOCKS5_DEBUG << "waitForWrite" << msecs; - - QElapsedTimer stopWatch; - stopWatch.start(); + QSOCKS5_DEBUG << "waitForWrite" << deadline.remainingTimeAsDuration(); // are we connected yet? - if (!d->waitForConnected(msecs, timedOut)) + if (!d->waitForConnected(deadline, timedOut)) return false; if (d->data->controlSocket->state() == QAbstractSocket::UnconnectedState) return true; @@ -1782,27 +1769,32 @@ bool QSocks5SocketEngine::waitForWrite(int msecs, bool *timedOut) // flush any bytes we may still have buffered in the time that we have left if (d->data->controlSocket->bytesToWrite()) - d->data->controlSocket->waitForBytesWritten(qt_subtract_from_timeout(msecs, stopWatch.elapsed())); - while ((msecs == -1 || stopWatch.elapsed() < msecs) - && d->data->controlSocket->state() == QAbstractSocket::ConnectedState - && d->data->controlSocket->bytesToWrite() >= MaxWriteBufferSize) - d->data->controlSocket->waitForBytesWritten(qt_subtract_from_timeout(msecs, stopWatch.elapsed())); + d->data->controlSocket->waitForBytesWritten(deadline.remainingTime()); + + auto shouldWriteBytes = [&]() { + return d->data->controlSocket->state() == QAbstractSocket::ConnectedState + && d->data->controlSocket->bytesToWrite() >= MaxWriteBufferSize; + }; + + qint64 remainingTime = deadline.remainingTime(); + for (; remainingTime > 0 && shouldWriteBytes(); remainingTime = deadline.remainingTime()) + d->data->controlSocket->waitForBytesWritten(remainingTime); return d->data->controlSocket->bytesToWrite() < MaxWriteBufferSize; } bool QSocks5SocketEngine::waitForReadOrWrite(bool *readyToRead, bool *readyToWrite, bool checkRead, bool checkWrite, - int msecs, bool *timedOut) + QDeadlineTimer deadline, bool *timedOut) { Q_UNUSED(checkRead); if (!checkWrite) { - bool canRead = waitForRead(msecs, timedOut); + bool canRead = waitForRead(deadline, timedOut); if (readyToRead) *readyToRead = canRead; return canRead; } - bool canWrite = waitForWrite(msecs, timedOut); + bool canWrite = waitForWrite(deadline, timedOut); if (readyToWrite) *readyToWrite = canWrite; return canWrite; diff --git a/src/network/socket/qsocks5socketengine_p.h b/src/network/socket/qsocks5socketengine_p.h index 790c3077cf7..3a169812df8 100644 --- a/src/network/socket/qsocks5socketengine_p.h +++ b/src/network/socket/qsocks5socketengine_p.h @@ -78,11 +78,14 @@ public: int option(SocketOption option) const override; bool setOption(SocketOption option, int value) override; - bool waitForRead(int msecs = 30000, bool *timedOut = nullptr) override; - bool waitForWrite(int msecs = 30000, bool *timedOut = nullptr) override; + bool waitForRead(QDeadlineTimer deadline = QDeadlineTimer{DefaultTimeout}, + bool *timedOut = nullptr) override; + bool waitForWrite(QDeadlineTimer deadline = QDeadlineTimer{DefaultTimeout}, + bool *timedOut = nullptr) override; bool waitForReadOrWrite(bool *readyToRead, bool *readyToWrite, bool checkRead, bool checkWrite, - int msecs = 30000, bool *timedOut = nullptr) override; + QDeadlineTimer deadline = QDeadlineTimer{DefaultTimeout}, + bool *timedOut = nullptr) override; bool isReadNotificationEnabled() const override; void setReadNotificationEnabled(bool enable) override; @@ -208,7 +211,7 @@ public: void parseRequestMethodReply(); void parseNewConnection(); - bool waitForConnected(int msecs, bool *timedOut); + bool waitForConnected(QDeadlineTimer deadline, bool *timedOut); void _q_controlSocketConnected(); void _q_controlSocketReadNotification(); diff --git a/src/network/socket/qtcpserver.cpp b/src/network/socket/qtcpserver.cpp index eb2d757a08e..a0c0f00aaae 100644 --- a/src/network/socket/qtcpserver.cpp +++ b/src/network/socket/qtcpserver.cpp @@ -498,7 +498,7 @@ bool QTcpServer::waitForNewConnection(int msec, bool *timedOut) if (d->state != QAbstractSocket::ListeningState) return false; - if (!d->socketEngine->waitForRead(msec, timedOut)) { + if (!d->socketEngine->waitForRead(QDeadlineTimer(msec), timedOut)) { d->serverSocketError = d->socketEngine->error(); d->serverSocketErrorString = d->socketEngine->errorString(); return false; diff --git a/tests/auto/corelib/kernel/qsocketnotifier/tst_qsocketnotifier.cpp b/tests/auto/corelib/kernel/qsocketnotifier/tst_qsocketnotifier.cpp index 641b74bd9f0..c743ecab88b 100644 --- a/tests/auto/corelib/kernel/qsocketnotifier/tst_qsocketnotifier.cpp +++ b/tests/auto/corelib/kernel/qsocketnotifier/tst_qsocketnotifier.cpp @@ -189,8 +189,8 @@ void tst_QSocketNotifier::unexpectedDisconnection() writeEnd2->waitForBytesWritten(); // ensure both read ends are ready for reading, before the event loop - QVERIFY(readEnd1.waitForRead(5000)); - QVERIFY(readEnd2.waitForRead(5000)); + QVERIFY(readEnd1.waitForRead(5s)); + QVERIFY(readEnd2.waitForRead(5s)); UnexpectedDisconnectTester tester(&readEnd1, &readEnd2); diff --git a/tests/auto/network/socket/qhttpsocketengine/tst_qhttpsocketengine.cpp b/tests/auto/network/socket/qhttpsocketengine/tst_qhttpsocketengine.cpp index c9bf8b92f33..f1cf448c50c 100644 --- a/tests/auto/network/socket/qhttpsocketengine/tst_qhttpsocketengine.cpp +++ b/tests/auto/network/socket/qhttpsocketengine/tst_qhttpsocketengine.cpp @@ -18,6 +18,8 @@ #include "../../../network-settings.h" +using namespace std::chrono_literals; + class tst_QHttpSocketEngine : public QObject { Q_OBJECT @@ -323,7 +325,7 @@ void tst_QHttpSocketEngine::simpleErrorsAndStates() QCOMPARE(socketDevice.state(), QAbstractSocket::UnconnectedState); QVERIFY(!socketDevice.connectToHost(QHostAddress(QtNetworkSettings::socksProxyServerName()), 8088)); QCOMPARE(socketDevice.state(), QAbstractSocket::ConnectingState); - if (socketDevice.waitForWrite(30000)) { + if (socketDevice.waitForWrite(30s)) { QVERIFY(socketDevice.state() == QAbstractSocket::ConnectedState || socketDevice.state() == QAbstractSocket::UnconnectedState); } else { diff --git a/tests/auto/network/socket/qsocks5socketengine/tst_qsocks5socketengine.cpp b/tests/auto/network/socket/qsocks5socketengine/tst_qsocks5socketengine.cpp index aa860893bb1..5020612da3a 100644 --- a/tests/auto/network/socket/qsocks5socketengine/tst_qsocks5socketengine.cpp +++ b/tests/auto/network/socket/qsocks5socketengine/tst_qsocks5socketengine.cpp @@ -23,6 +23,8 @@ #include "../../../network-settings.h" +using namespace std::chrono_literals; + class tst_QSocks5SocketEngine : public QObject, public QAbstractSocketEngineReceiver { Q_OBJECT @@ -341,7 +343,7 @@ void tst_QSocks5SocketEngine::simpleErrorsAndStates() QCOMPARE(socketDevice.state(), QAbstractSocket::UnconnectedState); QVERIFY(!socketDevice.connectToHost(QHostInfo::fromName(QtNetworkSettings::socksProxyServerName()).addresses().first(), 8088)); QCOMPARE(socketDevice.state(), QAbstractSocket::ConnectingState); - if (socketDevice.waitForWrite(15000)) { + if (socketDevice.waitForWrite(15s)) { QVERIFY(socketDevice.state() == QAbstractSocket::UnconnectedState || socketDevice.state() == QAbstractSocket::ConnectedState); } else { diff --git a/tests/manual/socketengine/main.cpp b/tests/manual/socketengine/main.cpp index d79f14f339b..79a000fa76f 100644 --- a/tests/manual/socketengine/main.cpp +++ b/tests/manual/socketengine/main.cpp @@ -13,6 +13,8 @@ #include <cstdio> #include <QCoreApplication> +using namespace std::chrono_literals; + const int bufsize = 16*1024; char buf[bufsize]; @@ -39,7 +41,7 @@ int main(int argc, char**argv) int r = socketEngine->connectToHost(QHostAddress("74.125.77.99"), 80); // google bool readyToRead = false; bool readyToWrite = false; - socketEngine->waitForReadOrWrite(&readyToRead, &readyToWrite, true, true, 10*1000); + socketEngine->waitForReadOrWrite(&readyToRead, &readyToWrite, true, true, 10s); if (r <= 0) //timeout or error exit(1); if (readyToWrite) { @@ -49,7 +51,7 @@ int main(int argc, char**argv) if (ret == request.length()) { // read the response in a loop do { - bool waitReadResult = socketEngine->waitForRead(10*1000); + bool waitReadResult = socketEngine->waitForRead(10s); int available = socketEngine->bytesAvailable(); if (waitReadResult == true && available == 0) { // disconnected |