1/****************************************************************************
2**
3** Copyright (C) 2016 The Qt Company Ltd.
4** Copyright (C) 2017 Intel Corporation.
5** Contact: https://www.qt.io/licensing/
6**
7** This file is part of the test suite of the Qt Toolkit.
8**
9** $QT_BEGIN_LICENSE:GPL-EXCEPT$
10** Commercial License Usage
11** Licensees holding valid commercial Qt licenses may use this file in
12** accordance with the commercial license agreement provided with the
13** Software or, alternatively, in accordance with the terms contained in
14** a written agreement between you and The Qt Company. For licensing terms
15** and conditions see https://www.qt.io/terms-conditions. For further
16** information use the contact form at https://www.qt.io/contact-us.
17**
18** GNU General Public License Usage
19** Alternatively, this file may be used under the terms of the GNU
20** General Public License version 3 as published by the Free Software
21** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
22** included in the packaging of this file. Please review the following
23** information to ensure the GNU General Public License requirements will
24** be met: https://www.gnu.org/licenses/gpl-3.0.html.
25**
26** $QT_END_LICENSE$
27**
28****************************************************************************/
29
30#include <qglobal.h>
31
32// To prevent windows system header files from re-defining min/max
33#define NOMINMAX 1
34#if defined(_WIN32)
35#include <winsock2.h>
36#else
37#include <sys/types.h>
38#include <sys/socket.h>
39#include <fcntl.h>
40#include <unistd.h>
41#define SOCKET int
42#define INVALID_SOCKET -1
43#endif
44
45#include <qplatformdefs.h>
46
47#include <QtTest/QtTest>
48
49#include <QAuthenticator>
50#include <QCoreApplication>
51#include <QEventLoop>
52#include <QFile>
53#include <QHostAddress>
54#include <QHostInfo>
55#include <QMap>
56#include <QPointer>
57#if QT_CONFIG(process)
58# include <QProcess>
59#endif
60#include <QRandomGenerator>
61#include <QStringList>
62#include <QTcpServer>
63#include <QTcpSocket>
64#ifndef QT_NO_SSL
65#include <QSslSocket>
66#endif
67#include <QTextStream>
68#include <QThread>
69#include <QElapsedTimer>
70#include <QTimer>
71#include <QDebug>
72// RVCT compiles also unused inline methods
73# include <QNetworkProxy>
74
75#include <time.h>
76#ifdef Q_OS_LINUX
77#include <stdio.h>
78#include <stdlib.h>
79#include <sys/stat.h>
80#include <unistd.h>
81#endif
82
83#include <memory>
84
85#include "private/qhostinfo_p.h"
86
87#include "../../../network-settings.h"
88
89QT_FORWARD_DECLARE_CLASS(QTcpSocket)
90class SocketPair;
91
92class tst_QTcpSocket : public QObject
93{
94 Q_OBJECT
95
96public:
97 tst_QTcpSocket();
98
99 static void enterLoop(int secs)
100 {
101 ++loopLevel;
102 QTestEventLoop::instance().enterLoop(secs);
103 --loopLevel;
104 }
105 static void exitLoop()
106 {
107 // Safe exit - if we aren't in an event loop, don't
108 // exit one.
109 if (loopLevel > 0)
110 QTestEventLoop::instance().exitLoop();
111 }
112 static bool timeout()
113 {
114 return QTestEventLoop::instance().timeout();
115 }
116
117public slots:
118 void initTestCase_data();
119 void initTestCase();
120 void init();
121 void cleanup();
122private slots:
123 void socketsConstructedBeforeEventLoop();
124 void constructing();
125 void bind_data();
126 void bind();
127 void bindThenResolveHost_data();
128 void bindThenResolveHost();
129 void setInvalidSocketDescriptor();
130#ifndef Q_OS_WINRT
131 void setSocketDescriptor();
132#endif
133 void socketDescriptor();
134 void blockingIMAP();
135 void nonBlockingIMAP();
136 void hostNotFound();
137 void timeoutConnect_data();
138 void timeoutConnect();
139 void delayedClose();
140 void partialRead();
141 void unget();
142 void readAllAfterClose();
143 void openCloseOpenClose();
144 void connectDisconnectConnectDisconnect();
145 void disconnectWhileConnecting_data();
146 void disconnectWhileConnecting();
147 void disconnectWhileConnectingNoEventLoop_data();
148 void disconnectWhileConnectingNoEventLoop();
149 void disconnectWhileLookingUp_data();
150 void disconnectWhileLookingUp();
151 void downloadBigFile();
152 void readLine();
153 void readLineString();
154 void readChunks();
155 void waitForBytesWritten();
156 void waitForBytesWrittenMinusOne();
157 void waitForReadyRead();
158 void waitForReadyReadMinusOne();
159 void flush();
160 void synchronousApi();
161 void dontCloseOnTimeout();
162 void recursiveReadyRead();
163 void atEnd();
164 void socketInAThread();
165 void socketsInThreads();
166 void waitForReadyReadInASlot();
167 void remoteCloseError();
168 void nestedEventLoopInErrorSlot();
169 void connectToHostError_data();
170 void connectToHostError();
171 void waitForConnectedInHostLookupSlot();
172 void waitForConnectedInHostLookupSlot2();
173 void readyReadSignalsAfterWaitForReadyRead();
174#ifdef Q_OS_LINUX
175 void linuxKernelBugLocalSocket();
176#endif
177 void abortiveClose();
178 void localAddressEmptyOnBSD();
179 void zeroAndMinusOneReturns();
180 void connectionRefused();
181 void suddenRemoteDisconnect_data();
182 void suddenRemoteDisconnect();
183 void connectToMultiIP();
184 void moveToThread0();
185 void increaseReadBufferSize();
186 void increaseReadBufferSizeFromSlot();
187 void taskQtBug5799ConnectionErrorWaitForConnected();
188 void taskQtBug5799ConnectionErrorEventLoop();
189 void taskQtBug7054TimeoutErrorResetting();
190
191#ifndef QT_NO_NETWORKPROXY
192 void invalidProxy_data();
193 void invalidProxy();
194 void proxyFactory_data();
195 void proxyFactory();
196#endif // !QT_NO_NETWORKPROXY
197
198 void qtbug14268_peek();
199
200 void setSocketOption();
201 void clientSendDataOnDelayedDisconnect();
202 void serverDisconnectWithBuffered();
203 void socketDiscardDataInWriteMode();
204 void writeOnReadBufferOverflow();
205 void readNotificationsAfterBind();
206
207protected slots:
208 void nonBlockingIMAP_hostFound();
209 void nonBlockingIMAP_connected();
210 void nonBlockingIMAP_closed();
211 void nonBlockingIMAP_readyRead();
212 void nonBlockingIMAP_bytesWritten(qint64);
213 void readRegularFile_readyRead();
214 void exitLoopSlot();
215 void downloadBigFileSlot();
216 void recursiveReadyReadSlot();
217 void waitForReadyReadInASlotSlot();
218 void enterLoopSlot();
219 void hostLookupSlot();
220 void abortiveClose_abortSlot();
221 void remoteCloseErrorSlot();
222#ifndef QT_NO_NETWORKPROXY
223 void proxyAuthenticationRequired(const QNetworkProxy &, QAuthenticator *auth);
224#endif
225 void earlySocketBytesSent(qint64 bytes);
226 void earlySocketReadyRead();
227 void slotIncreaseReadBufferSizeReadyRead();
228
229private:
230 QByteArray expectedReplyIMAP();
231 void fetchExpectedReplyIMAP();
232 QTcpSocket *newSocket() const;
233 QTcpSocket *nonBlockingIMAP_socket;
234 QStringList nonBlockingIMAP_data;
235 qint64 nonBlockingIMAP_totalWritten;
236
237 QTcpSocket *tmpSocket;
238 qint64 bytesAvailable;
239 qint64 expectedLength;
240 bool readingBody;
241
242 QByteArray expectedReplyIMAP_cached;
243
244 mutable int proxyAuthCalled;
245
246 static int loopLevel;
247
248 SocketPair *earlyConstructedSockets;
249 int earlyBytesWrittenCount;
250 int earlyReadyReadCount;
251 QString stressTestDir;
252
253 QString firstFailName;
254 QHostInfo firstFailInfo;
255};
256
257enum ProxyTests {
258 NoProxy = 0x00,
259 Socks5Proxy = 0x01,
260 HttpProxy = 0x02,
261 TypeMask = 0x0f,
262
263 NoAuth = 0x00,
264 AuthBasic = 0x10,
265 AuthNtlm = 0x20,
266 AuthMask = 0xf0
267};
268
269int tst_QTcpSocket::loopLevel = 0;
270
271class SocketPair: public QObject
272{
273 Q_OBJECT
274public:
275 QTcpSocket *endPoints[2];
276
277 SocketPair(QObject *parent = 0)
278 : QObject(parent)
279 {
280 endPoints[0] = endPoints[1] = 0;
281 }
282
283 bool create()
284 {
285 QTcpServer server;
286 server.listen();
287
288 QTcpSocket *active = new QTcpSocket(this);
289 active->connectToHost(hostName: "127.0.0.1", port: server.serverPort());
290
291 if (!active->waitForConnected(msecs: 1000))
292 return false;
293
294 if (!server.waitForNewConnection(msec: 1000))
295 return false;
296
297 QTcpSocket *passive = server.nextPendingConnection();
298 passive->setParent(this);
299
300 endPoints[0] = active;
301 endPoints[1] = passive;
302 return true;
303 }
304};
305
306tst_QTcpSocket::tst_QTcpSocket()
307 : firstFailName("qt-test-server-first-fail")
308{
309 tmpSocket = 0;
310
311 //This code relates to the socketsConstructedBeforeEventLoop test case
312 earlyConstructedSockets = new SocketPair;
313 QVERIFY(earlyConstructedSockets->create());
314 earlyBytesWrittenCount = 0;
315 earlyReadyReadCount = 0;
316 connect(sender: earlyConstructedSockets->endPoints[0], SIGNAL(readyRead()), receiver: this, SLOT(earlySocketReadyRead()));
317 connect(sender: earlyConstructedSockets->endPoints[1], SIGNAL(bytesWritten(qint64)), receiver: this, SLOT(earlySocketBytesSent(qint64)));
318 earlyConstructedSockets->endPoints[1]->write(data: "hello work");
319
320 firstFailInfo.setAddresses(QList<QHostAddress>() << QHostAddress("224.0.0.0") << QtNetworkSettings::httpServerIp());
321}
322
323void tst_QTcpSocket::initTestCase_data()
324{
325 QTest::addColumn<bool>(name: "setProxy");
326 QTest::addColumn<int>(name: "proxyType");
327 QTest::addColumn<bool>(name: "ssl");
328
329 QTest::newRow(dataTag: "WithoutProxy") << false << 0 << false;
330 QTest::newRow(dataTag: "WithSocks5Proxy") << true << int(Socks5Proxy) << false;
331 QTest::newRow(dataTag: "WithSocks5ProxyAuth") << true << int(Socks5Proxy | AuthBasic) << false;
332
333 QTest::newRow(dataTag: "WithHttpProxy") << true << int(HttpProxy) << false;
334 QTest::newRow(dataTag: "WithHttpProxyBasicAuth") << true << int(HttpProxy | AuthBasic) << false;
335// QTest::newRow("WithHttpProxyNtlmAuth") << true << int(HttpProxy | AuthNtlm) << false;
336
337#ifndef QT_NO_SSL
338 QTest::newRow(dataTag: "WithoutProxy SSL") << false << 0 << true;
339 QTest::newRow(dataTag: "WithSocks5Proxy SSL") << true << int(Socks5Proxy) << true;
340 QTest::newRow(dataTag: "WithSocks5AuthProxy SSL") << true << int(Socks5Proxy | AuthBasic) << true;
341
342 QTest::newRow(dataTag: "WithHttpProxy SSL") << true << int(HttpProxy) << true;
343 QTest::newRow(dataTag: "WithHttpProxyBasicAuth SSL") << true << int(HttpProxy | AuthBasic) << true;
344// QTest::newRow("WithHttpProxyNtlmAuth SSL") << true << int(HttpProxy | AuthNtlm) << true;
345#endif
346
347 stressTestDir = QFINDTESTDATA("stressTest");
348 QVERIFY2(!stressTestDir.isEmpty(), qPrintable(
349 QString::fromLatin1("Couldn't find stressTest dir starting from %1.").arg(QDir::currentPath())));
350}
351
352void tst_QTcpSocket::initTestCase()
353{
354#ifdef QT_TEST_SERVER
355 QVERIFY(QtNetworkSettings::verifyConnection(QtNetworkSettings::httpServerName(), 80));
356 QVERIFY(QtNetworkSettings::verifyConnection(QtNetworkSettings::httpProxyServerName(), 3128));
357 QVERIFY(QtNetworkSettings::verifyConnection(QtNetworkSettings::imapServerName(), 143));
358 //QVERIFY(QtNetworkSettings::verifyConnection(QtNetworkSettings::firewallServerName(), 1357));
359 QVERIFY(QtNetworkSettings::verifyConnection(QtNetworkSettings::socksProxyServerName(), 1080));
360 QVERIFY(QtNetworkSettings::verifyConnection(QtNetworkSettings::ftpServerName(), 21));
361 QVERIFY(QtNetworkSettings::verifyConnection(QtNetworkSettings::ftpProxyServerName(), 2121));
362#else
363 if (!QtNetworkSettings::verifyTestNetworkSettings())
364 QSKIP("No network test server available");
365#endif
366}
367
368void tst_QTcpSocket::init()
369{
370 QFETCH_GLOBAL(bool, setProxy);
371 if (setProxy) {
372#ifndef QT_NO_NETWORKPROXY
373 QFETCH_GLOBAL(int, proxyType);
374 QList<QHostAddress> socks5Addresses = QHostInfo::fromName(name: QtNetworkSettings::socksProxyServerName()).addresses();
375 QList<QHostAddress> httpProxyAddresses = QHostInfo::fromName(name: QtNetworkSettings::httpProxyServerName()).addresses();
376 QVERIFY2(socks5Addresses.count() > 0, "failed to get ip address for SOCKS5 proxy server");
377 QVERIFY2(httpProxyAddresses.count() > 0, "failed to get ip address for HTTP proxy server");
378 QString socks5Address = socks5Addresses.first().toString();
379 QString httpProxyAddress = httpProxyAddresses.first().toString();
380 QNetworkProxy proxy;
381
382 switch (proxyType) {
383 case Socks5Proxy:
384 proxy = QNetworkProxy(QNetworkProxy::Socks5Proxy, socks5Address, 1080);
385 break;
386
387 case Socks5Proxy | AuthBasic:
388 proxy = QNetworkProxy(QNetworkProxy::Socks5Proxy, socks5Address, 1081);
389 break;
390
391 case HttpProxy | NoAuth:
392 proxy = QNetworkProxy(QNetworkProxy::HttpProxy, httpProxyAddress, 3128);
393 break;
394
395 case HttpProxy | AuthBasic:
396 proxy = QNetworkProxy(QNetworkProxy::HttpProxy, httpProxyAddress, 3129);
397 break;
398
399 case HttpProxy | AuthNtlm:
400 proxy = QNetworkProxy(QNetworkProxy::HttpProxy, httpProxyAddress, 3130);
401 break;
402 }
403 QNetworkProxy::setApplicationProxy(proxy);
404#else // !QT_NO_NETWORKPROXY
405 QSKIP("No proxy support");
406#endif // QT_NO_NETWORKPROXY
407 }
408
409 qt_qhostinfo_clear_cache();
410 qt_qhostinfo_cache_inject(hostname: firstFailName, resolution: firstFailInfo);
411}
412
413QTcpSocket *tst_QTcpSocket::newSocket() const
414{
415 QTcpSocket *socket;
416#ifndef QT_NO_SSL
417 QFETCH_GLOBAL(bool, ssl);
418 socket = ssl ? new QSslSocket : new QTcpSocket;
419#else
420 socket = new QTcpSocket;
421#endif
422
423 proxyAuthCalled = 0;
424 connect(asender: socket, SIGNAL(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)),
425 SLOT(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)),
426 atype: Qt::DirectConnection);
427 return socket;
428}
429
430void tst_QTcpSocket::cleanup()
431{
432#ifndef QT_NO_NETWORKPROXY
433 QNetworkProxy::setApplicationProxy(QNetworkProxy::DefaultProxy);
434#endif
435}
436
437#ifndef QT_NO_NETWORKPROXY
438void tst_QTcpSocket::proxyAuthenticationRequired(const QNetworkProxy &, QAuthenticator *auth)
439{
440 ++proxyAuthCalled;
441 auth->setUser("qsockstest");
442 auth->setPassword("password");
443}
444#endif // !QT_NO_NETWORKPROXY
445
446//----------------------------------------------------------------------------------
447
448void tst_QTcpSocket::socketsConstructedBeforeEventLoop()
449{
450 QFETCH_GLOBAL(bool, setProxy);
451 QFETCH_GLOBAL(bool, ssl);
452 if (setProxy || ssl)
453 return;
454 //This test checks that sockets constructed before QCoreApplication::exec() still emit signals
455 //see construction code in the tst_QTcpSocket constructor
456 enterLoop(secs: 3);
457 QCOMPARE(earlyBytesWrittenCount, 1);
458 QCOMPARE(earlyReadyReadCount, 1);
459 earlyConstructedSockets->endPoints[0]->close();
460 earlyConstructedSockets->endPoints[1]->close();
461}
462
463void tst_QTcpSocket::earlySocketBytesSent(qint64 /* bytes */)
464{
465 earlyBytesWrittenCount++;
466}
467
468void tst_QTcpSocket::earlySocketReadyRead()
469{
470 earlyReadyReadCount++;
471}
472
473//----------------------------------------------------------------------------------
474
475void tst_QTcpSocket::constructing()
476{
477 QTcpSocket *socket = newSocket();
478
479 // Check the initial state of the QTcpSocket.
480 QCOMPARE(socket->state(), QTcpSocket::UnconnectedState);
481 QVERIFY(socket->isSequential());
482 QVERIFY(!socket->isOpen());
483 QVERIFY(!socket->isValid());
484 QCOMPARE(socket->socketType(), QTcpSocket::TcpSocket);
485
486 char c;
487 QCOMPARE(socket->getChar(&c), false);
488 QCOMPARE((int) socket->bytesAvailable(), 0);
489 QCOMPARE(socket->canReadLine(), false);
490 QCOMPARE(socket->readLine(), QByteArray());
491 QCOMPARE(socket->socketDescriptor(), (qintptr)-1);
492 QCOMPARE((int) socket->localPort(), 0);
493 QCOMPARE(socket->localAddress(), QHostAddress());
494 QCOMPARE((int) socket->peerPort(), 0);
495 QCOMPARE(socket->peerAddress(), QHostAddress());
496 QCOMPARE(socket->readChannelCount(), 0);
497 QCOMPARE(socket->writeChannelCount(), 0);
498 QCOMPARE(socket->error(), QTcpSocket::UnknownSocketError);
499 QCOMPARE(socket->errorString(), QString("Unknown error"));
500
501 // Check the state of the socket layer?
502 delete socket;
503}
504
505//----------------------------------------------------------------------------------
506
507void tst_QTcpSocket::bind_data()
508{
509 QTest::addColumn<QString>(name: "stringAddr");
510 QTest::addColumn<int>(name: "port");
511 QTest::addColumn<bool>(name: "successExpected");
512 QTest::addColumn<QString>(name: "stringExpectedLocalAddress");
513
514 bool testIpv6 = false;
515
516 // iterate all interfaces, add all addresses on them as test data
517 QList<QNetworkInterface> interfaces = QNetworkInterface::allInterfaces();
518 foreach (const QNetworkInterface &netinterface, interfaces) {
519 if (!netinterface.isValid())
520 continue;
521
522 foreach (const QNetworkAddressEntry &entry, netinterface.addressEntries()) {
523 if (entry.ip().isInSubnet(subnet: QHostAddress::parseSubnet(subnet: "fe80::/10"))
524 || entry.ip().isInSubnet(subnet: QHostAddress::parseSubnet(subnet: "169.254/16")))
525 continue; // link-local bind will fail, at least on Linux, so skip it.
526
527 QString ip(entry.ip().toString());
528 QTest::addRow(format: "%s:0", ip.toLatin1().constData()) << ip << 0 << true << ip;
529
530 if (!testIpv6 && entry.ip().protocol() == QAbstractSocket::IPv6Protocol)
531 testIpv6 = true;
532 }
533 }
534
535 // test binding to localhost
536 QTest::newRow(dataTag: "0.0.0.0:0") << "0.0.0.0" << 0 << true << "0.0.0.0";
537 if (testIpv6)
538 QTest::newRow(dataTag: "[::]:0") << "::" << 0 << true << "::";
539
540 // and binding with a port number...
541 // Since we want to test that we got the port number we asked for, we need a random port number.
542 // We use random in case a previous run of the test left the port lingering open.
543 // -1 indicates "random port"
544 QTest::newRow(dataTag: "0.0.0.0:randomport") << "0.0.0.0" << -1 << true << "0.0.0.0";
545 if (testIpv6)
546 QTest::newRow(dataTag: "[::]:randomport") << "::" << -1 << true << "::";
547
548 // additionally, try bind to known-bad addresses, and make sure this doesn't work
549 // these ranges are guaranteed to be reserved for 'documentation purposes',
550 // and thus, should be unused in the real world. Not that I'm assuming the
551 // world is full of competent administrators, or anything.
552 QStringList knownBad;
553 knownBad << "198.51.100.1";
554 knownBad << "2001:0DB8::1";
555 foreach (const QString &badAddress, knownBad) {
556 QTest::addRow(format: "%s:0", badAddress.toLatin1().constData()) << badAddress << 0 << false << QString();
557 }
558
559 // try to bind to a privileged ports
560 // we should fail if we're not root (unless the ports are in use!)
561#ifdef Q_OS_DARWIN
562 // Alas, some quirk (starting from macOS 10.14): bind with port number 1
563 // fails with IPv4 (not IPv6 though, see below).
564 QTest::newRow("127.0.0.1:1") << "127.0.0.1" << 1 << false << QString();
565#else
566 QTest::newRow(dataTag: "127.0.0.1:1") << "127.0.0.1" << 1 << QtNetworkSettings::canBindToLowPorts()
567 << (QtNetworkSettings::canBindToLowPorts() ? "127.0.0.1" : QString());
568#endif // Q_OS_DARWIN
569 if (testIpv6)
570 QTest::newRow(dataTag: "[::]:1") << "::" << 1 << QtNetworkSettings::canBindToLowPorts()
571 << (QtNetworkSettings::canBindToLowPorts() ? "::" : QString());
572}
573
574void tst_QTcpSocket::bind()
575{
576 QFETCH_GLOBAL(bool, setProxy);
577 if (setProxy)
578 return; // QTBUG-22964 for proxies, QTBUG-29972 for QSKIP
579 QFETCH(QString, stringAddr);
580 QFETCH(int, port);
581 QFETCH(bool, successExpected);
582 QFETCH(QString, stringExpectedLocalAddress);
583
584 QHostAddress addr(stringAddr);
585 QHostAddress expectedLocalAddress(stringExpectedLocalAddress);
586
587 QTcpSocket dummySocket; // used only to "use up" a file descriptor
588 dummySocket.bind();
589
590 std::unique_ptr<QTcpSocket> socket(newSocket());
591 quint16 boundPort;
592 qintptr fd;
593
594 if (successExpected) {
595 bool randomPort = port == -1;
596 int attemptsLeft = 5; // only used with randomPort or Windows
597 do {
598 if (randomPort) {
599 // try to get a random port number
600 // we do this to ensure we're not trying to bind to the same port as we've just used in
601 // a previous run - race condition with the OS actually freeing the port
602 port = QRandomGenerator::global()->generate() & USHRT_MAX;
603 if (port < 1024)
604 continue;
605 }
606
607 bool bindSuccess = socket->bind(address: addr, port);
608 if (!bindSuccess && randomPort && socket->error() == QTcpSocket::AddressInUseError) {
609 // we may have been unlucky and hit an already open port, so try another
610 --attemptsLeft;
611 continue;
612 }
613
614 QVERIFY2(bindSuccess, qPrintable(socket->errorString() + ", tried port " + QString::number(port)));
615 break;
616 } while (randomPort && attemptsLeft);
617
618 QCOMPARE(socket->state(), QAbstractSocket::BoundState);
619 QCOMPARE(socket->readChannelCount(), 0);
620 QCOMPARE(socket->writeChannelCount(), 0);
621 boundPort = socket->localPort();
622 if (port)
623 QCOMPARE(int(boundPort), port);
624 fd = socket->socketDescriptor();
625 QVERIFY(fd != qintptr(INVALID_SOCKET));
626 } else {
627 QVERIFY(!socket->bind(addr, port));
628 QCOMPARE(socket->localPort(), quint16(0));
629 }
630
631 QCOMPARE(socket->localAddress(), expectedLocalAddress);
632
633 if (successExpected) {
634 // try to use the socket and expect it to remain working
635 QTcpServer server;
636 QVERIFY(server.listen(addr));
637
638 // free up the file descriptor
639 dummySocket.close();
640
641 QHostAddress remoteAddr = addr;
642 if (addr == QHostAddress::AnyIPv4)
643 remoteAddr = QHostAddress::LocalHost;
644 else if (addr == QHostAddress::AnyIPv6)
645 remoteAddr = QHostAddress::LocalHostIPv6;
646
647 socket->connectToHost(address: remoteAddr, port: server.serverPort());
648 QVERIFY2(socket->waitForConnected(2000), socket->errorString().toLocal8Bit());
649 QVERIFY(server.waitForNewConnection(2000));
650
651 QTcpSocket *acceptedSocket = server.nextPendingConnection();
652 QCOMPARE(socket->localPort(), boundPort);
653 QCOMPARE(acceptedSocket->peerPort(), boundPort);
654 QCOMPARE(socket->localAddress(), remoteAddr);
655 QCOMPARE(socket->socketDescriptor(), fd);
656#ifdef Q_OS_DARWIN
657 // Normally, we don't see this problem: macOS sometimes does not
658 // allow us to immediately re-use a port, thinking connection is
659 // still alive. With fixed port 1 (we testing starting from
660 // macOS 10.14), this problem shows, making the test flaky:
661 // we run this 'bind' with port 1 several times (different
662 // test cases) and the problem manifests itself as
663 // "The bound address is already in use, tried port 1".
664 QTestEventLoop cleanupHelper;
665 auto client = socket.get();
666 connect(client, &QTcpSocket::disconnected, [&cleanupHelper, client](){
667 client->close();
668 cleanupHelper.exitLoop();
669 });
670 acceptedSocket->close();
671 cleanupHelper.enterLoopMSecs(100);
672#endif // Q_OS_DARWIN
673 }
674}
675
676//----------------------------------------------------------------------------------
677
678void tst_QTcpSocket::bindThenResolveHost_data()
679{
680 QTest::addColumn<QString>(name: "hostName");
681 QTest::newRow(dataTag: "ip-literal") << QtNetworkSettings::httpServerIp().toString();
682 QTest::newRow(dataTag: "name") << QtNetworkSettings::httpServerName();
683 QTest::newRow(dataTag: "first-fail") << firstFailName;
684}
685
686// similar to the previous test, but we'll connect to a host name that needs resolving
687void tst_QTcpSocket::bindThenResolveHost()
688{
689 QFETCH_GLOBAL(bool, setProxy);
690 if (setProxy)
691 return; // doesn't make sense to test binding locally with proxies
692
693 QFETCH(QString, hostName);
694
695 QTcpSocket dummySocket; // used only to "use up" a file descriptor
696 dummySocket.bind();
697
698 QTcpSocket *socket = newSocket();
699
700 QVERIFY2(socket->bind(QHostAddress(QHostAddress::AnyIPv4), 0), socket->errorString().toLocal8Bit());
701 QCOMPARE(socket->state(), QAbstractSocket::BoundState);
702 quint16 boundPort = socket->localPort();
703 qintptr fd = socket->socketDescriptor();
704 QVERIFY(fd != quint16(INVALID_SOCKET));
705
706 dummySocket.close();
707
708 const quint16 port = 80;
709 socket->connectToHost(hostName, port);
710 // Additionally, initiate a delayed close before the socket connects
711 // to ensure that we don't lose the socket engine in HostLookupState.
712 // After a connection has been established, socket should send all
713 // the pending data and close the socket engine automatically.
714 QVERIFY(socket->putChar(0));
715 socket->close();
716 QVERIFY2(socket->waitForConnected(), (hostName.toLocal8Bit() + ": " + QByteArray::number(port) + ' '
717 + QtNetworkSettings::msgSocketError(*socket)).constData());
718
719 QCOMPARE(socket->localPort(), boundPort);
720 QCOMPARE(socket->socketDescriptor(), fd);
721
722 delete socket;
723}
724
725//----------------------------------------------------------------------------------
726
727
728void tst_QTcpSocket::setInvalidSocketDescriptor()
729{
730 QTcpSocket *socket = newSocket();
731 QCOMPARE(socket->socketDescriptor(), (qintptr)-1);
732 QVERIFY(!socket->setSocketDescriptor(-5, QTcpSocket::UnconnectedState));
733 QCOMPARE(socket->socketDescriptor(), (qintptr)-1);
734
735 QCOMPARE(socket->error(), QTcpSocket::UnsupportedSocketOperationError);
736
737 delete socket;
738}
739
740//----------------------------------------------------------------------------------
741
742#ifndef Q_OS_WINRT
743void tst_QTcpSocket::setSocketDescriptor()
744{
745 QFETCH_GLOBAL(bool, setProxy);
746 if (setProxy)
747 return; // this test doesn't make sense with proxies
748
749#ifdef Q_OS_WIN
750 // need the dummy to ensure winsock is started
751 QTcpSocket *dummy = newSocket();
752 dummy->connectToHost(QtNetworkSettings::imapServerName(), 143);
753 QVERIFY(dummy->waitForConnected());
754
755 SOCKET sock = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
756 if (sock == INVALID_SOCKET) {
757 qErrnoWarning(WSAGetLastError(), "INVALID_SOCKET");
758 }
759#else
760 SOCKET sock = ::socket(AF_INET, SOCK_STREAM, protocol: 0);
761
762 // artificially increase the value of sock
763 SOCKET sock2 = ::fcntl(fd: sock, F_DUPFD, sock + 50);
764 ::close(fd: sock);
765 sock = sock2;
766#endif
767
768 QVERIFY(sock != INVALID_SOCKET);
769 QTcpSocket *socket = newSocket();
770 QVERIFY(socket->setSocketDescriptor(sock, QTcpSocket::UnconnectedState));
771 QCOMPARE(socket->socketDescriptor(), (qintptr)sock);
772
773 qt_qhostinfo_clear_cache(); //avoid the HostLookupState being skipped due to address being in cache from previous test.
774 socket->connectToHost(hostName: QtNetworkSettings::httpServerName(), port: 80);
775 QCOMPARE(socket->state(), QTcpSocket::HostLookupState);
776 QCOMPARE(socket->socketDescriptor(), (qintptr)sock);
777 QVERIFY(socket->waitForConnected(10000));
778 QCOMPARE(socket->socketDescriptor(), (qintptr)sock);
779 QCOMPARE(socket->readChannelCount(), 1);
780 QCOMPARE(socket->writeChannelCount(), 1);
781 delete socket;
782#ifdef Q_OS_WIN
783 delete dummy;
784#endif
785}
786#endif // !Q_OS_WINRT
787
788//----------------------------------------------------------------------------------
789
790void tst_QTcpSocket::socketDescriptor()
791{
792 QTcpSocket *socket = newSocket();
793
794 QCOMPARE(socket->socketDescriptor(), (qintptr)-1);
795 socket->connectToHost(hostName: QtNetworkSettings::imapServerName(), port: 143);
796 QVERIFY(socket->state() == QAbstractSocket::HostLookupState ||
797 socket->state() == QAbstractSocket::ConnectingState);
798 QVERIFY(socket->waitForConnected(10000));
799 QCOMPARE(socket->state(), QAbstractSocket::ConnectedState);
800 QVERIFY(socket->socketDescriptor() != -1);
801
802 delete socket;
803}
804
805//----------------------------------------------------------------------------------
806
807void tst_QTcpSocket::blockingIMAP()
808{
809 QTcpSocket *socket = newSocket();
810
811 // Connect
812 socket->connectToHost(hostName: QtNetworkSettings::imapServerName(), port: 143);
813 QVERIFY(socket->waitForConnected(10000));
814 QCOMPARE(socket->state(), QTcpSocket::ConnectedState);
815 QVERIFY(socket->isValid());
816 QCOMPARE(socket->readChannelCount(), 1);
817 QCOMPARE(socket->writeChannelCount(), 1);
818
819 // Read greeting
820 QVERIFY(socket->waitForReadyRead(5000));
821 QString s = socket->readLine();
822 // only test if an OK was returned, to make the test compatible between different
823 // IMAP server versions
824 QCOMPARE(s.left(4).toLatin1().constData(), "* OK");
825
826 // Write NOOP
827 QCOMPARE((int) socket->write("1 NOOP\r\n", 8), 8);
828 QCOMPARE((int) socket->write("2 NOOP\r\n", 8), 8);
829
830 if (!socket->canReadLine())
831 QVERIFY(socket->waitForReadyRead(5000));
832
833 // Read response
834 s = socket->readLine();
835 QCOMPARE(s.toLatin1().constData(), "1 OK Completed\r\n");
836
837 // Write a third NOOP to verify that write doesn't clear the read buffer
838 QCOMPARE((int) socket->write("3 NOOP\r\n", 8), 8);
839
840 // Read second response
841 if (!socket->canReadLine())
842 QVERIFY(socket->waitForReadyRead(5000));
843 s = socket->readLine();
844 QCOMPARE(s.toLatin1().constData(), "2 OK Completed\r\n");
845
846 // Read third response
847 if (!socket->canReadLine())
848 QVERIFY(socket->waitForReadyRead(5000));
849 s = socket->readLine();
850 QCOMPARE(s.toLatin1().constData(), "3 OK Completed\r\n");
851
852
853 // Write LOGOUT
854 QCOMPARE((int) socket->write("4 LOGOUT\r\n", 10), 10);
855
856 if (!socket->canReadLine())
857 QVERIFY(socket->waitForReadyRead(5000));
858
859 // Read two lines of respose
860 s = socket->readLine();
861 QCOMPARE(s.toLatin1().constData(), "* BYE LOGOUT received\r\n");
862
863 if (!socket->canReadLine())
864 QVERIFY(socket->waitForReadyRead(5000));
865
866 s = socket->readLine();
867 QCOMPARE(s.toLatin1().constData(), "4 OK Completed\r\n");
868
869 // Close the socket
870 socket->close();
871
872 // Check that it's closed
873 QCOMPARE(socket->state(), QTcpSocket::UnconnectedState);
874 QCOMPARE(socket->readChannelCount(), 0);
875 QCOMPARE(socket->writeChannelCount(), 0);
876
877 delete socket;
878}
879
880//----------------------------------------------------------------------------------
881
882void tst_QTcpSocket::hostNotFound()
883{
884 QTcpSocket *socket = newSocket();
885
886 socket->connectToHost(hostName: "nosuchserver.qt-project.org", port: 80);
887 QVERIFY(!socket->waitForConnected());
888 QCOMPARE(socket->state(), QTcpSocket::UnconnectedState);
889#ifdef QT_TEST_SERVER
890 QFETCH_GLOBAL(bool, setProxy);
891 QFETCH_GLOBAL(int, proxyType);
892 if (setProxy && (proxyType & HttpProxy) == HttpProxy) {
893 QEXPECT_FAIL("", "QTBUG-73953: The version of Squid in the docker container behaves "
894 "differently to the one in the network testing server, returning 503 "
895 "when we expect 404", Continue);
896 }
897#endif
898 QCOMPARE(int(socket->error()), int(QTcpSocket::HostNotFoundError));
899
900 delete socket;
901}
902
903//----------------------------------------------------------------------------------
904void tst_QTcpSocket::timeoutConnect_data()
905{
906 QTest::addColumn<QString>(name: "address");
907 QTest::newRow(dataTag: "host") << QtNetworkSettings::firewallServerName();
908 QTest::newRow(dataTag: "ip") << QtNetworkSettings::firewallServerIp().toString();
909}
910
911void tst_QTcpSocket::timeoutConnect()
912{
913 QFETCH(QString, address);
914 QTcpSocket *socket = newSocket();
915
916 QElapsedTimer timer;
917 timer.start();
918
919 // Port 1357 is configured to drop packets on the test server
920 socket->connectToHost(hostName: address, port: 1357);
921 QVERIFY(timer.elapsed() < 150);
922 QVERIFY(!socket->waitForConnected(1000)); //200ms is too short when using SOCKS proxy authentication
923 QCOMPARE(socket->state(), QTcpSocket::UnconnectedState);
924 QCOMPARE(int(socket->error()), int(QTcpSocket::SocketTimeoutError));
925 QCOMPARE(socket->readChannelCount(), 0);
926 QCOMPARE(socket->writeChannelCount(), 0);
927
928 timer.start();
929 socket->connectToHost(hostName: address, port: 1357);
930 QVERIFY(timer.elapsed() < 150);
931 QTimer::singleShot(msec: 50, receiver: &QTestEventLoop::instance(), SLOT(exitLoop()));
932 QTestEventLoop::instance().enterLoop(secs: 5);
933 QVERIFY(!QTestEventLoop::instance().timeout());
934 QVERIFY(socket->state() == QTcpSocket::ConnectingState
935 || socket->state() == QTcpSocket::HostLookupState);
936 socket->abort();
937 QCOMPARE(socket->state(), QTcpSocket::UnconnectedState);
938 QCOMPARE(socket->openMode(), QIODevice::NotOpen);
939
940 delete socket;
941}
942
943//----------------------------------------------------------------------------------
944
945void tst_QTcpSocket::nonBlockingIMAP()
946{
947 QTcpSocket *socket = newSocket();
948 connect(asender: socket, SIGNAL(hostFound()), SLOT(nonBlockingIMAP_hostFound()));
949 connect(asender: socket, SIGNAL(connected()), SLOT(nonBlockingIMAP_connected()));
950 connect(asender: socket, SIGNAL(disconnected()), SLOT(nonBlockingIMAP_closed()));
951 connect(asender: socket, SIGNAL(bytesWritten(qint64)), SLOT(nonBlockingIMAP_bytesWritten(qint64)));
952 connect(asender: socket, SIGNAL(readyRead()), SLOT(nonBlockingIMAP_readyRead()));
953 nonBlockingIMAP_socket = socket;
954
955 // Connect
956 socket->connectToHost(hostName: QtNetworkSettings::imapServerName(), port: 143);
957 QVERIFY(socket->state() == QTcpSocket::HostLookupState ||
958 socket->state() == QTcpSocket::ConnectingState);
959
960 enterLoop(secs: 30);
961 if (timeout()) {
962 QFAIL("Timed out");
963 }
964
965 if (socket->state() == QTcpSocket::ConnectingState) {
966 enterLoop(secs: 30);
967 if (timeout()) {
968 QFAIL("Timed out");
969 }
970 }
971
972 QCOMPARE(socket->state(), QTcpSocket::ConnectedState);
973 QCOMPARE(socket->readChannelCount(), 1);
974 QCOMPARE(socket->writeChannelCount(), 1);
975
976 enterLoop(secs: 30);
977 if (timeout()) {
978 QFAIL("Timed out");
979 }
980
981 // Read greeting
982 QVERIFY(!nonBlockingIMAP_data.isEmpty());
983 QCOMPARE(nonBlockingIMAP_data.at(0).left(4).toLatin1().constData(), "* OK");
984 nonBlockingIMAP_data.clear();
985
986 nonBlockingIMAP_totalWritten = 0;
987
988 // Write NOOP
989 QCOMPARE((int) socket->write("1 NOOP\r\n", 8), 8);
990
991
992 enterLoop(secs: 30);
993 if (timeout()) {
994 QFAIL("Timed out");
995 }
996
997 QCOMPARE(nonBlockingIMAP_totalWritten, 8);
998
999
1000 enterLoop(secs: 30);
1001 if (timeout()) {
1002 QFAIL("Timed out");
1003 }
1004
1005
1006 // Read response
1007 QVERIFY(!nonBlockingIMAP_data.isEmpty());
1008 QCOMPARE(nonBlockingIMAP_data.at(0).toLatin1().constData(), "1 OK Completed\r\n");
1009 nonBlockingIMAP_data.clear();
1010
1011
1012 nonBlockingIMAP_totalWritten = 0;
1013
1014 // Write LOGOUT
1015 QCOMPARE((int) socket->write("2 LOGOUT\r\n", 10), 10);
1016
1017 enterLoop(secs: 30);
1018 if (timeout()) {
1019 QFAIL("Timed out");
1020 }
1021
1022 QCOMPARE(nonBlockingIMAP_totalWritten, 10);
1023
1024 // Wait for greeting
1025 enterLoop(secs: 30);
1026 if (timeout()) {
1027 QFAIL("Timed out");
1028 }
1029
1030 // Read two lines of respose
1031 QCOMPARE(nonBlockingIMAP_data.at(0).toLatin1().constData(), "* BYE LOGOUT received\r\n");
1032 QCOMPARE(nonBlockingIMAP_data.at(1).toLatin1().constData(), "2 OK Completed\r\n");
1033 nonBlockingIMAP_data.clear();
1034
1035 // Close the socket
1036 socket->close();
1037
1038 // Check that it's closed
1039 QCOMPARE(socket->state(), QTcpSocket::UnconnectedState);
1040 QCOMPARE(socket->readChannelCount(), 0);
1041 QCOMPARE(socket->writeChannelCount(), 0);
1042
1043 delete socket;
1044}
1045
1046void tst_QTcpSocket::nonBlockingIMAP_hostFound()
1047{
1048 exitLoop();
1049}
1050
1051void tst_QTcpSocket::nonBlockingIMAP_connected()
1052{
1053 exitLoop();
1054}
1055
1056void tst_QTcpSocket::nonBlockingIMAP_readyRead()
1057{
1058 while (nonBlockingIMAP_socket->canReadLine())
1059 nonBlockingIMAP_data.append(t: nonBlockingIMAP_socket->readLine());
1060
1061 exitLoop();
1062}
1063
1064void tst_QTcpSocket::nonBlockingIMAP_bytesWritten(qint64 written)
1065{
1066 nonBlockingIMAP_totalWritten += written;
1067 exitLoop();
1068}
1069
1070void tst_QTcpSocket::nonBlockingIMAP_closed()
1071{
1072}
1073
1074//----------------------------------------------------------------------------------
1075
1076void tst_QTcpSocket::delayedClose()
1077{
1078 QTcpSocket *socket = newSocket();
1079 connect(asender: socket, SIGNAL(connected()), SLOT(nonBlockingIMAP_connected()));
1080 connect(asender: socket, SIGNAL(disconnected()), SLOT(exitLoopSlot()));
1081
1082 socket->connectToHost(hostName: QtNetworkSettings::imapServerName(), port: 143);
1083
1084 enterLoop(secs: 30);
1085 if (timeout())
1086 QFAIL("Timed out");
1087
1088 QCOMPARE(socket->state(), QTcpSocket::ConnectedState);
1089
1090 QCOMPARE((int) socket->write("1 LOGOUT\r\n", 10), 10);
1091
1092 // Add a huge bulk of data to be written after the logout
1093 // command. The server will shut down after receiving the LOGOUT,
1094 // so this data will not be read. But our close call should
1095 // schedule a delayed close because all the data can not be
1096 // written in one go.
1097 QCOMPARE((int) socket->write(QByteArray(100000, '\n'), 100000), 100000);
1098
1099 socket->close();
1100
1101 QCOMPARE((int) socket->state(), (int) QTcpSocket::ClosingState);
1102
1103 enterLoop(secs: 10);
1104 if (timeout())
1105 QFAIL("Timed out");
1106
1107 QCOMPARE(socket->state(), QTcpSocket::UnconnectedState);
1108
1109 delete socket;
1110}
1111
1112
1113//----------------------------------------------------------------------------------
1114
1115QByteArray tst_QTcpSocket::expectedReplyIMAP()
1116{
1117 if (expectedReplyIMAP_cached.isEmpty()) {
1118 fetchExpectedReplyIMAP();
1119 }
1120
1121 return expectedReplyIMAP_cached;
1122}
1123
1124// Figure out how the current IMAP server responds
1125void tst_QTcpSocket::fetchExpectedReplyIMAP()
1126{
1127 QTcpSocket *socket = newSocket();
1128 socket->connectToHost(hostName: QtNetworkSettings::imapServerName(), port: 143);
1129 QVERIFY2(socket->waitForConnected(10000), qPrintable(socket->errorString()));
1130 QVERIFY2(socket->state() == QTcpSocket::ConnectedState, qPrintable(socket->errorString()));
1131
1132 QTRY_VERIFY(socket->canReadLine());
1133
1134 QByteArray greeting = socket->readLine();
1135 delete socket;
1136
1137 QVERIFY2(QtNetworkSettings::compareReplyIMAP(greeting), greeting.constData());
1138
1139 expectedReplyIMAP_cached = greeting;
1140}
1141
1142//----------------------------------------------------------------------------------
1143
1144void tst_QTcpSocket::partialRead()
1145{
1146 QTcpSocket *socket = newSocket();
1147 socket->connectToHost(hostName: QtNetworkSettings::imapServerName(), port: 143);
1148 QVERIFY(socket->waitForConnected(10000));
1149 QCOMPARE(socket->state(), QTcpSocket::ConnectedState);
1150 char buf[512];
1151
1152 QByteArray greeting = expectedReplyIMAP();
1153 QVERIFY(!greeting.isEmpty());
1154
1155 for (int i = 0; i < 10; i += 2) {
1156 while (socket->bytesAvailable() < 2)
1157 QVERIFY(socket->waitForReadyRead(5000));
1158 QVERIFY(socket->read(buf, 2) == 2);
1159 buf[2] = '\0';
1160 QCOMPARE((char *)buf, greeting.mid(i, 2).data());
1161 }
1162
1163 delete socket;
1164}
1165
1166//----------------------------------------------------------------------------------
1167
1168void tst_QTcpSocket::unget()
1169{
1170 QTcpSocket *socket = newSocket();
1171 socket->connectToHost(hostName: QtNetworkSettings::imapServerName(), port: 143);
1172 QVERIFY(socket->waitForConnected(10000));
1173 QCOMPARE(socket->state(), QTcpSocket::ConnectedState);
1174 char buf[512];
1175
1176 QByteArray greeting = expectedReplyIMAP();
1177 QVERIFY(!greeting.isEmpty());
1178
1179 for (int i = 0; i < 10; i += 2) {
1180 while (socket->bytesAvailable() < 2)
1181 QVERIFY(socket->waitForReadyRead(10000));
1182 int bA = socket->bytesAvailable();
1183 QVERIFY(socket->read(buf, 2) == 2);
1184 buf[2] = '\0';
1185 QCOMPARE((char *)buf, greeting.mid(i, 2).data());
1186 QCOMPARE((int)socket->bytesAvailable(), bA - 2);
1187 socket->ungetChar(c: buf[1]);
1188 socket->ungetChar(c: buf[0]);
1189 QCOMPARE((int)socket->bytesAvailable(), bA);
1190 QVERIFY(socket->read(buf, 2) == 2);
1191 buf[2] = '\0';
1192 QCOMPARE((char *)buf, greeting.mid(i, 2).data());
1193 }
1194
1195 delete socket;
1196}
1197
1198//----------------------------------------------------------------------------------
1199void tst_QTcpSocket::readRegularFile_readyRead()
1200{
1201 exitLoop();
1202}
1203
1204//----------------------------------------------------------------------------------
1205void tst_QTcpSocket::readAllAfterClose()
1206{
1207 QTcpSocket *socket = newSocket();
1208 socket->connectToHost(hostName: QtNetworkSettings::imapServerName(), port: 143);
1209 connect(asender: socket, SIGNAL(readyRead()), SLOT(readRegularFile_readyRead()));
1210 enterLoop(secs: 10);
1211 if (timeout())
1212 QFAIL("Network operation timed out");
1213
1214 socket->close();
1215 QByteArray array = socket->readAll();
1216 QCOMPARE(array.size(), 0);
1217
1218 delete socket;
1219}
1220
1221//----------------------------------------------------------------------------------
1222void tst_QTcpSocket::openCloseOpenClose()
1223{
1224 QTcpSocket *socket = newSocket();
1225
1226 for (int i = 0; i < 3; ++i) {
1227 QCOMPARE(socket->state(), QTcpSocket::UnconnectedState);
1228 QCOMPARE(int(socket->openMode()), int(QIODevice::NotOpen));
1229 QVERIFY(socket->isSequential());
1230 QVERIFY(!socket->isOpen());
1231 QCOMPARE(socket->socketType(), QTcpSocket::TcpSocket);
1232
1233 char c;
1234 QCOMPARE(socket->getChar(&c), false);
1235 QCOMPARE((int) socket->bytesAvailable(), 0);
1236 QCOMPARE(socket->canReadLine(), false);
1237 QCOMPARE(socket->readLine(), QByteArray());
1238 QCOMPARE(socket->socketDescriptor(), (qintptr)-1);
1239 QCOMPARE((int) socket->localPort(), 0);
1240 QCOMPARE(socket->localAddress(), QHostAddress());
1241 QCOMPARE((int) socket->peerPort(), 0);
1242 QCOMPARE(socket->peerAddress(), QHostAddress());
1243 QCOMPARE(socket->error(), QTcpSocket::UnknownSocketError);
1244 QCOMPARE(socket->errorString(), QString("Unknown error"));
1245
1246 QCOMPARE(socket->state(), QTcpSocket::UnconnectedState);
1247
1248 socket->connectToHost(hostName: QtNetworkSettings::imapServerName(), port: 143);
1249 QVERIFY(socket->waitForConnected(10000));
1250 socket->close();
1251 }
1252
1253 delete socket;
1254}
1255
1256//----------------------------------------------------------------------------------
1257void tst_QTcpSocket::connectDisconnectConnectDisconnect()
1258{
1259 QTcpSocket *socket = newSocket();
1260
1261 for (int i = 0; i < 3; ++i) {
1262 QCOMPARE(socket->state(), QTcpSocket::UnconnectedState);
1263 QCOMPARE(socket->socketType(), QTcpSocket::TcpSocket);
1264
1265 QCOMPARE(socket->socketDescriptor(), qintptr(-1));
1266 QCOMPARE(int(socket->localPort()), 0);
1267 QCOMPARE(socket->localAddress(), QHostAddress());
1268 QCOMPARE(int(socket->peerPort()), 0);
1269 QCOMPARE(socket->peerAddress(), QHostAddress());
1270
1271 socket->connectToHost(hostName: QtNetworkSettings::imapServerName(), port: 143);
1272 QVERIFY(socket->waitForReadyRead(10000));
1273 QCOMPARE(QString::fromLatin1(socket->read(4)), QString("* OK"));
1274
1275 socket->disconnectFromHost();
1276 if (socket->state() != QTcpSocket::UnconnectedState)
1277 QVERIFY(socket->waitForDisconnected(10000));
1278 QCOMPARE(int(socket->openMode()), int(QIODevice::ReadWrite));
1279 }
1280
1281 delete socket;
1282}
1283
1284//----------------------------------------------------------------------------------
1285void tst_QTcpSocket::disconnectWhileConnecting_data()
1286{
1287 QTest::addColumn<QByteArray>(name: "data");
1288 QTest::addColumn<bool>(name: "closeDirectly");
1289
1290 QTest::newRow(dataTag: "without-data") << QByteArray() << false;
1291 QTest::newRow(dataTag: "without-data+close") << QByteArray() << true;
1292 QTest::newRow(dataTag: "with-data") << QByteArray("Hello, world!") << false;
1293 QTest::newRow(dataTag: "with-data+close") << QByteArray("Hello, world!") << true;
1294
1295 QByteArray bigData(1024*1024, '@');
1296 QTest::newRow(dataTag: "with-big-data") << bigData << false;
1297 QTest::newRow(dataTag: "with-big-data+close") << bigData << true;
1298}
1299
1300void tst_QTcpSocket::disconnectWhileConnecting()
1301{
1302 QFETCH(QByteArray, data);
1303 QFETCH_GLOBAL(bool, setProxy);
1304 if (setProxy)
1305 return; //proxy not useful for localhost test case
1306
1307 QTcpServer server;
1308 QVERIFY(server.listen(QHostAddress::LocalHost));
1309
1310 // proceed to the connect-write-disconnect
1311 QTcpSocket *socket = newSocket();
1312 socket->connectToHost(hostName: "127.0.0.1", port: server.serverPort());
1313 if (!data.isEmpty())
1314 socket->write(data);
1315 if (socket->state() == QAbstractSocket::ConnectedState)
1316 QSKIP("localhost connections are immediate, test case is invalid");
1317
1318 QFETCH(bool, closeDirectly);
1319 if (closeDirectly) {
1320 socket->close();
1321 QCOMPARE(int(socket->openMode()), int(QIODevice::NotOpen));
1322 } else {
1323 socket->disconnectFromHost();
1324 }
1325
1326 connect(asender: socket, SIGNAL(disconnected()), SLOT(exitLoopSlot()));
1327 enterLoop(secs: 10);
1328 QVERIFY2(!timeout(), "Network timeout");
1329 QCOMPARE(socket->state(), QAbstractSocket::UnconnectedState);
1330 if (!closeDirectly) {
1331 QCOMPARE(int(socket->openMode()), int(QIODevice::ReadWrite));
1332 socket->close();
1333 }
1334 QCOMPARE(int(socket->openMode()), int(QIODevice::NotOpen));
1335
1336 // accept the other side and verify that it was sent properly:
1337 QVERIFY(server.hasPendingConnections() || server.waitForNewConnection(0));
1338 QTcpSocket *othersocket = server.nextPendingConnection();
1339 if (othersocket->state() != QAbstractSocket::UnconnectedState)
1340 QVERIFY2(othersocket->waitForDisconnected(10000), "Network timeout");
1341 QCOMPARE(othersocket->state(), QAbstractSocket::UnconnectedState);
1342 QCOMPARE(othersocket->readAll(), data);
1343
1344 delete socket;
1345 delete othersocket;
1346}
1347
1348//----------------------------------------------------------------------------------
1349class ReceiverThread: public QThread
1350{
1351 QTcpServer *server;
1352public:
1353 int serverPort;
1354 bool ok;
1355 QByteArray receivedData;
1356 volatile bool quit;
1357
1358 ReceiverThread()
1359 : server(0), ok(false), quit(false)
1360 { }
1361
1362 ~ReceiverThread() { }
1363
1364 bool listen()
1365 {
1366 server = new QTcpServer;
1367 if (!server->listen(address: QHostAddress::LocalHost))
1368 return false;
1369 serverPort = server->serverPort();
1370 server->moveToThread(thread: this);
1371 return true;
1372 }
1373
1374 static void cleanup(void *ptr)
1375 {
1376 ReceiverThread* self = reinterpret_cast<ReceiverThread*>(ptr);
1377 self->quit = true;
1378 self->wait(time: 30000);
1379 delete self;
1380 }
1381
1382protected:
1383 void run()
1384 {
1385 bool timedOut = false;
1386 while (!quit) {
1387 if (server->waitForNewConnection(msec: 500, timedOut: &timedOut))
1388 break;
1389 if (!timedOut)
1390 return;
1391 }
1392
1393 QTcpSocket *socket = server->nextPendingConnection();
1394 while (!quit) {
1395 if (socket->waitForDisconnected(msecs: 500))
1396 break;
1397 if (socket->error() != QAbstractSocket::SocketTimeoutError)
1398 return;
1399 }
1400
1401 if (!quit) {
1402 receivedData = socket->readAll();
1403 ok = true;
1404 }
1405 delete socket;
1406 delete server;
1407 server = 0;
1408 }
1409};
1410
1411void tst_QTcpSocket::disconnectWhileConnectingNoEventLoop_data()
1412{
1413 disconnectWhileConnecting_data();
1414}
1415
1416void tst_QTcpSocket::disconnectWhileConnectingNoEventLoop()
1417{
1418 QFETCH(QByteArray, data);
1419 QFETCH_GLOBAL(bool, setProxy);
1420 if (setProxy)
1421 return; //proxy not useful for localhost test case
1422
1423 QScopedPointer<ReceiverThread, ReceiverThread> thread (new ReceiverThread);
1424 QVERIFY(thread->listen());
1425 thread->start();
1426
1427 // proceed to the connect-write-disconnect
1428 QTcpSocket *socket = newSocket();
1429 socket->connectToHost(hostName: "127.0.0.1", port: thread->serverPort);
1430 if (!data.isEmpty())
1431 socket->write(data);
1432 if (socket->state() == QAbstractSocket::ConnectedState)
1433 QSKIP("localhost connections are immediate, test case is invalid");
1434
1435 QFETCH(bool, closeDirectly);
1436 if (closeDirectly) {
1437 socket->close();
1438 QCOMPARE(int(socket->openMode()), int(QIODevice::NotOpen));
1439 } else {
1440 socket->disconnectFromHost();
1441 }
1442
1443 QVERIFY2(socket->waitForDisconnected(10000), "Network timeout");
1444 QCOMPARE(socket->state(), QAbstractSocket::UnconnectedState);
1445 if (!closeDirectly) {
1446 QCOMPARE(int(socket->openMode()), int(QIODevice::ReadWrite));
1447 socket->close();
1448 }
1449 QCOMPARE(int(socket->openMode()), int(QIODevice::NotOpen));
1450 delete socket;
1451
1452 // check if the other side received everything ok
1453 QVERIFY(thread->wait(30000));
1454 QVERIFY(thread->ok);
1455 QCOMPARE(thread->receivedData, data);
1456}
1457
1458//----------------------------------------------------------------------------------
1459void tst_QTcpSocket::disconnectWhileLookingUp_data()
1460{
1461 QTest::addColumn<bool>(name: "doClose");
1462
1463 QTest::newRow(dataTag: "disconnect") << false;
1464 QTest::newRow(dataTag: "close") << true;
1465}
1466
1467void tst_QTcpSocket::disconnectWhileLookingUp()
1468{
1469 QFETCH_GLOBAL(bool, setProxy);
1470 if (setProxy)
1471 return; // we let the proxies do the lookup now
1472
1473 // just connect and disconnect, then make sure nothing weird happened
1474 QTcpSocket *socket = newSocket();
1475 socket->connectToHost(hostName: QtNetworkSettings::ftpServerName(), port: 21);
1476
1477 // check that connect is in progress
1478 QVERIFY(socket->state() != QAbstractSocket::UnconnectedState);
1479
1480 QFETCH(bool, doClose);
1481 if (doClose) {
1482 socket->close();
1483 QCOMPARE(socket->openMode(), QIODevice::NotOpen);
1484 } else {
1485 socket->disconnectFromHost();
1486 QCOMPARE(socket->openMode(), QIODevice::ReadWrite);
1487 QVERIFY(socket->waitForDisconnected(5000));
1488 }
1489
1490 // let anything queued happen
1491
1492 QEventLoop loop;
1493 // If 'doClose' is false then we called '::waitForDisconnected' earlier, meaning
1494 // we are already 'Unconnected'. So we don't need to wait for any potentially slow host lookups.
1495 QTimer::singleShot(msec: doClose ? 4000 : 50, receiver: &loop, SLOT(quit()));
1496 connect(sender: socket, signal: &QTcpSocket::stateChanged, slot: [&loop](QAbstractSocket::SocketState state) {
1497 if (state == QAbstractSocket::UnconnectedState)
1498 loop.exit(); // we don't need to wait for the timer to expire; we're done.
1499 });
1500 loop.exec();
1501
1502 // recheck
1503 if (doClose) {
1504 QCOMPARE(socket->openMode(), QIODevice::NotOpen);
1505 } else {
1506 QCOMPARE(socket->openMode(), QIODevice::ReadWrite);
1507 }
1508
1509 QCOMPARE(socket->state(), QAbstractSocket::UnconnectedState);
1510}
1511
1512//----------------------------------------------------------------------------------
1513void tst_QTcpSocket::downloadBigFile()
1514{
1515 if (tmpSocket)
1516 delete tmpSocket;
1517 tmpSocket = newSocket();
1518
1519 connect(asender: tmpSocket, SIGNAL(connected()), SLOT(exitLoopSlot()));
1520 connect(asender: tmpSocket, SIGNAL(readyRead()), SLOT(downloadBigFileSlot()));
1521 connect(asender: tmpSocket, SIGNAL(disconnected()), SLOT(exitLoopSlot()));
1522
1523 tmpSocket->connectToHost(hostName: QtNetworkSettings::httpServerName(), port: 80);
1524
1525 enterLoop(secs: 30);
1526 if (timeout()) {
1527 delete tmpSocket;
1528 tmpSocket = 0;
1529 QFAIL("Network operation timed out");
1530 }
1531
1532 QByteArray hostName = QtNetworkSettings::httpServerName().toLatin1();
1533 QCOMPARE(tmpSocket->state(), QAbstractSocket::ConnectedState);
1534 QVERIFY(tmpSocket->write("GET /qtest/mediumfile HTTP/1.0\r\n") > 0);
1535 QVERIFY(tmpSocket->write("HOST: ") > 0);
1536 QVERIFY(tmpSocket->write(hostName.data()) > 0);
1537 QVERIFY(tmpSocket->write("\r\n") > 0);
1538 QVERIFY(tmpSocket->write("\r\n") > 0);
1539
1540 bytesAvailable = 0;
1541 expectedLength = 0;
1542 readingBody = false;
1543
1544 QElapsedTimer stopWatch;
1545 stopWatch.start();
1546
1547 enterLoop(secs: 600);
1548 if (timeout()) {
1549 delete tmpSocket;
1550 tmpSocket = 0;
1551 if (bytesAvailable > 0)
1552 qDebug(msg: "Slow Connection, only downloaded %ld of %d", long(bytesAvailable), 10000281);
1553 QFAIL("Network operation timed out");
1554 }
1555
1556 QCOMPARE(bytesAvailable, expectedLength);
1557
1558 qDebug(msg: "\t\t%.1fMB/%.1fs: %.1fMB/s",
1559 bytesAvailable / (1024.0 * 1024.0),
1560 stopWatch.elapsed() / 1024.0,
1561 (bytesAvailable / (stopWatch.elapsed() / 1000.0)) / (1024 * 1024));
1562
1563 delete tmpSocket;
1564 tmpSocket = 0;
1565}
1566
1567//----------------------------------------------------------------------------------
1568void tst_QTcpSocket::exitLoopSlot()
1569{
1570 exitLoop();
1571}
1572
1573//----------------------------------------------------------------------------------
1574void tst_QTcpSocket::downloadBigFileSlot()
1575{
1576 if (!readingBody) {
1577 while (tmpSocket->canReadLine()) {
1578 QByteArray array = tmpSocket->readLine();
1579 if (array.startsWith(c: "Content-Length"))
1580 expectedLength = array.simplified().split(sep: ' ').at(i: 1).toInt();
1581 if (array == "\r\n") {
1582 readingBody = true;
1583 break;
1584 }
1585 }
1586 }
1587 if (readingBody) {
1588 bytesAvailable += tmpSocket->readAll().size();
1589 if (bytesAvailable == expectedLength)
1590 exitLoop();
1591 }
1592}
1593
1594//----------------------------------------------------------------------------------
1595void tst_QTcpSocket::readLine()
1596{
1597 QTcpSocket *socket = newSocket();
1598 socket->connectToHost(hostName: QtNetworkSettings::imapServerName(), port: 143);
1599 QVERIFY(socket->waitForConnected(5000));
1600
1601 while (!socket->canReadLine())
1602 QVERIFY(socket->waitForReadyRead(10000));
1603
1604 char buffer[1024];
1605
1606 qint64 linelen = socket->readLine(data: buffer, maxlen: sizeof(buffer));
1607 QVERIFY(linelen >= 3);
1608 QVERIFY(linelen < 1024);
1609
1610 QByteArray reply = QByteArray::fromRawData(buffer, size: linelen);
1611 QCOMPARE((int) buffer[linelen-2], (int) '\r');
1612 QCOMPARE((int) buffer[linelen-1], (int) '\n');
1613 QCOMPARE((int) buffer[linelen], (int) '\0');
1614
1615 QVERIFY2(QtNetworkSettings::compareReplyIMAP(reply), reply.constData());
1616
1617 QCOMPARE(socket->write("1 NOOP\r\n"), qint64(8));
1618
1619 while (socket->bytesAvailable() < 10)
1620 QVERIFY(socket->waitForReadyRead(10000));
1621
1622 QCOMPARE(socket->readLine(buffer, 11), qint64(10));
1623 QCOMPARE((const char *)buffer, "1 OK Compl");
1624
1625 while (socket->bytesAvailable() < 6)
1626 QVERIFY(socket->waitForReadyRead(10000));
1627
1628 QCOMPARE(socket->readLine(buffer, 11), qint64(6));
1629 QCOMPARE((const char *)buffer, "eted\r\n");
1630
1631 QVERIFY(!socket->waitForReadyRead(100));
1632 QCOMPARE(socket->readLine(buffer, sizeof(buffer)), qint64(0));
1633 QVERIFY(socket->error() == QAbstractSocket::SocketTimeoutError
1634 || socket->error() == QAbstractSocket::RemoteHostClosedError);
1635 QCOMPARE(socket->bytesAvailable(), qint64(0));
1636
1637 socket->close();
1638 QCOMPARE(socket->readLine(buffer, sizeof(buffer)), qint64(-1));
1639
1640 delete socket;
1641}
1642
1643//----------------------------------------------------------------------------------
1644void tst_QTcpSocket::readLineString()
1645{
1646 QTcpSocket *socket = newSocket();
1647 socket->connectToHost(hostName: QtNetworkSettings::imapServerName(), port: 143);
1648 QVERIFY(socket->waitForReadyRead(10000));
1649
1650 QByteArray arr = socket->readLine();
1651 QVERIFY2(QtNetworkSettings::compareReplyIMAP(arr), arr.constData());
1652
1653 delete socket;
1654}
1655
1656//----------------------------------------------------------------------------------
1657void tst_QTcpSocket::readChunks()
1658{
1659 QTcpSocket *socket = newSocket();
1660 socket->connectToHost(hostName: QtNetworkSettings::imapServerName(), port: 143);
1661 QVERIFY(socket->waitForConnected(10000));
1662 QVERIFY(socket->waitForReadyRead(5000));
1663
1664 char buf[4096];
1665 memset(s: buf, c: '@', n: sizeof(buf));
1666 qint64 dataLength = socket->read(data: buf, maxlen: sizeof(buf));
1667 QVERIFY(dataLength > 0);
1668
1669 QCOMPARE(buf[dataLength - 2], '\r');
1670 QCOMPARE(buf[dataLength - 1], '\n');
1671 QCOMPARE(buf[dataLength], '@');
1672
1673 delete socket;
1674}
1675
1676//----------------------------------------------------------------------------------
1677void tst_QTcpSocket::waitForBytesWritten()
1678{
1679 QTcpSocket *socket = newSocket();
1680 socket->connectToHost(hostName: QtNetworkSettings::httpServerName(), port: 80);
1681 QVERIFY(socket->waitForConnected(10000));
1682
1683 socket->write(data: "GET / HTTP/1.0\r\n\r\n");
1684 qint64 toWrite = socket->bytesToWrite();
1685 QVERIFY(socket->waitForBytesWritten(5000));
1686 QVERIFY(toWrite > socket->bytesToWrite());
1687
1688 delete socket;
1689}
1690
1691//----------------------------------------------------------------------------------
1692void tst_QTcpSocket::waitForBytesWrittenMinusOne()
1693{
1694#ifdef Q_OS_WIN
1695 QSKIP("QTBUG-24451 - indefinite wait may hang");
1696#endif
1697 QTcpSocket *socket = newSocket();
1698 socket->connectToHost(hostName: QtNetworkSettings::httpServerName(), port: 80);
1699 QVERIFY(socket->waitForConnected(10000));
1700
1701 socket->write(data: "GET / HTTP/1.0\r\n\r\n");
1702 qint64 toWrite = socket->bytesToWrite();
1703 QVERIFY(socket->waitForBytesWritten(-1));
1704 QVERIFY(toWrite > socket->bytesToWrite());
1705
1706 delete socket;
1707}
1708
1709//----------------------------------------------------------------------------------
1710void tst_QTcpSocket::waitForReadyRead()
1711{
1712 QTcpSocket *socket = newSocket();
1713 socket->connectToHost(hostName: QtNetworkSettings::httpServerName(), port: 80);
1714 socket->write(data: "GET / HTTP/1.0\r\n\r\n");
1715 QVERIFY(socket->waitForReadyRead(5000));
1716 delete socket;
1717}
1718
1719//----------------------------------------------------------------------------------
1720void tst_QTcpSocket::waitForReadyReadMinusOne()
1721{
1722#ifdef Q_OS_WIN
1723 QSKIP("QTBUG-24451 - indefinite wait may hang");
1724#endif
1725 QTcpSocket *socket = newSocket();
1726 socket->connectToHost(hostName: QtNetworkSettings::httpServerName(), port: 80);
1727 socket->write(data: "GET / HTTP/1.0\r\n\r\n");
1728 QVERIFY(socket->waitForReadyRead(-1));
1729 delete socket;
1730}
1731
1732//----------------------------------------------------------------------------------
1733void tst_QTcpSocket::flush()
1734{
1735 QTcpSocket *socket = newSocket();
1736 socket->flush();
1737
1738 connect(asender: socket, SIGNAL(connected()), SLOT(exitLoopSlot()));
1739 socket->connectToHost(hostName: QtNetworkSettings::imapServerName(), port: 143);
1740 enterLoop(secs: 60);
1741 QVERIFY(socket->isOpen());
1742
1743 socket->write(data: "1 LOGOUT\r\n");
1744 QCOMPARE(socket->bytesToWrite(), qint64(10));
1745 socket->flush();
1746 QCOMPARE(socket->bytesToWrite(), qint64(0));
1747 socket->close();
1748
1749 delete socket;
1750}
1751
1752//----------------------------------------------------------------------------------
1753void tst_QTcpSocket::synchronousApi()
1754{
1755 QTcpSocket *ftpSocket = newSocket();
1756 ftpSocket->connectToHost(hostName: QtNetworkSettings::ftpServerName(), port: 21);
1757 ftpSocket->write(data: "QUIT\r\n");
1758 QVERIFY(ftpSocket->waitForDisconnected(10000));
1759 QVERIFY(ftpSocket->bytesAvailable() > 0);
1760 QByteArray arr = ftpSocket->readAll();
1761 QVERIFY(arr.size() > 0);
1762 delete ftpSocket;
1763}
1764
1765//----------------------------------------------------------------------------------
1766void tst_QTcpSocket::dontCloseOnTimeout()
1767{
1768 QTcpServer server;
1769#ifndef QT_NO_NETWORKPROXY
1770 server.setProxy(QNetworkProxy(QNetworkProxy::NoProxy));
1771#endif
1772 QVERIFY(server.listen());
1773
1774 QHostAddress serverAddress = QHostAddress::LocalHost;
1775 if (!(server.serverAddress() == QHostAddress::AnyIPv4)
1776 && !(server.serverAddress() == QHostAddress::AnyIPv6)
1777 && !(server.serverAddress() == QHostAddress::Any))
1778 serverAddress = server.serverAddress();
1779
1780 QTcpSocket *socket = newSocket();
1781 socket->connectToHost(address: serverAddress, port: server.serverPort());
1782 QVERIFY(!socket->waitForReadyRead(100));
1783 QCOMPARE(socket->error(), QTcpSocket::SocketTimeoutError);
1784 QVERIFY(socket->isOpen());
1785
1786 QVERIFY(!socket->waitForDisconnected(100));
1787 QCOMPARE(socket->error(), QTcpSocket::SocketTimeoutError);
1788 QVERIFY(socket->isOpen());
1789
1790 delete socket;
1791}
1792
1793//----------------------------------------------------------------------------------
1794void tst_QTcpSocket::recursiveReadyRead()
1795{
1796 QTcpSocket *testSocket = newSocket();
1797 connect(asender: testSocket, SIGNAL(connected()), SLOT(exitLoopSlot()));
1798 connect(asender: testSocket, SIGNAL(readyRead()), SLOT(recursiveReadyReadSlot()));
1799 tmpSocket = testSocket;
1800
1801 QSignalSpy spy(testSocket, SIGNAL(readyRead()));
1802
1803 testSocket->connectToHost(hostName: QtNetworkSettings::imapServerName(), port: 143);
1804 enterLoop(secs: 30);
1805 QVERIFY2(!timeout(),
1806 "Timed out when connecting to QtNetworkSettings::imapServerName().");
1807
1808 enterLoop(secs: 30);
1809 QVERIFY2(!timeout(),
1810 "Timed out when waiting for the readyRead() signal.");
1811
1812 QCOMPARE(spy.count(), 1);
1813
1814 delete testSocket;
1815}
1816
1817void tst_QTcpSocket::recursiveReadyReadSlot()
1818{
1819 // make sure the server spits out more data
1820 tmpSocket->write(data: "NOOP\r\n");
1821 tmpSocket->flush();
1822
1823 // indiscriminately enter the event loop and start processing
1824 // events again. but oops! future socket notifications will cause
1825 // undesired recursive behavior. Unless QTcpSocket is smart, which
1826 // it of course is. :-)
1827 QEventLoop loop;
1828 for (int i = 0; i < 100; ++i)
1829 loop.processEvents();
1830
1831 // all we really wanted to do was process some events, then exit
1832 // the loop
1833 exitLoop();
1834}
1835
1836//----------------------------------------------------------------------------------
1837void tst_QTcpSocket::atEnd()
1838{
1839 QTcpSocket *socket = newSocket();
1840 socket->connectToHost(hostName: QtNetworkSettings::ftpServerName(), port: 21);
1841
1842 QVERIFY(socket->waitForReadyRead(15000));
1843 QTextStream stream(socket);
1844 QVERIFY(!stream.atEnd());
1845 QString greeting = stream.readLine();
1846 QVERIFY(stream.atEnd());
1847
1848#ifdef QT_TEST_SERVER
1849 // Test server must use some vsFTPd 3.x.x version
1850 QVERIFY2(greeting.length() == sizeof("220 (vsFTPd 3.x.x)")-1, qPrintable(greeting));
1851 QVERIFY2(greeting.startsWith("220 (vsFTPd 3."), qPrintable(greeting));
1852#else
1853 // Test server must use some vsFTPd 2.x.x version
1854 QVERIFY2(greeting.length() == sizeof("220 (vsFTPd 2.x.x)")-1, qPrintable(greeting));
1855 QVERIFY2(greeting.startsWith("220 (vsFTPd 2."), qPrintable(greeting));
1856#endif
1857 QVERIFY2(greeting.endsWith(QLatin1Char(')')), qPrintable(greeting));
1858
1859 delete socket;
1860}
1861
1862class TestThread : public QThread
1863{
1864 Q_OBJECT
1865
1866public:
1867 inline QByteArray data() const
1868 {
1869 return socketData;
1870 }
1871
1872protected:
1873 inline void run()
1874 {
1875#ifndef QT_NO_SSL
1876 QFETCH_GLOBAL(bool, ssl);
1877 if (ssl)
1878 socket = new QSslSocket;
1879 else
1880#endif
1881 socket = new QTcpSocket;
1882 connect(sender: socket, SIGNAL(readyRead()), receiver: this, SLOT(getData()), Qt::DirectConnection);
1883 connect(sender: socket, SIGNAL(disconnected()), receiver: this, SLOT(closed()), Qt::DirectConnection);
1884 connect(asender: socket, SIGNAL(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)),
1885 SLOT(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)), atype: Qt::DirectConnection);
1886
1887 socket->connectToHost(hostName: QtNetworkSettings::ftpServerName(), port: 21);
1888 socket->write(data: "QUIT\r\n");
1889 exec();
1890
1891 delete socket;
1892 }
1893
1894private slots:
1895 inline void getData()
1896 {
1897 socketData += socket->readAll();
1898 }
1899
1900 inline void closed()
1901 {
1902 quit();
1903 }
1904#ifndef QT_NO_NETWORKPROXY
1905 inline void proxyAuthenticationRequired(const QNetworkProxy &, QAuthenticator *auth)
1906 {
1907 auth->setUser("qsockstest");
1908 auth->setPassword("password");
1909 }
1910#endif // !QT_NO_NETWORKPROXY
1911private:
1912 QTcpSocket *socket;
1913 QByteArray socketData;
1914};
1915
1916//----------------------------------------------------------------------------------
1917void tst_QTcpSocket::socketInAThread()
1918{
1919 for (int i = 0; i < 3; ++i) {
1920 TestThread thread;
1921 thread.start();
1922 QVERIFY(thread.wait(15000));
1923 QByteArray data = thread.data();
1924 QVERIFY2(QtNetworkSettings::compareReplyFtp(data), data.constData());
1925 }
1926}
1927
1928//----------------------------------------------------------------------------------
1929void tst_QTcpSocket::socketsInThreads()
1930{
1931 for (int i = 0; i < 3; ++i) {
1932 TestThread thread1;
1933 TestThread thread2;
1934 TestThread thread3;
1935
1936 thread1.start();
1937 thread2.start();
1938 thread3.start();
1939
1940 QVERIFY(thread2.wait(15000));
1941 QVERIFY(thread3.wait(15000));
1942 QVERIFY(thread1.wait(15000));
1943
1944 QByteArray data1 = thread1.data();
1945 QByteArray data2 = thread2.data();
1946 QByteArray data3 = thread3.data();
1947
1948 QVERIFY2(QtNetworkSettings::compareReplyFtp(data1), data1.constData());
1949 QVERIFY2(QtNetworkSettings::compareReplyFtp(data2), data2.constData());
1950 QVERIFY2(QtNetworkSettings::compareReplyFtp(data3), data3.constData());
1951 }
1952}
1953
1954//----------------------------------------------------------------------------------
1955void tst_QTcpSocket::waitForReadyReadInASlot()
1956{
1957 QTcpSocket *socket = newSocket();
1958 tmpSocket = socket;
1959 connect(sender: socket, SIGNAL(connected()), receiver: this, SLOT(waitForReadyReadInASlotSlot()));
1960
1961 socket->connectToHost(hostName: QtNetworkSettings::httpServerName(), port: 80);
1962 socket->write(data: "GET / HTTP/1.0\r\n\r\n");
1963
1964 enterLoop(secs: 30);
1965 QVERIFY(!timeout());
1966
1967 delete socket;
1968}
1969
1970void tst_QTcpSocket::waitForReadyReadInASlotSlot()
1971{
1972 QVERIFY(tmpSocket->waitForReadyRead(10000));
1973 exitLoop();
1974}
1975
1976class RemoteCloseErrorServer : public QTcpServer
1977{
1978 Q_OBJECT
1979public:
1980 RemoteCloseErrorServer()
1981 {
1982 connect(sender: this, SIGNAL(newConnection()),
1983 receiver: this, SLOT(getConnection()));
1984 }
1985
1986private slots:
1987 void getConnection()
1988 {
1989 tst_QTcpSocket::exitLoop();
1990 }
1991};
1992
1993//----------------------------------------------------------------------------------
1994void tst_QTcpSocket::remoteCloseError()
1995{
1996 QFETCH_GLOBAL(bool, setProxy);
1997 if (setProxy)
1998 return; //proxy not useful for localhost test case
1999 RemoteCloseErrorServer server;
2000 QVERIFY(server.listen(QHostAddress::LocalHost));
2001
2002 QCoreApplication::instance()->processEvents();
2003
2004 QTcpSocket *clientSocket = newSocket();
2005 connect(sender: clientSocket, SIGNAL(readyRead()), receiver: this, SLOT(exitLoopSlot()));
2006
2007 clientSocket->connectToHost(address: server.serverAddress(), port: server.serverPort());
2008
2009 enterLoop(secs: 30);
2010 QVERIFY(!timeout());
2011
2012 QVERIFY(server.hasPendingConnections());
2013 QTcpSocket *serverSocket = server.nextPendingConnection();
2014 connect(sender: clientSocket, SIGNAL(disconnected()), receiver: this, SLOT(exitLoopSlot()));
2015
2016 serverSocket->write(data: "Hello");
2017
2018 enterLoop(secs: 30);
2019 QVERIFY(!timeout());
2020
2021 QCOMPARE(clientSocket->bytesAvailable(), qint64(5));
2022
2023 qRegisterMetaType<QAbstractSocket::SocketError>(typeName: "QAbstractSocket::SocketError");
2024 QSignalSpy errorSpy(clientSocket, SIGNAL(errorOccurred(QAbstractSocket::SocketError)));
2025 QSignalSpy disconnectedSpy(clientSocket, SIGNAL(disconnected()));
2026
2027 clientSocket->write(data: "World");
2028 serverSocket->disconnectFromHost();
2029
2030 tmpSocket = clientSocket;
2031 connect(sender: clientSocket, SIGNAL(errorOccurred(QAbstractSocket::SocketError)),
2032 receiver: this, SLOT(remoteCloseErrorSlot()));
2033
2034 enterLoop(secs: 30);
2035 QVERIFY(!timeout());
2036
2037 QCOMPARE(disconnectedSpy.count(), 1);
2038 QCOMPARE(errorSpy.count(), 1);
2039 QCOMPARE(clientSocket->error(), QAbstractSocket::RemoteHostClosedError);
2040
2041 delete serverSocket;
2042
2043 clientSocket->connectToHost(address: server.serverAddress(), port: server.serverPort());
2044
2045 enterLoop(secs: 30);
2046 QVERIFY(!timeout());
2047
2048 QVERIFY(server.hasPendingConnections());
2049 serverSocket = server.nextPendingConnection();
2050 serverSocket->disconnectFromHost();
2051
2052 enterLoop(secs: 30);
2053 QVERIFY(!timeout());
2054
2055 QCOMPARE(clientSocket->state(), QAbstractSocket::UnconnectedState);
2056
2057 delete clientSocket;
2058}
2059
2060void tst_QTcpSocket::remoteCloseErrorSlot()
2061{
2062 QCOMPARE(tmpSocket->state(), QAbstractSocket::ConnectedState);
2063 static_cast<QTcpSocket *>(sender())->close();
2064}
2065
2066void tst_QTcpSocket::enterLoopSlot()
2067{
2068 QTcpSocket *socket = qobject_cast<QTcpSocket *>(object: sender());
2069 socket->deleteLater();
2070
2071 // enter nested event loop
2072 QEventLoop loop;
2073 QTimer::singleShot(msec: 100, receiver: &loop, SLOT(quit()));
2074 loop.exec();
2075
2076 // Fire a non-0 singleshot to leave time for the delete
2077 QTimer::singleShot(msec: 250, receiver: this, SLOT(exitLoopSlot()));
2078}
2079//----------------------------------------------------------------------------------
2080void tst_QTcpSocket::nestedEventLoopInErrorSlot()
2081{
2082 QTcpSocket *socket = newSocket();
2083 QPointer<QTcpSocket> p(socket);
2084 connect(sender: socket, SIGNAL(errorOccurred(QAbstractSocket::SocketError)), receiver: this, SLOT(enterLoopSlot()));
2085
2086 socket->connectToHost(hostName: "hostnotfoundhostnotfound.qt-project.org", port: 9999);
2087 enterLoop(secs: 30);
2088 QVERIFY(!p);
2089}
2090
2091//----------------------------------------------------------------------------------
2092
2093void tst_QTcpSocket::connectToHostError_data()
2094{
2095 QTest::addColumn<QString>(name: "host");
2096 QTest::addColumn<int>(name: "port");
2097 QTest::addColumn<QAbstractSocket::SocketError>(name: "expectedError");
2098
2099 QTest::newRow(dataTag: "localhost no service") << QStringLiteral("localhost") << 31415 << QAbstractSocket::ConnectionRefusedError;
2100 QTest::newRow(dataTag: "unreachable") << QStringLiteral("0.0.0.1") << 65000 << QAbstractSocket::NetworkError;
2101}
2102
2103
2104void tst_QTcpSocket::connectToHostError()
2105{
2106 std::unique_ptr<QTcpSocket> socket(newSocket());
2107
2108 QAbstractSocket::SocketError error = QAbstractSocket::UnknownSocketError;
2109
2110 QFETCH(QString, host);
2111 QFETCH(int, port);
2112 QFETCH(QAbstractSocket::SocketError, expectedError);
2113
2114 connect(sender: socket.get(), signal: &QAbstractSocket::errorOccurred, slot: [&](QAbstractSocket::SocketError socketError){
2115 error = socketError;
2116 });
2117 socket->connectToHost(hostName: host, port); // no service running here, one suspects
2118 QTRY_COMPARE_WITH_TIMEOUT(socket->state(), QTcpSocket::UnconnectedState, 7000);
2119 if (error != expectedError && error == QAbstractSocket::ConnectionRefusedError)
2120 QEXPECT_FAIL("unreachable", "CI firewall interfers with this test", Continue);
2121 QCOMPARE(error, expectedError);
2122}
2123
2124//----------------------------------------------------------------------------------
2125void tst_QTcpSocket::waitForConnectedInHostLookupSlot()
2126{
2127 // This test tries to reproduce the problem where waitForConnected() is
2128 // called at a point where the host lookup is already done. QTcpSocket
2129 // will try to abort the "pending lookup", but since it's already done and
2130 // the queued signal is already underway, we will receive the signal after
2131 // waitForConnected() has returned, and control goes back to the event
2132 // loop. When the signal has been received, the connection is torn down,
2133 // then reopened. Yikes. If we reproduce this by calling
2134 // waitForConnected() inside hostLookupSlot(), it will even crash.
2135 tmpSocket = newSocket();
2136 QEventLoop loop;
2137 connect(sender: tmpSocket, SIGNAL(connected()), receiver: &loop, SLOT(quit()));
2138 QTimer timer;
2139 connect(sender: &timer, SIGNAL(timeout()), receiver: &loop, SLOT(quit()));
2140 QSignalSpy timerSpy(&timer, SIGNAL(timeout()));
2141 timer.start(msec: 15000);
2142
2143 connect(sender: tmpSocket, SIGNAL(hostFound()), receiver: this, SLOT(hostLookupSlot()));
2144 tmpSocket->connectToHost(hostName: QtNetworkSettings::imapServerName(), port: 143);
2145
2146 // only execute the loop if not already connected
2147 if (tmpSocket->state() != QAbstractSocket::ConnectedState)
2148 loop.exec();
2149
2150 QCOMPARE(timerSpy.count(), 0);
2151
2152 delete tmpSocket;
2153}
2154
2155void tst_QTcpSocket::hostLookupSlot()
2156{
2157 // This will fail to cancel the pending signal
2158 QVERIFY(tmpSocket->waitForConnected(10000));
2159}
2160
2161class Foo : public QObject
2162{
2163 Q_OBJECT
2164 QTcpSocket *sock;
2165public:
2166 bool attemptedToConnect;
2167 bool networkTimeout;
2168 int count;
2169
2170 inline Foo(QObject *parent = 0) : QObject(parent)
2171 {
2172 attemptedToConnect = false;
2173 networkTimeout = false;
2174 count = 0;
2175#ifndef QT_NO_SSL
2176 QFETCH_GLOBAL(bool, ssl);
2177 if (ssl)
2178 sock = new QSslSocket;
2179 else
2180#endif
2181 sock = new QTcpSocket;
2182 connect(sender: sock, SIGNAL(connected()), receiver: this, SLOT(connectedToIt()));
2183 connect(asender: sock, SIGNAL(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)),
2184 SLOT(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)));
2185 }
2186
2187 inline ~Foo()
2188 {
2189 delete sock;
2190 }
2191
2192public slots:
2193 inline void connectedToIt()
2194 { count++; }
2195
2196 inline void doIt()
2197 {
2198 attemptedToConnect = true;
2199 sock->connectToHost(hostName: QtNetworkSettings::httpServerName(), port: 80);
2200
2201#if defined(Q_OS_MAC)
2202 pthread_yield_np();
2203#elif defined Q_OS_LINUX && !defined Q_OS_ANDROID
2204 pthread_yield();
2205#endif
2206 if (!sock->waitForConnected()) {
2207 networkTimeout = true;
2208 }
2209 tst_QTcpSocket::exitLoop();
2210 }
2211
2212 inline void exitLoop()
2213 {
2214 tst_QTcpSocket::exitLoop();
2215 }
2216
2217#ifndef QT_NO_NETWORKPROXY
2218 inline void proxyAuthenticationRequired(const QNetworkProxy &, QAuthenticator *auth)
2219 {
2220 auth->setUser("qsockstest");
2221 auth->setPassword("password");
2222 }
2223#endif // !QT_NO_NETWORKPROXY
2224};
2225
2226//----------------------------------------------------------------------------------
2227void tst_QTcpSocket::waitForConnectedInHostLookupSlot2()
2228{
2229 Foo foo;
2230
2231 QTimer::singleShot(msec: 100, receiver: &foo, SLOT(doIt()));
2232 QTimer::singleShot(msec: 5000, receiver: &foo, SLOT(exitLoop()));
2233
2234 enterLoop(secs: 30);
2235 if (timeout() || foo.networkTimeout)
2236 QFAIL("Network timeout");
2237
2238 QVERIFY(foo.attemptedToConnect);
2239 QCOMPARE(foo.count, 1);
2240}
2241
2242//----------------------------------------------------------------------------------
2243void tst_QTcpSocket::readyReadSignalsAfterWaitForReadyRead()
2244{
2245 QTcpSocket *socket = newSocket();
2246
2247 QSignalSpy readyReadSpy(socket, SIGNAL(readyRead()));
2248
2249 // Connect
2250 socket->connectToHost(hostName: QtNetworkSettings::imapServerName(), port: 143);
2251
2252 // Wait for the read
2253 QVERIFY(socket->waitForReadyRead(10000));
2254
2255 QCOMPARE(readyReadSpy.count(), 1);
2256
2257 QString s = socket->readLine();
2258 QVERIFY2(QtNetworkSettings::compareReplyIMAP(s.toLatin1()), s.toLatin1().constData());
2259 QCOMPARE(socket->bytesAvailable(), qint64(0));
2260
2261 QCoreApplication::instance()->processEvents();
2262 QCOMPARE(socket->bytesAvailable(), qint64(0));
2263 QCOMPARE(readyReadSpy.count(), 1);
2264
2265 delete socket;
2266}
2267
2268class TestThread2 : public QThread
2269{
2270 Q_OBJECT
2271public:
2272 void run()
2273 {
2274 QFile fileWriter("fifo");
2275 QVERIFY(fileWriter.open(QFile::WriteOnly));
2276 QCOMPARE(fileWriter.write(QByteArray(32, '@')), qint64(32));
2277 QCOMPARE(fileWriter.write(QByteArray(32, '@')), qint64(32));
2278 QCOMPARE(fileWriter.write(QByteArray(32, '@')), qint64(32));
2279 QCOMPARE(fileWriter.write(QByteArray(32, '@')), qint64(32));
2280 }
2281};
2282
2283//----------------------------------------------------------------------------------
2284#ifdef Q_OS_LINUX
2285void tst_QTcpSocket::linuxKernelBugLocalSocket()
2286{
2287 QFile::remove(fileName: "fifo");
2288 mkfifo(path: "fifo", mode: 0666);
2289
2290 TestThread2 test;
2291 test.start();
2292
2293 QFile fileReader("fifo");
2294 QVERIFY(fileReader.open(QFile::ReadOnly));
2295
2296 test.wait();
2297
2298 QTcpSocket *socket = newSocket();
2299 socket->setSocketDescriptor(socketDescriptor: fileReader.handle());
2300 QVERIFY(socket->waitForReadyRead(5000));
2301 QCOMPARE(socket->bytesAvailable(), qint64(128));
2302
2303 QFile::remove(fileName: "fifo");
2304
2305 delete socket;
2306}
2307#endif
2308
2309//----------------------------------------------------------------------------------
2310void tst_QTcpSocket::abortiveClose()
2311{
2312 QFETCH_GLOBAL(bool, setProxy);
2313 if (setProxy)
2314 return; //proxy not useful for localhost test case
2315 QTcpServer server;
2316 QVERIFY(server.listen(QHostAddress::LocalHost));
2317 connect(sender: &server, SIGNAL(newConnection()), receiver: this, SLOT(exitLoopSlot()));
2318
2319 QTcpSocket *clientSocket = newSocket();
2320 clientSocket->connectToHost(address: server.serverAddress(), port: server.serverPort());
2321
2322 enterLoop(secs: 10);
2323 QVERIFY(server.hasPendingConnections());
2324
2325 tmpSocket = server.nextPendingConnection();
2326 QVERIFY(tmpSocket != nullptr);
2327
2328 qRegisterMetaType<QAbstractSocket::SocketError>(typeName: "QAbstractSocket::SocketError");
2329 QSignalSpy readyReadSpy(clientSocket, SIGNAL(readyRead()));
2330 QSignalSpy errorSpy(clientSocket, SIGNAL(errorOccurred(QAbstractSocket::SocketError)));
2331
2332 connect(sender: clientSocket, SIGNAL(disconnected()), receiver: this, SLOT(exitLoopSlot()));
2333 QTimer::singleShot(msec: 0, receiver: this, SLOT(abortiveClose_abortSlot()));
2334
2335 enterLoop(secs: 5);
2336
2337 QCOMPARE(readyReadSpy.count(), 0);
2338 QCOMPARE(errorSpy.count(), 1);
2339
2340 QCOMPARE(*static_cast<const int *>(errorSpy.at(0).at(0).constData()),
2341 int(QAbstractSocket::RemoteHostClosedError));
2342
2343 delete clientSocket;
2344}
2345
2346void tst_QTcpSocket::abortiveClose_abortSlot()
2347{
2348 tmpSocket->abort();
2349}
2350
2351//----------------------------------------------------------------------------------
2352void tst_QTcpSocket::localAddressEmptyOnBSD()
2353{
2354#ifdef Q_OS_WIN
2355 QSKIP("QTBUG-24451 - indefinite wait may hang");
2356#endif
2357 QFETCH_GLOBAL(bool, setProxy);
2358 if (setProxy)
2359 return; //proxy not useful for localhost test case
2360 QTcpServer server;
2361 QVERIFY(server.listen(QHostAddress::LocalHost));
2362
2363 QTcpSocket *tcpSocket = 0;
2364 // we try 10 times, but note that this doesn't always provoke the bug
2365 for (int i = 0; i < 10; ++i) {
2366 delete tcpSocket;
2367 tcpSocket = newSocket();
2368 tcpSocket->connectToHost(address: QHostAddress::LocalHost, port: server.serverPort());
2369 if (!tcpSocket->waitForConnected(msecs: 0)) {
2370 // to provoke the bug, we need a local socket that connects immediately
2371 // --i;
2372 tcpSocket->abort();
2373 if (tcpSocket->state() != QTcpSocket::UnconnectedState)
2374 QVERIFY(tcpSocket->waitForDisconnected(-1));
2375 continue;
2376 }
2377 QCOMPARE(tcpSocket->localAddress(), QHostAddress(QHostAddress::LocalHost));
2378 }
2379 delete tcpSocket;
2380}
2381
2382//----------------------------------------------------------------------------------
2383void tst_QTcpSocket::zeroAndMinusOneReturns()
2384{
2385 QTcpSocket *socket = newSocket();
2386 socket->connectToHost(hostName: QtNetworkSettings::httpServerName(), port: 80);
2387 socket->write(data: "GET / HTTP/1.0\r\nConnection: keep-alive\r\n\r\n");
2388 QVERIFY(socket->waitForReadyRead(15000));
2389
2390 char c[16];
2391 QVERIFY(socket->getChar(c));
2392 QCOMPARE(socket->read(c, 16), qint64(16));
2393 QVERIFY(socket->readLine(c, 16) > 0);
2394 QVERIFY(!socket->readAll().isEmpty());
2395
2396 // the last operation emptied the read buffer
2397 // all read operations from this point on should fail
2398 // with return 0 because the socket is still open
2399 QVERIFY(socket->readAll().isEmpty());
2400 QCOMPARE(socket->read(c, 16), qint64(0));
2401 QCOMPARE(socket->readLine(c, 16), qint64(0));
2402 QVERIFY(!socket->getChar(c));
2403
2404 socket->write(data: "GET / HTTP/1.0\r\n\r\n");
2405 QVERIFY(socket->waitForDisconnected(15000));
2406 QCOMPARE(socket->error(), QAbstractSocket::RemoteHostClosedError);
2407
2408 QCOMPARE(socket->write("BLUBBER"), qint64(-1));
2409 QVERIFY(socket->getChar(c));
2410 QCOMPARE(socket->read(c, 16), qint64(16));
2411 QVERIFY(socket->readLine(c, 16) > 0);
2412 QVERIFY(!socket->readAll().isEmpty());
2413
2414 // the last operation emptied the read buffer
2415 // all read operations from this point on should fail
2416 // with return -1 because the socket is not connected
2417 QVERIFY(socket->readAll().isEmpty());
2418 QCOMPARE(socket->read(c, 16), qint64(-1));
2419 QCOMPARE(socket->readLine(c, 16), qint64(-1));
2420 QVERIFY(!socket->getChar(c));
2421 QVERIFY(!socket->putChar('a'));
2422
2423 socket->close();
2424
2425 // now the QIODevice is closed, which means getChar complains
2426 QCOMPARE(socket->write("BLUBBER"), qint64(-1));
2427 QCOMPARE(socket->read(c, 16), qint64(-1));
2428 QCOMPARE(socket->readLine(c, 16), qint64(-1));
2429 QVERIFY(!socket->getChar(c));
2430 QVERIFY(!socket->putChar('a'));
2431
2432 delete socket;
2433}
2434
2435//----------------------------------------------------------------------------------
2436void tst_QTcpSocket::connectionRefused()
2437{
2438 qRegisterMetaType<QAbstractSocket::SocketError>(typeName: "QAbstractSocket::SocketError");
2439 qRegisterMetaType<QAbstractSocket::SocketState>(typeName: "QAbstractSocket::SocketState");
2440
2441 QTcpSocket *socket = newSocket();
2442 QSignalSpy stateSpy(socket, SIGNAL(stateChanged(QAbstractSocket::SocketState)));
2443 QSignalSpy errorSpy(socket, SIGNAL(errorOccurred(QAbstractSocket::SocketError)));
2444 connect(sender: socket, SIGNAL(errorOccurred(QAbstractSocket::SocketError)),
2445 receiver: &QTestEventLoop::instance(), SLOT(exitLoop()));
2446
2447 socket->connectToHost(hostName: QtNetworkSettings::httpServerName(), port: 144);
2448
2449 enterLoop(secs: 10);
2450 disconnect(sender: socket, SIGNAL(errorOccurred(QAbstractSocket::SocketError)),
2451 receiver: &QTestEventLoop::instance(), SLOT(exitLoop()));
2452 QVERIFY2(!timeout(), "Network timeout");
2453
2454 QCOMPARE(socket->state(), QAbstractSocket::UnconnectedState);
2455 QCOMPARE(socket->error(), QAbstractSocket::ConnectionRefusedError);
2456
2457 QCOMPARE(stateSpy.count(), 3);
2458 QCOMPARE(qvariant_cast<QAbstractSocket::SocketState>(stateSpy.at(0).at(0)), QAbstractSocket::HostLookupState);
2459 QCOMPARE(qvariant_cast<QAbstractSocket::SocketState>(stateSpy.at(1).at(0)), QAbstractSocket::ConnectingState);
2460 QCOMPARE(qvariant_cast<QAbstractSocket::SocketState>(stateSpy.at(2).at(0)), QAbstractSocket::UnconnectedState);
2461 QCOMPARE(errorSpy.count(), 1);
2462
2463 delete socket;
2464}
2465
2466//----------------------------------------------------------------------------------
2467void tst_QTcpSocket::suddenRemoteDisconnect_data()
2468{
2469 QTest::addColumn<QString>(name: "client");
2470 QTest::addColumn<QString>(name: "server");
2471
2472 QTest::newRow(dataTag: "Qt4 Client <-> Qt4 Server") << QString::fromLatin1(str: "qt4client") << QString::fromLatin1(str: "qt4server");
2473}
2474
2475void tst_QTcpSocket::suddenRemoteDisconnect()
2476{
2477#if !QT_CONFIG(process)
2478 QSKIP("This test requires QProcess support");
2479#else
2480 QFETCH(QString, client);
2481 QFETCH(QString, server);
2482
2483 QFETCH_GLOBAL(bool, setProxy);
2484 if (setProxy)
2485 return;
2486 QFETCH_GLOBAL(bool, ssl);
2487 if (ssl)
2488 return;
2489
2490 QString processExe = stressTestDir + "/stressTest";
2491
2492 // Start server
2493 QProcess serverProcess;
2494 serverProcess.setReadChannel(QProcess::StandardError);
2495 serverProcess.start(program: processExe, arguments: QStringList(server), mode: QIODevice::ReadWrite | QIODevice::Text);
2496 QVERIFY2(serverProcess.waitForStarted(), qPrintable(
2497 QString::fromLatin1("Could not start %1: %2").arg(processExe, serverProcess.errorString())));
2498 while (!serverProcess.canReadLine())
2499 QVERIFY(serverProcess.waitForReadyRead(10000));
2500
2501 QByteArray line = serverProcess.readLine();
2502
2503 // Ignore following print, happens on Qemu:
2504 if (line == "getsockopt level=41 optname=26 not yet supported\n") {
2505 while (!serverProcess.canReadLine())
2506 QVERIFY(serverProcess.waitForReadyRead(10000));
2507 line = serverProcess.readLine();
2508 }
2509
2510 QCOMPARE(line.data(), QByteArray(server.toLatin1() + "\n").data());
2511
2512 // Start client
2513 QProcess clientProcess;
2514 clientProcess.setReadChannel(QProcess::StandardError);
2515 clientProcess.start(program: processExe, arguments: QStringList(client), mode: QIODevice::ReadWrite | QIODevice::Text);
2516 QVERIFY2(clientProcess.waitForStarted(), qPrintable(
2517 QString::fromLatin1("Could not start %1: %2").arg(processExe, clientProcess.errorString())));
2518 while (!clientProcess.canReadLine())
2519 QVERIFY(clientProcess.waitForReadyRead(10000));
2520 QCOMPARE(clientProcess.readLine().data(), QByteArray(client.toLatin1() + "\n").data());
2521
2522 // Let them play for a while
2523 qDebug(msg: "Running stress test for 5 seconds");
2524 QEventLoop loop;
2525 connect(sender: &serverProcess, SIGNAL(finished(int)), receiver: &loop, SLOT(quit()));
2526 connect(sender: &clientProcess, SIGNAL(finished(int)), receiver: &loop, SLOT(quit()));
2527 QElapsedTimer stopWatch;
2528 stopWatch.start();
2529 QTimer::singleShot(msec: 20000, receiver: &loop, SLOT(quit()));
2530
2531 while ((serverProcess.state() == QProcess::Running
2532 || clientProcess.state() == QProcess::Running) && stopWatch.elapsed() < 20000)
2533 loop.exec();
2534
2535 QVERIFY(stopWatch.elapsed() < 20000);
2536
2537 // Check that both exited normally.
2538#if defined(UBUNTU_ONEIRIC) && defined(__x86_64__)
2539 QEXPECT_FAIL("", "Fails on this platform", Abort);
2540#endif
2541 QCOMPARE(clientProcess.readAll().constData(), "SUCCESS\n");
2542 QCOMPARE(serverProcess.readAll().constData(), "SUCCESS\n");
2543#endif // QT_CONFIG(process)
2544}
2545
2546//----------------------------------------------------------------------------------
2547
2548void tst_QTcpSocket::connectToMultiIP()
2549{
2550 QSKIP("TODO: setup DNS in the new network");
2551#if defined(Q_OS_VXWORKS)
2552 QSKIP("VxSim in standard config doesn't even run a DNS resolver");
2553#else
2554 QFETCH_GLOBAL(bool, ssl);
2555 if (ssl)
2556 return;
2557 QFETCH_GLOBAL(bool, setProxy);
2558 if (setProxy)
2559 QSKIP("This test takes too long if we also add the proxies.");
2560
2561 qDebug(msg: "Please wait, this test can take a while...");
2562
2563 QTcpSocket *socket = newSocket();
2564 // rationale: this domain resolves to 3 A-records, 2 of them are
2565 // invalid. QTcpSocket should never spend more than 30 seconds per IP, and
2566 // 30s*2 = 60s.
2567 QElapsedTimer stopWatch;
2568 stopWatch.start();
2569 socket->connectToHost(hostName: "multi.dev.qt-project.org", port: 80);
2570 QVERIFY(socket->waitForConnected(60500));
2571 QVERIFY(stopWatch.elapsed() < 70000);
2572 socket->abort();
2573
2574 stopWatch.restart();
2575 socket->connectToHost(hostName: "multi.dev.qt-project.org", port: 81);
2576 QVERIFY(!socket->waitForConnected(2000));
2577 QVERIFY(stopWatch.elapsed() < 2000);
2578 QCOMPARE(socket->error(), QAbstractSocket::SocketTimeoutError);
2579
2580 delete socket;
2581#endif
2582}
2583
2584//----------------------------------------------------------------------------------
2585void tst_QTcpSocket::moveToThread0()
2586{
2587 QFETCH_GLOBAL(int, proxyType);
2588 if (proxyType & AuthMask)
2589 return;
2590
2591 {
2592 // Case 1: Moved after connecting, before waiting for connection.
2593 QTcpSocket *socket = newSocket();;
2594 socket->connectToHost(hostName: QtNetworkSettings::imapServerName(), port: 143);
2595 socket->moveToThread(thread: 0);
2596 QVERIFY(socket->waitForConnected(5000));
2597 socket->write(data: "XXX LOGOUT\r\n");
2598 QVERIFY(socket->waitForBytesWritten(5000));
2599 QVERIFY(socket->waitForDisconnected());
2600 delete socket;
2601 }
2602 {
2603 // Case 2: Moved before connecting
2604 QTcpSocket *socket = newSocket();
2605 socket->moveToThread(thread: 0);
2606 socket->connectToHost(hostName: QtNetworkSettings::imapServerName(), port: 143);
2607 QVERIFY(socket->waitForConnected(5000));
2608 socket->write(data: "XXX LOGOUT\r\n");
2609 QVERIFY(socket->waitForBytesWritten(5000));
2610 QVERIFY(socket->waitForDisconnected());
2611 delete socket;
2612 }
2613 {
2614 // Case 3: Moved after writing, while waiting for bytes to be written.
2615 QTcpSocket *socket = newSocket();
2616 socket->connectToHost(hostName: QtNetworkSettings::imapServerName(), port: 143);
2617 QVERIFY(socket->waitForConnected(5000));
2618 socket->write(data: "XXX LOGOUT\r\n");
2619 socket->moveToThread(thread: 0);
2620 QVERIFY(socket->waitForBytesWritten(5000));
2621 QVERIFY(socket->waitForDisconnected());
2622 delete socket;
2623 }
2624 {
2625 // Case 4: Moved after writing, while waiting for response.
2626 QTcpSocket *socket = newSocket();
2627 socket->connectToHost(hostName: QtNetworkSettings::imapServerName(), port: 143);
2628 QVERIFY(socket->waitForConnected(5000));
2629 socket->write(data: "XXX LOGOUT\r\n");
2630 QVERIFY(socket->waitForBytesWritten(5000));
2631 socket->moveToThread(thread: 0);
2632 QVERIFY(socket->waitForDisconnected());
2633 delete socket;
2634 }
2635}
2636
2637void tst_QTcpSocket::increaseReadBufferSize()
2638{
2639 QFETCH_GLOBAL(bool, setProxy);
2640 if (setProxy)
2641 return; //proxy not useful for localhost test case
2642 QTcpServer server;
2643 QTcpSocket *active = newSocket();
2644 connect(asender: active, SIGNAL(readyRead()), SLOT(exitLoopSlot()));
2645
2646 // connect two sockets to each other:
2647 QVERIFY(server.listen(QHostAddress::LocalHost));
2648 active->connectToHost(hostName: "127.0.0.1", port: server.serverPort());
2649 QVERIFY(active->waitForConnected(5000));
2650 QVERIFY(server.waitForNewConnection(5000));
2651
2652 QTcpSocket *passive = server.nextPendingConnection();
2653 QVERIFY(passive);
2654
2655 // now write 512 bytes of data on one end
2656 QByteArray data(512, 'a');
2657 passive->write(data);
2658 QVERIFY2(passive->waitForBytesWritten(5000), "Network timeout");
2659
2660 // set the read buffer size to less than what was written and iterate:
2661 active->setReadBufferSize(256);
2662 enterLoop(secs: 10);
2663 QVERIFY2(!timeout(), "Network timeout");
2664 QCOMPARE(active->bytesAvailable(), active->readBufferSize());
2665
2666 // increase the buffer size and iterate again:
2667 active->setReadBufferSize(384);
2668 enterLoop(secs: 10);
2669 QVERIFY2(!timeout(), "Network timeout");
2670 QCOMPARE(active->bytesAvailable(), active->readBufferSize());
2671
2672 // once more, but now it should read everything there was to read
2673 active->setReadBufferSize(1024);
2674 enterLoop(secs: 10);
2675 QVERIFY2(!timeout(), "Network timeout");
2676 QCOMPARE(active->bytesAvailable(), qint64(data.size()));
2677
2678 // drain it and compare
2679 QCOMPARE(active->readAll(), data);
2680
2681 // now one more test by setting the buffer size to unlimited:
2682 passive->write(data);
2683 QVERIFY2(passive->waitForBytesWritten(5000), "Network timeout");
2684 active->setReadBufferSize(256);
2685 enterLoop(secs: 10);
2686 QVERIFY2(!timeout(), "Network timeout");
2687 QCOMPARE(active->bytesAvailable(), active->readBufferSize());
2688 active->setReadBufferSize(0);
2689 enterLoop(secs: 10);
2690 QVERIFY2(!timeout(), "Network timeout");
2691 QCOMPARE(active->bytesAvailable(), qint64(data.size()));
2692 QCOMPARE(active->readAll(), data);
2693
2694 delete active;
2695}
2696
2697void tst_QTcpSocket::increaseReadBufferSizeFromSlot() // like KIO's socketconnectionbackend
2698{
2699 QFETCH_GLOBAL(bool, setProxy);
2700 if (setProxy)
2701 return; //proxy not useful for localhost test case
2702 QTcpServer server;
2703 QTcpSocket *active = newSocket();
2704 connect(asender: active, SIGNAL(readyRead()), SLOT(slotIncreaseReadBufferSizeReadyRead()));
2705
2706 // connect two sockets to each other:
2707 QVERIFY(server.listen(QHostAddress::LocalHost));
2708 active->connectToHost(hostName: "127.0.0.1", port: server.serverPort());
2709 QVERIFY(active->waitForConnected(5000));
2710 QVERIFY(server.waitForNewConnection(5000));
2711
2712 QTcpSocket *passive = server.nextPendingConnection();
2713 QVERIFY(passive);
2714
2715 // now write 512 bytes of data on one end
2716 QByteArray data(512, 'a');
2717 passive->write(data);
2718 QVERIFY2(passive->waitForBytesWritten(5000), "Network timeout");
2719
2720 // set the read buffer size to less than what was written,
2721 // and increase it from the slot, first to 384 then to 512.
2722 active->setReadBufferSize(256);
2723 enterLoop(secs: 10);
2724 QVERIFY2(!timeout(), "Network timeout");
2725 QCOMPARE(active->bytesAvailable(), qint64(data.size()));
2726
2727 // drain it and compare
2728 QCOMPARE(active->readAll(), data);
2729
2730 delete active;
2731}
2732
2733void tst_QTcpSocket::slotIncreaseReadBufferSizeReadyRead()
2734{
2735 QTcpSocket *socket = qobject_cast<QTcpSocket *>(object: sender());
2736 const int currentBufferSize = socket->readBufferSize();
2737 QCOMPARE(currentBufferSize, socket->bytesAvailable());
2738 if (currentBufferSize == 256)
2739 socket->setReadBufferSize(384);
2740 else if (currentBufferSize == 384)
2741 socket->setReadBufferSize(512);
2742 else if (currentBufferSize == 512)
2743 exitLoopSlot();
2744 else // should not happen
2745 qFatal(msg: "buffer size was %d", currentBufferSize);
2746}
2747
2748void tst_QTcpSocket::taskQtBug5799ConnectionErrorWaitForConnected()
2749{
2750 QFETCH_GLOBAL(bool, setProxy);
2751 if (setProxy)
2752 return;
2753
2754 // check that we get a proper error connecting to port 12346
2755 // use waitForConnected, e.g. this should use a synchronous select() on the OS level
2756
2757 QTcpSocket socket;
2758 socket.connectToHost(hostName: QtNetworkSettings::httpServerName(), port: 12346);
2759 QElapsedTimer timer;
2760 timer.start();
2761 socket.waitForConnected(msecs: 10000);
2762 QVERIFY2(timer.elapsed() < 9900, "Connection to closed port timed out instead of refusing, something is wrong");
2763 QVERIFY2(socket.state() == QAbstractSocket::UnconnectedState, "Socket connected unexpectedly!");
2764 QVERIFY2(socket.error() == QAbstractSocket::ConnectionRefusedError,
2765 QString("Could not reach server: %1").arg(socket.errorString()).toLocal8Bit());
2766}
2767
2768void tst_QTcpSocket::taskQtBug5799ConnectionErrorEventLoop()
2769{
2770 QFETCH_GLOBAL(bool, setProxy);
2771 if (setProxy)
2772 return;
2773
2774 // check that we get a proper error connecting to port 12346
2775 // This testcase uses an event loop
2776 QTcpSocket socket;
2777 connect(sender: &socket, SIGNAL(errorOccurred(QAbstractSocket::SocketError)), receiver: &QTestEventLoop::instance(), SLOT(exitLoop()));
2778 socket.connectToHost(hostName: QtNetworkSettings::httpServerName(), port: 12346);
2779
2780 QTestEventLoop::instance().enterLoop(secs: 10);
2781 QVERIFY2(!QTestEventLoop::instance().timeout(), "Connection to closed port timed out instead of refusing, something is wrong");
2782 QVERIFY2(socket.state() == QAbstractSocket::UnconnectedState, "Socket connected unexpectedly!");
2783 QVERIFY2(socket.error() == QAbstractSocket::ConnectionRefusedError,
2784 QString("Could not reach server: %1").arg(socket.errorString()).toLocal8Bit());
2785}
2786
2787void tst_QTcpSocket::taskQtBug7054TimeoutErrorResetting()
2788{
2789 QTcpSocket *socket = newSocket();
2790
2791 socket->connectToHost(hostName: QtNetworkSettings::httpServerName(), port: 443);
2792 QVERIFY(socket->waitForConnected(5*1000));
2793 QCOMPARE(socket->error(), QAbstractSocket::UnknownSocketError);
2794
2795 // We connected to the HTTPS port. Wait two seconds to receive data. We will receive
2796 // nothing because we would need to start the SSL handshake
2797 QVERIFY(!socket->waitForReadyRead(2*1000));
2798 QCOMPARE(socket->error(), QAbstractSocket::SocketTimeoutError);
2799
2800 // Now write some crap to make the server disconnect us. 4 lines are enough.
2801 socket->write(data: "a\r\nb\r\nc\r\nd\r\n");
2802 socket->waitForBytesWritten(msecs: 2*1000);
2803
2804 // we try to waitForReadyRead another time, but this time instead of a timeout we
2805 // should get a better error since the server disconnected us
2806 QVERIFY(!socket->waitForReadyRead(2*1000));
2807 // It must NOT be the SocketTimeoutError that had been set before
2808 QCOMPARE(socket->error(), QAbstractSocket::RemoteHostClosedError);
2809}
2810
2811#ifndef QT_NO_NETWORKPROXY
2812void tst_QTcpSocket::invalidProxy_data()
2813{
2814 QTest::addColumn<int>(name: "type");
2815 QTest::addColumn<QString>(name: "host");
2816 QTest::addColumn<int>(name: "port");
2817 QTest::addColumn<bool>(name: "failsAtConnect");
2818 QTest::addColumn<int>(name: "expectedError");
2819
2820 const QString ftpAddress = QtNetworkSettings::ftpServerIp().toString();
2821 const QString httpProxyAddress = QtNetworkSettings::httpProxyServerIp().toString();
2822 const QString socksProxyAddress = QtNetworkSettings::socksProxyServerIp().toString();
2823 QTest::newRow(dataTag: "ftp-proxy") << int(QNetworkProxy::FtpCachingProxy) << ftpAddress << 21 << true
2824 << int(QAbstractSocket::UnsupportedSocketOperationError);
2825 QTest::newRow(dataTag: "http-caching-proxy") << int(QNetworkProxy::HttpCachingProxy) << httpProxyAddress << 3128 << true
2826 << int(QAbstractSocket::UnsupportedSocketOperationError);
2827 QTest::newRow(dataTag: "no-such-host-socks5") << int(QNetworkProxy::Socks5Proxy)
2828 << "this-host-will-never-exist.qt-project.org" << 1080 << false
2829 << int(QAbstractSocket::ProxyNotFoundError);
2830 QTest::newRow(dataTag: "no-such-host-http") << int(QNetworkProxy::HttpProxy)
2831 << "this-host-will-never-exist.qt-project.org" << 3128 << false
2832 << int(QAbstractSocket::ProxyNotFoundError);
2833 QTest::newRow(dataTag: "http-on-socks5") << int(QNetworkProxy::HttpProxy) << socksProxyAddress << 1080 << false
2834 << int(QAbstractSocket::ProxyConnectionClosedError);
2835 QTest::newRow(dataTag: "socks5-on-http") << int(QNetworkProxy::Socks5Proxy) << httpProxyAddress << 3128 << false
2836 << int(QAbstractSocket::SocketTimeoutError);
2837}
2838
2839void tst_QTcpSocket::invalidProxy()
2840{
2841 QFETCH_GLOBAL(bool, setProxy);
2842 if (setProxy)
2843 return;
2844
2845 QFETCH(int, type);
2846 QFETCH(QString, host);
2847 QFETCH(int, port);
2848 QFETCH(bool, failsAtConnect);
2849 QNetworkProxy::ProxyType proxyType = QNetworkProxy::ProxyType(type);
2850 QNetworkProxy proxy(proxyType, host, port);
2851
2852 QTcpSocket *socket = newSocket();
2853 socket->setProxy(proxy);
2854 socket->connectToHost(hostName: QtNetworkSettings::httpServerIp().toString(), port: 80);
2855
2856 if (failsAtConnect) {
2857 QCOMPARE(socket->state(), QAbstractSocket::UnconnectedState);
2858 } else {
2859 QCOMPARE(socket->state(), QAbstractSocket::ConnectingState);
2860 QVERIFY(!socket->waitForConnected(5000));
2861 }
2862 QVERIFY(!socket->errorString().isEmpty());
2863
2864 // note: the following test is not a hard failure.
2865 // Sometimes, error codes change for the better
2866 QTEST(int(socket->error()), "expectedError");
2867
2868 delete socket;
2869}
2870
2871// copied from tst_qnetworkreply.cpp
2872class MyProxyFactory: public QNetworkProxyFactory
2873{
2874public:
2875 int callCount;
2876 QList<QNetworkProxy> toReturn;
2877 QNetworkProxyQuery lastQuery;
2878 inline MyProxyFactory() { clear(); }
2879
2880 inline void clear()
2881 {
2882 callCount = 0;
2883 toReturn = QList<QNetworkProxy>() << QNetworkProxy::DefaultProxy;
2884 lastQuery = QNetworkProxyQuery();
2885 }
2886
2887 virtual QList<QNetworkProxy> queryProxy(const QNetworkProxyQuery &query)
2888 {
2889 lastQuery = query;
2890 ++callCount;
2891 return toReturn;
2892 }
2893};
2894
2895void tst_QTcpSocket::proxyFactory_data()
2896{
2897 QTest::addColumn<QList<QNetworkProxy> >(name: "proxyList");
2898 QTest::addColumn<QNetworkProxy>(name: "proxyUsed");
2899 QTest::addColumn<bool>(name: "failsAtConnect");
2900 QTest::addColumn<int>(name: "expectedError");
2901
2902 QList<QNetworkProxy> proxyList;
2903
2904 // tests that do connect
2905
2906 proxyList << QNetworkProxy(QNetworkProxy::HttpProxy, QtNetworkSettings::httpProxyServerName(), 3129);
2907 QTest::newRow(dataTag: "http")
2908 << proxyList << proxyList.at(i: 0)
2909 << false << int(QAbstractSocket::UnknownSocketError);
2910
2911 proxyList.clear();
2912 proxyList << QNetworkProxy(QNetworkProxy::Socks5Proxy, QtNetworkSettings::socksProxyServerName(), 1081);
2913 QTest::newRow(dataTag: "socks5")
2914 << proxyList << proxyList.at(i: 0)
2915 << false << int(QAbstractSocket::UnknownSocketError);
2916
2917 proxyList.clear();
2918 proxyList << QNetworkProxy(QNetworkProxy::HttpCachingProxy, QtNetworkSettings::httpProxyServerName(), 3129)
2919 << QNetworkProxy(QNetworkProxy::Socks5Proxy, QtNetworkSettings::socksProxyServerName(), 1081);
2920 QTest::newRow(dataTag: "cachinghttp+socks5")
2921 << proxyList << proxyList.at(i: 1)
2922 << false << int(QAbstractSocket::UnknownSocketError);
2923
2924 proxyList.clear();
2925 proxyList << QNetworkProxy(QNetworkProxy::FtpCachingProxy, QtNetworkSettings::ftpProxyServerName(), 2121)
2926 << QNetworkProxy(QNetworkProxy::HttpCachingProxy, QtNetworkSettings::httpProxyServerName(), 3129)
2927 << QNetworkProxy(QNetworkProxy::Socks5Proxy, QtNetworkSettings::socksProxyServerName(), 1081);
2928 QTest::newRow(dataTag: "ftp+cachinghttp+socks5")
2929 << proxyList << proxyList.at(i: 2)
2930 << false << int(QAbstractSocket::UnknownSocketError);
2931
2932 // tests that fail to connect
2933 proxyList.clear();
2934 proxyList << QNetworkProxy(QNetworkProxy::HttpCachingProxy, QtNetworkSettings::httpProxyServerName(), 3129);
2935 QTest::newRow(dataTag: "cachinghttp")
2936 << proxyList << QNetworkProxy()
2937 << true << int(QAbstractSocket::UnsupportedSocketOperationError);
2938
2939 proxyList.clear();
2940 proxyList << QNetworkProxy(QNetworkProxy::FtpCachingProxy, QtNetworkSettings::ftpProxyServerName(), 2121);
2941 QTest::newRow(dataTag: "ftp")
2942 << proxyList << QNetworkProxy()
2943 << true << int(QAbstractSocket::UnsupportedSocketOperationError);
2944
2945 proxyList.clear();
2946 proxyList << QNetworkProxy(QNetworkProxy::FtpCachingProxy, QtNetworkSettings::ftpProxyServerName(), 2121)
2947 << QNetworkProxy(QNetworkProxy::HttpCachingProxy, QtNetworkSettings::httpProxyServerName(), 3129);
2948 QTest::newRow(dataTag: "ftp+cachinghttp")
2949 << proxyList << QNetworkProxy()
2950 << true << int(QAbstractSocket::UnsupportedSocketOperationError);
2951}
2952
2953void tst_QTcpSocket::proxyFactory()
2954{
2955 QFETCH_GLOBAL(bool, setProxy);
2956 if (setProxy)
2957 return;
2958
2959 QFETCH(QList<QNetworkProxy>, proxyList);
2960 QFETCH(QNetworkProxy, proxyUsed);
2961 QFETCH(bool, failsAtConnect);
2962
2963 MyProxyFactory *factory = new MyProxyFactory;
2964 factory->toReturn = proxyList;
2965 QNetworkProxyFactory::setApplicationProxyFactory(factory);
2966
2967 QTcpSocket *socket = newSocket();
2968 QString host = QtNetworkSettings::httpServerName();
2969 socket->connectToHost(hostName: host, port: 80);
2970
2971 // Verify that the factory was called properly
2972 QCOMPARE(factory->callCount, 1);
2973 QCOMPARE(factory->lastQuery, QNetworkProxyQuery(host, 80));
2974
2975 if (failsAtConnect) {
2976 QCOMPARE(socket->state(), QAbstractSocket::UnconnectedState);
2977 } else {
2978 QCOMPARE(socket->state(), QAbstractSocket::ConnectingState);
2979 QVERIFY(socket->waitForConnected(5000));
2980 QCOMPARE(proxyAuthCalled, 1);
2981 }
2982 QVERIFY(!socket->errorString().isEmpty());
2983
2984 // note: the following test is not a hard failure.
2985 // Sometimes, error codes change for the better
2986 QTEST(int(socket->error()), "expectedError");
2987
2988 delete socket;
2989}
2990#endif // !QT_NO_NETWORKPROXY
2991
2992// there is a similar test inside tst_qtcpserver that uses the event loop instead
2993void tst_QTcpSocket::qtbug14268_peek()
2994{
2995 QFETCH_GLOBAL(bool, setProxy);
2996 if (setProxy)
2997 return;
2998
2999 SocketPair socketPair;
3000 QVERIFY(socketPair.create());
3001 QTcpSocket *outgoing = socketPair.endPoints[0];
3002 QTcpSocket *incoming = socketPair.endPoints[1];
3003
3004 QCOMPARE(incoming->state(), QTcpSocket::ConnectedState);
3005 QCOMPARE(outgoing->state(), QTcpSocket::ConnectedState);
3006
3007 outgoing->write(data: "abc\n");
3008 QVERIFY(outgoing->waitForBytesWritten(2000));
3009 QVERIFY(incoming->waitForReadyRead(2000));
3010 QCOMPARE(incoming->peek(128*1024), QByteArray("abc\n"));
3011
3012 outgoing->write(data: "def\n");
3013 QVERIFY(outgoing->waitForBytesWritten(2000));
3014 QVERIFY(incoming->waitForReadyRead(2000));
3015 QCOMPARE(incoming->peek(128*1024), QByteArray("abc\ndef\n"));
3016
3017 outgoing->write(data: "ghi\n");
3018 QVERIFY(outgoing->waitForBytesWritten(2000));
3019 QVERIFY(incoming->waitForReadyRead(2000));
3020 QCOMPARE(incoming->peek(128*1024), QByteArray("abc\ndef\nghi\n"));
3021
3022 QCOMPARE(incoming->read(128*1024), QByteArray("abc\ndef\nghi\n"));
3023}
3024
3025void tst_QTcpSocket::setSocketOption()
3026{
3027 QFETCH_GLOBAL(bool, setProxy);
3028 if (setProxy)
3029 return;
3030
3031 SocketPair socketPair;
3032 QVERIFY(socketPair.create());
3033 QTcpSocket *outgoing = socketPair.endPoints[0];
3034 QTcpSocket *incoming = socketPair.endPoints[1];
3035
3036 QCOMPARE(incoming->state(), QTcpSocket::ConnectedState);
3037 QCOMPARE(outgoing->state(), QTcpSocket::ConnectedState);
3038
3039 outgoing->setSocketOption(option: QAbstractSocket::LowDelayOption, value: true);
3040 QVariant v = outgoing->socketOption(option: QAbstractSocket::LowDelayOption);
3041 QVERIFY(v.isValid() && v.toBool());
3042 outgoing->setSocketOption(option: QAbstractSocket::KeepAliveOption, value: true);
3043 v = outgoing->socketOption(option: QAbstractSocket::KeepAliveOption);
3044 QVERIFY(v.isValid() && v.toBool());
3045
3046 outgoing->setSocketOption(option: QAbstractSocket::LowDelayOption, value: false);
3047 v = outgoing->socketOption(option: QAbstractSocket::LowDelayOption);
3048 QVERIFY(v.isValid() && !v.toBool());
3049 outgoing->setSocketOption(option: QAbstractSocket::KeepAliveOption, value: false);
3050 v = outgoing->socketOption(option: QAbstractSocket::KeepAliveOption);
3051 QVERIFY(v.isValid() && !v.toBool());
3052
3053#ifdef Q_OS_WIN
3054 QEXPECT_FAIL("", "QTBUG-23323", Abort);
3055#endif
3056 outgoing->setSocketOption(option: QAbstractSocket::TypeOfServiceOption, value: 32); //high priority
3057 v = outgoing->socketOption(option: QAbstractSocket::TypeOfServiceOption);
3058 QVERIFY(v.isValid() && v.toInt() == 32);
3059}
3060
3061// Test buffered socket properly send data on delayed disconnect
3062void tst_QTcpSocket::clientSendDataOnDelayedDisconnect()
3063{
3064 QFETCH_GLOBAL(bool, setProxy);
3065 if (setProxy)
3066 return;
3067
3068 QTcpServer server;
3069 QTcpSocket *socket = newSocket();
3070
3071 QVERIFY(server.listen(QHostAddress::LocalHost));
3072
3073 // Connect to server, write data and close socket
3074 const QByteArray sendData("GET /\r\n");
3075 socket->connectToHost(address: server.serverAddress(), port: server.serverPort());
3076 QVERIFY(socket->waitForConnected(5000)); // ready for write
3077 QCOMPARE(socket->write(sendData), sendData.size());
3078 socket->close();
3079 QVERIFY(socket->waitForDisconnected(5000)); // flush buffer
3080
3081 // Check data on server side
3082 QByteArray recData;
3083 QVERIFY(server.waitForNewConnection(5000));
3084 QTcpSocket *newConnection = server.nextPendingConnection();
3085 QVERIFY(newConnection != NULL);
3086 while (newConnection->waitForReadyRead(msecs: 5000)) // have data to read
3087 recData += newConnection->readAll();
3088 QCOMPARE(sendData, recData);
3089
3090 delete socket;
3091}
3092
3093// Test buffered socket being properly closed on remote disconnect
3094void tst_QTcpSocket::serverDisconnectWithBuffered()
3095{
3096 QFETCH_GLOBAL(bool, setProxy);
3097 if (setProxy)
3098 return;
3099
3100 qRegisterMetaType<QAbstractSocket::SocketState>(typeName: "QAbstractSocket::SocketState");
3101
3102 QTcpServer tcpServer;
3103 QTcpSocket *socket = newSocket();
3104
3105 QVERIFY(tcpServer.listen(QHostAddress::LocalHost));
3106 socket->connectToHost(address: tcpServer.serverAddress(), port: tcpServer.serverPort());
3107 // Accept connection on server side
3108 QVERIFY(tcpServer.waitForNewConnection(5000));
3109 QTcpSocket *newConnection = tcpServer.nextPendingConnection();
3110 // Send one char and drop link
3111 QVERIFY(newConnection != NULL);
3112 QVERIFY(newConnection->putChar(0));
3113 QVERIFY(newConnection->flush());
3114 delete newConnection;
3115
3116 QVERIFY(socket->waitForConnected(5000)); // ready for write
3117 QCOMPARE(socket->state(), QAbstractSocket::ConnectedState);
3118
3119 QSignalSpy spyStateChanged(socket, SIGNAL(stateChanged(QAbstractSocket::SocketState)));
3120 QSignalSpy spyDisconnected(socket, SIGNAL(disconnected()));
3121
3122 QVERIFY(socket->waitForReadyRead(5000)); // have one char already in internal buffer
3123 char buf[128];
3124 QCOMPARE(socket->read(buf, sizeof(buf)), Q_INT64_C(1));
3125 if (socket->state() != QAbstractSocket::UnconnectedState) {
3126 QVERIFY(socket->waitForDisconnected(5000));
3127 QCOMPARE(socket->state(), QAbstractSocket::UnconnectedState);
3128 }
3129 // Test signal emitting
3130 QCOMPARE(spyDisconnected.count(), 1);
3131 QVERIFY(spyStateChanged.count() > 0);
3132 QVERIFY(qvariant_cast<QAbstractSocket::SocketState>(spyStateChanged.last().first())
3133 == QAbstractSocket::UnconnectedState);
3134
3135 delete socket;
3136}
3137
3138// Test buffered sockets discard input when opened in WriteOnly mode
3139void tst_QTcpSocket::socketDiscardDataInWriteMode()
3140{
3141 QFETCH_GLOBAL(bool, setProxy);
3142 if (setProxy)
3143 return;
3144
3145 QTcpServer tcpServer;
3146 QTcpSocket *socket = newSocket();
3147
3148 QVERIFY(tcpServer.listen(QHostAddress::LocalHost));
3149 socket->connectToHost(address: tcpServer.serverAddress(), port: tcpServer.serverPort(),
3150 mode: QIODevice::WriteOnly);
3151 QVERIFY(socket->waitForConnected(5000)); // ready for write
3152 QCOMPARE(socket->state(), QAbstractSocket::ConnectedState);
3153
3154 // Accept connection on server side
3155 QVERIFY2(tcpServer.waitForNewConnection(5000), "Network timeout");
3156 QTcpSocket *newConnection = tcpServer.nextPendingConnection();
3157 // Send one char and drop link
3158 QVERIFY(newConnection != NULL);
3159 QVERIFY(newConnection->putChar(0));
3160 QVERIFY(newConnection->flush());
3161 delete newConnection;
3162
3163 QVERIFY(socket->waitForReadyRead(5000)); // discard input
3164 QVERIFY(socket->atEnd());
3165
3166 delete socket;
3167}
3168
3169// Test waitForBytesWritten() does not fail on read buffer overflow
3170void tst_QTcpSocket::writeOnReadBufferOverflow()
3171{
3172 QFETCH_GLOBAL(bool, setProxy);
3173 if (setProxy)
3174 return;
3175
3176 QTcpServer tcpServer;
3177 QTcpSocket *socket = newSocket();
3178
3179 QVERIFY(tcpServer.listen(QHostAddress::LocalHost));
3180 socket->setReadBufferSize(1);
3181 socket->connectToHost(address: tcpServer.serverAddress(), port: tcpServer.serverPort());
3182 QVERIFY(socket->waitForConnected(5000));
3183 QCOMPARE(socket->state(), QAbstractSocket::ConnectedState);
3184
3185 // Accept connection on server side
3186 QVERIFY2(tcpServer.waitForNewConnection(5000), "Network timeout");
3187 QTcpSocket *newConnection = tcpServer.nextPendingConnection();
3188 QVERIFY(newConnection != nullptr);
3189 QCOMPARE(newConnection->write("1", 2), Q_INT64_C(2));
3190 QVERIFY(newConnection->flush());
3191
3192 // Wait for buffer overflow
3193 QVERIFY(socket->waitForReadyRead(5000));
3194 QCOMPARE(socket->bytesAvailable(), Q_INT64_C(1));
3195 // Write data and wait for successful send
3196 QVERIFY(socket->putChar(0));
3197 QVERIFY(socket->waitForBytesWritten(5000));
3198
3199 delete newConnection;
3200 delete socket;
3201}
3202
3203// Test that the socket does not enable the read notifications in bind()
3204void tst_QTcpSocket::readNotificationsAfterBind()
3205{
3206 QFETCH_GLOBAL(bool, setProxy);
3207 if (setProxy)
3208 return;
3209
3210 QAbstractSocket socket(QAbstractSocket::TcpSocket, nullptr);
3211 QVERIFY2(socket.bind(), "Bind error!");
3212
3213 connect(sender: &socket, SIGNAL(errorOccurred(QAbstractSocket::SocketError)), receiver: &QTestEventLoop::instance(), SLOT(exitLoop()));
3214 QSignalSpy spyReadyRead(&socket, SIGNAL(readyRead()));
3215 socket.connectToHost(hostName: QtNetworkSettings::serverName(), port: 12346);
3216
3217 QTestEventLoop::instance().enterLoop(secs: 10);
3218 QVERIFY2(!QTestEventLoop::instance().timeout(), "Connection to closed port timed out instead of refusing, something is wrong");
3219 QVERIFY2(socket.state() == QAbstractSocket::UnconnectedState, "Socket connected unexpectedly!");
3220 QCOMPARE(spyReadyRead.count(), 0);
3221}
3222
3223QTEST_MAIN(tst_QTcpSocket)
3224#include "tst_qtcpsocket.moc"
3225

source code of qtbase/tests/auto/network/socket/qtcpsocket/tst_qtcpsocket.cpp