diff options
Diffstat (limited to 'src/network/socket/qsocks5socketengine.cpp')
-rw-r--r-- | src/network/socket/qsocks5socketengine.cpp | 184 |
1 files changed, 74 insertions, 110 deletions
diff --git a/src/network/socket/qsocks5socketengine.cpp b/src/network/socket/qsocks5socketengine.cpp index 884199581f..b0fdc63d66 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) |