diff options
Diffstat (limited to 'tests')
-rw-r--r-- | tests/auto/network/socket/qsocks5socketengine/tst_qsocks5socketengine.cpp | 157 |
1 files changed, 138 insertions, 19 deletions
diff --git a/tests/auto/network/socket/qsocks5socketengine/tst_qsocks5socketengine.cpp b/tests/auto/network/socket/qsocks5socketengine/tst_qsocks5socketengine.cpp index 3cc1f32622..461ec55dea 100644 --- a/tests/auto/network/socket/qsocks5socketengine/tst_qsocks5socketengine.cpp +++ b/tests/auto/network/socket/qsocks5socketengine/tst_qsocks5socketengine.cpp @@ -47,6 +47,7 @@ #include <QtCore/QString> #include <QtCore/QCoreApplication> #include <QtCore/QMetaType> +#include <QtCore/QTimer> #include <private/qsocks5socketengine_p.h> #include <qhostinfo.h> @@ -89,6 +90,10 @@ private slots: // void tcpLoopbackPerformance(); void passwordAuth(); void passwordAuth2(); + void fragmentation_data(); + void fragmentation(); + void incomplete_data(); + void incomplete(); protected slots: void tcpSocketNonBlocking_hostFound(); @@ -112,40 +117,55 @@ private: qint64 bytesAvailable; }; -class MiniSocks5Server: public QTcpServer +class MiniSocks5ResponseHandler : public QObject { Q_OBJECT public: QQueue<QByteArray> responses; + QTcpSocket *client; - MiniSocks5Server(const QQueue<QByteArray> r) - : responses(r) + MiniSocks5ResponseHandler(QQueue<QByteArray> r, QTcpSocket *c, int autoResponseTime) + : responses(r), client(c) { - listen(); - connect(this, SIGNAL(newConnection()), SLOT(handleNewConnection())); + client->setParent(this); + connect(client, SIGNAL(disconnected()), SLOT(deleteLater())); + connect(client, SIGNAL(readyRead()), SLOT(sendNextResponse())); + if (autoResponseTime) + QTimer::singleShot(autoResponseTime, this, SLOT(sendNextResponse())); } private slots: - void handleNewConnection() - { - QTcpSocket *client = nextPendingConnection(); - connect(client, SIGNAL(readyRead()), SLOT(handleClientCommand())); - client->setProperty("pendingResponses", QVariant::fromValue(responses)); - } - - void handleClientCommand() + void sendNextResponse() { // WARNING // this assumes that the client command is received in its entirety // should be ok, since SOCKSv5 commands are rather small - QTcpSocket *client = static_cast<QTcpSocket *>(sender()); - QQueue<QByteArray> pendingResponses = - qvariant_cast<QQueue<QByteArray> >(client->property("pendingResponses")); - if (pendingResponses.isEmpty()) + if (responses.isEmpty()) client->disconnectFromHost(); else - client->write(pendingResponses.dequeue()); - client->setProperty("pendingResponses", QVariant::fromValue(pendingResponses)); + client->write(responses.dequeue()); + } +}; + +class MiniSocks5Server: public QTcpServer +{ + Q_OBJECT +public: + QQueue<QByteArray> responses; + int autoResponseTime; + + MiniSocks5Server(const QQueue<QByteArray> r, int t = 0) + : responses(r), autoResponseTime(t) + { + listen(); + connect(this, SIGNAL(newConnection()), SLOT(handleNewConnection())); + } + +private slots: + void handleNewConnection() + { + QTcpSocket *client = nextPendingConnection(); + new MiniSocks5ResponseHandler(responses, client, autoResponseTime); } }; @@ -966,6 +986,105 @@ void tst_QSocks5SocketEngine::passwordAuth2() QVERIFY(socketDevice.state() == QAbstractSocket::UnconnectedState); } +void tst_QSocks5SocketEngine::fragmentation_data() +{ + QTest::addColumn<QQueue<QByteArray> >("responses"); + + QByteArray authMethodNone = QByteArray::fromRawData("\5\0", 2); + QByteArray authMethodBasic = QByteArray::fromRawData("\5\2", 2); + QByteArray authSuccess = QByteArray::fromRawData("\1\0", 2); + QByteArray connectResponseIPv4 = QByteArray::fromRawData("\5\0\0\1\1\2\3\4\5\6", 10); + QByteArray connectResponseIPv6 = QByteArray::fromRawData("\5\0\0\4\x01\x23\x45\x67\x89\xab\xcd\xef\x01\x23\x45\x67\x89\xab\xcd\xef\5\6", 22); + + QQueue<QByteArray> responses; + responses << authMethodNone.left(1) << authMethodNone.mid(1) << connectResponseIPv4; + QTest::newRow("auth-method") << responses; + + responses.clear(); + responses << authMethodBasic << authSuccess.left(1) << authSuccess.mid(1) << connectResponseIPv4; + QTest::newRow("auth-response") << responses; + + for (int i = 1; i < connectResponseIPv4.length() - 1; i++) { + responses.clear(); + responses << authMethodNone << connectResponseIPv4.left(i) << connectResponseIPv4.mid(i); + QTest::newRow(qPrintable(QString("connect-response-ipv4-") + QString::number(i))) << responses; + } + + for (int i = 1; i < connectResponseIPv6.length() - 1; i++) { + responses.clear(); + responses << authMethodNone << connectResponseIPv6.left(i) << connectResponseIPv6.mid(i); + QTest::newRow(qPrintable(QString("connect-response-ipv6-") + QString::number(i))) << responses; + } +} + +void tst_QSocks5SocketEngine::fragmentation() +{ + QFETCH(QQueue<QByteArray>, responses); + MiniSocks5Server server(responses, 500); + + QTcpSocket socket; + socket.setProxy(QNetworkProxy(QNetworkProxy::Socks5Proxy, "localhost", server.serverPort(), "user", "password")); + socket.connectToHost("0.1.2.3", 12345); + + connect(&socket, SIGNAL(connected()), + &QTestEventLoop::instance(), SLOT(exitLoop())); + QTestEventLoop::instance().enterLoop(10); + QVERIFY(!QTestEventLoop::instance().timeout()); + + QVERIFY(socket.localAddress() == QHostAddress("1.2.3.4") || socket.localAddress() == QHostAddress("0123:4567:89ab:cdef:0123:4567:89ab:cdef")); + QVERIFY(socket.localPort() == 0x0506); +} + +void tst_QSocks5SocketEngine::incomplete_data() +{ + QTest::addColumn<QQueue<QByteArray> >("responses"); + + QByteArray authMethodNone = QByteArray::fromRawData("\5\0", 2); + QByteArray authMethodBasic = QByteArray::fromRawData("\5\2", 2); + QByteArray authSuccess = QByteArray::fromRawData("\1\0", 2); + QByteArray connectResponseIPv4 = QByteArray::fromRawData("\5\0\0\1\1\2\3\4\5\6", 10); + QByteArray connectResponseIPv6 = QByteArray::fromRawData("\5\0\0\4\x01\x23\x45\x67\x89\xab\xcd\xef\x01\x23\x45\x67\x89\xab\xcd\xef\5\6", 22); + + QQueue<QByteArray> responses; + responses << authMethodNone.left(1); + QTest::newRow("auth-method") << responses; + + responses.clear(); + responses << authMethodBasic << authSuccess.left(1); + QTest::newRow("auth-response") << responses; + + for (int i = 1; i < connectResponseIPv4.length() - 1; i++) { + responses.clear(); + responses << authMethodNone << connectResponseIPv4.left(i); + QTest::newRow(qPrintable(QString("connect-response-ipv4-") + QString::number(i))) << responses; + } + + for (int i = 1; i < connectResponseIPv6.length() - 1; i++) { + responses.clear(); + responses << authMethodNone << connectResponseIPv6.left(i); + QTest::newRow(qPrintable(QString("connect-response-ipv6-") + QString::number(i))) << responses; + } +} + +void tst_QSocks5SocketEngine::incomplete() +{ + QFETCH(QQueue<QByteArray>, responses); + MiniSocks5Server server(responses, 500); + + QTcpSocket socket; + socket.setProxy(QNetworkProxy(QNetworkProxy::Socks5Proxy, "127.0.0.1", server.serverPort(), "user", "password")); + socket.connectToHost("0.1.2.3", 12345); + + connect(&socket, SIGNAL(connected()), + &QTestEventLoop::instance(), SLOT(exitLoop())); + connect(&socket, SIGNAL(error(QAbstractSocket::SocketError)), + &QTestEventLoop::instance(), SLOT(exitLoop())); + QTestEventLoop::instance().enterLoop(70); + QVERIFY(!QTestEventLoop::instance().timeout()); + + QCOMPARE(socket.error(), QAbstractSocket::ProxyConnectionClosedError); +} + //---------------------------------------------------------------------------------- QTEST_MAIN(tst_QSocks5SocketEngine) |