mirror of
https://github.com/crystalidea/qt6windows7.git
synced 2024-12-02 08:33:00 +08:00
1003 lines
36 KiB
C++
1003 lines
36 KiB
C++
|
// Copyright (C) 2016 The Qt Company Ltd.
|
||
|
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
||
|
|
||
|
|
||
|
#include <QtTest/QTest>
|
||
|
#include <QtTest/QTestEventLoop>
|
||
|
|
||
|
#include <QtCore/QQueue>
|
||
|
#include <QtCore/QString>
|
||
|
#include <QtCore/QCoreApplication>
|
||
|
#include <QtCore/QMetaType>
|
||
|
#include <QtCore/QTimer>
|
||
|
|
||
|
#include <private/qsocks5socketengine_p.h>
|
||
|
#include <qhostinfo.h>
|
||
|
#include <qhostaddress.h>
|
||
|
#include <qtcpsocket.h>
|
||
|
#include <qauthenticator.h>
|
||
|
#include <qdebug.h>
|
||
|
#include <qtcpserver.h>
|
||
|
#include <qmetatype.h>
|
||
|
#include <qdebug.h>
|
||
|
|
||
|
#include "../../../network-settings.h"
|
||
|
|
||
|
class tst_QSocks5SocketEngine : public QObject, public QAbstractSocketEngineReceiver
|
||
|
{
|
||
|
Q_OBJECT
|
||
|
|
||
|
private slots:
|
||
|
void initTestCase();
|
||
|
void construction();
|
||
|
void errorTest_data();
|
||
|
void errorTest();
|
||
|
void simpleConnectToIMAP();
|
||
|
void simpleErrorsAndStates();
|
||
|
void udpTest();
|
||
|
void serverTest();
|
||
|
void tcpSocketBlockingTest();
|
||
|
void tcpSocketNonBlockingTest();
|
||
|
void downloadBigFile();
|
||
|
// void tcpLoopbackPerformance();
|
||
|
void passwordAuth();
|
||
|
void passwordAuth2();
|
||
|
void fragmentation_data();
|
||
|
void fragmentation();
|
||
|
void incomplete_data();
|
||
|
void incomplete();
|
||
|
|
||
|
protected slots:
|
||
|
void proxyAuthenticationRequired(const QNetworkProxy &proxy, QAuthenticator *auth) override;
|
||
|
|
||
|
private:
|
||
|
void readNotification() override { }
|
||
|
void writeNotification() override { }
|
||
|
void closeNotification() override { }
|
||
|
void exceptionNotification() override { }
|
||
|
void connectionNotification() override { }
|
||
|
};
|
||
|
|
||
|
class MiniSocks5ResponseHandler : public QObject
|
||
|
{
|
||
|
Q_OBJECT
|
||
|
public:
|
||
|
QQueue<QByteArray> responses;
|
||
|
QTcpSocket *client;
|
||
|
|
||
|
MiniSocks5ResponseHandler(QQueue<QByteArray> r, QTcpSocket *c, int autoResponseTime)
|
||
|
: responses(r), client(c)
|
||
|
{
|
||
|
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 sendNextResponse()
|
||
|
{
|
||
|
// WARNING
|
||
|
// this assumes that the client command is received in its entirety
|
||
|
// should be ok, since SOCKSv5 commands are rather small
|
||
|
if (responses.isEmpty())
|
||
|
client->disconnectFromHost();
|
||
|
else
|
||
|
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);
|
||
|
}
|
||
|
};
|
||
|
|
||
|
void tst_QSocks5SocketEngine::initTestCase()
|
||
|
{
|
||
|
if (qEnvironmentVariable("QT_QPA_PLATFORM").contains("offscreen")
|
||
|
&& !qEnvironmentVariableIsEmpty("QEMU_LD_PREFIX"))
|
||
|
QSKIP("Not support yet for B2Qt");
|
||
|
|
||
|
#ifdef QT_TEST_SERVER
|
||
|
QVERIFY(QtNetworkSettings::verifyConnection(QtNetworkSettings::socksProxyServerName(), 1080));
|
||
|
QVERIFY(QtNetworkSettings::verifyConnection(QtNetworkSettings::httpServerName(), 80));
|
||
|
QVERIFY(QtNetworkSettings::verifyConnection(QtNetworkSettings::imapServerName(), 143));
|
||
|
#else
|
||
|
if (!QtNetworkSettings::verifyTestNetworkSettings())
|
||
|
QSKIP("No network test server available");
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
//---------------------------------------------------------------------------
|
||
|
void tst_QSocks5SocketEngine::construction()
|
||
|
{
|
||
|
QSocks5SocketEngine socketDevice;
|
||
|
|
||
|
QVERIFY(!socketDevice.isValid());
|
||
|
|
||
|
// Initialize device
|
||
|
QVERIFY(socketDevice.initialize(QAbstractSocket::TcpSocket, QAbstractSocket::IPv4Protocol));
|
||
|
QVERIFY(socketDevice.isValid());
|
||
|
QCOMPARE(socketDevice.protocol(), QAbstractSocket::IPv4Protocol);
|
||
|
QCOMPARE(socketDevice.socketType(), QAbstractSocket::TcpSocket);
|
||
|
QCOMPARE(socketDevice.state(), QAbstractSocket::UnconnectedState);
|
||
|
// QVERIFY(socketDevice.socketDescriptor() != -1);
|
||
|
QCOMPARE(socketDevice.localAddress(), QHostAddress());
|
||
|
QCOMPARE(socketDevice.localPort(), quint16(0));
|
||
|
QCOMPARE(socketDevice.peerAddress(), QHostAddress());
|
||
|
QCOMPARE(socketDevice.peerPort(), quint16(0));
|
||
|
QCOMPARE(socketDevice.error(), QAbstractSocket::UnknownSocketError);
|
||
|
|
||
|
//QTest::ignoreMessage(QtWarningMsg, "QSocketLayer::bytesAvailable() was called in QAbstractSocket::UnconnectedState");
|
||
|
QCOMPARE(socketDevice.bytesAvailable(), 0);
|
||
|
|
||
|
//QTest::ignoreMessage(QtWarningMsg, "QSocketLayer::hasPendingDatagrams() was called in QAbstractSocket::UnconnectedState");
|
||
|
QVERIFY(!socketDevice.hasPendingDatagrams());
|
||
|
}
|
||
|
|
||
|
//---------------------------------------------------------------------------
|
||
|
void tst_QSocks5SocketEngine::errorTest_data()
|
||
|
{
|
||
|
QTest::addColumn<QString>("hostname");
|
||
|
QTest::addColumn<int>("port");
|
||
|
QTest::addColumn<QString>("username");
|
||
|
QTest::addColumn<QQueue<QByteArray> >("responses");
|
||
|
QTest::addColumn<int>("expectedError");
|
||
|
|
||
|
QQueue<QByteArray> responses;
|
||
|
QTest::newRow("proxy-host-not-found") << "this-host-does-not-exist." << 1080 << QString()
|
||
|
<< responses
|
||
|
<< int(QAbstractSocket::ProxyNotFoundError);
|
||
|
QTest::newRow("proxy-connection-refused") << "127.0.0.1" << 2 << QString()
|
||
|
<< responses
|
||
|
<< int(QAbstractSocket::ProxyConnectionRefusedError);
|
||
|
|
||
|
#define REPLY(name, contents) \
|
||
|
static const char raw_ ## name [] = contents; \
|
||
|
const QByteArray name = QByteArray::fromRawData(raw_ ## name, sizeof raw_ ## name - 1)
|
||
|
|
||
|
REPLY(garbage, "\4\4\4\4");
|
||
|
// authentication method replies
|
||
|
REPLY(noAuthentication, "\5\0");
|
||
|
REPLY(passwordAuthentication, "\5\2");
|
||
|
REPLY(garbageAuthentication, "\5\177");
|
||
|
REPLY(noAcceptableAuthentication, "\5\377");
|
||
|
// authentication replies
|
||
|
REPLY(authenticationAccepted, "\5\0");
|
||
|
REPLY(authenticationNotAccepted, "\5\1");
|
||
|
// connection replies
|
||
|
REPLY(connectionAccepted, "\5\0\0\4\177\0\0\1\0\100");
|
||
|
REPLY(connectionNotAllowed, "\5\2\0");
|
||
|
REPLY(networkUnreachable, "\5\3\0");
|
||
|
REPLY(hostUnreachable, "\5\4\0");
|
||
|
REPLY(connectionRefused, "\5\5\0");
|
||
|
|
||
|
#undef REPLY
|
||
|
|
||
|
responses << garbage;
|
||
|
QTest::newRow("garbage1") << QString() << 0 << QString() << responses
|
||
|
<< int(QAbstractSocket::ProxyProtocolError);
|
||
|
|
||
|
responses.clear();
|
||
|
responses << noAuthentication << garbage;
|
||
|
QTest::newRow("garbage2") << QString() << 0 << QString() << responses
|
||
|
<< int(QAbstractSocket::ProxyProtocolError);
|
||
|
|
||
|
responses.clear();
|
||
|
responses << garbageAuthentication;
|
||
|
QTest::newRow("unknown-auth-method") << QString() << 0 << QString()
|
||
|
<< responses
|
||
|
<< int(QAbstractSocket::SocketAccessError);
|
||
|
|
||
|
responses.clear();
|
||
|
responses << noAcceptableAuthentication;
|
||
|
QTest::newRow("no-acceptable-authentication") << QString() << 0 << QString()
|
||
|
<< responses
|
||
|
<< int(QAbstractSocket::ProxyAuthenticationRequiredError);
|
||
|
|
||
|
responses.clear();
|
||
|
responses << passwordAuthentication << authenticationNotAccepted;
|
||
|
QTest::newRow("authentication-required") << QString() << 0 << "foo"
|
||
|
<< responses
|
||
|
<< int(QAbstractSocket::ProxyAuthenticationRequiredError);
|
||
|
|
||
|
responses.clear();
|
||
|
responses << noAuthentication << connectionNotAllowed;
|
||
|
QTest::newRow("connection-not-allowed") << QString() << 0 << QString()
|
||
|
<< responses
|
||
|
<< int(QAbstractSocket::SocketAccessError);
|
||
|
|
||
|
responses.clear();
|
||
|
responses << noAuthentication << networkUnreachable;
|
||
|
QTest::newRow("network-unreachable") << QString() << 0 << QString()
|
||
|
<< responses
|
||
|
<< int(QAbstractSocket::NetworkError);
|
||
|
|
||
|
responses.clear();
|
||
|
responses << noAuthentication << hostUnreachable;
|
||
|
QTest::newRow("host-unreachable") << QString() << 0 << QString()
|
||
|
<< responses
|
||
|
<< int(QAbstractSocket::HostNotFoundError);
|
||
|
|
||
|
responses.clear();
|
||
|
responses << noAuthentication << connectionRefused;
|
||
|
QTest::newRow("connection-refused") << QString() << 0 << QString()
|
||
|
<< responses
|
||
|
<< int(QAbstractSocket::ConnectionRefusedError);
|
||
|
}
|
||
|
|
||
|
void tst_QSocks5SocketEngine::errorTest()
|
||
|
{
|
||
|
QFETCH(QString, hostname);
|
||
|
QFETCH(int, port);
|
||
|
QFETCH(QString, username);
|
||
|
QFETCH(QQueue<QByteArray>, responses);
|
||
|
QFETCH(int, expectedError);
|
||
|
|
||
|
MiniSocks5Server server(responses);
|
||
|
|
||
|
if (hostname.isEmpty()) {
|
||
|
hostname = "127.0.0.1";
|
||
|
port = server.serverPort();
|
||
|
}
|
||
|
QTcpSocket socket;
|
||
|
socket.setProxy(QNetworkProxy(QNetworkProxy::Socks5Proxy, hostname, port, username, username));
|
||
|
socket.connectToHost("0.1.2.3", 12345);
|
||
|
|
||
|
connect(&socket, SIGNAL(errorOccurred(QAbstractSocket::SocketError)),
|
||
|
&QTestEventLoop::instance(), SLOT(exitLoop()));
|
||
|
QTestEventLoop::instance().enterLoop(10);
|
||
|
QVERIFY(!QTestEventLoop::instance().timeout());
|
||
|
|
||
|
QCOMPARE(int(socket.error()), expectedError);
|
||
|
}
|
||
|
|
||
|
//---------------------------------------------------------------------------
|
||
|
void tst_QSocks5SocketEngine::simpleConnectToIMAP()
|
||
|
{
|
||
|
QSocks5SocketEngine socketDevice;
|
||
|
|
||
|
// Initialize device
|
||
|
QVERIFY(socketDevice.initialize(QAbstractSocket::TcpSocket, QAbstractSocket::IPv4Protocol));
|
||
|
QCOMPARE(socketDevice.state(), QAbstractSocket::UnconnectedState);
|
||
|
|
||
|
socketDevice.setProxy(QNetworkProxy(QNetworkProxy::Socks5Proxy, QtNetworkSettings::socksProxyServerName(), 1080));
|
||
|
|
||
|
QVERIFY(!socketDevice.connectToHost(QtNetworkSettings::imapServerIp(), 143));
|
||
|
QCOMPARE(socketDevice.state(), QAbstractSocket::ConnectingState);
|
||
|
QVERIFY(socketDevice.waitForWrite());
|
||
|
QCOMPARE(socketDevice.state(), QAbstractSocket::ConnectedState);
|
||
|
QCOMPARE(socketDevice.peerAddress(), QtNetworkSettings::imapServerIp());
|
||
|
|
||
|
// Wait for the greeting, if it hasn't arrived yet
|
||
|
qint64 available = socketDevice.bytesAvailable();
|
||
|
if (available == 0) {
|
||
|
QVERIFY2(socketDevice.waitForRead(), qPrintable("Socket error:" + socketDevice.errorString()));
|
||
|
available = socketDevice.bytesAvailable();
|
||
|
}
|
||
|
QVERIFY(available > 0);
|
||
|
|
||
|
// Read the greeting
|
||
|
QByteArray array;
|
||
|
array.resize(available);
|
||
|
QVERIFY(socketDevice.read(array.data(), array.size()) == available);
|
||
|
|
||
|
// Check that the greeting is what we expect it to be
|
||
|
QVERIFY2(QtNetworkSettings::compareReplyIMAP(array), array.constData());
|
||
|
|
||
|
// Write a logout message
|
||
|
QByteArray array2 = "XXXX LOGOUT\r\n";
|
||
|
QVERIFY(socketDevice.write(array2.data(),
|
||
|
array2.size()) == array2.size());
|
||
|
|
||
|
// Wait for the response
|
||
|
QVERIFY(socketDevice.waitForRead());
|
||
|
|
||
|
available = socketDevice.bytesAvailable();
|
||
|
QVERIFY(available > 0);
|
||
|
array.resize(available);
|
||
|
QVERIFY(socketDevice.read(array.data(), array.size()) == available);
|
||
|
|
||
|
// Check that the greeting is what we expect it to be
|
||
|
QCOMPARE(array.constData(), "* BYE LOGOUT received\r\nXXXX OK Completed\r\n");
|
||
|
|
||
|
// Wait for the response
|
||
|
QVERIFY(socketDevice.waitForRead());
|
||
|
char c;
|
||
|
QVERIFY(socketDevice.read(&c, sizeof(c)) == -1);
|
||
|
QCOMPARE(socketDevice.error(), QAbstractSocket::RemoteHostClosedError);
|
||
|
QCOMPARE(socketDevice.state(), QAbstractSocket::UnconnectedState);
|
||
|
}
|
||
|
|
||
|
//---------------------------------------------------------------------------
|
||
|
void tst_QSocks5SocketEngine::simpleErrorsAndStates()
|
||
|
{
|
||
|
{
|
||
|
QSocks5SocketEngine socketDevice;
|
||
|
|
||
|
// Initialize device
|
||
|
QVERIFY(socketDevice.initialize(QAbstractSocket::TcpSocket, QAbstractSocket::IPv4Protocol));
|
||
|
|
||
|
socketDevice.setProxy(QNetworkProxy(QNetworkProxy::Socks5Proxy, QtNetworkSettings::socksProxyServerName(), 1080));
|
||
|
|
||
|
QCOMPARE(socketDevice.state(), QAbstractSocket::UnconnectedState);
|
||
|
QVERIFY(!socketDevice.connectToHost(QHostInfo::fromName(QtNetworkSettings::socksProxyServerName()).addresses().first(), 8088));
|
||
|
QCOMPARE(socketDevice.state(), QAbstractSocket::ConnectingState);
|
||
|
if (socketDevice.waitForWrite(15000)) {
|
||
|
QVERIFY(socketDevice.state() == QAbstractSocket::UnconnectedState ||
|
||
|
socketDevice.state() == QAbstractSocket::ConnectedState);
|
||
|
} else {
|
||
|
QCOMPARE(socketDevice.error(), QAbstractSocket::SocketTimeoutError);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
//---------------------------------------------------------------------------
|
||
|
void tst_QSocks5SocketEngine::tcpLoopbackPerformance()
|
||
|
{
|
||
|
QTcpServer server;
|
||
|
|
||
|
// Bind to any port on all interfaces
|
||
|
QVERIFY(server.bind(QHostAddress("0.0.0.0"), 0));
|
||
|
QCOMPARE(server.state(), QAbstractSocket::BoundState);
|
||
|
quint16 port = server.localPort();
|
||
|
|
||
|
// Listen for incoming connections
|
||
|
QVERIFY(server.listen());
|
||
|
QCOMPARE(server.state(), QAbstractSocket::ListeningState);
|
||
|
|
||
|
// Initialize a Tcp socket
|
||
|
QSocks5SocketEngine client;
|
||
|
QVERIFY(client.initialize(QAbstractSocket::TcpSocket));
|
||
|
|
||
|
client.setProxy(QHostAddress("80.232.37.158"), 1081);
|
||
|
|
||
|
// Connect to our server
|
||
|
if (!client.connectToHost(QHostAddress("127.0.0.1"), port)) {
|
||
|
QVERIFY(client.waitForWrite());
|
||
|
QVERIFY(client.connectToHost(QHostAddress("127.0.0.1"), port));
|
||
|
}
|
||
|
|
||
|
// The server accepts the connectio
|
||
|
int socketDescriptor = server.accept();
|
||
|
QVERIFY(socketDescriptor > 0);
|
||
|
|
||
|
// A socket device is initialized on the server side, passing the
|
||
|
// socket descriptor from accept(). It's pre-connected.
|
||
|
QSocketLayer serverSocket;
|
||
|
QVERIFY(serverSocket.initialize(socketDescriptor));
|
||
|
QCOMPARE(serverSocket.state(), QAbstractSocket::ConnectedState);
|
||
|
|
||
|
const int messageSize = 1024 * 256;
|
||
|
QByteArray message1(messageSize, '@');
|
||
|
QByteArray answer(messageSize, '@');
|
||
|
|
||
|
QTime timer;
|
||
|
timer.start();
|
||
|
qlonglong readBytes = 0;
|
||
|
while (timer.elapsed() < 5000) {
|
||
|
qlonglong written = serverSocket.write(message1.data(), message1.size());
|
||
|
while (written > 0) {
|
||
|
client.waitForRead();
|
||
|
if (client.bytesAvailable() > 0) {
|
||
|
qlonglong readNow = client.read(answer.data(), answer.size());
|
||
|
written -= readNow;
|
||
|
readBytes += readNow;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
qDebug("\t\t%.1fMB/%.1fs: %.1fMB/s",
|
||
|
readBytes / (1024.0 * 1024.0),
|
||
|
timer.elapsed() / 1024.0,
|
||
|
(readBytes / (timer.elapsed() / 1000.0)) / (1024 * 1024));
|
||
|
}
|
||
|
*/
|
||
|
|
||
|
//---------------------------------------------------------------------------
|
||
|
void tst_QSocks5SocketEngine::serverTest()
|
||
|
{
|
||
|
QSocks5SocketEngine server;
|
||
|
|
||
|
// Initialize a Tcp socket
|
||
|
QVERIFY(server.initialize(QAbstractSocket::TcpSocket));
|
||
|
|
||
|
QNetworkProxy proxy(QNetworkProxy::Socks5Proxy, QtNetworkSettings::socksProxyServerName(), 1080);
|
||
|
|
||
|
server.setProxy(proxy);
|
||
|
|
||
|
// Bind to any port on all interfaces
|
||
|
QVERIFY(server.bind(QHostAddress("0.0.0.0"), 0));
|
||
|
QCOMPARE(server.state(), QAbstractSocket::BoundState);
|
||
|
|
||
|
// Listen for incoming connections
|
||
|
QVERIFY(server.listen(50));
|
||
|
QCOMPARE(server.state(), QAbstractSocket::ListeningState);
|
||
|
|
||
|
// Initialize a Tcp socket
|
||
|
QSocks5SocketEngine client;
|
||
|
QVERIFY(client.initialize(QAbstractSocket::TcpSocket));
|
||
|
|
||
|
client.setProxy(proxy);
|
||
|
|
||
|
// QTest::wait(100000); // ### timing problem on win32
|
||
|
|
||
|
|
||
|
// Connect to our server
|
||
|
if (!client.connectToHost(server.localAddress(), server.localPort())) {
|
||
|
QVERIFY(client.waitForWrite());
|
||
|
// QTest::wait(100); // ### timing problem on win32
|
||
|
QCOMPARE(client.state(), QAbstractSocket::ConnectedState);
|
||
|
//QTest::wait(100);
|
||
|
}
|
||
|
|
||
|
QVERIFY(server.waitForRead());
|
||
|
|
||
|
// The server accepts the connection
|
||
|
int socketDescriptor = server.accept();
|
||
|
QVERIFY(socketDescriptor > 0);
|
||
|
|
||
|
// A socket device is initialized on the server side, passing the
|
||
|
// socket descriptor from accept(). It's pre-connected.
|
||
|
|
||
|
QSocks5SocketEngine serverSocket;
|
||
|
QVERIFY(serverSocket.initialize(socketDescriptor));
|
||
|
QCOMPARE(serverSocket.state(), QAbstractSocket::ConnectedState);
|
||
|
|
||
|
QCOMPARE(serverSocket.localAddress(), client.peerAddress());
|
||
|
QCOMPARE(serverSocket.localPort(), client.peerPort());
|
||
|
// this seems depends on the socks server implementation, especially
|
||
|
// when connecting /to/ the socks server /through/ the same socks server
|
||
|
//QCOMPARE(serverSocket.peerAddress(), client.localAddress());
|
||
|
//QCOMPARE(serverSocket.peerPort(), client.localPort());
|
||
|
|
||
|
// The server socket sends a greeting to the client
|
||
|
QByteArray greeting = "Greetings!";
|
||
|
QVERIFY(serverSocket.write(greeting.data(),
|
||
|
greeting.size()) == greeting.size());
|
||
|
|
||
|
// The client waits for the greeting to arrive
|
||
|
QVERIFY(client.waitForRead());
|
||
|
qint64 available = client.bytesAvailable();
|
||
|
QVERIFY(available > 0);
|
||
|
|
||
|
// The client reads the greeting and checks that it's correct
|
||
|
QByteArray response;
|
||
|
response.resize(available);
|
||
|
QVERIFY(client.read(response.data(),
|
||
|
response.size()) == response.size());
|
||
|
QCOMPARE(response, greeting);
|
||
|
}
|
||
|
|
||
|
|
||
|
//---------------------------------------------------------------------------
|
||
|
void tst_QSocks5SocketEngine::udpTest()
|
||
|
{
|
||
|
QSocks5SocketEngine udpSocket;
|
||
|
|
||
|
// Initialize device #1
|
||
|
QVERIFY(udpSocket.initialize(QAbstractSocket::UdpSocket));
|
||
|
QVERIFY(udpSocket.isValid());
|
||
|
|
||
|
QNetworkProxy proxy(QNetworkProxy::Socks5Proxy, QtNetworkSettings::socksProxyServerName(), 1080);
|
||
|
|
||
|
udpSocket.setProxy(proxy);
|
||
|
|
||
|
QCOMPARE(udpSocket.protocol(), QAbstractSocket::IPv4Protocol);
|
||
|
QCOMPARE(udpSocket.socketType(), QAbstractSocket::UdpSocket);
|
||
|
QCOMPARE(udpSocket.state(), QAbstractSocket::UnconnectedState);
|
||
|
|
||
|
// Bind #1
|
||
|
bool bindSuccessful = udpSocket.bind(QHostAddress("0.0.0.0"), 0);
|
||
|
if (!bindSuccessful)
|
||
|
QEXPECT_FAIL("", "QTBUG-23380 / QTBUG-35490: Fails on some Ubuntu 11.10 x64 configurations and on new network test server", Abort);
|
||
|
QVERIFY(bindSuccessful);
|
||
|
QCOMPARE(udpSocket.state(), QAbstractSocket::BoundState);
|
||
|
QVERIFY(udpSocket.localPort() != 0);
|
||
|
|
||
|
// Initialize device #2
|
||
|
QSocks5SocketEngine udpSocket2;
|
||
|
QVERIFY(udpSocket2.initialize(QAbstractSocket::UdpSocket));
|
||
|
|
||
|
udpSocket2.setProxy(proxy);
|
||
|
|
||
|
// Connect device #2 to #1
|
||
|
QVERIFY(udpSocket2.connectToHost(udpSocket.localAddress(), udpSocket.localPort()));
|
||
|
QCOMPARE(udpSocket2.state(), QAbstractSocket::ConnectedState);
|
||
|
|
||
|
// Write a message to #1
|
||
|
QByteArray message1 = "hei der";
|
||
|
QVERIFY(udpSocket2.write(message1.data(),
|
||
|
message1.size()) == message1.size());
|
||
|
|
||
|
// Read the message from #2
|
||
|
QVERIFY(udpSocket.waitForRead());
|
||
|
QVERIFY(udpSocket.hasPendingDatagrams());
|
||
|
qint64 available = udpSocket.pendingDatagramSize();
|
||
|
QVERIFY(available > 0);
|
||
|
QByteArray answer;
|
||
|
answer.resize(available);
|
||
|
QIpPacketHeader header;
|
||
|
QCOMPARE(udpSocket.readDatagram(answer.data(), answer.size(),
|
||
|
&header, QAbstractSocketEngine::WantDatagramSender),
|
||
|
qint64(message1.size()));
|
||
|
QVERIFY(header.senderAddress == udpSocket2.localAddress());
|
||
|
QCOMPARE(header.senderAddress, udpSocket2.localAddress());
|
||
|
QCOMPARE(header.senderPort, udpSocket2.localPort());
|
||
|
}
|
||
|
|
||
|
void tst_QSocks5SocketEngine::tcpSocketBlockingTest()
|
||
|
{
|
||
|
QSocks5SocketEngineHandler socks5;
|
||
|
|
||
|
QTcpSocket socket;
|
||
|
|
||
|
// Connect
|
||
|
socket.connectToHost(QtNetworkSettings::imapServerName(), 143);
|
||
|
QVERIFY(socket.waitForConnected());
|
||
|
QCOMPARE(socket.state(), QTcpSocket::ConnectedState);
|
||
|
|
||
|
// Read greeting
|
||
|
QVERIFY(socket.waitForReadyRead(5000));
|
||
|
QByteArray s = socket.readLine();
|
||
|
QVERIFY2(QtNetworkSettings::compareReplyIMAP(s), s.constData());
|
||
|
|
||
|
// Write NOOP
|
||
|
QCOMPARE((int) socket.write("1 NOOP\r\n", 8), 8);
|
||
|
|
||
|
if (!socket.canReadLine())
|
||
|
QVERIFY(socket.waitForReadyRead(5000));
|
||
|
|
||
|
// Read response
|
||
|
s = socket.readLine();
|
||
|
QCOMPARE(s, QByteArrayLiteral("1 OK Completed\r\n"));
|
||
|
|
||
|
// Write LOGOUT
|
||
|
QCOMPARE((int) socket.write("2 LOGOUT\r\n", 10), 10);
|
||
|
|
||
|
if (!socket.canReadLine())
|
||
|
QVERIFY(socket.waitForReadyRead(5000));
|
||
|
|
||
|
// Read two lines of respose
|
||
|
s = socket.readLine();
|
||
|
QCOMPARE(s, QByteArrayLiteral("* BYE LOGOUT received\r\n"));
|
||
|
|
||
|
if (!socket.canReadLine())
|
||
|
QVERIFY(socket.waitForReadyRead(5000));
|
||
|
|
||
|
s = socket.readLine();
|
||
|
QCOMPARE(s, QByteArrayLiteral("2 OK Completed\r\n"));
|
||
|
|
||
|
// Close the socket
|
||
|
socket.close();
|
||
|
|
||
|
// Check that it's closed
|
||
|
QCOMPARE(socket.state(), QTcpSocket::UnconnectedState);
|
||
|
}
|
||
|
|
||
|
//----------------------------------------------------------------------------------
|
||
|
|
||
|
void tst_QSocks5SocketEngine::tcpSocketNonBlockingTest()
|
||
|
{
|
||
|
QSocks5SocketEngineHandler socks5;
|
||
|
|
||
|
qint64 tcpSocketNonBlocking_totalWritten = 0;
|
||
|
QStringList tcpSocketNonBlocking_data;
|
||
|
QTcpSocket socket;
|
||
|
connect(&socket, &QAbstractSocket::hostFound,
|
||
|
&QTestEventLoop::instance(), &QTestEventLoop::exitLoop);
|
||
|
connect(&socket, &QAbstractSocket::connected,
|
||
|
&QTestEventLoop::instance(), &QTestEventLoop::exitLoop);
|
||
|
connect(&socket, &QIODevice::bytesWritten,
|
||
|
[&tcpSocketNonBlocking_totalWritten] (qint64 written)
|
||
|
{
|
||
|
tcpSocketNonBlocking_totalWritten += written;
|
||
|
QTestEventLoop::instance().exitLoop();
|
||
|
});
|
||
|
|
||
|
connect(&socket, &QIODevice::readyRead,
|
||
|
[&tcpSocketNonBlocking_data, &socket] ()
|
||
|
{
|
||
|
while (socket.canReadLine())
|
||
|
tcpSocketNonBlocking_data.append(socket.readLine());
|
||
|
QTestEventLoop::instance().exitLoop();
|
||
|
});
|
||
|
|
||
|
// Connect
|
||
|
socket.connectToHost(QtNetworkSettings::imapServerName(), 143);
|
||
|
QVERIFY(socket.state() == QTcpSocket::HostLookupState ||
|
||
|
socket.state() == QTcpSocket::ConnectingState);
|
||
|
|
||
|
QTestEventLoop::instance().enterLoop(30);
|
||
|
if (QTestEventLoop::instance().timeout()) {
|
||
|
QFAIL("Timed out");
|
||
|
}
|
||
|
|
||
|
if (socket.state() == QTcpSocket::ConnectingState) {
|
||
|
QTestEventLoop::instance().enterLoop(30);
|
||
|
if (QTestEventLoop::instance().timeout()) {
|
||
|
QFAIL("Timed out");
|
||
|
}
|
||
|
}
|
||
|
|
||
|
QCOMPARE(socket.state(), QTcpSocket::ConnectedState);
|
||
|
|
||
|
QTestEventLoop::instance().enterLoop(30);
|
||
|
if (QTestEventLoop::instance().timeout()) {
|
||
|
QFAIL("Timed out");
|
||
|
}
|
||
|
|
||
|
// Read greeting
|
||
|
QVERIFY(!tcpSocketNonBlocking_data.isEmpty());
|
||
|
QByteArray data = tcpSocketNonBlocking_data.at(0).toLatin1();
|
||
|
QVERIFY2(QtNetworkSettings::compareReplyIMAP(data), data.constData());
|
||
|
|
||
|
tcpSocketNonBlocking_data.clear();
|
||
|
|
||
|
tcpSocketNonBlocking_totalWritten = 0;
|
||
|
|
||
|
// Write NOOP
|
||
|
QCOMPARE((int) socket.write("1 NOOP\r\n", 8), 8);
|
||
|
|
||
|
|
||
|
QTestEventLoop::instance().enterLoop(30);
|
||
|
if (QTestEventLoop::instance().timeout()) {
|
||
|
QFAIL("Timed out");
|
||
|
}
|
||
|
|
||
|
QCOMPARE(tcpSocketNonBlocking_totalWritten, 8);
|
||
|
|
||
|
|
||
|
QTestEventLoop::instance().enterLoop(30);
|
||
|
if (QTestEventLoop::instance().timeout()) {
|
||
|
QFAIL("Timed out");
|
||
|
}
|
||
|
|
||
|
// Read response
|
||
|
QVERIFY(!tcpSocketNonBlocking_data.isEmpty());
|
||
|
QCOMPARE(tcpSocketNonBlocking_data.at(0), QLatin1String("1 OK Completed\r\n"));
|
||
|
tcpSocketNonBlocking_data.clear();
|
||
|
|
||
|
|
||
|
tcpSocketNonBlocking_totalWritten = 0;
|
||
|
|
||
|
// Write LOGOUT
|
||
|
QCOMPARE((int) socket.write("2 LOGOUT\r\n", 10), 10);
|
||
|
|
||
|
QTestEventLoop::instance().enterLoop(30);
|
||
|
if (QTestEventLoop::instance().timeout()) {
|
||
|
QFAIL("Timed out");
|
||
|
}
|
||
|
|
||
|
QCOMPARE(tcpSocketNonBlocking_totalWritten, 10);
|
||
|
|
||
|
// Wait for greeting
|
||
|
QTestEventLoop::instance().enterLoop(30);
|
||
|
if (QTestEventLoop::instance().timeout()) {
|
||
|
QFAIL("Timed out");
|
||
|
}
|
||
|
|
||
|
// Read two lines of respose
|
||
|
QCOMPARE(tcpSocketNonBlocking_data.at(0).toLatin1().constData(), "* BYE LOGOUT received\r\n");
|
||
|
QCOMPARE(tcpSocketNonBlocking_data.at(1).toLatin1().constData(), "2 OK Completed\r\n");
|
||
|
tcpSocketNonBlocking_data.clear();
|
||
|
|
||
|
// Close the socket
|
||
|
socket.close();
|
||
|
|
||
|
// Check that it's closed
|
||
|
QCOMPARE(socket.state(), QTcpSocket::UnconnectedState);
|
||
|
}
|
||
|
|
||
|
//----------------------------------------------------------------------------------
|
||
|
|
||
|
void tst_QSocks5SocketEngine::downloadBigFile()
|
||
|
{
|
||
|
QSocks5SocketEngineHandler socks5;
|
||
|
|
||
|
QTcpSocket socket;
|
||
|
qint64 bytesAvailable = 0;
|
||
|
|
||
|
QElapsedTimer stopWatch;
|
||
|
stopWatch.start();
|
||
|
|
||
|
connect(&socket, &QAbstractSocket::connected,
|
||
|
&QTestEventLoop::instance(), &QTestEventLoop::exitLoop);
|
||
|
connect(&socket, &QIODevice::readyRead,
|
||
|
[&socket, &bytesAvailable] ()
|
||
|
{
|
||
|
const QByteArray tmp = socket.readAll();
|
||
|
int correction = tmp.indexOf(char(0), 0); //skip header
|
||
|
if (correction == -1)
|
||
|
correction = 0;
|
||
|
bytesAvailable += (tmp.size() - correction);
|
||
|
if (bytesAvailable >= 10000000)
|
||
|
QTestEventLoop::instance().exitLoop();
|
||
|
});
|
||
|
|
||
|
connect(&socket, &QAbstractSocket::errorOccurred,
|
||
|
[&socket, &stopWatch] (QAbstractSocket::SocketError errorCode)
|
||
|
{
|
||
|
qWarning().noquote().nospace() << QTest::currentTestFunction()
|
||
|
<< ": error " << errorCode << ": " << socket.errorString()
|
||
|
<< " (" << stopWatch.elapsed() << "ms)";
|
||
|
});
|
||
|
|
||
|
socket.connectToHost(QtNetworkSettings::httpServerName(), 80);
|
||
|
|
||
|
QTestEventLoop::instance().enterLoop(30);
|
||
|
if (QTestEventLoop::instance().timeout())
|
||
|
QFAIL("Network operation timed out");
|
||
|
|
||
|
QByteArray hostName = QtNetworkSettings::httpServerName().toLatin1();
|
||
|
QCOMPARE(socket.state(), QAbstractSocket::ConnectedState);
|
||
|
QVERIFY(socket.write("GET /qtest/mediumfile HTTP/1.0\r\n") > 0);
|
||
|
QVERIFY(socket.write("HOST: ") > 0);
|
||
|
QVERIFY(socket.write(hostName.data()) > 0);
|
||
|
QVERIFY(socket.write("\r\n") > 0);
|
||
|
QVERIFY(socket.write("\r\n") > 0);
|
||
|
|
||
|
stopWatch.restart();
|
||
|
QTestEventLoop::instance().enterLoop(60);
|
||
|
if (QTestEventLoop::instance().timeout())
|
||
|
QFAIL("Network operation timed out");
|
||
|
|
||
|
QCOMPARE(bytesAvailable, qint64(10000000));
|
||
|
|
||
|
QCOMPARE(socket.state(), QAbstractSocket::ConnectedState);
|
||
|
|
||
|
/*qDebug("\t\t%.1fMB/%.1fs: %.1fMB/s",
|
||
|
bytesAvailable / (1024.0 * 1024.0),
|
||
|
stopWatch.elapsed() / 1024.0,
|
||
|
(bytesAvailable / (stopWatch.elapsed() / 1000.0)) / (1024 * 1024));*/
|
||
|
}
|
||
|
|
||
|
void tst_QSocks5SocketEngine::passwordAuth()
|
||
|
{
|
||
|
QSocks5SocketEngine socketDevice;
|
||
|
|
||
|
// Initialize device
|
||
|
QVERIFY(socketDevice.initialize(QAbstractSocket::TcpSocket, QAbstractSocket::IPv4Protocol));
|
||
|
QCOMPARE(socketDevice.state(), QAbstractSocket::UnconnectedState);
|
||
|
|
||
|
socketDevice.setProxy(QNetworkProxy(QNetworkProxy::Socks5Proxy, QtNetworkSettings::socksProxyServerName(), 1080, "qsockstest", "password"));
|
||
|
|
||
|
// Connect to imap.trolltech.com's IP
|
||
|
QVERIFY(!socketDevice.connectToHost(QtNetworkSettings::imapServerIp(), 143));
|
||
|
QCOMPARE(socketDevice.state(), QAbstractSocket::ConnectingState);
|
||
|
QVERIFY(socketDevice.waitForWrite());
|
||
|
if (!socketDevice.connectToHost(QtNetworkSettings::imapServerIp(), 143)) {
|
||
|
qDebug("%d, %s", socketDevice.error(), socketDevice.errorString().toLatin1().constData());
|
||
|
}
|
||
|
QCOMPARE(socketDevice.state(), QAbstractSocket::ConnectedState);
|
||
|
QCOMPARE(socketDevice.peerAddress(), QtNetworkSettings::serverIP());
|
||
|
|
||
|
// Wait for the greeting
|
||
|
QVERIFY(socketDevice.waitForRead());
|
||
|
|
||
|
// Read the greeting
|
||
|
qint64 available = socketDevice.bytesAvailable();
|
||
|
QVERIFY(available > 0);
|
||
|
QByteArray array;
|
||
|
array.resize(available);
|
||
|
QVERIFY(socketDevice.read(array.data(), array.size()) == available);
|
||
|
|
||
|
// Check that the greeting is what we expect it to be
|
||
|
QVERIFY2(QtNetworkSettings::compareReplyIMAP(array), array.constData());
|
||
|
|
||
|
// Write a logout message
|
||
|
QByteArray array2 = "XXXX LOGOUT\r\n";
|
||
|
QVERIFY(socketDevice.write(array2.data(),
|
||
|
array2.size()) == array2.size());
|
||
|
|
||
|
// Wait for the response
|
||
|
QVERIFY(socketDevice.waitForRead());
|
||
|
|
||
|
available = socketDevice.bytesAvailable();
|
||
|
QVERIFY(available > 0);
|
||
|
array.resize(available);
|
||
|
QVERIFY(socketDevice.read(array.data(), array.size()) == available);
|
||
|
|
||
|
// Check that the greeting is what we expect it to be
|
||
|
QCOMPARE(array.constData(), "* BYE LOGOUT received\r\nXXXX OK Completed\r\n");
|
||
|
|
||
|
// Wait for the response
|
||
|
QVERIFY(socketDevice.waitForRead());
|
||
|
char c;
|
||
|
QVERIFY(socketDevice.read(&c, sizeof(c)) == -1);
|
||
|
QCOMPARE(socketDevice.error(), QAbstractSocket::RemoteHostClosedError);
|
||
|
QCOMPARE(socketDevice.state(), QAbstractSocket::UnconnectedState);
|
||
|
}
|
||
|
|
||
|
//----------------------------------------------------------------------------------
|
||
|
|
||
|
void tst_QSocks5SocketEngine::proxyAuthenticationRequired(const QNetworkProxy &,
|
||
|
QAuthenticator *auth)
|
||
|
{
|
||
|
auth->setUser("qsockstest");
|
||
|
auth->setPassword("password");
|
||
|
}
|
||
|
|
||
|
void tst_QSocks5SocketEngine::passwordAuth2()
|
||
|
{
|
||
|
QSocks5SocketEngine socketDevice;
|
||
|
|
||
|
// Initialize device
|
||
|
QVERIFY(socketDevice.initialize(QAbstractSocket::TcpSocket, QAbstractSocket::IPv4Protocol));
|
||
|
QCOMPARE(socketDevice.state(), QAbstractSocket::UnconnectedState);
|
||
|
|
||
|
socketDevice.setProxy(QNetworkProxy(QNetworkProxy::Socks5Proxy, QtNetworkSettings::socksProxyServerName(), 1081));
|
||
|
socketDevice.setReceiver(this);
|
||
|
|
||
|
QVERIFY(!socketDevice.connectToHost(QtNetworkSettings::imapServerIp(), 143));
|
||
|
QCOMPARE(socketDevice.state(), QAbstractSocket::ConnectingState);
|
||
|
while (socketDevice.state() == QAbstractSocket::ConnectingState) {
|
||
|
QVERIFY(socketDevice.waitForWrite());
|
||
|
socketDevice.connectToHost(QtNetworkSettings::imapServerIp(), 143);
|
||
|
}
|
||
|
if (socketDevice.state() != QAbstractSocket::ConnectedState)
|
||
|
qDebug("%d, %s", socketDevice.error(), socketDevice.errorString().toLatin1().constData());
|
||
|
QCOMPARE(socketDevice.state(), QAbstractSocket::ConnectedState);
|
||
|
QCOMPARE(socketDevice.peerAddress(), QtNetworkSettings::imapServerIp());
|
||
|
|
||
|
// Wait for the greeting
|
||
|
QVERIFY(socketDevice.waitForRead());
|
||
|
|
||
|
// Read the greeting
|
||
|
qint64 available = socketDevice.bytesAvailable();
|
||
|
QVERIFY(available > 0);
|
||
|
QByteArray array;
|
||
|
array.resize(available);
|
||
|
QVERIFY(socketDevice.read(array.data(), array.size()) == available);
|
||
|
|
||
|
// Check that the greeting is what we expect it to be
|
||
|
QVERIFY2(QtNetworkSettings::compareReplyIMAP(array), array.constData());
|
||
|
|
||
|
// Write a logout message
|
||
|
QByteArray array2 = "XXXX LOGOUT\r\n";
|
||
|
QVERIFY(socketDevice.write(array2.data(),
|
||
|
array2.size()) == array2.size());
|
||
|
|
||
|
// Wait for the response
|
||
|
QVERIFY(socketDevice.waitForRead());
|
||
|
|
||
|
available = socketDevice.bytesAvailable();
|
||
|
QVERIFY(available > 0);
|
||
|
array.resize(available);
|
||
|
QVERIFY(socketDevice.read(array.data(), array.size()) == available);
|
||
|
|
||
|
// Check that the greeting is what we expect it to be
|
||
|
QCOMPARE(array.constData(), "* BYE LOGOUT received\r\nXXXX OK Completed\r\n");
|
||
|
|
||
|
// Wait for the response
|
||
|
QVERIFY(socketDevice.waitForRead());
|
||
|
char c;
|
||
|
QVERIFY(socketDevice.read(&c, sizeof(c)) == -1);
|
||
|
QCOMPARE(socketDevice.error(), QAbstractSocket::RemoteHostClosedError);
|
||
|
QCOMPARE(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.size() - 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.size() - 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"));
|
||
|
QCOMPARE(socket.localPort(), quint16(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.size() - 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.size() - 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(errorOccurred(QAbstractSocket::SocketError)),
|
||
|
&QTestEventLoop::instance(), SLOT(exitLoop()));
|
||
|
QTestEventLoop::instance().enterLoop(70);
|
||
|
QVERIFY(!QTestEventLoop::instance().timeout());
|
||
|
|
||
|
QCOMPARE(socket.error(), QAbstractSocket::ProxyConnectionClosedError);
|
||
|
}
|
||
|
|
||
|
//----------------------------------------------------------------------------------
|
||
|
|
||
|
QTEST_MAIN(tst_QSocks5SocketEngine)
|
||
|
#include "tst_qsocks5socketengine.moc"
|