1 | /**************************************************************************** |
2 | ** |
3 | ** Copyright (C) 2016 The Qt Company Ltd. |
4 | ** Contact: https://www.qt.io/licensing/ |
5 | ** |
6 | ** This file is part of the test suite of the Qt Toolkit. |
7 | ** |
8 | ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ |
9 | ** Commercial License Usage |
10 | ** Licensees holding valid commercial Qt licenses may use this file in |
11 | ** accordance with the commercial license agreement provided with the |
12 | ** Software or, alternatively, in accordance with the terms contained in |
13 | ** a written agreement between you and The Qt Company. For licensing terms |
14 | ** and conditions see https://www.qt.io/terms-conditions. For further |
15 | ** information use the contact form at https://www.qt.io/contact-us. |
16 | ** |
17 | ** GNU General Public License Usage |
18 | ** Alternatively, this file may be used under the terms of the GNU |
19 | ** General Public License version 3 as published by the Free Software |
20 | ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT |
21 | ** included in the packaging of this file. Please review the following |
22 | ** information to ensure the GNU General Public License requirements will |
23 | ** be met: https://www.gnu.org/licenses/gpl-3.0.html. |
24 | ** |
25 | ** $QT_END_LICENSE$ |
26 | ** |
27 | ****************************************************************************/ |
28 | |
29 | |
30 | #include <QtTest/QTest> |
31 | #include <QtTest/QTestEventLoop> |
32 | |
33 | #include <QtCore/QQueue> |
34 | #include <QtCore/QString> |
35 | #include <QtCore/QCoreApplication> |
36 | #include <QtCore/QMetaType> |
37 | #include <QtCore/QTimer> |
38 | |
39 | #include <private/qsocks5socketengine_p.h> |
40 | #include <qhostinfo.h> |
41 | #include <qhostaddress.h> |
42 | #include <qtcpsocket.h> |
43 | #include <qauthenticator.h> |
44 | #include <qdebug.h> |
45 | #include <qtcpserver.h> |
46 | #include <qmetatype.h> |
47 | #include <qdebug.h> |
48 | |
49 | #include "../../../network-settings.h" |
50 | |
51 | class tst_QSocks5SocketEngine : public QObject, public QAbstractSocketEngineReceiver |
52 | { |
53 | Q_OBJECT |
54 | |
55 | private slots: |
56 | void initTestCase(); |
57 | void construction(); |
58 | void errorTest_data(); |
59 | void errorTest(); |
60 | void simpleConnectToIMAP(); |
61 | void simpleErrorsAndStates(); |
62 | void udpTest(); |
63 | void serverTest(); |
64 | void tcpSocketBlockingTest(); |
65 | void tcpSocketNonBlockingTest(); |
66 | void downloadBigFile(); |
67 | // void tcpLoopbackPerformance(); |
68 | void passwordAuth(); |
69 | void passwordAuth2(); |
70 | void fragmentation_data(); |
71 | void fragmentation(); |
72 | void incomplete_data(); |
73 | void incomplete(); |
74 | |
75 | protected slots: |
76 | void proxyAuthenticationRequired(const QNetworkProxy &proxy, QAuthenticator *auth); |
77 | |
78 | private: |
79 | void readNotification() { } |
80 | void writeNotification() { } |
81 | void closeNotification() { } |
82 | void exceptionNotification() { } |
83 | void connectionNotification() { } |
84 | }; |
85 | |
86 | class MiniSocks5ResponseHandler : public QObject |
87 | { |
88 | Q_OBJECT |
89 | public: |
90 | QQueue<QByteArray> responses; |
91 | QTcpSocket *client; |
92 | |
93 | MiniSocks5ResponseHandler(QQueue<QByteArray> r, QTcpSocket *c, int autoResponseTime) |
94 | : responses(r), client(c) |
95 | { |
96 | client->setParent(this); |
97 | connect(asender: client, SIGNAL(disconnected()), SLOT(deleteLater())); |
98 | connect(asender: client, SIGNAL(readyRead()), SLOT(sendNextResponse())); |
99 | if (autoResponseTime) |
100 | QTimer::singleShot(msec: autoResponseTime, receiver: this, SLOT(sendNextResponse())); |
101 | } |
102 | |
103 | private slots: |
104 | void sendNextResponse() |
105 | { |
106 | // WARNING |
107 | // this assumes that the client command is received in its entirety |
108 | // should be ok, since SOCKSv5 commands are rather small |
109 | if (responses.isEmpty()) |
110 | client->disconnectFromHost(); |
111 | else |
112 | client->write(data: responses.dequeue()); |
113 | } |
114 | }; |
115 | |
116 | class MiniSocks5Server: public QTcpServer |
117 | { |
118 | Q_OBJECT |
119 | public: |
120 | QQueue<QByteArray> responses; |
121 | int autoResponseTime; |
122 | |
123 | MiniSocks5Server(const QQueue<QByteArray> r, int t = 0) |
124 | : responses(r), autoResponseTime(t) |
125 | { |
126 | listen(); |
127 | connect(asender: this, SIGNAL(newConnection()), SLOT(handleNewConnection())); |
128 | } |
129 | |
130 | private slots: |
131 | void handleNewConnection() |
132 | { |
133 | QTcpSocket *client = nextPendingConnection(); |
134 | new MiniSocks5ResponseHandler(responses, client, autoResponseTime); |
135 | } |
136 | }; |
137 | |
138 | void tst_QSocks5SocketEngine::initTestCase() |
139 | { |
140 | #ifdef QT_TEST_SERVER |
141 | QVERIFY(QtNetworkSettings::verifyConnection(QtNetworkSettings::socksProxyServerName(), 1080)); |
142 | QVERIFY(QtNetworkSettings::verifyConnection(QtNetworkSettings::httpServerName(), 80)); |
143 | QVERIFY(QtNetworkSettings::verifyConnection(QtNetworkSettings::imapServerName(), 143)); |
144 | #else |
145 | if (!QtNetworkSettings::verifyTestNetworkSettings()) |
146 | QSKIP("No network test server available" ); |
147 | #endif |
148 | } |
149 | |
150 | //--------------------------------------------------------------------------- |
151 | void tst_QSocks5SocketEngine::construction() |
152 | { |
153 | QSocks5SocketEngine socketDevice; |
154 | |
155 | QVERIFY(!socketDevice.isValid()); |
156 | |
157 | // Initialize device |
158 | QVERIFY(socketDevice.initialize(QAbstractSocket::TcpSocket, QAbstractSocket::IPv4Protocol)); |
159 | QVERIFY(socketDevice.isValid()); |
160 | QCOMPARE(socketDevice.protocol(), QAbstractSocket::IPv4Protocol); |
161 | QCOMPARE(socketDevice.socketType(), QAbstractSocket::TcpSocket); |
162 | QCOMPARE(socketDevice.state(), QAbstractSocket::UnconnectedState); |
163 | // QVERIFY(socketDevice.socketDescriptor() != -1); |
164 | QCOMPARE(socketDevice.localAddress(), QHostAddress()); |
165 | QCOMPARE(socketDevice.localPort(), quint16(0)); |
166 | QCOMPARE(socketDevice.peerAddress(), QHostAddress()); |
167 | QCOMPARE(socketDevice.peerPort(), quint16(0)); |
168 | QCOMPARE(socketDevice.error(), QAbstractSocket::UnknownSocketError); |
169 | |
170 | //QTest::ignoreMessage(QtWarningMsg, "QSocketLayer::bytesAvailable() was called in QAbstractSocket::UnconnectedState"); |
171 | QCOMPARE(socketDevice.bytesAvailable(), 0); |
172 | |
173 | //QTest::ignoreMessage(QtWarningMsg, "QSocketLayer::hasPendingDatagrams() was called in QAbstractSocket::UnconnectedState"); |
174 | QVERIFY(!socketDevice.hasPendingDatagrams()); |
175 | } |
176 | |
177 | //--------------------------------------------------------------------------- |
178 | void tst_QSocks5SocketEngine::errorTest_data() |
179 | { |
180 | QTest::addColumn<QString>(name: "hostname" ); |
181 | QTest::addColumn<int>(name: "port" ); |
182 | QTest::addColumn<QString>(name: "username" ); |
183 | QTest::addColumn<QQueue<QByteArray> >(name: "responses" ); |
184 | QTest::addColumn<int>(name: "expectedError" ); |
185 | |
186 | QQueue<QByteArray> responses; |
187 | QTest::newRow(dataTag: "proxy-host-not-found" ) << "this-host-does-not-exist." << 1080 << QString() |
188 | << responses |
189 | << int(QAbstractSocket::ProxyNotFoundError); |
190 | QTest::newRow(dataTag: "proxy-connection-refused" ) << "127.0.0.1" << 2 << QString() |
191 | << responses |
192 | << int(QAbstractSocket::ProxyConnectionRefusedError); |
193 | |
194 | #define REPLY(name, contents) \ |
195 | static const char raw_ ## name [] = contents; \ |
196 | const QByteArray name = QByteArray::fromRawData(raw_ ## name, sizeof raw_ ## name - 1) |
197 | |
198 | REPLY(garbage, "\4\4\4\4" ); |
199 | // authentication method replies |
200 | REPLY(noAuthentication, "\5\0" ); |
201 | REPLY(passwordAuthentication, "\5\2" ); |
202 | REPLY(garbageAuthentication, "\5\177" ); |
203 | REPLY(noAcceptableAuthentication, "\5\377" ); |
204 | // authentication replies |
205 | REPLY(authenticationAccepted, "\5\0" ); |
206 | REPLY(authenticationNotAccepted, "\5\1" ); |
207 | // connection replies |
208 | REPLY(connectionAccepted, "\5\0\0\4\177\0\0\1\0\100" ); |
209 | REPLY(connectionNotAllowed, "\5\2\0" ); |
210 | REPLY(networkUnreachable, "\5\3\0" ); |
211 | REPLY(hostUnreachable, "\5\4\0" ); |
212 | REPLY(connectionRefused, "\5\5\0" ); |
213 | |
214 | #undef REPLY |
215 | |
216 | responses << garbage; |
217 | QTest::newRow(dataTag: "garbage1" ) << QString() << 0 << QString() << responses |
218 | << int(QAbstractSocket::ProxyProtocolError); |
219 | |
220 | responses.clear(); |
221 | responses << noAuthentication << garbage; |
222 | QTest::newRow(dataTag: "garbage2" ) << QString() << 0 << QString() << responses |
223 | << int(QAbstractSocket::ProxyProtocolError); |
224 | |
225 | responses.clear(); |
226 | responses << garbageAuthentication; |
227 | QTest::newRow(dataTag: "unknown-auth-method" ) << QString() << 0 << QString() |
228 | << responses |
229 | << int(QAbstractSocket::SocketAccessError); |
230 | |
231 | responses.clear(); |
232 | responses << noAcceptableAuthentication; |
233 | QTest::newRow(dataTag: "no-acceptable-authentication" ) << QString() << 0 << QString() |
234 | << responses |
235 | << int(QAbstractSocket::ProxyAuthenticationRequiredError); |
236 | |
237 | responses.clear(); |
238 | responses << passwordAuthentication << authenticationNotAccepted; |
239 | QTest::newRow(dataTag: "authentication-required" ) << QString() << 0 << "foo" |
240 | << responses |
241 | << int(QAbstractSocket::ProxyAuthenticationRequiredError); |
242 | |
243 | responses.clear(); |
244 | responses << noAuthentication << connectionNotAllowed; |
245 | QTest::newRow(dataTag: "connection-not-allowed" ) << QString() << 0 << QString() |
246 | << responses |
247 | << int(QAbstractSocket::SocketAccessError); |
248 | |
249 | responses.clear(); |
250 | responses << noAuthentication << networkUnreachable; |
251 | QTest::newRow(dataTag: "network-unreachable" ) << QString() << 0 << QString() |
252 | << responses |
253 | << int(QAbstractSocket::NetworkError); |
254 | |
255 | responses.clear(); |
256 | responses << noAuthentication << hostUnreachable; |
257 | QTest::newRow(dataTag: "host-unreachable" ) << QString() << 0 << QString() |
258 | << responses |
259 | << int(QAbstractSocket::HostNotFoundError); |
260 | |
261 | responses.clear(); |
262 | responses << noAuthentication << connectionRefused; |
263 | QTest::newRow(dataTag: "connection-refused" ) << QString() << 0 << QString() |
264 | << responses |
265 | << int(QAbstractSocket::ConnectionRefusedError); |
266 | } |
267 | |
268 | void tst_QSocks5SocketEngine::errorTest() |
269 | { |
270 | QFETCH(QString, hostname); |
271 | QFETCH(int, port); |
272 | QFETCH(QString, username); |
273 | QFETCH(QQueue<QByteArray>, responses); |
274 | QFETCH(int, expectedError); |
275 | |
276 | MiniSocks5Server server(responses); |
277 | |
278 | if (hostname.isEmpty()) { |
279 | hostname = "127.0.0.1" ; |
280 | port = server.serverPort(); |
281 | } |
282 | QTcpSocket socket; |
283 | socket.setProxy(QNetworkProxy(QNetworkProxy::Socks5Proxy, hostname, port, username, username)); |
284 | socket.connectToHost(hostName: "0.1.2.3" , port: 12345); |
285 | |
286 | connect(sender: &socket, SIGNAL(errorOccurred(QAbstractSocket::SocketError)), |
287 | receiver: &QTestEventLoop::instance(), SLOT(exitLoop())); |
288 | QTestEventLoop::instance().enterLoop(secs: 10); |
289 | QVERIFY(!QTestEventLoop::instance().timeout()); |
290 | |
291 | QCOMPARE(int(socket.error()), expectedError); |
292 | } |
293 | |
294 | //--------------------------------------------------------------------------- |
295 | void tst_QSocks5SocketEngine::simpleConnectToIMAP() |
296 | { |
297 | QSocks5SocketEngine socketDevice; |
298 | |
299 | // Initialize device |
300 | QVERIFY(socketDevice.initialize(QAbstractSocket::TcpSocket, QAbstractSocket::IPv4Protocol)); |
301 | QCOMPARE(socketDevice.state(), QAbstractSocket::UnconnectedState); |
302 | |
303 | socketDevice.setProxy(QNetworkProxy(QNetworkProxy::Socks5Proxy, QtNetworkSettings::socksProxyServerName(), 1080)); |
304 | |
305 | QVERIFY(!socketDevice.connectToHost(QtNetworkSettings::imapServerIp(), 143)); |
306 | QCOMPARE(socketDevice.state(), QAbstractSocket::ConnectingState); |
307 | QVERIFY(socketDevice.waitForWrite()); |
308 | QCOMPARE(socketDevice.state(), QAbstractSocket::ConnectedState); |
309 | QCOMPARE(socketDevice.peerAddress(), QtNetworkSettings::imapServerIp()); |
310 | |
311 | // Wait for the greeting |
312 | QVERIFY2(socketDevice.waitForRead(), qPrintable("Socket error:" + socketDevice.errorString())); |
313 | |
314 | // Read the greeting |
315 | qint64 available = socketDevice.bytesAvailable(); |
316 | QVERIFY(available > 0); |
317 | QByteArray array; |
318 | array.resize(size: available); |
319 | QVERIFY(socketDevice.read(array.data(), array.size()) == available); |
320 | |
321 | // Check that the greeting is what we expect it to be |
322 | QVERIFY2(QtNetworkSettings::compareReplyIMAP(array), array.constData()); |
323 | |
324 | // Write a logout message |
325 | QByteArray array2 = "XXXX LOGOUT\r\n" ; |
326 | QVERIFY(socketDevice.write(array2.data(), |
327 | array2.size()) == array2.size()); |
328 | |
329 | // Wait for the response |
330 | QVERIFY(socketDevice.waitForRead()); |
331 | |
332 | available = socketDevice.bytesAvailable(); |
333 | QVERIFY(available > 0); |
334 | array.resize(size: available); |
335 | QVERIFY(socketDevice.read(array.data(), array.size()) == available); |
336 | |
337 | // Check that the greeting is what we expect it to be |
338 | QCOMPARE(array.constData(), "* BYE LOGOUT received\r\nXXXX OK Completed\r\n" ); |
339 | |
340 | // Wait for the response |
341 | QVERIFY(socketDevice.waitForRead()); |
342 | char c; |
343 | QVERIFY(socketDevice.read(&c, sizeof(c)) == -1); |
344 | QCOMPARE(socketDevice.error(), QAbstractSocket::RemoteHostClosedError); |
345 | QCOMPARE(socketDevice.state(), QAbstractSocket::UnconnectedState); |
346 | } |
347 | |
348 | //--------------------------------------------------------------------------- |
349 | void tst_QSocks5SocketEngine::simpleErrorsAndStates() |
350 | { |
351 | { |
352 | QSocks5SocketEngine socketDevice; |
353 | |
354 | // Initialize device |
355 | QVERIFY(socketDevice.initialize(QAbstractSocket::TcpSocket, QAbstractSocket::IPv4Protocol)); |
356 | |
357 | socketDevice.setProxy(QNetworkProxy(QNetworkProxy::Socks5Proxy, QtNetworkSettings::socksProxyServerName(), 1080)); |
358 | |
359 | QCOMPARE(socketDevice.state(), QAbstractSocket::UnconnectedState); |
360 | QVERIFY(!socketDevice.connectToHost(QHostInfo::fromName(QtNetworkSettings::socksProxyServerName()).addresses().first(), 8088)); |
361 | QCOMPARE(socketDevice.state(), QAbstractSocket::ConnectingState); |
362 | if (socketDevice.waitForWrite(msecs: 15000)) { |
363 | QVERIFY(socketDevice.state() == QAbstractSocket::UnconnectedState || |
364 | socketDevice.state() == QAbstractSocket::ConnectedState); |
365 | } else { |
366 | QCOMPARE(socketDevice.error(), QAbstractSocket::SocketTimeoutError); |
367 | } |
368 | } |
369 | |
370 | } |
371 | |
372 | /* |
373 | //--------------------------------------------------------------------------- |
374 | void tst_QSocks5SocketEngine::tcpLoopbackPerformance() |
375 | { |
376 | QTcpServer server; |
377 | |
378 | // Bind to any port on all interfaces |
379 | QVERIFY(server.bind(QHostAddress("0.0.0.0"), 0)); |
380 | QCOMPARE(server.state(), QAbstractSocket::BoundState); |
381 | quint16 port = server.localPort(); |
382 | |
383 | // Listen for incoming connections |
384 | QVERIFY(server.listen()); |
385 | QCOMPARE(server.state(), QAbstractSocket::ListeningState); |
386 | |
387 | // Initialize a Tcp socket |
388 | QSocks5SocketEngine client; |
389 | QVERIFY(client.initialize(QAbstractSocket::TcpSocket)); |
390 | |
391 | client.setProxy(QHostAddress("80.232.37.158"), 1081); |
392 | |
393 | // Connect to our server |
394 | if (!client.connectToHost(QHostAddress("127.0.0.1"), port)) { |
395 | QVERIFY(client.waitForWrite()); |
396 | QVERIFY(client.connectToHost(QHostAddress("127.0.0.1"), port)); |
397 | } |
398 | |
399 | // The server accepts the connectio |
400 | int socketDescriptor = server.accept(); |
401 | QVERIFY(socketDescriptor > 0); |
402 | |
403 | // A socket device is initialized on the server side, passing the |
404 | // socket descriptor from accept(). It's pre-connected. |
405 | QSocketLayer serverSocket; |
406 | QVERIFY(serverSocket.initialize(socketDescriptor)); |
407 | QCOMPARE(serverSocket.state(), QAbstractSocket::ConnectedState); |
408 | |
409 | const int messageSize = 1024 * 256; |
410 | QByteArray message1(messageSize, '@'); |
411 | QByteArray answer(messageSize, '@'); |
412 | |
413 | QTime timer; |
414 | timer.start(); |
415 | qlonglong readBytes = 0; |
416 | while (timer.elapsed() < 5000) { |
417 | qlonglong written = serverSocket.write(message1.data(), message1.size()); |
418 | while (written > 0) { |
419 | client.waitForRead(); |
420 | if (client.bytesAvailable() > 0) { |
421 | qlonglong readNow = client.read(answer.data(), answer.size()); |
422 | written -= readNow; |
423 | readBytes += readNow; |
424 | } |
425 | } |
426 | } |
427 | |
428 | qDebug("\t\t%.1fMB/%.1fs: %.1fMB/s", |
429 | readBytes / (1024.0 * 1024.0), |
430 | timer.elapsed() / 1024.0, |
431 | (readBytes / (timer.elapsed() / 1000.0)) / (1024 * 1024)); |
432 | } |
433 | */ |
434 | |
435 | //--------------------------------------------------------------------------- |
436 | void tst_QSocks5SocketEngine::serverTest() |
437 | { |
438 | QSocks5SocketEngine server; |
439 | |
440 | // Initialize a Tcp socket |
441 | QVERIFY(server.initialize(QAbstractSocket::TcpSocket)); |
442 | |
443 | QNetworkProxy proxy(QNetworkProxy::Socks5Proxy, QtNetworkSettings::socksProxyServerName(), 1080); |
444 | |
445 | server.setProxy(proxy); |
446 | |
447 | // Bind to any port on all interfaces |
448 | QVERIFY(server.bind(QHostAddress("0.0.0.0" ), 0)); |
449 | QCOMPARE(server.state(), QAbstractSocket::BoundState); |
450 | |
451 | // Listen for incoming connections |
452 | QVERIFY(server.listen()); |
453 | QCOMPARE(server.state(), QAbstractSocket::ListeningState); |
454 | |
455 | // Initialize a Tcp socket |
456 | QSocks5SocketEngine client; |
457 | QVERIFY(client.initialize(QAbstractSocket::TcpSocket)); |
458 | |
459 | client.setProxy(proxy); |
460 | |
461 | // QTest::wait(100000); // ### timing problem on win32 |
462 | |
463 | |
464 | // Connect to our server |
465 | if (!client.connectToHost(address: server.localAddress(), port: server.localPort())) { |
466 | QVERIFY(client.waitForWrite()); |
467 | // QTest::wait(100); // ### timing problem on win32 |
468 | QCOMPARE(client.state(), QAbstractSocket::ConnectedState); |
469 | //QTest::wait(100); |
470 | } |
471 | |
472 | QVERIFY(server.waitForRead()); |
473 | |
474 | // The server accepts the connection |
475 | int socketDescriptor = server.accept(); |
476 | QVERIFY(socketDescriptor > 0); |
477 | |
478 | // A socket device is initialized on the server side, passing the |
479 | // socket descriptor from accept(). It's pre-connected. |
480 | |
481 | QSocks5SocketEngine serverSocket; |
482 | QVERIFY(serverSocket.initialize(socketDescriptor)); |
483 | QCOMPARE(serverSocket.state(), QAbstractSocket::ConnectedState); |
484 | |
485 | QCOMPARE(serverSocket.localAddress(), client.peerAddress()); |
486 | QCOMPARE(serverSocket.localPort(), client.peerPort()); |
487 | // this seems depends on the socks server implementation, especially |
488 | // when connecting /to/ the socks server /through/ the same socks server |
489 | //QCOMPARE(serverSocket.peerAddress(), client.localAddress()); |
490 | //QCOMPARE(serverSocket.peerPort(), client.localPort()); |
491 | |
492 | // The server socket sends a greeting to the client |
493 | QByteArray greeting = "Greetings!" ; |
494 | QVERIFY(serverSocket.write(greeting.data(), |
495 | greeting.size()) == greeting.size()); |
496 | |
497 | // The client waits for the greeting to arrive |
498 | QVERIFY(client.waitForRead()); |
499 | qint64 available = client.bytesAvailable(); |
500 | QVERIFY(available > 0); |
501 | |
502 | // The client reads the greeting and checks that it's correct |
503 | QByteArray response; |
504 | response.resize(size: available); |
505 | QVERIFY(client.read(response.data(), |
506 | response.size()) == response.size()); |
507 | QCOMPARE(response, greeting); |
508 | } |
509 | |
510 | |
511 | //--------------------------------------------------------------------------- |
512 | void tst_QSocks5SocketEngine::udpTest() |
513 | { |
514 | QSocks5SocketEngine udpSocket; |
515 | |
516 | // Initialize device #1 |
517 | QVERIFY(udpSocket.initialize(QAbstractSocket::UdpSocket)); |
518 | QVERIFY(udpSocket.isValid()); |
519 | |
520 | QNetworkProxy proxy(QNetworkProxy::Socks5Proxy, QtNetworkSettings::socksProxyServerName(), 1080); |
521 | |
522 | udpSocket.setProxy(proxy); |
523 | |
524 | QCOMPARE(udpSocket.protocol(), QAbstractSocket::IPv4Protocol); |
525 | QCOMPARE(udpSocket.socketType(), QAbstractSocket::UdpSocket); |
526 | QCOMPARE(udpSocket.state(), QAbstractSocket::UnconnectedState); |
527 | |
528 | // Bind #1 |
529 | bool bindSuccessful = udpSocket.bind(address: QHostAddress("0.0.0.0" ), port: 0); |
530 | if (!bindSuccessful) |
531 | QEXPECT_FAIL("" , "QTBUG-23380 / QTBUG-35490: Fails on some Ubuntu 11.10 x64 configurations and on new network test server" , Abort); |
532 | QVERIFY(bindSuccessful); |
533 | QCOMPARE(udpSocket.state(), QAbstractSocket::BoundState); |
534 | QVERIFY(udpSocket.localPort() != 0); |
535 | |
536 | // Initialize device #2 |
537 | QSocks5SocketEngine udpSocket2; |
538 | QVERIFY(udpSocket2.initialize(QAbstractSocket::UdpSocket)); |
539 | |
540 | udpSocket2.setProxy(proxy); |
541 | |
542 | // Connect device #2 to #1 |
543 | QVERIFY(udpSocket2.connectToHost(udpSocket.localAddress(), udpSocket.localPort())); |
544 | QCOMPARE(udpSocket2.state(), QAbstractSocket::ConnectedState); |
545 | |
546 | // Write a message to #1 |
547 | QByteArray message1 = "hei der" ; |
548 | QVERIFY(udpSocket2.write(message1.data(), |
549 | message1.size()) == message1.size()); |
550 | |
551 | // Read the message from #2 |
552 | QVERIFY(udpSocket.waitForRead()); |
553 | QVERIFY(udpSocket.hasPendingDatagrams()); |
554 | qint64 available = udpSocket.pendingDatagramSize(); |
555 | QVERIFY(available > 0); |
556 | QByteArray answer; |
557 | answer.resize(size: available); |
558 | QIpPacketHeader ; |
559 | QCOMPARE(udpSocket.readDatagram(answer.data(), answer.size(), |
560 | &header, QAbstractSocketEngine::WantDatagramSender), |
561 | qint64(message1.size())); |
562 | QVERIFY(header.senderAddress == udpSocket2.localAddress()); |
563 | QCOMPARE(header.senderAddress, udpSocket2.localAddress()); |
564 | QCOMPARE(header.senderPort, udpSocket2.localPort()); |
565 | } |
566 | |
567 | void tst_QSocks5SocketEngine::tcpSocketBlockingTest() |
568 | { |
569 | QSocks5SocketEngineHandler socks5; |
570 | |
571 | QTcpSocket socket; |
572 | |
573 | // Connect |
574 | socket.connectToHost(hostName: QtNetworkSettings::imapServerName(), port: 143); |
575 | QVERIFY(socket.waitForConnected()); |
576 | QCOMPARE(socket.state(), QTcpSocket::ConnectedState); |
577 | |
578 | // Read greeting |
579 | QVERIFY(socket.waitForReadyRead(5000)); |
580 | QByteArray s = socket.readLine(); |
581 | QVERIFY2(QtNetworkSettings::compareReplyIMAP(s), s.constData()); |
582 | |
583 | // Write NOOP |
584 | QCOMPARE((int) socket.write("1 NOOP\r\n" , 8), 8); |
585 | |
586 | if (!socket.canReadLine()) |
587 | QVERIFY(socket.waitForReadyRead(5000)); |
588 | |
589 | // Read response |
590 | s = socket.readLine(); |
591 | QCOMPARE(s, QByteArrayLiteral("1 OK Completed\r\n" )); |
592 | |
593 | // Write LOGOUT |
594 | QCOMPARE((int) socket.write("2 LOGOUT\r\n" , 10), 10); |
595 | |
596 | if (!socket.canReadLine()) |
597 | QVERIFY(socket.waitForReadyRead(5000)); |
598 | |
599 | // Read two lines of respose |
600 | s = socket.readLine(); |
601 | QCOMPARE(s, QByteArrayLiteral("* BYE LOGOUT received\r\n" )); |
602 | |
603 | if (!socket.canReadLine()) |
604 | QVERIFY(socket.waitForReadyRead(5000)); |
605 | |
606 | s = socket.readLine(); |
607 | QCOMPARE(s, QByteArrayLiteral("2 OK Completed\r\n" )); |
608 | |
609 | // Close the socket |
610 | socket.close(); |
611 | |
612 | // Check that it's closed |
613 | QCOMPARE(socket.state(), QTcpSocket::UnconnectedState); |
614 | } |
615 | |
616 | //---------------------------------------------------------------------------------- |
617 | |
618 | void tst_QSocks5SocketEngine::tcpSocketNonBlockingTest() |
619 | { |
620 | QSocks5SocketEngineHandler socks5; |
621 | |
622 | qint64 tcpSocketNonBlocking_totalWritten = 0; |
623 | QStringList tcpSocketNonBlocking_data; |
624 | QTcpSocket socket; |
625 | connect(sender: &socket, signal: &QAbstractSocket::hostFound, |
626 | receiver: &QTestEventLoop::instance(), slot: &QTestEventLoop::exitLoop); |
627 | connect(sender: &socket, signal: &QAbstractSocket::connected, |
628 | receiver: &QTestEventLoop::instance(), slot: &QTestEventLoop::exitLoop); |
629 | connect(sender: &socket, signal: &QIODevice::bytesWritten, |
630 | slot: [&tcpSocketNonBlocking_totalWritten] (qint64 written) |
631 | { |
632 | tcpSocketNonBlocking_totalWritten += written; |
633 | QTestEventLoop::instance().exitLoop(); |
634 | }); |
635 | |
636 | connect(sender: &socket, signal: &QIODevice::readyRead, |
637 | slot: [&tcpSocketNonBlocking_data, &socket] () |
638 | { |
639 | while (socket.canReadLine()) |
640 | tcpSocketNonBlocking_data.append(t: socket.readLine()); |
641 | QTestEventLoop::instance().exitLoop(); |
642 | }); |
643 | |
644 | // Connect |
645 | socket.connectToHost(hostName: QtNetworkSettings::imapServerName(), port: 143); |
646 | QVERIFY(socket.state() == QTcpSocket::HostLookupState || |
647 | socket.state() == QTcpSocket::ConnectingState); |
648 | |
649 | QTestEventLoop::instance().enterLoop(secs: 30); |
650 | if (QTestEventLoop::instance().timeout()) { |
651 | QFAIL("Timed out" ); |
652 | } |
653 | |
654 | if (socket.state() == QTcpSocket::ConnectingState) { |
655 | QTestEventLoop::instance().enterLoop(secs: 30); |
656 | if (QTestEventLoop::instance().timeout()) { |
657 | QFAIL("Timed out" ); |
658 | } |
659 | } |
660 | |
661 | QCOMPARE(socket.state(), QTcpSocket::ConnectedState); |
662 | |
663 | QTestEventLoop::instance().enterLoop(secs: 30); |
664 | if (QTestEventLoop::instance().timeout()) { |
665 | QFAIL("Timed out" ); |
666 | } |
667 | |
668 | // Read greeting |
669 | QVERIFY(!tcpSocketNonBlocking_data.isEmpty()); |
670 | QByteArray data = tcpSocketNonBlocking_data.at(i: 0).toLatin1(); |
671 | QVERIFY2(QtNetworkSettings::compareReplyIMAP(data), data.constData()); |
672 | |
673 | tcpSocketNonBlocking_data.clear(); |
674 | |
675 | tcpSocketNonBlocking_totalWritten = 0; |
676 | |
677 | // Write NOOP |
678 | QCOMPARE((int) socket.write("1 NOOP\r\n" , 8), 8); |
679 | |
680 | |
681 | QTestEventLoop::instance().enterLoop(secs: 30); |
682 | if (QTestEventLoop::instance().timeout()) { |
683 | QFAIL("Timed out" ); |
684 | } |
685 | |
686 | QCOMPARE(tcpSocketNonBlocking_totalWritten, 8); |
687 | |
688 | |
689 | QTestEventLoop::instance().enterLoop(secs: 30); |
690 | if (QTestEventLoop::instance().timeout()) { |
691 | QFAIL("Timed out" ); |
692 | } |
693 | |
694 | // Read response |
695 | QVERIFY(!tcpSocketNonBlocking_data.isEmpty()); |
696 | QCOMPARE(tcpSocketNonBlocking_data.at(0), QLatin1String("1 OK Completed\r\n" )); |
697 | tcpSocketNonBlocking_data.clear(); |
698 | |
699 | |
700 | tcpSocketNonBlocking_totalWritten = 0; |
701 | |
702 | // Write LOGOUT |
703 | QCOMPARE((int) socket.write("2 LOGOUT\r\n" , 10), 10); |
704 | |
705 | QTestEventLoop::instance().enterLoop(secs: 30); |
706 | if (QTestEventLoop::instance().timeout()) { |
707 | QFAIL("Timed out" ); |
708 | } |
709 | |
710 | QCOMPARE(tcpSocketNonBlocking_totalWritten, 10); |
711 | |
712 | // Wait for greeting |
713 | QTestEventLoop::instance().enterLoop(secs: 30); |
714 | if (QTestEventLoop::instance().timeout()) { |
715 | QFAIL("Timed out" ); |
716 | } |
717 | |
718 | // Read two lines of respose |
719 | QCOMPARE(tcpSocketNonBlocking_data.at(0).toLatin1().constData(), "* BYE LOGOUT received\r\n" ); |
720 | QCOMPARE(tcpSocketNonBlocking_data.at(1).toLatin1().constData(), "2 OK Completed\r\n" ); |
721 | tcpSocketNonBlocking_data.clear(); |
722 | |
723 | // Close the socket |
724 | socket.close(); |
725 | |
726 | // Check that it's closed |
727 | QCOMPARE(socket.state(), QTcpSocket::UnconnectedState); |
728 | } |
729 | |
730 | //---------------------------------------------------------------------------------- |
731 | |
732 | void tst_QSocks5SocketEngine::downloadBigFile() |
733 | { |
734 | QSocks5SocketEngineHandler socks5; |
735 | |
736 | QTcpSocket socket; |
737 | qint64 bytesAvailable = 0; |
738 | |
739 | QElapsedTimer stopWatch; |
740 | stopWatch.start(); |
741 | |
742 | connect(sender: &socket, signal: &QAbstractSocket::connected, |
743 | receiver: &QTestEventLoop::instance(), slot: &QTestEventLoop::exitLoop); |
744 | connect(sender: &socket, signal: &QIODevice::readyRead, |
745 | slot: [&socket, &bytesAvailable] () |
746 | { |
747 | const QByteArray tmp = socket.readAll(); |
748 | int correction = tmp.indexOf(c: char(0), from: 0); //skip header |
749 | if (correction == -1) |
750 | correction = 0; |
751 | bytesAvailable += (tmp.size() - correction); |
752 | if (bytesAvailable >= 10000000) |
753 | QTestEventLoop::instance().exitLoop(); |
754 | }); |
755 | |
756 | connect(sender: &socket, signal: &QAbstractSocket::errorOccurred, |
757 | slot: [&socket, &stopWatch] (QAbstractSocket::SocketError errorCode) |
758 | { |
759 | qWarning().noquote().nospace() << QTest::currentTestFunction() |
760 | << ": error " << errorCode << ": " << socket.errorString() |
761 | << " (" << stopWatch.elapsed() << "ms)" ; |
762 | }); |
763 | |
764 | socket.connectToHost(hostName: QtNetworkSettings::httpServerName(), port: 80); |
765 | |
766 | QTestEventLoop::instance().enterLoop(secs: 30); |
767 | if (QTestEventLoop::instance().timeout()) |
768 | QFAIL("Network operation timed out" ); |
769 | |
770 | QByteArray hostName = QtNetworkSettings::httpServerName().toLatin1(); |
771 | QCOMPARE(socket.state(), QAbstractSocket::ConnectedState); |
772 | QVERIFY(socket.write("GET /qtest/mediumfile HTTP/1.0\r\n" ) > 0); |
773 | QVERIFY(socket.write("HOST: " ) > 0); |
774 | QVERIFY(socket.write(hostName.data()) > 0); |
775 | QVERIFY(socket.write("\r\n" ) > 0); |
776 | QVERIFY(socket.write("\r\n" ) > 0); |
777 | |
778 | stopWatch.restart(); |
779 | QTestEventLoop::instance().enterLoop(secs: 60); |
780 | if (QTestEventLoop::instance().timeout()) |
781 | QFAIL("Network operation timed out" ); |
782 | |
783 | QCOMPARE(bytesAvailable, qint64(10000000)); |
784 | |
785 | QCOMPARE(socket.state(), QAbstractSocket::ConnectedState); |
786 | |
787 | /*qDebug("\t\t%.1fMB/%.1fs: %.1fMB/s", |
788 | bytesAvailable / (1024.0 * 1024.0), |
789 | stopWatch.elapsed() / 1024.0, |
790 | (bytesAvailable / (stopWatch.elapsed() / 1000.0)) / (1024 * 1024));*/ |
791 | } |
792 | |
793 | void tst_QSocks5SocketEngine::passwordAuth() |
794 | { |
795 | QSocks5SocketEngine socketDevice; |
796 | |
797 | // Initialize device |
798 | QVERIFY(socketDevice.initialize(QAbstractSocket::TcpSocket, QAbstractSocket::IPv4Protocol)); |
799 | QCOMPARE(socketDevice.state(), QAbstractSocket::UnconnectedState); |
800 | |
801 | socketDevice.setProxy(QNetworkProxy(QNetworkProxy::Socks5Proxy, QtNetworkSettings::socksProxyServerName(), 1080, "qsockstest" , "password" )); |
802 | |
803 | // Connect to imap.trolltech.com's IP |
804 | QVERIFY(!socketDevice.connectToHost(QtNetworkSettings::imapServerIp(), 143)); |
805 | QCOMPARE(socketDevice.state(), QAbstractSocket::ConnectingState); |
806 | QVERIFY(socketDevice.waitForWrite()); |
807 | if (!socketDevice.connectToHost(address: QtNetworkSettings::imapServerIp(), port: 143)) { |
808 | qDebug(msg: "%d, %s" , socketDevice.error(), socketDevice.errorString().toLatin1().constData()); |
809 | } |
810 | QCOMPARE(socketDevice.state(), QAbstractSocket::ConnectedState); |
811 | QCOMPARE(socketDevice.peerAddress(), QtNetworkSettings::serverIP()); |
812 | |
813 | // Wait for the greeting |
814 | QVERIFY(socketDevice.waitForRead()); |
815 | |
816 | // Read the greeting |
817 | qint64 available = socketDevice.bytesAvailable(); |
818 | QVERIFY(available > 0); |
819 | QByteArray array; |
820 | array.resize(size: available); |
821 | QVERIFY(socketDevice.read(array.data(), array.size()) == available); |
822 | |
823 | // Check that the greeting is what we expect it to be |
824 | QVERIFY2(QtNetworkSettings::compareReplyIMAP(array), array.constData()); |
825 | |
826 | // Write a logout message |
827 | QByteArray array2 = "XXXX LOGOUT\r\n" ; |
828 | QVERIFY(socketDevice.write(array2.data(), |
829 | array2.size()) == array2.size()); |
830 | |
831 | // Wait for the response |
832 | QVERIFY(socketDevice.waitForRead()); |
833 | |
834 | available = socketDevice.bytesAvailable(); |
835 | QVERIFY(available > 0); |
836 | array.resize(size: available); |
837 | QVERIFY(socketDevice.read(array.data(), array.size()) == available); |
838 | |
839 | // Check that the greeting is what we expect it to be |
840 | QCOMPARE(array.constData(), "* BYE LOGOUT received\r\nXXXX OK Completed\r\n" ); |
841 | |
842 | // Wait for the response |
843 | QVERIFY(socketDevice.waitForRead()); |
844 | char c; |
845 | QVERIFY(socketDevice.read(&c, sizeof(c)) == -1); |
846 | QCOMPARE(socketDevice.error(), QAbstractSocket::RemoteHostClosedError); |
847 | QCOMPARE(socketDevice.state(), QAbstractSocket::UnconnectedState); |
848 | } |
849 | |
850 | //---------------------------------------------------------------------------------- |
851 | |
852 | void tst_QSocks5SocketEngine::proxyAuthenticationRequired(const QNetworkProxy &, |
853 | QAuthenticator *auth) |
854 | { |
855 | auth->setUser("qsockstest" ); |
856 | auth->setPassword("password" ); |
857 | } |
858 | |
859 | void tst_QSocks5SocketEngine::passwordAuth2() |
860 | { |
861 | QSocks5SocketEngine socketDevice; |
862 | |
863 | // Initialize device |
864 | QVERIFY(socketDevice.initialize(QAbstractSocket::TcpSocket, QAbstractSocket::IPv4Protocol)); |
865 | QCOMPARE(socketDevice.state(), QAbstractSocket::UnconnectedState); |
866 | |
867 | socketDevice.setProxy(QNetworkProxy(QNetworkProxy::Socks5Proxy, QtNetworkSettings::socksProxyServerName(), 1081)); |
868 | socketDevice.setReceiver(this); |
869 | |
870 | QVERIFY(!socketDevice.connectToHost(QtNetworkSettings::imapServerIp(), 143)); |
871 | QCOMPARE(socketDevice.state(), QAbstractSocket::ConnectingState); |
872 | while (socketDevice.state() == QAbstractSocket::ConnectingState) { |
873 | QVERIFY(socketDevice.waitForWrite()); |
874 | socketDevice.connectToHost(address: QtNetworkSettings::imapServerIp(), port: 143); |
875 | } |
876 | if (socketDevice.state() != QAbstractSocket::ConnectedState) |
877 | qDebug(msg: "%d, %s" , socketDevice.error(), socketDevice.errorString().toLatin1().constData()); |
878 | QCOMPARE(socketDevice.state(), QAbstractSocket::ConnectedState); |
879 | QCOMPARE(socketDevice.peerAddress(), QtNetworkSettings::imapServerIp()); |
880 | |
881 | // Wait for the greeting |
882 | QVERIFY(socketDevice.waitForRead()); |
883 | |
884 | // Read the greeting |
885 | qint64 available = socketDevice.bytesAvailable(); |
886 | QVERIFY(available > 0); |
887 | QByteArray array; |
888 | array.resize(size: available); |
889 | QVERIFY(socketDevice.read(array.data(), array.size()) == available); |
890 | |
891 | // Check that the greeting is what we expect it to be |
892 | QVERIFY2(QtNetworkSettings::compareReplyIMAP(array), array.constData()); |
893 | |
894 | // Write a logout message |
895 | QByteArray array2 = "XXXX LOGOUT\r\n" ; |
896 | QVERIFY(socketDevice.write(array2.data(), |
897 | array2.size()) == array2.size()); |
898 | |
899 | // Wait for the response |
900 | QVERIFY(socketDevice.waitForRead()); |
901 | |
902 | available = socketDevice.bytesAvailable(); |
903 | QVERIFY(available > 0); |
904 | array.resize(size: available); |
905 | QVERIFY(socketDevice.read(array.data(), array.size()) == available); |
906 | |
907 | // Check that the greeting is what we expect it to be |
908 | QCOMPARE(array.constData(), "* BYE LOGOUT received\r\nXXXX OK Completed\r\n" ); |
909 | |
910 | // Wait for the response |
911 | QVERIFY(socketDevice.waitForRead()); |
912 | char c; |
913 | QVERIFY(socketDevice.read(&c, sizeof(c)) == -1); |
914 | QCOMPARE(socketDevice.error(), QAbstractSocket::RemoteHostClosedError); |
915 | QCOMPARE(socketDevice.state(), QAbstractSocket::UnconnectedState); |
916 | } |
917 | |
918 | void tst_QSocks5SocketEngine::fragmentation_data() |
919 | { |
920 | QTest::addColumn<QQueue<QByteArray> >(name: "responses" ); |
921 | |
922 | QByteArray authMethodNone = QByteArray::fromRawData("\5\0" , size: 2); |
923 | QByteArray authMethodBasic = QByteArray::fromRawData("\5\2" , size: 2); |
924 | QByteArray authSuccess = QByteArray::fromRawData("\1\0" , size: 2); |
925 | QByteArray connectResponseIPv4 = QByteArray::fromRawData("\5\0\0\1\1\2\3\4\5\6" , size: 10); |
926 | 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" , size: 22); |
927 | |
928 | QQueue<QByteArray> responses; |
929 | responses << authMethodNone.left(len: 1) << authMethodNone.mid(index: 1) << connectResponseIPv4; |
930 | QTest::newRow(dataTag: "auth-method" ) << responses; |
931 | |
932 | responses.clear(); |
933 | responses << authMethodBasic << authSuccess.left(len: 1) << authSuccess.mid(index: 1) << connectResponseIPv4; |
934 | QTest::newRow(dataTag: "auth-response" ) << responses; |
935 | |
936 | for (int i = 1; i < connectResponseIPv4.length() - 1; i++) { |
937 | responses.clear(); |
938 | responses << authMethodNone << connectResponseIPv4.left(len: i) << connectResponseIPv4.mid(index: i); |
939 | QTest::newRow(qPrintable(QString("connect-response-ipv4-" ) + QString::number(i))) << responses; |
940 | } |
941 | |
942 | for (int i = 1; i < connectResponseIPv6.length() - 1; i++) { |
943 | responses.clear(); |
944 | responses << authMethodNone << connectResponseIPv6.left(len: i) << connectResponseIPv6.mid(index: i); |
945 | QTest::newRow(qPrintable(QString("connect-response-ipv6-" ) + QString::number(i))) << responses; |
946 | } |
947 | } |
948 | |
949 | void tst_QSocks5SocketEngine::fragmentation() |
950 | { |
951 | QFETCH(QQueue<QByteArray>, responses); |
952 | MiniSocks5Server server(responses, 500); |
953 | |
954 | QTcpSocket socket; |
955 | socket.setProxy(QNetworkProxy(QNetworkProxy::Socks5Proxy, "localhost" , server.serverPort(), "user" , "password" )); |
956 | socket.connectToHost(hostName: "0.1.2.3" , port: 12345); |
957 | |
958 | connect(sender: &socket, SIGNAL(connected()), |
959 | receiver: &QTestEventLoop::instance(), SLOT(exitLoop())); |
960 | QTestEventLoop::instance().enterLoop(secs: 10); |
961 | QVERIFY(!QTestEventLoop::instance().timeout()); |
962 | |
963 | QVERIFY(socket.localAddress() == QHostAddress("1.2.3.4" ) || socket.localAddress() == QHostAddress("0123:4567:89ab:cdef:0123:4567:89ab:cdef" )); |
964 | QCOMPARE(socket.localPort(), quint16(0x0506)); |
965 | } |
966 | |
967 | void tst_QSocks5SocketEngine::incomplete_data() |
968 | { |
969 | QTest::addColumn<QQueue<QByteArray> >(name: "responses" ); |
970 | |
971 | QByteArray authMethodNone = QByteArray::fromRawData("\5\0" , size: 2); |
972 | QByteArray authMethodBasic = QByteArray::fromRawData("\5\2" , size: 2); |
973 | QByteArray authSuccess = QByteArray::fromRawData("\1\0" , size: 2); |
974 | QByteArray connectResponseIPv4 = QByteArray::fromRawData("\5\0\0\1\1\2\3\4\5\6" , size: 10); |
975 | 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" , size: 22); |
976 | |
977 | QQueue<QByteArray> responses; |
978 | responses << authMethodNone.left(len: 1); |
979 | QTest::newRow(dataTag: "auth-method" ) << responses; |
980 | |
981 | responses.clear(); |
982 | responses << authMethodBasic << authSuccess.left(len: 1); |
983 | QTest::newRow(dataTag: "auth-response" ) << responses; |
984 | |
985 | for (int i = 1; i < connectResponseIPv4.length() - 1; i++) { |
986 | responses.clear(); |
987 | responses << authMethodNone << connectResponseIPv4.left(len: i); |
988 | QTest::newRow(qPrintable(QString("connect-response-ipv4-" ) + QString::number(i))) << responses; |
989 | } |
990 | |
991 | for (int i = 1; i < connectResponseIPv6.length() - 1; i++) { |
992 | responses.clear(); |
993 | responses << authMethodNone << connectResponseIPv6.left(len: i); |
994 | QTest::newRow(qPrintable(QString("connect-response-ipv6-" ) + QString::number(i))) << responses; |
995 | } |
996 | } |
997 | |
998 | void tst_QSocks5SocketEngine::incomplete() |
999 | { |
1000 | QFETCH(QQueue<QByteArray>, responses); |
1001 | MiniSocks5Server server(responses, 500); |
1002 | |
1003 | QTcpSocket socket; |
1004 | socket.setProxy(QNetworkProxy(QNetworkProxy::Socks5Proxy, "127.0.0.1" , server.serverPort(), "user" , "password" )); |
1005 | socket.connectToHost(hostName: "0.1.2.3" , port: 12345); |
1006 | |
1007 | connect(sender: &socket, SIGNAL(connected()), |
1008 | receiver: &QTestEventLoop::instance(), SLOT(exitLoop())); |
1009 | connect(sender: &socket, SIGNAL(errorOccurred(QAbstractSocket::SocketError)), |
1010 | receiver: &QTestEventLoop::instance(), SLOT(exitLoop())); |
1011 | QTestEventLoop::instance().enterLoop(secs: 70); |
1012 | QVERIFY(!QTestEventLoop::instance().timeout()); |
1013 | |
1014 | QCOMPARE(socket.error(), QAbstractSocket::ProxyConnectionClosedError); |
1015 | } |
1016 | |
1017 | //---------------------------------------------------------------------------------- |
1018 | |
1019 | QTEST_MAIN(tst_QSocks5SocketEngine) |
1020 | #include "tst_qsocks5socketengine.moc" |
1021 | |