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 <qt_ci_bot@qt-project.org> Reviewed-by: Mårten Nordheim <marten.nordheim@qt.io>
This commit is contained in:
parent
51c812af07
commit
032ffb70a8
@ -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());
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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()
|
||||
|
@ -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;
|
||||
|
@ -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();
|
||||
|
@ -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.
|
||||
|
@ -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))
|
||||
|
@ -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;
|
||||
|
@ -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();
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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 {
|
||||
|
@ -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 {
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user