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 <qmetaobject.h>
|
||||||
#include <qpointer.h>
|
#include <qpointer.h>
|
||||||
#include <qtimer.h>
|
#include <qtimer.h>
|
||||||
#include <qelapsedtimer.h>
|
#include <qdeadlinetimer.h>
|
||||||
#include <qscopedvaluerollback.h>
|
#include <qscopedvaluerollback.h>
|
||||||
#include <qvarlengtharray.h>
|
#include <qvarlengtharray.h>
|
||||||
|
|
||||||
@ -465,11 +465,12 @@
|
|||||||
QT_BEGIN_NAMESPACE
|
QT_BEGIN_NAMESPACE
|
||||||
|
|
||||||
using namespace Qt::StringLiterals;
|
using namespace Qt::StringLiterals;
|
||||||
|
using namespace std::chrono_literals;
|
||||||
|
|
||||||
QT_IMPL_METATYPE_EXTERN_TAGGED(QAbstractSocket::SocketState, QAbstractSocket__SocketState)
|
QT_IMPL_METATYPE_EXTERN_TAGGED(QAbstractSocket::SocketState, QAbstractSocket__SocketState)
|
||||||
QT_IMPL_METATYPE_EXTERN_TAGGED(QAbstractSocket::SocketError, QAbstractSocket__SocketError)
|
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)
|
static bool isProxyError(QAbstractSocket::SocketError error)
|
||||||
{
|
{
|
||||||
@ -2051,8 +2052,7 @@ bool QAbstractSocket::waitForConnected(int msecs)
|
|||||||
|
|
||||||
bool wasPendingClose = d->pendingClose;
|
bool wasPendingClose = d->pendingClose;
|
||||||
d->pendingClose = false;
|
d->pendingClose = false;
|
||||||
QElapsedTimer stopWatch;
|
QDeadlineTimer deadline{msecs};
|
||||||
stopWatch.start();
|
|
||||||
|
|
||||||
if (d->state == HostLookupState) {
|
if (d->state == HostLookupState) {
|
||||||
#if defined (QABSTRACTSOCKET_DEBUG)
|
#if defined (QABSTRACTSOCKET_DEBUG)
|
||||||
@ -2076,17 +2076,17 @@ bool QAbstractSocket::waitForConnected(int msecs)
|
|||||||
#if defined (QABSTRACTSOCKET_DEBUG)
|
#if defined (QABSTRACTSOCKET_DEBUG)
|
||||||
int attempt = 1;
|
int attempt = 1;
|
||||||
#endif
|
#endif
|
||||||
while (state() == ConnectingState && (msecs == -1 || stopWatch.elapsed() < msecs)) {
|
while (state() == ConnectingState && !deadline.hasExpired()) {
|
||||||
int timeout = qt_subtract_from_timeout(msecs, stopWatch.elapsed());
|
QDeadlineTimer timer = deadline;
|
||||||
if (msecs != -1 && timeout > DefaultConnectTimeout)
|
if (!deadline.isForever() && deadline.remainingTimeAsDuration() > DefaultConnectTimeout)
|
||||||
timeout = DefaultConnectTimeout;
|
timer = QDeadlineTimer(DefaultConnectTimeout);
|
||||||
#if defined (QABSTRACTSOCKET_DEBUG)
|
#if defined (QABSTRACTSOCKET_DEBUG)
|
||||||
qDebug("QAbstractSocket::waitForConnected(%i) waiting %.2f secs for connection attempt #%i",
|
qDebug("QAbstractSocket::waitForConnected(%i) waiting %.2f secs for connection attempt #%i",
|
||||||
msecs, timeout / 1000.0, attempt++);
|
msecs, timer.remainingTime() / 1000.0, attempt++);
|
||||||
#endif
|
#endif
|
||||||
timedOut = false;
|
timedOut = false;
|
||||||
|
|
||||||
if (d->socketEngine && d->socketEngine->waitForWrite(timeout, &timedOut) && !timedOut) {
|
if (d->socketEngine && d->socketEngine->waitForWrite(timer, &timedOut) && !timedOut) {
|
||||||
d->_q_testConnection();
|
d->_q_testConnection();
|
||||||
} else {
|
} else {
|
||||||
d->_q_connectToNextAddress();
|
d->_q_connectToNextAddress();
|
||||||
@ -2141,8 +2141,7 @@ bool QAbstractSocket::waitForReadyRead(int msecs)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
QElapsedTimer stopWatch;
|
QDeadlineTimer deadline{msecs};
|
||||||
stopWatch.start();
|
|
||||||
|
|
||||||
// handle a socket in connecting state
|
// handle a socket in connecting state
|
||||||
if (state() == HostLookupState || state() == ConnectingState) {
|
if (state() == HostLookupState || state() == ConnectingState) {
|
||||||
@ -2158,7 +2157,7 @@ bool QAbstractSocket::waitForReadyRead(int msecs)
|
|||||||
bool readyToRead = false;
|
bool readyToRead = false;
|
||||||
bool readyToWrite = false;
|
bool readyToWrite = false;
|
||||||
if (!d->socketEngine->waitForReadOrWrite(&readyToRead, &readyToWrite, true, !d->writeBuffer.isEmpty(),
|
if (!d->socketEngine->waitForReadOrWrite(&readyToRead, &readyToWrite, true, !d->writeBuffer.isEmpty(),
|
||||||
qt_subtract_from_timeout(msecs, stopWatch.elapsed()))) {
|
deadline)) {
|
||||||
#if defined (QABSTRACTSOCKET_DEBUG)
|
#if defined (QABSTRACTSOCKET_DEBUG)
|
||||||
qDebug("QAbstractSocket::waitForReadyRead(%i) failed (%i, %s)",
|
qDebug("QAbstractSocket::waitForReadyRead(%i) failed (%i, %s)",
|
||||||
msecs, d->socketEngine->error(), d->socketEngine->errorString().toLatin1().constData());
|
msecs, d->socketEngine->error(), d->socketEngine->errorString().toLatin1().constData());
|
||||||
@ -2176,7 +2175,7 @@ bool QAbstractSocket::waitForReadyRead(int msecs)
|
|||||||
|
|
||||||
if (readyToWrite)
|
if (readyToWrite)
|
||||||
d->canWriteNotification();
|
d->canWriteNotification();
|
||||||
} while (msecs == -1 || qt_subtract_from_timeout(msecs, stopWatch.elapsed()) > 0);
|
} while (!deadline.hasExpired());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2212,8 +2211,7 @@ bool QAbstractSocket::waitForBytesWritten(int msecs)
|
|||||||
if (d->writeBuffer.isEmpty())
|
if (d->writeBuffer.isEmpty())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
QElapsedTimer stopWatch;
|
QDeadlineTimer deadline{msecs};
|
||||||
stopWatch.start();
|
|
||||||
|
|
||||||
// handle a socket in connecting state
|
// handle a socket in connecting state
|
||||||
if (state() == HostLookupState || state() == ConnectingState) {
|
if (state() == HostLookupState || state() == ConnectingState) {
|
||||||
@ -2221,13 +2219,13 @@ bool QAbstractSocket::waitForBytesWritten(int msecs)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
forever {
|
for (;;) {
|
||||||
bool readyToRead = false;
|
bool readyToRead = false;
|
||||||
bool readyToWrite = false;
|
bool readyToWrite = false;
|
||||||
if (!d->socketEngine->waitForReadOrWrite(&readyToRead, &readyToWrite,
|
if (!d->socketEngine->waitForReadOrWrite(&readyToRead, &readyToWrite,
|
||||||
!d->readBufferMaxSize || d->buffer.size() < d->readBufferMaxSize,
|
!d->readBufferMaxSize || d->buffer.size() < d->readBufferMaxSize,
|
||||||
!d->writeBuffer.isEmpty(),
|
!d->writeBuffer.isEmpty(),
|
||||||
qt_subtract_from_timeout(msecs, stopWatch.elapsed()))) {
|
deadline)) {
|
||||||
#if defined (QABSTRACTSOCKET_DEBUG)
|
#if defined (QABSTRACTSOCKET_DEBUG)
|
||||||
qDebug("QAbstractSocket::waitForBytesWritten(%i) failed (%i, %s)",
|
qDebug("QAbstractSocket::waitForBytesWritten(%i) failed (%i, %s)",
|
||||||
msecs, d->socketEngine->error(), d->socketEngine->errorString().toLatin1().constData());
|
msecs, d->socketEngine->error(), d->socketEngine->errorString().toLatin1().constData());
|
||||||
@ -2291,8 +2289,7 @@ bool QAbstractSocket::waitForDisconnected(int msecs)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
QElapsedTimer stopWatch;
|
QDeadlineTimer deadline{msecs};
|
||||||
stopWatch.start();
|
|
||||||
|
|
||||||
// handle a socket in connecting state
|
// handle a socket in connecting state
|
||||||
if (state() == HostLookupState || state() == ConnectingState) {
|
if (state() == HostLookupState || state() == ConnectingState) {
|
||||||
@ -2302,12 +2299,12 @@ bool QAbstractSocket::waitForDisconnected(int msecs)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
forever {
|
for (;;) {
|
||||||
bool readyToRead = false;
|
bool readyToRead = false;
|
||||||
bool readyToWrite = false;
|
bool readyToWrite = false;
|
||||||
if (!d->socketEngine->waitForReadOrWrite(&readyToRead, &readyToWrite, state() == ConnectedState,
|
if (!d->socketEngine->waitForReadOrWrite(&readyToRead, &readyToWrite, state() == ConnectedState,
|
||||||
!d->writeBuffer.isEmpty(),
|
!d->writeBuffer.isEmpty(),
|
||||||
qt_subtract_from_timeout(msecs, stopWatch.elapsed()))) {
|
deadline)) {
|
||||||
#if defined (QABSTRACTSOCKET_DEBUG)
|
#if defined (QABSTRACTSOCKET_DEBUG)
|
||||||
qDebug("QAbstractSocket::waitForReadyRead(%i) failed (%i, %s)",
|
qDebug("QAbstractSocket::waitForReadyRead(%i) failed (%i, %s)",
|
||||||
msecs, d->socketEngine->error(), d->socketEngine->errorString().toLatin1().constData());
|
msecs, d->socketEngine->error(), d->socketEngine->errorString().toLatin1().constData());
|
||||||
|
@ -19,8 +19,9 @@
|
|||||||
#include <QtNetwork/private/qtnetworkglobal_p.h>
|
#include <QtNetwork/private/qtnetworkglobal_p.h>
|
||||||
#include "QtNetwork/qhostaddress.h"
|
#include "QtNetwork/qhostaddress.h"
|
||||||
#include "QtNetwork/qabstractsocket.h"
|
#include "QtNetwork/qabstractsocket.h"
|
||||||
#include "private/qobject_p.h"
|
#include <QtCore/qdeadlinetimer.h>
|
||||||
#include "private/qnetworkdatagram_p.h"
|
#include "private/qnetworkdatagram_p.h"
|
||||||
|
#include "private/qobject_p.h"
|
||||||
|
|
||||||
QT_BEGIN_NAMESPACE
|
QT_BEGIN_NAMESPACE
|
||||||
|
|
||||||
@ -44,6 +45,8 @@ public:
|
|||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static constexpr std::chrono::seconds DefaultTimeout{30};
|
||||||
|
|
||||||
class Q_AUTOTEST_EXPORT QAbstractSocketEngine : public QObject
|
class Q_AUTOTEST_EXPORT QAbstractSocketEngine : public QObject
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
@ -128,11 +131,14 @@ public:
|
|||||||
virtual int option(SocketOption option) const = 0;
|
virtual int option(SocketOption option) const = 0;
|
||||||
virtual bool setOption(SocketOption option, int value) = 0;
|
virtual bool setOption(SocketOption option, int value) = 0;
|
||||||
|
|
||||||
virtual bool waitForRead(int msecs = 30000, bool *timedOut = nullptr) = 0;
|
virtual bool waitForRead(QDeadlineTimer deadline = QDeadlineTimer{DefaultTimeout},
|
||||||
virtual bool waitForWrite(int msecs = 30000, bool *timedOut = nullptr) = 0;
|
bool *timedOut = nullptr) = 0;
|
||||||
|
virtual bool waitForWrite(QDeadlineTimer deadline = QDeadlineTimer{DefaultTimeout},
|
||||||
|
bool *timedOut = nullptr) = 0;
|
||||||
virtual bool waitForReadOrWrite(bool *readyToRead, bool *readyToWrite,
|
virtual bool waitForReadOrWrite(bool *readyToRead, bool *readyToWrite,
|
||||||
bool checkRead, bool checkWrite,
|
bool checkRead, bool checkWrite,
|
||||||
int msecs = 30000, bool *timedOut = nullptr) = 0;
|
QDeadlineTimer deadline = QDeadlineTimer{DefaultTimeout},
|
||||||
|
bool *timedOut = nullptr) = 0;
|
||||||
|
|
||||||
QAbstractSocket::SocketError error() const;
|
QAbstractSocket::SocketError error() const;
|
||||||
QString errorString() const;
|
QString errorString() const;
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
#include "qurl.h"
|
#include "qurl.h"
|
||||||
#include "private/qhttpnetworkreply_p.h"
|
#include "private/qhttpnetworkreply_p.h"
|
||||||
#include "private/qiodevice_p.h"
|
#include "private/qiodevice_p.h"
|
||||||
#include "qelapsedtimer.h"
|
#include "qdeadlinetimer.h"
|
||||||
#include "qnetworkinterface.h"
|
#include "qnetworkinterface.h"
|
||||||
|
|
||||||
#if !defined(QT_NO_NETWORKPROXY)
|
#if !defined(QT_NO_NETWORKPROXY)
|
||||||
@ -310,19 +310,16 @@ bool QHttpSocketEngine::setOption(SocketOption option, int value)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool QHttpSocketEngine::waitForRead(int msecs, bool *timedOut)
|
bool QHttpSocketEngine::waitForRead(QDeadlineTimer deadline, bool *timedOut)
|
||||||
{
|
{
|
||||||
Q_D(const QHttpSocketEngine);
|
Q_D(const QHttpSocketEngine);
|
||||||
|
|
||||||
if (!d->socket || d->socket->state() == QAbstractSocket::UnconnectedState)
|
if (!d->socket || d->socket->state() == QAbstractSocket::UnconnectedState)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
QElapsedTimer stopWatch;
|
|
||||||
stopWatch.start();
|
|
||||||
|
|
||||||
// Wait for more data if nothing is available.
|
// Wait for more data if nothing is available.
|
||||||
if (!d->socket->bytesAvailable()) {
|
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)
|
if (d->socket->state() == QAbstractSocket::UnconnectedState)
|
||||||
return true;
|
return true;
|
||||||
setError(d->socket->error(), d->socket->errorString());
|
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
|
// If we're not connected yet, wait until we are, or until an error
|
||||||
// occurs.
|
// 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.
|
// Loop while the protocol handshake is taking place.
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -348,14 +345,14 @@ bool QHttpSocketEngine::waitForRead(int msecs, bool *timedOut)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool QHttpSocketEngine::waitForWrite(int msecs, bool *timedOut)
|
bool QHttpSocketEngine::waitForWrite(QDeadlineTimer deadline, bool *timedOut)
|
||||||
{
|
{
|
||||||
Q_D(const QHttpSocketEngine);
|
Q_D(const QHttpSocketEngine);
|
||||||
|
|
||||||
// If we're connected, just forward the call.
|
// If we're connected, just forward the call.
|
||||||
if (d->state == Connected) {
|
if (d->state == Connected) {
|
||||||
if (d->socket->bytesToWrite()) {
|
if (d->socket->bytesToWrite()) {
|
||||||
if (!d->socket->waitForBytesWritten(msecs)) {
|
if (!d->socket->waitForBytesWritten(deadline.remainingTime())) {
|
||||||
if (d->socket->error() == QAbstractSocket::SocketTimeoutError && timedOut)
|
if (d->socket->error() == QAbstractSocket::SocketTimeoutError && timedOut)
|
||||||
*timedOut = true;
|
*timedOut = true;
|
||||||
return false;
|
return false;
|
||||||
@ -364,13 +361,10 @@ bool QHttpSocketEngine::waitForWrite(int msecs, bool *timedOut)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
QElapsedTimer stopWatch;
|
|
||||||
stopWatch.start();
|
|
||||||
|
|
||||||
// If we're not connected yet, wait until we are, and until bytes have
|
// 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
|
// been received (i.e., the socket has connected, we have sent the
|
||||||
// greeting, and then received the response).
|
// 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.
|
// 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 QHttpSocketEngine::waitForReadOrWrite(bool *readyToRead, bool *readyToWrite,
|
||||||
bool checkRead, bool checkWrite,
|
bool checkRead, bool checkWrite,
|
||||||
int msecs, bool *timedOut)
|
QDeadlineTimer deadline, bool *timedOut)
|
||||||
{
|
{
|
||||||
Q_UNUSED(checkRead);
|
Q_UNUSED(checkRead);
|
||||||
|
|
||||||
if (!checkWrite) {
|
if (!checkWrite) {
|
||||||
// Not interested in writing? Then we wait for read notifications.
|
// Not interested in writing? Then we wait for read notifications.
|
||||||
bool canRead = waitForRead(msecs, timedOut);
|
bool canRead = waitForRead(deadline, timedOut);
|
||||||
if (readyToRead)
|
if (readyToRead)
|
||||||
*readyToRead = canRead;
|
*readyToRead = canRead;
|
||||||
return canRead;
|
return canRead;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Interested in writing? Then we wait for write notifications.
|
// Interested in writing? Then we wait for write notifications.
|
||||||
bool canWrite = waitForWrite(msecs, timedOut);
|
bool canWrite = waitForWrite(deadline, timedOut);
|
||||||
if (readyToWrite)
|
if (readyToWrite)
|
||||||
*readyToWrite = canWrite;
|
*readyToWrite = canWrite;
|
||||||
return canWrite;
|
return canWrite;
|
||||||
|
@ -92,11 +92,14 @@ public:
|
|||||||
int option(SocketOption option) const override;
|
int option(SocketOption option) const override;
|
||||||
bool setOption(SocketOption option, int value) override;
|
bool setOption(SocketOption option, int value) override;
|
||||||
|
|
||||||
bool waitForRead(int msecs = 30000, bool *timedOut = nullptr) override;
|
bool waitForRead(QDeadlineTimer deadline = QDeadlineTimer{DefaultTimeout},
|
||||||
bool waitForWrite(int msecs = 30000, bool *timedOut = nullptr) override;
|
bool *timedOut = nullptr) override;
|
||||||
|
bool waitForWrite(QDeadlineTimer deadline = QDeadlineTimer{DefaultTimeout},
|
||||||
|
bool *timedOut = nullptr) override;
|
||||||
bool waitForReadOrWrite(bool *readyToRead, bool *readyToWrite,
|
bool waitForReadOrWrite(bool *readyToRead, bool *readyToWrite,
|
||||||
bool checkRead, bool checkWrite,
|
bool checkRead, bool checkWrite,
|
||||||
int msecs = 30000, bool *timedOut = nullptr) override;
|
QDeadlineTimer deadline = QDeadlineTimer{DefaultTimeout},
|
||||||
|
bool *timedOut = nullptr) override;
|
||||||
|
|
||||||
bool isReadNotificationEnabled() const override;
|
bool isReadNotificationEnabled() const override;
|
||||||
void setReadNotificationEnabled(bool enable) 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
|
Waits until \a deadline has expired or until the socket is ready for
|
||||||
reading. If \a timedOut is not \nullptr and \a msecs milliseconds
|
reading. If \a timedOut is not \nullptr and \a deadline has expired,
|
||||||
have passed, the value of \a timedOut is set to true.
|
the value of \a timedOut is set to true.
|
||||||
|
|
||||||
Returns \c true if data is available for reading; otherwise returns
|
Returns \c true if data is available for reading; otherwise returns
|
||||||
false.
|
false.
|
||||||
@ -976,7 +976,7 @@ void QNativeSocketEngine::close()
|
|||||||
is to create a QSocketNotifier, passing the socket descriptor
|
is to create a QSocketNotifier, passing the socket descriptor
|
||||||
returned by socketDescriptor() to its constructor.
|
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_D(const QNativeSocketEngine);
|
||||||
Q_CHECK_VALID_SOCKETLAYER(QNativeSocketEngine::waitForRead(), false);
|
Q_CHECK_VALID_SOCKETLAYER(QNativeSocketEngine::waitForRead(), false);
|
||||||
@ -986,7 +986,7 @@ bool QNativeSocketEngine::waitForRead(int msecs, bool *timedOut)
|
|||||||
if (timedOut)
|
if (timedOut)
|
||||||
*timedOut = false;
|
*timedOut = false;
|
||||||
|
|
||||||
int ret = d->nativeSelect(msecs, true);
|
int ret = d->nativeSelect(deadline, true);
|
||||||
if (ret == 0) {
|
if (ret == 0) {
|
||||||
if (timedOut)
|
if (timedOut)
|
||||||
*timedOut = true;
|
*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
|
Waits until \a deadline has expired or until the socket is ready for
|
||||||
writing. If \a timedOut is not \nullptr and \a msecs milliseconds
|
writing. If \a timedOut is not \nullptr and \a deadline has expired,
|
||||||
have passed, the value of \a timedOut is set to true.
|
the value of \a timedOut is set to true.
|
||||||
|
|
||||||
Returns \c true if data is available for writing; otherwise returns
|
Returns \c true if data is available for writing; otherwise returns
|
||||||
false.
|
false.
|
||||||
@ -1016,7 +1016,7 @@ bool QNativeSocketEngine::waitForRead(int msecs, bool *timedOut)
|
|||||||
is to create a QSocketNotifier, passing the socket descriptor
|
is to create a QSocketNotifier, passing the socket descriptor
|
||||||
returned by socketDescriptor() to its constructor.
|
returned by socketDescriptor() to its constructor.
|
||||||
*/
|
*/
|
||||||
bool QNativeSocketEngine::waitForWrite(int msecs, bool *timedOut)
|
bool QNativeSocketEngine::waitForWrite(QDeadlineTimer deadline, bool *timedOut)
|
||||||
{
|
{
|
||||||
Q_D(QNativeSocketEngine);
|
Q_D(QNativeSocketEngine);
|
||||||
Q_CHECK_VALID_SOCKETLAYER(QNativeSocketEngine::waitForWrite(), false);
|
Q_CHECK_VALID_SOCKETLAYER(QNativeSocketEngine::waitForWrite(), false);
|
||||||
@ -1026,7 +1026,7 @@ bool QNativeSocketEngine::waitForWrite(int msecs, bool *timedOut)
|
|||||||
if (timedOut)
|
if (timedOut)
|
||||||
*timedOut = false;
|
*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
|
// On Windows, the socket is in connected state if a call to
|
||||||
// select(writable) is successful. In this case we should not
|
// select(writable) is successful. In this case we should not
|
||||||
// issue a second call to WSAConnect()
|
// 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 QNativeSocketEngine::waitForReadOrWrite(bool *readyToRead, bool *readyToWrite,
|
||||||
bool checkRead, bool checkWrite,
|
bool checkRead, bool checkWrite,
|
||||||
int msecs, bool *timedOut)
|
QDeadlineTimer deadline, bool *timedOut)
|
||||||
{
|
{
|
||||||
Q_D(QNativeSocketEngine);
|
Q_D(QNativeSocketEngine);
|
||||||
Q_CHECK_VALID_SOCKETLAYER(QNativeSocketEngine::waitForReadOrWrite(), false);
|
Q_CHECK_VALID_SOCKETLAYER(QNativeSocketEngine::waitForReadOrWrite(), false);
|
||||||
Q_CHECK_NOT_STATE(QNativeSocketEngine::waitForReadOrWrite(),
|
Q_CHECK_NOT_STATE(QNativeSocketEngine::waitForReadOrWrite(),
|
||||||
QAbstractSocket::UnconnectedState, false);
|
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
|
// On Windows, the socket is in connected state if a call to
|
||||||
// select(writable) is successful. In this case we should not
|
// select(writable) is successful. In this case we should not
|
||||||
// issue a second call to WSAConnect()
|
// issue a second call to WSAConnect()
|
||||||
|
@ -154,11 +154,14 @@ public:
|
|||||||
int option(SocketOption option) const override;
|
int option(SocketOption option) const override;
|
||||||
bool setOption(SocketOption option, int value) override;
|
bool setOption(SocketOption option, int value) override;
|
||||||
|
|
||||||
bool waitForRead(int msecs = 30000, bool *timedOut = nullptr) override;
|
bool waitForRead(QDeadlineTimer deadline = QDeadlineTimer{DefaultTimeout},
|
||||||
bool waitForWrite(int msecs = 30000, bool *timedOut = nullptr) override;
|
bool *timedOut = nullptr) override;
|
||||||
|
bool waitForWrite(QDeadlineTimer deadline = QDeadlineTimer{DefaultTimeout},
|
||||||
|
bool *timedOut = nullptr) override;
|
||||||
bool waitForReadOrWrite(bool *readyToRead, bool *readyToWrite,
|
bool waitForReadOrWrite(bool *readyToRead, bool *readyToWrite,
|
||||||
bool checkRead, bool checkWrite,
|
bool checkRead, bool checkWrite,
|
||||||
int msecs = 30000, bool *timedOut = nullptr) override;
|
QDeadlineTimer deadline = QDeadlineTimer{DefaultTimeout},
|
||||||
|
bool *timedOut = nullptr) override;
|
||||||
|
|
||||||
bool isReadNotificationEnabled() const override;
|
bool isReadNotificationEnabled() const override;
|
||||||
void setReadNotificationEnabled(bool enable) override;
|
void setReadNotificationEnabled(bool enable) override;
|
||||||
|
@ -146,8 +146,8 @@ public:
|
|||||||
qint64 nativeSendDatagram(const char *data, qint64 length, const QIpPacketHeader &header);
|
qint64 nativeSendDatagram(const char *data, qint64 length, const QIpPacketHeader &header);
|
||||||
qint64 nativeRead(char *data, qint64 maxLength);
|
qint64 nativeRead(char *data, qint64 maxLength);
|
||||||
qint64 nativeWrite(const char *data, qint64 length);
|
qint64 nativeWrite(const char *data, qint64 length);
|
||||||
int nativeSelect(int timeout, bool selectForRead) const;
|
int nativeSelect(QDeadlineTimer deadline, bool selectForRead) const;
|
||||||
int nativeSelect(int timeout, bool checkRead, bool checkWrite,
|
int nativeSelect(QDeadlineTimer deadline, bool checkRead, bool checkWrite,
|
||||||
bool *selectForRead, bool *selectForWrite) const;
|
bool *selectForRead, bool *selectForWrite) const;
|
||||||
|
|
||||||
void nativeClose();
|
void nativeClose();
|
||||||
|
@ -5,9 +5,9 @@
|
|||||||
//#define QNATIVESOCKETENGINE_DEBUG
|
//#define QNATIVESOCKETENGINE_DEBUG
|
||||||
#include "qnativesocketengine_p_p.h"
|
#include "qnativesocketengine_p_p.h"
|
||||||
#include "private/qnet_unix_p.h"
|
#include "private/qnet_unix_p.h"
|
||||||
|
#include "qdeadlinetimer.h"
|
||||||
#include "qiodevice.h"
|
#include "qiodevice.h"
|
||||||
#include "qhostaddress.h"
|
#include "qhostaddress.h"
|
||||||
#include "qelapsedtimer.h"
|
|
||||||
#include "qvarlengtharray.h"
|
#include "qvarlengtharray.h"
|
||||||
#include "qnetworkinterface.h"
|
#include "qnetworkinterface.h"
|
||||||
#include "qendian.h"
|
#include "qendian.h"
|
||||||
@ -1344,16 +1344,17 @@ qint64 QNativeSocketEnginePrivate::nativeRead(char *data, qint64 maxSize)
|
|||||||
return qint64(r);
|
return qint64(r);
|
||||||
}
|
}
|
||||||
|
|
||||||
int QNativeSocketEnginePrivate::nativeSelect(int timeout, bool selectForRead) const
|
int QNativeSocketEnginePrivate::nativeSelect(QDeadlineTimer deadline, bool selectForRead) const
|
||||||
{
|
{
|
||||||
bool dummy;
|
bool dummy;
|
||||||
return nativeSelect(timeout, selectForRead, !selectForRead, &dummy, &dummy);
|
return nativeSelect(deadline, selectForRead, !selectForRead, &dummy, &dummy);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef Q_OS_WASM
|
#ifndef Q_OS_WASM
|
||||||
|
|
||||||
int QNativeSocketEnginePrivate::nativeSelect(int timeout, bool checkRead, bool checkWrite,
|
int QNativeSocketEnginePrivate::nativeSelect(QDeadlineTimer deadline, bool checkRead,
|
||||||
bool *selectForRead, bool *selectForWrite) const
|
bool checkWrite, bool *selectForRead,
|
||||||
|
bool *selectForWrite) const
|
||||||
{
|
{
|
||||||
pollfd pfd = qt_make_pollfd(socketDescriptor, 0);
|
pollfd pfd = qt_make_pollfd(socketDescriptor, 0);
|
||||||
|
|
||||||
@ -1363,7 +1364,7 @@ int QNativeSocketEnginePrivate::nativeSelect(int timeout, bool checkRead, bool c
|
|||||||
if (checkWrite)
|
if (checkWrite)
|
||||||
pfd.events |= POLLOUT;
|
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)
|
if (ret <= 0)
|
||||||
return ret;
|
return ret;
|
||||||
@ -1384,13 +1385,16 @@ int QNativeSocketEnginePrivate::nativeSelect(int timeout, bool checkRead, bool c
|
|||||||
|
|
||||||
#else
|
#else
|
||||||
|
|
||||||
int QNativeSocketEnginePrivate::nativeSelect(int timeout, bool checkRead, bool checkWrite,
|
int QNativeSocketEnginePrivate::nativeSelect(QDeadlineTimer deadline, bool checkRead,
|
||||||
bool *selectForRead, bool *selectForWrite) const
|
bool checkWrite, bool *selectForRead,
|
||||||
|
bool *selectForWrite) const
|
||||||
{
|
{
|
||||||
*selectForRead = checkRead;
|
*selectForRead = checkRead;
|
||||||
*selectForWrite = checkWrite;
|
*selectForWrite = checkWrite;
|
||||||
bool socketDisconnect = false;
|
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()
|
// The disconnect/close handling code in QAbstractsScket::canReadNotification()
|
||||||
// does not detect remote disconnect properly; do that here as a workardound.
|
// does not detect remote disconnect properly; do that here as a workardound.
|
||||||
|
@ -16,6 +16,7 @@
|
|||||||
#include <qvarlengtharray.h>
|
#include <qvarlengtharray.h>
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
#include <chrono>
|
||||||
|
|
||||||
//#define QNATIVESOCKETENGINE_DEBUG
|
//#define QNATIVESOCKETENGINE_DEBUG
|
||||||
#if defined(QNATIVESOCKETENGINE_DEBUG)
|
#if defined(QNATIVESOCKETENGINE_DEBUG)
|
||||||
@ -1428,7 +1429,18 @@ qint64 QNativeSocketEnginePrivate::nativeRead(char *data, qint64 maxLength)
|
|||||||
return ret;
|
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();
|
bool readEnabled = selectForRead && readNotifier && readNotifier->isEnabled();
|
||||||
if (readEnabled)
|
if (readEnabled)
|
||||||
@ -1442,12 +1454,10 @@ int QNativeSocketEnginePrivate::nativeSelect(int timeout, bool selectForRead) co
|
|||||||
fds.fd_count = 1;
|
fds.fd_count = 1;
|
||||||
fds.fd_array[0] = (SOCKET)socketDescriptor;
|
fds.fd_array[0] = (SOCKET)socketDescriptor;
|
||||||
|
|
||||||
struct timeval tv;
|
struct timeval tv = durationToTimeval(deadline.remainingTimeAsDuration());
|
||||||
tv.tv_sec = timeout / 1000;
|
|
||||||
tv.tv_usec = (timeout % 1000) * 1000;
|
|
||||||
|
|
||||||
if (selectForRead) {
|
if (selectForRead) {
|
||||||
ret = select(0, &fds, 0, 0, timeout < 0 ? 0 : &tv);
|
ret = select(0, &fds, 0, 0, &tv);
|
||||||
} else {
|
} else {
|
||||||
// select for write
|
// select for write
|
||||||
|
|
||||||
@ -1456,7 +1466,7 @@ int QNativeSocketEnginePrivate::nativeSelect(int timeout, bool selectForRead) co
|
|||||||
FD_ZERO(&fdexception);
|
FD_ZERO(&fdexception);
|
||||||
FD_SET((SOCKET)socketDescriptor, &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
|
// ... but if it is actually set, pretend it did not happen
|
||||||
if (ret > 0 && FD_ISSET((SOCKET)socketDescriptor, &fdexception))
|
if (ret > 0 && FD_ISSET((SOCKET)socketDescriptor, &fdexception))
|
||||||
@ -1469,7 +1479,7 @@ int QNativeSocketEnginePrivate::nativeSelect(int timeout, bool selectForRead) co
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
int QNativeSocketEnginePrivate::nativeSelect(int timeout,
|
int QNativeSocketEnginePrivate::nativeSelect(QDeadlineTimer deadline,
|
||||||
bool checkRead, bool checkWrite,
|
bool checkRead, bool checkWrite,
|
||||||
bool *selectForRead, bool *selectForWrite) const
|
bool *selectForRead, bool *selectForWrite) const
|
||||||
{
|
{
|
||||||
@ -1498,11 +1508,9 @@ int QNativeSocketEnginePrivate::nativeSelect(int timeout,
|
|||||||
FD_SET((SOCKET)socketDescriptor, &fdexception);
|
FD_SET((SOCKET)socketDescriptor, &fdexception);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct timeval tv;
|
struct timeval tv = durationToTimeval(deadline.remainingTimeAsDuration());
|
||||||
tv.tv_sec = timeout / 1000;
|
|
||||||
tv.tv_usec = (timeout % 1000) * 1000;
|
|
||||||
|
|
||||||
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
|
//... but if it is actually set, pretend it did not happen
|
||||||
if (ret > 0 && FD_ISSET((SOCKET)socketDescriptor, &fdexception))
|
if (ret > 0 && FD_ISSET((SOCKET)socketDescriptor, &fdexception))
|
||||||
|
@ -9,6 +9,7 @@
|
|||||||
#include "qdebug.h"
|
#include "qdebug.h"
|
||||||
#include "qhash.h"
|
#include "qhash.h"
|
||||||
#include "qqueue.h"
|
#include "qqueue.h"
|
||||||
|
#include "qdeadlinetimer.h"
|
||||||
#include "qelapsedtimer.h"
|
#include "qelapsedtimer.h"
|
||||||
#include "qmutex.h"
|
#include "qmutex.h"
|
||||||
#include "qthread.h"
|
#include "qthread.h"
|
||||||
@ -25,13 +26,14 @@
|
|||||||
QT_BEGIN_NAMESPACE
|
QT_BEGIN_NAMESPACE
|
||||||
|
|
||||||
using namespace Qt::StringLiterals;
|
using namespace Qt::StringLiterals;
|
||||||
|
using namespace std::chrono_literals;
|
||||||
|
|
||||||
static const int MaxWriteBufferSize = 128*1024;
|
static const int MaxWriteBufferSize = 128*1024;
|
||||||
|
|
||||||
//#define QSOCKS5SOCKETLAYER_DEBUG
|
//#define QSOCKS5SOCKETLAYER_DEBUG
|
||||||
|
|
||||||
#define MAX_DATA_DUMP 256
|
#define MAX_DATA_DUMP 256
|
||||||
#define SOCKS5_BLOCKING_BIND_TIMEOUT 5000
|
static constexpr auto Socks5BlockingBindTimeout = 5s;
|
||||||
|
|
||||||
#define Q_INIT_CHECK(returnValue) do { \
|
#define Q_INIT_CHECK(returnValue) do { \
|
||||||
if (!d->data) { \
|
if (!d->data) { \
|
||||||
@ -318,7 +320,6 @@ void QSocks5BindStore::add(qintptr socketDescriptor, QSocks5BindData *bindData)
|
|||||||
bindData->timeStamp.start();
|
bindData->timeStamp.start();
|
||||||
store.insert(socketDescriptor, bindData);
|
store.insert(socketDescriptor, bindData);
|
||||||
|
|
||||||
using namespace std::chrono_literals;
|
|
||||||
// start sweep timer if not started
|
// start sweep timer if not started
|
||||||
if (sweepTimerId == -1)
|
if (sweepTimerId == -1)
|
||||||
sweepTimerId = startTimer(1min);
|
sweepTimerId = startTimer(1min);
|
||||||
@ -1327,11 +1328,8 @@ bool QSocks5SocketEngine::bind(const QHostAddress &addr, quint16 port)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
int msecs = SOCKS5_BLOCKING_BIND_TIMEOUT;
|
|
||||||
QElapsedTimer stopWatch;
|
|
||||||
stopWatch.start();
|
|
||||||
d->data->controlSocket->connectToHost(d->proxyInfo.hostName(), d->proxyInfo.port());
|
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) {
|
d->data->controlSocket->state() == QAbstractSocket::UnconnectedState) {
|
||||||
// waitForConnected sets the error state and closes the socket
|
// waitForConnected sets the error state and closes the socket
|
||||||
QSOCKS5_Q_DEBUG << "waitForConnected to proxy server" << d->data->controlSocket->errorString();
|
QSOCKS5_Q_DEBUG << "waitForConnected to proxy server" << d->data->controlSocket->errorString();
|
||||||
@ -1422,11 +1420,9 @@ void QSocks5SocketEngine::close()
|
|||||||
Q_D(QSocks5SocketEngine);
|
Q_D(QSocks5SocketEngine);
|
||||||
if (d->data && d->data->controlSocket) {
|
if (d->data && d->data->controlSocket) {
|
||||||
if (d->data->controlSocket->state() == QAbstractSocket::ConnectedState) {
|
if (d->data->controlSocket->state() == QAbstractSocket::ConnectedState) {
|
||||||
int msecs = 100;
|
QDeadlineTimer deadline(100ms);
|
||||||
QElapsedTimer stopWatch;
|
|
||||||
stopWatch.start();
|
|
||||||
while (!d->data->controlSocket->bytesToWrite()) {
|
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;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1679,7 +1675,7 @@ bool QSocks5SocketEngine::setOption(SocketOption option, int value)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool QSocks5SocketEnginePrivate::waitForConnected(int msecs, bool *timedOut)
|
bool QSocks5SocketEnginePrivate::waitForConnected(QDeadlineTimer deadline, bool *timedOut)
|
||||||
{
|
{
|
||||||
if (data->controlSocket->state() == QAbstractSocket::UnconnectedState)
|
if (data->controlSocket->state() == QAbstractSocket::UnconnectedState)
|
||||||
return false;
|
return false;
|
||||||
@ -1689,11 +1685,8 @@ bool QSocks5SocketEnginePrivate::waitForConnected(int msecs, bool *timedOut)
|
|||||||
mode == BindMode ? BindSuccess :
|
mode == BindMode ? BindSuccess :
|
||||||
UdpAssociateSuccess;
|
UdpAssociateSuccess;
|
||||||
|
|
||||||
QElapsedTimer stopWatch;
|
|
||||||
stopWatch.start();
|
|
||||||
|
|
||||||
while (socks5State != wantedState) {
|
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)
|
if (data->controlSocket->state() == QAbstractSocket::UnconnectedState)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
@ -1707,18 +1700,15 @@ bool QSocks5SocketEnginePrivate::waitForConnected(int msecs, bool *timedOut)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool QSocks5SocketEngine::waitForRead(int msecs, bool *timedOut)
|
bool QSocks5SocketEngine::waitForRead(QDeadlineTimer deadline, bool *timedOut)
|
||||||
{
|
{
|
||||||
Q_D(QSocks5SocketEngine);
|
Q_D(QSocks5SocketEngine);
|
||||||
QSOCKS5_DEBUG << "waitForRead" << msecs;
|
QSOCKS5_DEBUG << "waitForRead" << deadline.remainingTimeAsDuration();
|
||||||
|
|
||||||
d->readNotificationActivated = false;
|
d->readNotificationActivated = false;
|
||||||
|
|
||||||
QElapsedTimer stopWatch;
|
|
||||||
stopWatch.start();
|
|
||||||
|
|
||||||
// are we connected yet?
|
// are we connected yet?
|
||||||
if (!d->waitForConnected(msecs, timedOut))
|
if (!d->waitForConnected(deadline, timedOut))
|
||||||
return false;
|
return false;
|
||||||
if (d->data->controlSocket->state() == QAbstractSocket::UnconnectedState)
|
if (d->data->controlSocket->state() == QAbstractSocket::UnconnectedState)
|
||||||
return true;
|
return true;
|
||||||
@ -1732,7 +1722,7 @@ bool QSocks5SocketEngine::waitForRead(int msecs, bool *timedOut)
|
|||||||
if (d->mode == QSocks5SocketEnginePrivate::ConnectMode ||
|
if (d->mode == QSocks5SocketEnginePrivate::ConnectMode ||
|
||||||
d->mode == QSocks5SocketEnginePrivate::BindMode) {
|
d->mode == QSocks5SocketEnginePrivate::BindMode) {
|
||||||
while (!d->readNotificationActivated) {
|
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)
|
if (d->data->controlSocket->state() == QAbstractSocket::UnconnectedState)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
@ -1745,7 +1735,7 @@ bool QSocks5SocketEngine::waitForRead(int msecs, bool *timedOut)
|
|||||||
#ifndef QT_NO_UDPSOCKET
|
#ifndef QT_NO_UDPSOCKET
|
||||||
} else {
|
} else {
|
||||||
while (!d->readNotificationActivated) {
|
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());
|
setError(d->udpData->udpSocket->error(), d->udpData->udpSocket->errorString());
|
||||||
if (timedOut && d->udpData->udpSocket->error() == QAbstractSocket::SocketTimeoutError)
|
if (timedOut && d->udpData->udpSocket->error() == QAbstractSocket::SocketTimeoutError)
|
||||||
*timedOut = true;
|
*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);
|
Q_D(QSocks5SocketEngine);
|
||||||
QSOCKS5_DEBUG << "waitForWrite" << msecs;
|
QSOCKS5_DEBUG << "waitForWrite" << deadline.remainingTimeAsDuration();
|
||||||
|
|
||||||
QElapsedTimer stopWatch;
|
|
||||||
stopWatch.start();
|
|
||||||
|
|
||||||
// are we connected yet?
|
// are we connected yet?
|
||||||
if (!d->waitForConnected(msecs, timedOut))
|
if (!d->waitForConnected(deadline, timedOut))
|
||||||
return false;
|
return false;
|
||||||
if (d->data->controlSocket->state() == QAbstractSocket::UnconnectedState)
|
if (d->data->controlSocket->state() == QAbstractSocket::UnconnectedState)
|
||||||
return true;
|
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
|
// flush any bytes we may still have buffered in the time that we have left
|
||||||
if (d->data->controlSocket->bytesToWrite())
|
if (d->data->controlSocket->bytesToWrite())
|
||||||
d->data->controlSocket->waitForBytesWritten(qt_subtract_from_timeout(msecs, stopWatch.elapsed()));
|
d->data->controlSocket->waitForBytesWritten(deadline.remainingTime());
|
||||||
while ((msecs == -1 || stopWatch.elapsed() < msecs)
|
|
||||||
&& d->data->controlSocket->state() == QAbstractSocket::ConnectedState
|
auto shouldWriteBytes = [&]() {
|
||||||
&& d->data->controlSocket->bytesToWrite() >= MaxWriteBufferSize)
|
return d->data->controlSocket->state() == QAbstractSocket::ConnectedState
|
||||||
d->data->controlSocket->waitForBytesWritten(qt_subtract_from_timeout(msecs, stopWatch.elapsed()));
|
&& 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;
|
return d->data->controlSocket->bytesToWrite() < MaxWriteBufferSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool QSocks5SocketEngine::waitForReadOrWrite(bool *readyToRead, bool *readyToWrite,
|
bool QSocks5SocketEngine::waitForReadOrWrite(bool *readyToRead, bool *readyToWrite,
|
||||||
bool checkRead, bool checkWrite,
|
bool checkRead, bool checkWrite,
|
||||||
int msecs, bool *timedOut)
|
QDeadlineTimer deadline, bool *timedOut)
|
||||||
{
|
{
|
||||||
Q_UNUSED(checkRead);
|
Q_UNUSED(checkRead);
|
||||||
if (!checkWrite) {
|
if (!checkWrite) {
|
||||||
bool canRead = waitForRead(msecs, timedOut);
|
bool canRead = waitForRead(deadline, timedOut);
|
||||||
if (readyToRead)
|
if (readyToRead)
|
||||||
*readyToRead = canRead;
|
*readyToRead = canRead;
|
||||||
return canRead;
|
return canRead;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool canWrite = waitForWrite(msecs, timedOut);
|
bool canWrite = waitForWrite(deadline, timedOut);
|
||||||
if (readyToWrite)
|
if (readyToWrite)
|
||||||
*readyToWrite = canWrite;
|
*readyToWrite = canWrite;
|
||||||
return canWrite;
|
return canWrite;
|
||||||
|
@ -78,11 +78,14 @@ public:
|
|||||||
int option(SocketOption option) const override;
|
int option(SocketOption option) const override;
|
||||||
bool setOption(SocketOption option, int value) override;
|
bool setOption(SocketOption option, int value) override;
|
||||||
|
|
||||||
bool waitForRead(int msecs = 30000, bool *timedOut = nullptr) override;
|
bool waitForRead(QDeadlineTimer deadline = QDeadlineTimer{DefaultTimeout},
|
||||||
bool waitForWrite(int msecs = 30000, bool *timedOut = nullptr) override;
|
bool *timedOut = nullptr) override;
|
||||||
|
bool waitForWrite(QDeadlineTimer deadline = QDeadlineTimer{DefaultTimeout},
|
||||||
|
bool *timedOut = nullptr) override;
|
||||||
bool waitForReadOrWrite(bool *readyToRead, bool *readyToWrite,
|
bool waitForReadOrWrite(bool *readyToRead, bool *readyToWrite,
|
||||||
bool checkRead, bool checkWrite,
|
bool checkRead, bool checkWrite,
|
||||||
int msecs = 30000, bool *timedOut = nullptr) override;
|
QDeadlineTimer deadline = QDeadlineTimer{DefaultTimeout},
|
||||||
|
bool *timedOut = nullptr) override;
|
||||||
|
|
||||||
bool isReadNotificationEnabled() const override;
|
bool isReadNotificationEnabled() const override;
|
||||||
void setReadNotificationEnabled(bool enable) override;
|
void setReadNotificationEnabled(bool enable) override;
|
||||||
@ -208,7 +211,7 @@ public:
|
|||||||
void parseRequestMethodReply();
|
void parseRequestMethodReply();
|
||||||
void parseNewConnection();
|
void parseNewConnection();
|
||||||
|
|
||||||
bool waitForConnected(int msecs, bool *timedOut);
|
bool waitForConnected(QDeadlineTimer deadline, bool *timedOut);
|
||||||
|
|
||||||
void _q_controlSocketConnected();
|
void _q_controlSocketConnected();
|
||||||
void _q_controlSocketReadNotification();
|
void _q_controlSocketReadNotification();
|
||||||
|
@ -498,7 +498,7 @@ bool QTcpServer::waitForNewConnection(int msec, bool *timedOut)
|
|||||||
if (d->state != QAbstractSocket::ListeningState)
|
if (d->state != QAbstractSocket::ListeningState)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (!d->socketEngine->waitForRead(msec, timedOut)) {
|
if (!d->socketEngine->waitForRead(QDeadlineTimer(msec), timedOut)) {
|
||||||
d->serverSocketError = d->socketEngine->error();
|
d->serverSocketError = d->socketEngine->error();
|
||||||
d->serverSocketErrorString = d->socketEngine->errorString();
|
d->serverSocketErrorString = d->socketEngine->errorString();
|
||||||
return false;
|
return false;
|
||||||
|
@ -189,8 +189,8 @@ void tst_QSocketNotifier::unexpectedDisconnection()
|
|||||||
writeEnd2->waitForBytesWritten();
|
writeEnd2->waitForBytesWritten();
|
||||||
|
|
||||||
// ensure both read ends are ready for reading, before the event loop
|
// ensure both read ends are ready for reading, before the event loop
|
||||||
QVERIFY(readEnd1.waitForRead(5000));
|
QVERIFY(readEnd1.waitForRead(5s));
|
||||||
QVERIFY(readEnd2.waitForRead(5000));
|
QVERIFY(readEnd2.waitForRead(5s));
|
||||||
|
|
||||||
UnexpectedDisconnectTester tester(&readEnd1, &readEnd2);
|
UnexpectedDisconnectTester tester(&readEnd1, &readEnd2);
|
||||||
|
|
||||||
|
@ -18,6 +18,8 @@
|
|||||||
|
|
||||||
#include "../../../network-settings.h"
|
#include "../../../network-settings.h"
|
||||||
|
|
||||||
|
using namespace std::chrono_literals;
|
||||||
|
|
||||||
class tst_QHttpSocketEngine : public QObject
|
class tst_QHttpSocketEngine : public QObject
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
@ -323,7 +325,7 @@ void tst_QHttpSocketEngine::simpleErrorsAndStates()
|
|||||||
QCOMPARE(socketDevice.state(), QAbstractSocket::UnconnectedState);
|
QCOMPARE(socketDevice.state(), QAbstractSocket::UnconnectedState);
|
||||||
QVERIFY(!socketDevice.connectToHost(QHostAddress(QtNetworkSettings::socksProxyServerName()), 8088));
|
QVERIFY(!socketDevice.connectToHost(QHostAddress(QtNetworkSettings::socksProxyServerName()), 8088));
|
||||||
QCOMPARE(socketDevice.state(), QAbstractSocket::ConnectingState);
|
QCOMPARE(socketDevice.state(), QAbstractSocket::ConnectingState);
|
||||||
if (socketDevice.waitForWrite(30000)) {
|
if (socketDevice.waitForWrite(30s)) {
|
||||||
QVERIFY(socketDevice.state() == QAbstractSocket::ConnectedState ||
|
QVERIFY(socketDevice.state() == QAbstractSocket::ConnectedState ||
|
||||||
socketDevice.state() == QAbstractSocket::UnconnectedState);
|
socketDevice.state() == QAbstractSocket::UnconnectedState);
|
||||||
} else {
|
} else {
|
||||||
|
@ -23,6 +23,8 @@
|
|||||||
|
|
||||||
#include "../../../network-settings.h"
|
#include "../../../network-settings.h"
|
||||||
|
|
||||||
|
using namespace std::chrono_literals;
|
||||||
|
|
||||||
class tst_QSocks5SocketEngine : public QObject, public QAbstractSocketEngineReceiver
|
class tst_QSocks5SocketEngine : public QObject, public QAbstractSocketEngineReceiver
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
@ -341,7 +343,7 @@ void tst_QSocks5SocketEngine::simpleErrorsAndStates()
|
|||||||
QCOMPARE(socketDevice.state(), QAbstractSocket::UnconnectedState);
|
QCOMPARE(socketDevice.state(), QAbstractSocket::UnconnectedState);
|
||||||
QVERIFY(!socketDevice.connectToHost(QHostInfo::fromName(QtNetworkSettings::socksProxyServerName()).addresses().first(), 8088));
|
QVERIFY(!socketDevice.connectToHost(QHostInfo::fromName(QtNetworkSettings::socksProxyServerName()).addresses().first(), 8088));
|
||||||
QCOMPARE(socketDevice.state(), QAbstractSocket::ConnectingState);
|
QCOMPARE(socketDevice.state(), QAbstractSocket::ConnectingState);
|
||||||
if (socketDevice.waitForWrite(15000)) {
|
if (socketDevice.waitForWrite(15s)) {
|
||||||
QVERIFY(socketDevice.state() == QAbstractSocket::UnconnectedState ||
|
QVERIFY(socketDevice.state() == QAbstractSocket::UnconnectedState ||
|
||||||
socketDevice.state() == QAbstractSocket::ConnectedState);
|
socketDevice.state() == QAbstractSocket::ConnectedState);
|
||||||
} else {
|
} else {
|
||||||
|
@ -13,6 +13,8 @@
|
|||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
#include <QCoreApplication>
|
#include <QCoreApplication>
|
||||||
|
|
||||||
|
using namespace std::chrono_literals;
|
||||||
|
|
||||||
const int bufsize = 16*1024;
|
const int bufsize = 16*1024;
|
||||||
char buf[bufsize];
|
char buf[bufsize];
|
||||||
|
|
||||||
@ -39,7 +41,7 @@ int main(int argc, char**argv)
|
|||||||
int r = socketEngine->connectToHost(QHostAddress("74.125.77.99"), 80); // google
|
int r = socketEngine->connectToHost(QHostAddress("74.125.77.99"), 80); // google
|
||||||
bool readyToRead = false;
|
bool readyToRead = false;
|
||||||
bool readyToWrite = 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
|
if (r <= 0) //timeout or error
|
||||||
exit(1);
|
exit(1);
|
||||||
if (readyToWrite) {
|
if (readyToWrite) {
|
||||||
@ -49,7 +51,7 @@ int main(int argc, char**argv)
|
|||||||
if (ret == request.length()) {
|
if (ret == request.length()) {
|
||||||
// read the response in a loop
|
// read the response in a loop
|
||||||
do {
|
do {
|
||||||
bool waitReadResult = socketEngine->waitForRead(10*1000);
|
bool waitReadResult = socketEngine->waitForRead(10s);
|
||||||
int available = socketEngine->bytesAvailable();
|
int available = socketEngine->bytesAvailable();
|
||||||
if (waitReadResult == true && available == 0) {
|
if (waitReadResult == true && available == 0) {
|
||||||
// disconnected
|
// disconnected
|
||||||
|
Loading…
x
Reference in New Issue
Block a user