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#include <qglobal.h>
30// To prevent windows system header files from re-defining min/max
31#define NOMINMAX 1
32#if defined(_WIN32)
33#include <winsock2.h>
34#else
35#include <sys/types.h>
36#include <sys/socket.h>
37#define SOCKET int
38#define INVALID_SOCKET -1
39#endif
40
41#include <QtTest/QtTest>
42
43#ifndef Q_OS_WIN
44#include <unistd.h>
45#include <sys/ioctl.h>
46#endif
47
48#include <qcoreapplication.h>
49#include <qtcpsocket.h>
50#include <qtcpserver.h>
51#include <qhostaddress.h>
52#if QT_CONFIG(process)
53# include <qprocess.h>
54#endif
55#include <qstringlist.h>
56#include <qplatformdefs.h>
57#include <qhostinfo.h>
58
59#include <QNetworkProxy>
60
61#include <QNetworkSession>
62#include <QNetworkConfiguration>
63#include <QNetworkConfigurationManager>
64#include "../../../network-settings.h"
65
66#if defined(Q_OS_LINUX)
67#define SHOULD_CHECK_SYSCALL_SUPPORT
68#include <netinet/in.h>
69#include <sys/socket.h>
70#include <errno.h>
71#endif
72
73class tst_QTcpServer : public QObject
74{
75 Q_OBJECT
76
77private slots:
78 void initTestCase_data();
79 void initTestCase();
80 void init();
81 void cleanup();
82 void getSetCheck();
83 void constructing();
84 void clientServerLoop();
85 void ipv6Server();
86 void dualStack_data();
87 void dualStack();
88 void ipv6ServerMapped();
89 void crashTests();
90 void maxPendingConnections();
91 void listenError();
92 void waitForConnectionTest();
93#ifndef Q_OS_WINRT
94 void setSocketDescriptor();
95#endif
96 void listenWhileListening();
97 void addressReusable();
98 void setNewSocketDescriptorBlocking();
99#ifndef QT_NO_NETWORKPROXY
100 void invalidProxy_data();
101 void invalidProxy();
102 void proxyFactory_data();
103 void proxyFactory();
104#endif // !QT_NO_NETWORKPROXY
105
106 void qtbug14268_peek();
107
108 void serverAddress_data();
109 void serverAddress();
110
111 void qtbug6305_data() { serverAddress_data(); }
112 void qtbug6305();
113
114 void linkLocal();
115
116 void eagainBlockingAccept();
117
118 void canAccessPendingConnectionsWhileNotListening();
119
120private:
121 bool shouldSkipIpv6TestsForBrokenGetsockopt();
122#ifdef SHOULD_CHECK_SYSCALL_SUPPORT
123 bool ipv6GetsockoptionMissing(int level, int optname);
124#endif
125
126#ifndef QT_NO_BEARERMANAGEMENT
127 QNetworkSession *networkSession;
128#endif
129 QString crashingServerDir;
130};
131
132// Testing get/set functions
133void tst_QTcpServer::getSetCheck()
134{
135 QTcpServer obj1;
136 // int QTcpServer::maxPendingConnections()
137 // void QTcpServer::setMaxPendingConnections(int)
138 obj1.setMaxPendingConnections(0);
139 QCOMPARE(0, obj1.maxPendingConnections());
140 obj1.setMaxPendingConnections(INT_MIN);
141 QCOMPARE(INT_MIN, obj1.maxPendingConnections());
142 obj1.setMaxPendingConnections(INT_MAX);
143 QCOMPARE(INT_MAX, obj1.maxPendingConnections());
144}
145
146void tst_QTcpServer::initTestCase_data()
147{
148 QTest::addColumn<bool>(name: "setProxy");
149 QTest::addColumn<int>(name: "proxyType");
150
151 QTest::newRow(dataTag: "WithoutProxy") << false << 0;
152#if QT_CONFIG(socks5)
153 QTest::newRow(dataTag: "WithSocks5Proxy") << true << int(QNetworkProxy::Socks5Proxy);
154#endif
155
156 crashingServerDir = QFINDTESTDATA("crashingServer");
157 QVERIFY2(!crashingServerDir.isEmpty(), qPrintable(
158 QString::fromLatin1("Couldn't find crashingServer dir starting from %1.").arg(QDir::currentPath())));
159}
160
161void tst_QTcpServer::initTestCase()
162{
163#ifdef QT_TEST_SERVER
164 QVERIFY(QtNetworkSettings::verifyConnection(QtNetworkSettings::socksProxyServerName(), 1080));
165 QVERIFY(QtNetworkSettings::verifyConnection(QtNetworkSettings::httpProxyServerName(), 3128));
166 QVERIFY(QtNetworkSettings::verifyConnection(QtNetworkSettings::ftpProxyServerName(), 2121));
167 QVERIFY(QtNetworkSettings::verifyConnection(QtNetworkSettings::imapServerName(), 143));
168#else
169 if (!QtNetworkSettings::verifyTestNetworkSettings())
170 QSKIP("No network test server available");
171#endif
172#ifndef QT_NO_BEARERMANAGEMENT
173 QNetworkConfigurationManager man;
174 networkSession = new QNetworkSession(man.defaultConfiguration(), this);
175 networkSession->open();
176 QVERIFY(networkSession->waitForOpened());
177#endif
178}
179
180void tst_QTcpServer::init()
181{
182 QFETCH_GLOBAL(bool, setProxy);
183 if (setProxy) {
184#ifndef QT_NO_NETWORKPROXY
185 QFETCH_GLOBAL(int, proxyType);
186 if (proxyType == QNetworkProxy::Socks5Proxy) {
187 QNetworkProxy::setApplicationProxy(QNetworkProxy(QNetworkProxy::Socks5Proxy, QtNetworkSettings::socksProxyServerName(), 1080));
188 }
189#else // !QT_NO_NETWORKPROXY
190 QSKIP("No proxy support");
191#endif // QT_NO_NETWORKPROXY
192 }
193}
194
195void tst_QTcpServer::cleanup()
196{
197#ifndef QT_NO_NETWORKPROXY
198 QNetworkProxy::setApplicationProxy(QNetworkProxy::DefaultProxy);
199#endif
200}
201
202#ifdef SHOULD_CHECK_SYSCALL_SUPPORT
203bool tst_QTcpServer::ipv6GetsockoptionMissing(int level, int optname)
204{
205 int testSocket;
206
207 testSocket = socket(PF_INET6, SOCK_STREAM, protocol: 0);
208
209 // If we can't test here, assume it's not missing
210 if (testSocket == -1)
211 return false;
212
213 bool result = false;
214 if (getsockopt(fd: testSocket, level: level, optname: optname, optval: nullptr, optlen: 0) == -1) {
215 if (errno == EOPNOTSUPP) {
216 result = true;
217 }
218 }
219
220 close(fd: testSocket);
221 return result;
222}
223#endif //SHOULD_CHECK_SYSCALL_SUPPORT
224
225bool tst_QTcpServer::shouldSkipIpv6TestsForBrokenGetsockopt()
226{
227#ifdef SHOULD_CHECK_SYSCALL_SUPPORT
228 // Following parameters for setsockopt are not supported by all QEMU versions:
229 if (ipv6GetsockoptionMissing(SOL_IPV6, IPV6_V6ONLY)) {
230 return true;
231 }
232#endif //SHOULD_CHECK_SYSCALL_SUPPORT
233
234 return false;
235}
236
237
238//----------------------------------------------------------------------------------
239
240void tst_QTcpServer::constructing()
241{
242 QTcpServer socket;
243
244 // Check the initial state of the QTcpSocket.
245 QCOMPARE(socket.isListening(), false);
246 QCOMPARE((int)socket.serverPort(), 0);
247 QCOMPARE(socket.serverAddress(), QHostAddress());
248 QCOMPARE(socket.maxPendingConnections(), 30);
249 QCOMPARE(socket.hasPendingConnections(), false);
250 QCOMPARE(socket.socketDescriptor(), (qintptr)-1);
251 QCOMPARE(socket.serverError(), QAbstractSocket::UnknownSocketError);
252
253 // Check the state of the socket layer?
254}
255
256//----------------------------------------------------------------------------------
257void tst_QTcpServer::clientServerLoop()
258{
259 QTcpServer server;
260
261 QSignalSpy spy(&server, SIGNAL(newConnection()));
262
263 QVERIFY(!server.isListening());
264 QVERIFY(!server.hasPendingConnections());
265 QVERIFY(server.listen(QHostAddress::Any, 11423));
266 QVERIFY(server.isListening());
267
268 QTcpSocket client;
269
270 QHostAddress serverAddress = QHostAddress::LocalHost;
271 if (!(server.serverAddress() == QHostAddress::Any) && !(server.serverAddress() == QHostAddress::AnyIPv6) && !(server.serverAddress() == QHostAddress::AnyIPv4))
272 serverAddress = server.serverAddress();
273
274 client.connectToHost(address: serverAddress, port: server.serverPort());
275 QVERIFY(client.waitForConnected(5000));
276
277 QVERIFY(server.waitForNewConnection(5000));
278 QVERIFY(server.hasPendingConnections());
279
280 QCOMPARE(spy.count(), 1);
281
282 QTcpSocket *serverSocket = server.nextPendingConnection();
283 QVERIFY(serverSocket != 0);
284
285 QVERIFY(serverSocket->write("Greetings, client!\n", 19) == 19);
286 serverSocket->flush();
287
288 QVERIFY(client.waitForReadyRead(5000));
289 QByteArray arr = client.readAll();
290 QCOMPARE(arr.constData(), "Greetings, client!\n");
291
292 QVERIFY(client.write("Well, hello to you!\n", 20) == 20);
293 client.flush();
294
295 QVERIFY(serverSocket->waitForReadyRead(5000));
296 arr = serverSocket->readAll();
297 QCOMPARE(arr.constData(), "Well, hello to you!\n");
298}
299
300//----------------------------------------------------------------------------------
301void tst_QTcpServer::ipv6Server()
302{
303 if (!QtNetworkSettings::hasIPv6())
304 QSKIP("system doesn't support ipv6!");
305 //### need to enter the event loop for the server to get the connection ?? ( windows)
306 QTcpServer server;
307 if (!server.listen(address: QHostAddress::LocalHostIPv6, port: 8944)) {
308 QCOMPARE(server.serverError(), QAbstractSocket::UnsupportedSocketOperationError);
309 return;
310 }
311
312 QCOMPARE(server.serverPort(), quint16(8944));
313 QVERIFY(server.serverAddress() == QHostAddress::LocalHostIPv6);
314
315 QTcpSocket client;
316 client.connectToHost(hostName: "::1", port: 8944);
317 QVERIFY(client.waitForConnected(5000));
318
319 QVERIFY(server.waitForNewConnection());
320 QVERIFY(server.hasPendingConnections());
321
322 QTcpSocket *serverSocket = 0;
323 QVERIFY((serverSocket = server.nextPendingConnection()));
324 serverSocket->close();
325 delete serverSocket;
326}
327
328Q_DECLARE_METATYPE(QHostAddress);
329
330void tst_QTcpServer::dualStack_data()
331{
332 QTest::addColumn<QHostAddress>(name: "bindAddress");
333 QTest::addColumn<bool>(name: "v4ok");
334 QTest::addColumn<bool>(name: "v6ok");
335 QTest::newRow(dataTag: "any") << QHostAddress(QHostAddress::Any) << true << true;
336 QTest::newRow(dataTag: "anyIPv4") << QHostAddress(QHostAddress::AnyIPv4) << true << false;
337 QTest::newRow(dataTag: "anyIPv6") << QHostAddress(QHostAddress::AnyIPv6) << false << true;
338}
339
340void tst_QTcpServer::dualStack()
341{
342 QFETCH_GLOBAL(bool, setProxy);
343 if (setProxy)
344 QSKIP("test server proxy doesn't support ipv6");
345 if (!QtNetworkSettings::hasIPv6())
346 QSKIP("system doesn't support ipv6!");
347 QFETCH(QHostAddress, bindAddress);
348 QFETCH(bool, v4ok);
349 QFETCH(bool, v6ok);
350
351 QTcpServer server;
352 QVERIFY(server.listen(bindAddress));
353
354 QTcpSocket v4client;
355 v4client.connectToHost(address: QHostAddress::LocalHost, port: server.serverPort());
356
357 QTcpSocket v6client;
358 v6client.connectToHost(address: QHostAddress::LocalHostIPv6, port: server.serverPort());
359
360 QCOMPARE(v4client.waitForConnected(5000), v4ok);
361 QCOMPARE(v6client.waitForConnected(5000), v6ok);
362}
363
364//----------------------------------------------------------------------------------
365void tst_QTcpServer::ipv6ServerMapped()
366{
367 QFETCH_GLOBAL(bool, setProxy);
368 if (setProxy)
369 return;
370
371 QTcpServer server;
372 QVERIFY(server.listen(QHostAddress::LocalHost));
373
374 // let's try the normal case
375 QTcpSocket client1;
376 client1.connectToHost(hostName: "127.0.0.1", port: server.serverPort());
377 QVERIFY(server.waitForNewConnection(5000));
378 delete server.nextPendingConnection();
379
380 if (!QtNetworkSettings::hasIPv6())
381 QSKIP("system doesn't support ipv6!");
382
383 // let's try the mapped one in the nice format
384 QTcpSocket client2;
385 client2.connectToHost(hostName: "::ffff:127.0.0.1", port: server.serverPort());
386 QVERIFY(server.waitForNewConnection(5000));
387 delete server.nextPendingConnection();
388
389 // let's try the mapped in hex format
390 QTcpSocket client3;
391 client3.connectToHost(hostName: "::ffff:7F00:0001", port: server.serverPort());
392 QVERIFY(server.waitForNewConnection(5000));
393 delete server.nextPendingConnection();
394
395 // However connecting to the v6 localhost should not work
396 QTcpSocket client4;
397 client4.connectToHost(hostName: "::1", port: server.serverPort());
398 QVERIFY(!server.waitForNewConnection(5000));
399}
400
401//----------------------------------------------------------------------------------
402void tst_QTcpServer::crashTests()
403{
404 QTcpServer server;
405 server.close();
406 QVERIFY(server.listen());
407}
408
409//----------------------------------------------------------------------------------
410void tst_QTcpServer::maxPendingConnections()
411{
412 QFETCH_GLOBAL(bool, setProxy);
413 if (setProxy) {
414#ifndef QT_NO_NETWORKPROXY
415 QFETCH_GLOBAL(int, proxyType);
416 if (proxyType == QNetworkProxy::Socks5Proxy)
417 QSKIP("With socks5 only 1 connection is allowed ever");
418#else // !QT_NO_NETWORKPROXY
419 QSKIP("No proxy support");
420#endif // QT_NO_NETWORKPROXY
421 }
422 //### sees to fail sometimes ... a timing issue with the test on windows
423 QTcpServer server;
424 server.setMaxPendingConnections(2);
425
426 QTcpSocket socket1;
427 QTcpSocket socket2;
428 QTcpSocket socket3;
429
430 QSignalSpy spy(&server, SIGNAL(newConnection()));
431 QVERIFY(server.listen());
432
433 socket1.connectToHost(address: QHostAddress::LocalHost, port: server.serverPort());
434 socket2.connectToHost(address: QHostAddress::LocalHost, port: server.serverPort());
435 socket3.connectToHost(address: QHostAddress::LocalHost, port: server.serverPort());
436
437 // We must have two and only two connections. First compare waits until
438 // two connections have been made. The second compare makes sure no
439 // more are accepted. Creating connections happens multithreaded so
440 // qWait must be used for that.
441 QTRY_COMPARE(spy.count(), 2);
442 QTest::qWait(ms: 100);
443 QCOMPARE(spy.count(), 2);
444
445 QVERIFY(server.hasPendingConnections());
446 QVERIFY(server.nextPendingConnection());
447 QVERIFY(server.hasPendingConnections());
448 QVERIFY(server.nextPendingConnection());
449 QVERIFY(!server.hasPendingConnections());
450 QCOMPARE(server.nextPendingConnection(), (QTcpSocket*)0);
451
452 QVERIFY(server.waitForNewConnection(5000));
453
454 QVERIFY(server.hasPendingConnections());
455 QVERIFY(server.nextPendingConnection());
456}
457
458//----------------------------------------------------------------------------------
459void tst_QTcpServer::listenError()
460{
461 QFETCH_GLOBAL(bool, setProxy);
462 if (setProxy) {
463#ifndef QT_NO_NETWORKPROXY
464 QFETCH_GLOBAL(int, proxyType);
465 if (proxyType == QNetworkProxy::Socks5Proxy)
466 QSKIP("With socks5 we can not make hard requirements on the address or port");
467#else // !QT_NO_NETWORKPROXY
468 QSKIP("No proxy support");
469#endif //QT_NO_NETWORKPROXY
470 }
471 QTcpServer server;
472 QVERIFY(!server.listen(QHostAddress("1.2.3.4"), 0));
473 QCOMPARE(server.serverError(), QAbstractSocket::SocketAddressNotAvailableError);
474 QCOMPARE(server.errorString().toLatin1().constData(), "The address is not available");
475}
476
477class ThreadConnector : public QThread
478{
479public:
480 ThreadConnector(const QHostAddress &host, quint16 port)
481 : host(host), port(port)
482 { }
483
484 ~ThreadConnector()
485 {
486 wait();
487 }
488
489protected:
490 void run()
491 {
492 sleep(2);
493
494 QTcpSocket socket;
495 socket.connectToHost(address: host, port);
496
497 QEventLoop loop;
498 QTimer::singleShot(msec: 5000, receiver: &loop, SLOT(quit()));
499 loop.exec();
500 }
501
502private:
503 QHostAddress host;
504 quint16 port;
505};
506
507//----------------------------------------------------------------------------------
508void tst_QTcpServer::waitForConnectionTest()
509{
510
511 QFETCH_GLOBAL(bool, setProxy);
512 if (setProxy) {
513#ifndef QT_NO_NETWORKPROXY
514 QFETCH_GLOBAL(int, proxyType);
515 if (proxyType == QNetworkProxy::Socks5Proxy)
516 QSKIP("Localhost servers don't work well with SOCKS5");
517#else // !QT_NO_NETWORKPROXY
518 QSKIP("No proxy support");
519#endif // QT_NO_NETWORKPROXY
520 }
521
522 QTcpSocket findLocalIpSocket;
523 findLocalIpSocket.connectToHost(hostName: QtNetworkSettings::imapServerName(), port: 143);
524 QVERIFY(findLocalIpSocket.waitForConnected(5000));
525
526 QTcpServer server;
527 bool timeout = false;
528 QVERIFY(server.listen(findLocalIpSocket.localAddress()));
529 QVERIFY(!server.waitForNewConnection(1000, &timeout));
530 QCOMPARE(server.serverError(), QAbstractSocket::SocketTimeoutError);
531 QVERIFY(timeout);
532
533 ThreadConnector connector(findLocalIpSocket.localAddress(), server.serverPort());
534 connector.start();
535
536 QVERIFY(server.waitForNewConnection(3000, &timeout));
537 QVERIFY(!timeout);
538}
539
540//----------------------------------------------------------------------------------
541#ifndef Q_OS_WINRT
542void tst_QTcpServer::setSocketDescriptor()
543{
544 QTcpServer server;
545 QVERIFY(!server.setSocketDescriptor(42));
546 QCOMPARE(server.serverError(), QAbstractSocket::UnsupportedSocketOperationError);
547 //adopting Open C sockets is not supported, neither is adopting externally created RSocket
548#ifdef Q_OS_WIN
549 // ensure winsock is started
550 WSADATA wsaData;
551 QVERIFY(WSAStartup(MAKEWORD(2,0), &wsaData) == NO_ERROR);
552#endif
553
554 SOCKET sock = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
555
556 QVERIFY(sock != INVALID_SOCKET);
557
558 sockaddr_in sin;
559 memset(s: &sin, c: 0, n: sizeof(sockaddr_in));
560 sin.sin_family = AF_INET;
561 sin.sin_port = 0;
562 sin.sin_addr.s_addr = 0x00000000;
563 QVERIFY(::bind(sock, (sockaddr*)&sin, sizeof(sockaddr_in)) == 0);
564 QVERIFY(::listen(sock, 10) == 0);
565 QVERIFY(server.setSocketDescriptor(sock));
566
567#ifdef Q_OS_WIN
568 WSACleanup();
569#endif
570}
571#endif // !Q_OS_WINRT
572
573//----------------------------------------------------------------------------------
574void tst_QTcpServer::listenWhileListening()
575{
576 QTcpServer server;
577 QVERIFY(server.listen());
578 QTest::ignoreMessage(type: QtWarningMsg, message: "QTcpServer::listen() called when already listening");
579 QVERIFY(!server.listen());
580}
581
582//----------------------------------------------------------------------------------
583
584class SeverWithBlockingSockets : public QTcpServer
585{
586public:
587 SeverWithBlockingSockets()
588 : ok(false) { }
589
590 bool ok;
591
592protected:
593#ifndef Q_OS_WINRT
594 void incomingConnection(qintptr socketDescriptor)
595 {
596 // how a user woulddo it (qabstractsocketengine is not public)
597 unsigned long arg = 0;
598#if defined(Q_OS_WIN)
599 ok = ::ioctlsocket(socketDescriptor, FIONBIO, &arg) == 0;
600 ::closesocket(socketDescriptor);
601#else
602 ok = ::ioctl(fd: socketDescriptor, FIONBIO, &arg) == 0;
603 ::close(fd: socketDescriptor);
604#endif
605 }
606#endif // !Q_OS_WINRT
607};
608
609void tst_QTcpServer::addressReusable()
610{
611#if !QT_CONFIG(process)
612 QSKIP("No qprocess support", SkipAll);
613#else
614#ifdef Q_OS_LINUX
615 QSKIP("The addressReusable test is unstable on Linux. See QTBUG-39985.");
616#endif
617 QFETCH_GLOBAL(bool, setProxy);
618 if (setProxy) {
619#ifndef QT_NO_NETWORKPROXY
620 QFETCH_GLOBAL(int, proxyType);
621 if (proxyType == QNetworkProxy::Socks5Proxy)
622 QSKIP("With socks5 this test does not make senans at the momment");
623#else // !QT_NO_NETWORKPROXY
624 QSKIP("No proxy support");
625#endif // QT_NO_NETWORKPROXY
626 }
627 // The crashingServer process will crash once it gets a connection.
628 QProcess process;
629 QString processExe = crashingServerDir + "/crashingServer";
630 process.start(command: processExe);
631 QVERIFY2(process.waitForStarted(), qPrintable(
632 QString::fromLatin1("Could not start %1: %2").arg(processExe, process.errorString())));
633 QVERIFY(process.waitForReadyRead(5000));
634
635 QTcpSocket socket;
636 socket.connectToHost(address: QHostAddress::LocalHost, port: 49199);
637 QVERIFY(socket.waitForConnected(5000));
638
639 QVERIFY(process.waitForFinished(30000));
640
641 // Give the system some time.
642 QTest::qSleep(ms: 10);
643
644 QTcpServer server;
645 QVERIFY(server.listen(QHostAddress::LocalHost, 49199));
646#endif
647}
648
649void tst_QTcpServer::setNewSocketDescriptorBlocking()
650{
651 QFETCH_GLOBAL(bool, setProxy);
652 if (setProxy) {
653#ifndef QT_NO_NETWORKPROXY
654 QFETCH_GLOBAL(int, proxyType);
655 if (proxyType == QNetworkProxy::Socks5Proxy)
656 QSKIP("With socks5 we can not make the socket descripter blocking");
657#else // !QT_NO_NETWORKPROXY
658 QSKIP("No proxy support");
659#endif // QT_NO_NETWORKPROXY
660 }
661 SeverWithBlockingSockets server;
662 QVERIFY(server.listen());
663
664 QTcpSocket socket;
665 socket.connectToHost(address: QHostAddress::LocalHost, port: server.serverPort());
666 QVERIFY(server.waitForNewConnection(5000));
667 QVERIFY(server.ok);
668}
669
670#ifndef QT_NO_NETWORKPROXY
671void tst_QTcpServer::invalidProxy_data()
672{
673 QTest::addColumn<int>(name: "type");
674 QTest::addColumn<QString>(name: "host");
675 QTest::addColumn<int>(name: "port");
676 QTest::addColumn<int>(name: "expectedError");
677
678 const QString imapIp = QtNetworkSettings::imapServerIp().toString();
679 const QString httpProxyIp = QtNetworkSettings::httpProxyServerIp().toString();
680 const QString socksIp = QtNetworkSettings::socksProxyServerIp().toString();
681 QTest::newRow(dataTag: "ftp-proxy") << int(QNetworkProxy::FtpCachingProxy) << imapIp << 143
682 << int(QAbstractSocket::UnsupportedSocketOperationError);
683 QTest::newRow(dataTag: "http-proxy") << int(QNetworkProxy::HttpProxy) << httpProxyIp << 3128
684 << int(QAbstractSocket::UnsupportedSocketOperationError);
685
686 QTest::newRow(dataTag: "no-such-host") << int(QNetworkProxy::Socks5Proxy)
687 << "invalid.test.qt-project.org" << 1080
688 << int(QAbstractSocket::ProxyNotFoundError);
689 QTest::newRow(dataTag: "socks5-on-http") << int(QNetworkProxy::Socks5Proxy) << httpProxyIp << 3128
690 << int(QAbstractSocket::SocketTimeoutError);
691}
692
693void tst_QTcpServer::invalidProxy()
694{
695 QFETCH_GLOBAL(bool, setProxy);
696 if (setProxy)
697 return;
698
699 QFETCH(int, type);
700 QFETCH(QString, host);
701 QFETCH(int, port);
702 QNetworkProxy::ProxyType proxyType = QNetworkProxy::ProxyType(type);
703 QNetworkProxy proxy(proxyType, host, port);
704
705 QTcpServer server;
706 server.setProxy(proxy);
707 bool listenResult = server.listen();
708
709 QVERIFY(!listenResult);
710 QVERIFY(!server.errorString().isEmpty());
711
712 // note: the following test is not a hard failure.
713 // Sometimes, error codes change for the better
714 QTEST(int(server.serverError()), "expectedError");
715}
716
717// copied from tst_qnetworkreply.cpp
718class MyProxyFactory: public QNetworkProxyFactory
719{
720public:
721 int callCount;
722 QList<QNetworkProxy> toReturn;
723 QNetworkProxyQuery lastQuery;
724 inline MyProxyFactory() { clear(); }
725
726 inline void clear()
727 {
728 callCount = 0;
729 toReturn = QList<QNetworkProxy>() << QNetworkProxy::DefaultProxy;
730 lastQuery = QNetworkProxyQuery();
731 }
732
733 virtual QList<QNetworkProxy> queryProxy(const QNetworkProxyQuery &query)
734 {
735 lastQuery = query;
736 ++callCount;
737 return toReturn;
738 }
739};
740
741void tst_QTcpServer::proxyFactory_data()
742{
743 QTest::addColumn<QList<QNetworkProxy> >(name: "proxyList");
744 QTest::addColumn<QNetworkProxy>(name: "proxyUsed");
745 QTest::addColumn<bool>(name: "fails");
746 QTest::addColumn<int>(name: "expectedError");
747
748 QList<QNetworkProxy> proxyList;
749
750 // tests that do get to listen
751
752 proxyList << QNetworkProxy(QNetworkProxy::Socks5Proxy, QtNetworkSettings::socksProxyServerName(), 1080);
753 QTest::newRow(dataTag: "socks5")
754 << proxyList << proxyList.at(i: 0)
755 << false << int(QAbstractSocket::UnknownSocketError);
756
757 proxyList.clear();
758 proxyList << QNetworkProxy(QNetworkProxy::HttpCachingProxy, QtNetworkSettings::httpProxyServerName(), 3128)
759 << QNetworkProxy(QNetworkProxy::Socks5Proxy, QtNetworkSettings::socksProxyServerName(), 1080);
760 QTest::newRow(dataTag: "cachinghttp+socks5")
761 << proxyList << proxyList.at(i: 1)
762 << false << int(QAbstractSocket::UnknownSocketError);
763
764 proxyList.clear();
765 proxyList << QNetworkProxy(QNetworkProxy::FtpCachingProxy, QtNetworkSettings::ftpProxyServerName(), 2121)
766 << QNetworkProxy(QNetworkProxy::HttpCachingProxy, QtNetworkSettings::httpProxyServerName(), 3128)
767 << QNetworkProxy(QNetworkProxy::Socks5Proxy, QtNetworkSettings::socksProxyServerName(), 1080);
768 QTest::newRow(dataTag: "ftp+cachinghttp+socks5")
769 << proxyList << proxyList.at(i: 2)
770 << false << int(QAbstractSocket::UnknownSocketError);
771
772 // tests that fail to listen
773 proxyList.clear();
774 proxyList << QNetworkProxy(QNetworkProxy::HttpProxy, QtNetworkSettings::httpProxyServerName(), 3128);
775 QTest::newRow(dataTag: "http")
776 << proxyList << proxyList.at(i: 0)
777 << true << int(QAbstractSocket::UnsupportedSocketOperationError);
778
779 proxyList.clear();
780 proxyList << QNetworkProxy(QNetworkProxy::HttpCachingProxy, QtNetworkSettings::httpProxyServerName(), 3128);
781 QTest::newRow(dataTag: "cachinghttp")
782 << proxyList << QNetworkProxy()
783 << true << int(QAbstractSocket::UnsupportedSocketOperationError);
784
785 proxyList.clear();
786 proxyList << QNetworkProxy(QNetworkProxy::FtpCachingProxy, QtNetworkSettings::ftpProxyServerName(), 2121);
787 QTest::newRow(dataTag: "ftp")
788 << proxyList << QNetworkProxy()
789 << true << int(QAbstractSocket::UnsupportedSocketOperationError);
790
791 proxyList.clear();
792 proxyList << QNetworkProxy(QNetworkProxy::FtpCachingProxy, QtNetworkSettings::ftpProxyServerName(), 2121)
793 << QNetworkProxy(QNetworkProxy::HttpCachingProxy, QtNetworkSettings::httpProxyServerName(), 3128);
794 QTest::newRow(dataTag: "ftp+cachinghttp")
795 << proxyList << QNetworkProxy()
796 << true << int(QAbstractSocket::UnsupportedSocketOperationError);
797}
798
799void tst_QTcpServer::proxyFactory()
800{
801 QFETCH_GLOBAL(bool, setProxy);
802 if (setProxy)
803 return;
804
805 QFETCH(QList<QNetworkProxy>, proxyList);
806 QFETCH(QNetworkProxy, proxyUsed);
807 QFETCH(bool, fails);
808
809 MyProxyFactory *factory = new MyProxyFactory;
810 factory->toReturn = proxyList;
811 QNetworkProxyFactory::setApplicationProxyFactory(factory);
812
813 QTcpServer server;
814 bool listenResult = server.listen();
815
816 // Verify that the factory was called properly
817 QCOMPARE(factory->callCount, 1);
818 QCOMPARE(factory->lastQuery, QNetworkProxyQuery(0, QString(), QNetworkProxyQuery::TcpServer));
819
820 QCOMPARE(listenResult, !fails);
821 QCOMPARE(server.errorString().isEmpty(), !fails);
822
823 // note: the following test is not a hard failure.
824 // Sometimes, error codes change for the better
825 QTEST(int(server.serverError()), "expectedError");
826}
827#endif // !QT_NO_NETWORKPROXY
828
829class Qtbug14268Helper : public QObject
830{
831 Q_OBJECT
832public:
833 QByteArray lastDataPeeked;
834public slots:
835 void newConnection() {
836 QTcpServer* server=static_cast<QTcpServer*>(sender());
837 QTcpSocket* s=server->nextPendingConnection();
838 connect(sender: s,SIGNAL(readyRead()),receiver: this,SLOT(onServerReadyRead()));
839 }
840 void onServerReadyRead() {
841 QTcpSocket* clientSocket=static_cast<QTcpSocket*>(sender());
842 lastDataPeeked = clientSocket->peek(maxlen: 128*1024).toHex();
843 QTestEventLoop::instance().exitLoop();
844 }
845};
846
847// there is a similar test inside tst_qtcpsocket that uses the waitFor* functions instead
848void tst_QTcpServer::qtbug14268_peek()
849{
850 QFETCH_GLOBAL(bool, setProxy);
851 if (setProxy)
852 return;
853
854 QTcpServer server;
855 server.listen();
856
857 Qtbug14268Helper helper;
858 QObject::connect(sender: &server, SIGNAL(newConnection()), receiver: &helper, SLOT(newConnection()));
859
860 QTcpSocket client;
861 client.connectToHost(address: QHostAddress::LocalHost, port: server.serverPort());
862 QVERIFY(client.waitForConnected(2000));
863
864 client.write(data: "abc\n");
865 QTestEventLoop::instance().enterLoop(secs: 5);
866 QVERIFY(!QTestEventLoop::instance().timeout());
867 QCOMPARE(helper.lastDataPeeked, QByteArray("6162630a"));
868
869 client.write(data: "def\n");
870 QTestEventLoop::instance().enterLoop(secs: 5);
871 QVERIFY(!QTestEventLoop::instance().timeout());
872 QCOMPARE(helper.lastDataPeeked, QByteArray("6162630a6465660a"));
873
874 client.write(data: "ghi\n");
875 QTestEventLoop::instance().enterLoop(secs: 5);
876 QVERIFY(!QTestEventLoop::instance().timeout());
877 QCOMPARE(helper.lastDataPeeked, QByteArray("6162630a6465660a6768690a"));
878}
879
880void tst_QTcpServer::serverAddress_data()
881{
882 QTest::addColumn<QHostAddress>(name: "listenAddress");
883 QTest::addColumn<QHostAddress>(name: "serverAddress");
884 if (QtNetworkSettings::hasIPv6())
885 QTest::newRow(dataTag: "Any") << QHostAddress(QHostAddress::Any) << QHostAddress(QHostAddress::Any);
886 else
887 QTest::newRow(dataTag: "Any") << QHostAddress(QHostAddress::Any) << QHostAddress(QHostAddress::AnyIPv4);
888 QTest::newRow(dataTag: "AnyIPv4") << QHostAddress(QHostAddress::AnyIPv4) << QHostAddress(QHostAddress::AnyIPv4);
889 if (QtNetworkSettings::hasIPv6())
890 QTest::newRow(dataTag: "AnyIPv6") << QHostAddress(QHostAddress::AnyIPv6) << QHostAddress(QHostAddress::AnyIPv6);
891 foreach (const QNetworkInterface &iface, QNetworkInterface::allInterfaces()) {
892 if ((iface.flags() & QNetworkInterface::IsUp) == 0)
893 continue;
894 foreach (const QNetworkAddressEntry &entry, iface.addressEntries()) {
895 QTest::newRow(qPrintable(entry.ip().toString())) << entry.ip() << entry.ip();
896 }
897 }
898}
899
900void tst_QTcpServer::serverAddress()
901{
902 QFETCH_GLOBAL(bool, setProxy);
903 if (setProxy)
904 return;
905
906 QFETCH(QHostAddress, listenAddress);
907 QFETCH(QHostAddress, serverAddress);
908 QTcpServer server;
909
910 if (shouldSkipIpv6TestsForBrokenGetsockopt()
911 && listenAddress == QHostAddress(QHostAddress::Any)) {
912 QSKIP("Syscalls needed for ipv6 sockoptions missing functionality");
913 }
914
915 // TODO: why does this QSKIP?
916 if (!server.listen(address: listenAddress))
917 QSKIP(qPrintable(server.errorString()));
918 QCOMPARE(server.serverAddress(), serverAddress);
919}
920
921// on OS X, calling listen() multiple times would succeed each time, which is
922// most definitely not wanted.
923void tst_QTcpServer::qtbug6305()
924{
925 QFETCH_GLOBAL(bool, setProxy);
926 if (setProxy)
927 return;
928
929 QFETCH(QHostAddress, listenAddress);
930
931 QTcpServer server;
932 QVERIFY2(server.listen(listenAddress), qPrintable(server.errorString()));
933
934 QTcpServer server2;
935 QVERIFY(!server2.listen(listenAddress, server.serverPort())); // second listen should fail
936}
937
938void tst_QTcpServer::linkLocal()
939{
940 QFETCH_GLOBAL(bool, setProxy);
941 if (setProxy)
942 return;
943
944 QList <QHostAddress> addresses;
945 QSet <QString> scopes;
946 QHostAddress localMaskv4("169.254.0.0");
947 QHostAddress localMaskv6("fe80::");
948 foreach (const QNetworkInterface& iface, QNetworkInterface::allInterfaces()) {
949 //Windows preallocates link local addresses to interfaces that are down.
950 //These may or may not work depending on network driver (they do not work for the Bluetooth PAN driver)
951 if (iface.flags() & QNetworkInterface::IsUp) {
952#if defined(Q_OS_WIN)
953 // Do not connect to the Teredo Tunneling interface on Windows Xp.
954 if (iface.humanReadableName() == QString("Teredo Tunneling Pseudo-Interface"))
955 continue;
956#elif defined(Q_OS_DARWIN)
957 // Do not add "utun" interfaces on macOS: nothing ever gets received
958 // (we don't know why)
959 if (iface.name().startsWith("utun"))
960 continue;
961#endif
962 foreach (QNetworkAddressEntry addressEntry, iface.addressEntries()) {
963 QHostAddress addr = addressEntry.ip();
964 if (addr.isInSubnet(subnet: localMaskv4, netmask: 16)) {
965 addresses << addr;
966 qDebug() << addr;
967 }
968 else if (!addr.scopeId().isEmpty() && addr.isInSubnet(subnet: localMaskv6, netmask: 64)) {
969 scopes << addr.scopeId();
970 addresses << addr;
971 qDebug() << addr;
972 }
973 }
974 }
975 }
976 if (addresses.isEmpty())
977 QSKIP("no link local addresses");
978
979 QList<QTcpServer*> servers;
980 quint16 port = 0;
981 foreach (const QHostAddress& addr, addresses) {
982 QTcpServer *server = new QTcpServer;
983 QVERIFY(server->listen(addr, port));
984 port = server->serverPort(); //listen to same port on different interfaces
985 servers << server;
986 }
987
988 QList<QTcpSocket*> clients;
989 foreach (const QHostAddress& addr, addresses) {
990 //unbound socket
991 QTcpSocket *socket = new QTcpSocket;
992 socket->connectToHost(address: addr, port);
993 QVERIFY(socket->waitForConnected(5000));
994 clients << socket;
995 //bound socket
996 socket = new QTcpSocket;
997 QVERIFY(socket->bind(addr));
998 socket->connectToHost(address: addr, port);
999 QVERIFY(socket->waitForConnected(5000));
1000 clients << socket;
1001 }
1002
1003 //each server should have two connections
1004 foreach (QTcpServer* server, servers) {
1005 //qDebug() << "checking for connections" << server->serverAddress() << ":" << server->serverPort();
1006 QVERIFY(server->waitForNewConnection(5000));
1007 QTcpSocket* remote = server->nextPendingConnection();
1008 QVERIFY(remote != nullptr);
1009 remote->close();
1010 delete remote;
1011 if (!server->hasPendingConnections())
1012 QVERIFY(server->waitForNewConnection(5000));
1013 remote = server->nextPendingConnection();
1014 QVERIFY(remote != nullptr);
1015 remote->close();
1016 delete remote;
1017 QVERIFY(!server->hasPendingConnections());
1018 }
1019
1020 //Connecting to the same address with different scope should normally fail
1021 //However it will pass if there are two interfaces connected to the same physical network,
1022 //e.g. connected via wired and wireless interfaces, or two wired NICs.
1023 //which is a reasonably common case.
1024 //So this is not auto tested.
1025
1026 qDeleteAll(c: clients);
1027 qDeleteAll(c: servers);
1028}
1029
1030void tst_QTcpServer::eagainBlockingAccept()
1031{
1032 QTcpServer server;
1033 server.listen(address: QHostAddress::LocalHost, port: 7896);
1034
1035 // Receiving a new connection causes TemporaryError, but shouldn't pause accepting.
1036 QTcpSocket s;
1037 s.connectToHost(address: QHostAddress::LocalHost, port: 7896);
1038 QSignalSpy spy(&server, SIGNAL(newConnection()));
1039 QTRY_COMPARE_WITH_TIMEOUT(spy.count(), 1, 500);
1040 s.close();
1041
1042 // To test try again, should connect just fine.
1043 s.connectToHost(address: QHostAddress::LocalHost, port: 7896);
1044 QTRY_COMPARE_WITH_TIMEOUT(spy.count(), 2, 500);
1045 s.close();
1046 server.close();
1047}
1048
1049class NonListeningTcpServer : public QTcpServer
1050{
1051public:
1052 void addSocketFromOutside(QTcpSocket* s)
1053 {
1054 addPendingConnection(socket: s);
1055 }
1056};
1057
1058void tst_QTcpServer::canAccessPendingConnectionsWhileNotListening()
1059{
1060 NonListeningTcpServer server;
1061 QTcpSocket socket;
1062 server.addSocketFromOutside(s: &socket);
1063 QCOMPARE(&socket, server.nextPendingConnection());
1064}
1065
1066QTEST_MAIN(tst_QTcpServer)
1067#include "tst_qtcpserver.moc"
1068

source code of qtbase/tests/auto/network/socket/qtcpserver/tst_qtcpserver.cpp