summaryrefslogtreecommitdiffstats
path: root/src/network/socket/qsocks5socketengine.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/network/socket/qsocks5socketengine.cpp')
-rw-r--r--src/network/socket/qsocks5socketengine.cpp184
1 files changed, 74 insertions, 110 deletions
diff --git a/src/network/socket/qsocks5socketengine.cpp b/src/network/socket/qsocks5socketengine.cpp
index 884199581f..0564ad7a33 100644
--- a/src/network/socket/qsocks5socketengine.cpp
+++ b/src/network/socket/qsocks5socketengine.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNetwork module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qsocks5socketengine_p.h"
@@ -45,6 +9,7 @@
#include "qdebug.h"
#include "qhash.h"
#include "qqueue.h"
+#include "qdeadlinetimer.h"
#include "qelapsedtimer.h"
#include "qmutex.h"
#include "qthread.h"
@@ -56,14 +21,21 @@
#include <qendian.h>
#include <qnetworkinterface.h>
+#include <QtCore/qpointer.h>
+
+#include <memory>
+
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) { \
@@ -100,35 +72,35 @@ static const int MaxWriteBufferSize = 128*1024;
static QString s5StateToString(QSocks5SocketEnginePrivate::Socks5State s)
{
switch (s) {
- case QSocks5SocketEnginePrivate::Uninitialized: return QLatin1String("Uninitialized");
- case QSocks5SocketEnginePrivate::ConnectError: return QLatin1String("ConnectError");
- case QSocks5SocketEnginePrivate::AuthenticationMethodsSent: return QLatin1String("AuthenticationMethodsSent");
- case QSocks5SocketEnginePrivate::Authenticating: return QLatin1String("Authenticating");
- case QSocks5SocketEnginePrivate::AuthenticatingError: return QLatin1String("AuthenticatingError");
- case QSocks5SocketEnginePrivate::RequestMethodSent: return QLatin1String("RequestMethodSent");
- case QSocks5SocketEnginePrivate::RequestError: return QLatin1String("RequestError");
- case QSocks5SocketEnginePrivate::Connected: return QLatin1String("Connected");
- case QSocks5SocketEnginePrivate::UdpAssociateSuccess: return QLatin1String("UdpAssociateSuccess");
- case QSocks5SocketEnginePrivate::BindSuccess: return QLatin1String("BindSuccess");
- case QSocks5SocketEnginePrivate::ControlSocketError: return QLatin1String("ControlSocketError");
- case QSocks5SocketEnginePrivate::SocksError: return QLatin1String("SocksError");
- case QSocks5SocketEnginePrivate::HostNameLookupError: return QLatin1String("HostNameLookupError");
+ case QSocks5SocketEnginePrivate::Uninitialized: return "Uninitialized"_L1;
+ case QSocks5SocketEnginePrivate::ConnectError: return "ConnectError"_L1;
+ case QSocks5SocketEnginePrivate::AuthenticationMethodsSent: return "AuthenticationMethodsSent"_L1;
+ case QSocks5SocketEnginePrivate::Authenticating: return "Authenticating"_L1;
+ case QSocks5SocketEnginePrivate::AuthenticatingError: return "AuthenticatingError"_L1;
+ case QSocks5SocketEnginePrivate::RequestMethodSent: return "RequestMethodSent"_L1;
+ case QSocks5SocketEnginePrivate::RequestError: return "RequestError"_L1;
+ case QSocks5SocketEnginePrivate::Connected: return "Connected"_L1;
+ case QSocks5SocketEnginePrivate::UdpAssociateSuccess: return "UdpAssociateSuccess"_L1;
+ case QSocks5SocketEnginePrivate::BindSuccess: return "BindSuccess"_L1;
+ case QSocks5SocketEnginePrivate::ControlSocketError: return "ControlSocketError"_L1;
+ case QSocks5SocketEnginePrivate::SocksError: return "SocksError"_L1;
+ case QSocks5SocketEnginePrivate::HostNameLookupError: return "HostNameLookupError"_L1;
default: break;
}
- return QLatin1String("unknown state");
+ return "unknown state"_L1;
}
static QString dump(const QByteArray &buf)
{
QString data;
for (int i = 0; i < qMin<int>(MAX_DATA_DUMP, buf.size()); ++i) {
- if (i) data += QLatin1Char(' ');
+ if (i) data += u' ';
uint val = (unsigned char)buf.at(i);
- // data += QString("0x%1").arg(val, 3, 16, QLatin1Char('0'));
+ // data += QString("0x%1").arg(val, 3, 16, u'0');
data += QString::number(val);
}
if (buf.size() > MAX_DATA_DUMP)
- data += QLatin1String(" ...");
+ data += " ..."_L1;
return QString::fromLatin1("size: %1 data: { %2 }").arg(buf.size()).arg(data);
}
@@ -186,11 +158,11 @@ static bool qt_socks5_set_host_name_and_port(const QString &hostname, quint16 po
QByteArray encodedHostName = QUrl::toAce(hostname);
QByteArray &buf = *pBuf;
- if (encodedHostName.length() > 255)
+ if (encodedHostName.size() > 255)
return false;
buf.append(S5_DOMAINNAME);
- buf.append(uchar(encodedHostName.length()));
+ buf.append(uchar(encodedHostName.size()));
buf.append(encodedHostName);
// add port
@@ -349,9 +321,10 @@ void QSocks5BindStore::add(qintptr socketDescriptor, QSocks5BindData *bindData)
}
bindData->timeStamp.start();
store.insert(socketDescriptor, bindData);
+
// start sweep timer if not started
if (sweepTimerId == -1)
- sweepTimerId = startTimer(60000);
+ sweepTimerId = startTimer(1min);
}
bool QSocks5BindStore::contains(qintptr socketDescriptor)
@@ -492,7 +465,7 @@ bool QSocks5PasswordAuthenticator::continueAuthenticate(QTcpSocket *socket, bool
QString QSocks5PasswordAuthenticator::errorString()
{
- return QLatin1String("Socks5 user name or password incorrect");
+ return "Socks5 user name or password incorrect"_L1;
}
@@ -747,7 +720,7 @@ void QSocks5SocketEnginePrivate::parseAuthenticationMethodReply()
return;
} else if (buf.at(1) != data->authenticator->methodId()
|| !data->authenticator->beginAuthenticate(data->controlSocket, &authComplete)) {
- setErrorState(AuthenticatingError, QLatin1String("Socks5 host did not support authentication method."));
+ setErrorState(AuthenticatingError, "Socks5 host did not support authentication method."_L1);
socketError = QAbstractSocket::SocketAccessError; // change the socket error
emitConnectionNotification();
return;
@@ -1100,7 +1073,7 @@ bool QSocks5SocketEngine::connectInternal()
} else if (socketType() == QAbstractSocket::UdpSocket) {
d->initialize(QSocks5SocketEnginePrivate::UdpAssociateMode);
// all udp needs to be bound
- if (!bind(QHostAddress(QLatin1String("0.0.0.0")), 0))
+ if (!bind(QHostAddress("0.0.0.0"_L1), 0))
return false;
setState(QAbstractSocket::ConnectedState);
@@ -1190,7 +1163,7 @@ void QSocks5SocketEnginePrivate::_q_controlSocketReadNotification()
}
if (buf.size()) {
QSOCKS5_DEBUG << dump(buf);
- connectData->readBuffer.append(buf);
+ connectData->readBuffer.append(std::move(buf));
emitReadNotification();
}
break;
@@ -1357,11 +1330,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();
@@ -1383,7 +1353,7 @@ bool QSocks5SocketEngine::bind(const QHostAddress &addr, quint16 port)
// binding timed out
setError(QAbstractSocket::SocketTimeoutError,
- QLatin1String(QT_TRANSLATE_NOOP("QSocks5SocketEngine", "Network operation timed out")));
+ QLatin1StringView(QT_TRANSLATE_NOOP("QSocks5SocketEngine", "Network operation timed out")));
///### delete d->udpSocket;
///### d->udpSocket = 0;
@@ -1411,7 +1381,7 @@ bool QSocks5SocketEngine::listen(int backlog)
return false;
}
-int QSocks5SocketEngine::accept()
+qintptr QSocks5SocketEngine::accept()
{
Q_D(QSocks5SocketEngine);
// check we are listing ---
@@ -1437,10 +1407,10 @@ int QSocks5SocketEngine::accept()
d->socketState = QAbstractSocket::UnconnectedState;
break;
case QSocks5SocketEnginePrivate::ControlSocketError:
- setError(QAbstractSocket::ProxyProtocolError, QLatin1String("Control socket error"));
+ setError(QAbstractSocket::ProxyProtocolError, "Control socket error"_L1);
break;
default:
- setError(QAbstractSocket::ProxyProtocolError, QLatin1String("SOCKS5 proxy error"));
+ setError(QAbstractSocket::ProxyProtocolError, "SOCKS5 proxy error"_L1);
break;
}
return sd;
@@ -1452,11 +1422,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;
}
}
@@ -1477,7 +1445,7 @@ qint64 QSocks5SocketEngine::bytesAvailable() const
#ifndef QT_NO_UDPSOCKET
else if (d->mode == QSocks5SocketEnginePrivate::UdpAssociateMode
&& !d->udpData->pendingDatagrams.isEmpty())
- return d->udpData->pendingDatagrams.first().data.size();
+ return d->udpData->pendingDatagrams.constFirst().data.size();
#endif
return 0;
}
@@ -1492,7 +1460,7 @@ qint64 QSocks5SocketEngine::read(char *data, qint64 maxlen)
//imitate remote closed
close();
setError(QAbstractSocket::RemoteHostClosedError,
- QLatin1String("Remote host closed connection###"));
+ "Remote host closed connection###"_L1);
setState(QAbstractSocket::UnconnectedState);
return -1;
} else {
@@ -1555,7 +1523,7 @@ bool QSocks5SocketEngine::joinMulticastGroup(const QHostAddress &,
const QNetworkInterface &)
{
setError(QAbstractSocket::UnsupportedSocketOperationError,
- QLatin1String("Operation on socket is not supported"));
+ "Operation on socket is not supported"_L1);
return false;
}
@@ -1563,7 +1531,7 @@ bool QSocks5SocketEngine::leaveMulticastGroup(const QHostAddress &,
const QNetworkInterface &)
{
setError(QAbstractSocket::UnsupportedSocketOperationError,
- QLatin1String("Operation on socket is not supported"));
+ "Operation on socket is not supported"_L1);
return false;
}
@@ -1576,7 +1544,7 @@ QNetworkInterface QSocks5SocketEngine::multicastInterface() const
bool QSocks5SocketEngine::setMulticastInterface(const QNetworkInterface &)
{
setError(QAbstractSocket::UnsupportedSocketOperationError,
- QLatin1String("Operation on socket is not supported"));
+ "Operation on socket is not supported"_L1);
return false;
}
#endif // QT_NO_NETWORKINTERFACE
@@ -1632,7 +1600,7 @@ qint64 QSocks5SocketEngine::writeDatagram(const char *data, qint64 len, const QI
if (!d->data) {
d->initialize(QSocks5SocketEnginePrivate::UdpAssociateMode);
// all udp needs to be bound
- if (!bind(QHostAddress(QLatin1String("0.0.0.0")), 0)) {
+ if (!bind(QHostAddress("0.0.0.0"_L1), 0)) {
//### set error
return -1;
}
@@ -1709,7 +1677,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;
@@ -1719,11 +1687,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;
@@ -1737,18 +1702,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;
@@ -1762,7 +1724,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;
@@ -1775,7 +1737,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;
@@ -1794,16 +1756,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;
@@ -1812,27 +1771,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;
@@ -1912,9 +1876,9 @@ QSocks5SocketEngineHandler::createSocketEngine(QAbstractSocket::SocketType socke
QSOCKS5_DEBUG << "not proxying";
return nullptr;
}
- QScopedPointer<QSocks5SocketEngine> engine(new QSocks5SocketEngine(parent));
+ auto engine = std::make_unique<QSocks5SocketEngine>(parent);
engine->setProxy(proxy);
- return engine.take();
+ return engine.release();
}
QAbstractSocketEngine *QSocks5SocketEngineHandler::createSocketEngine(qintptr socketDescriptor, QObject *parent)