Fix regression that caused waitForXXX(-1) to fail.
[profile/ivi/qtbase.git] / tests / auto / qtcpsocket / tst_qtcpsocket.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: Nokia Corporation (qt-info@nokia.com)
6 **
7 ** This file is part of the test suite of the Qt Toolkit.
8 **
9 ** $QT_BEGIN_LICENSE:LGPL$
10 ** GNU Lesser General Public License Usage
11 ** This file may be used under the terms of the GNU Lesser General Public
12 ** License version 2.1 as published by the Free Software Foundation and
13 ** appearing in the file LICENSE.LGPL included in the packaging of this
14 ** file. Please review the following information to ensure the GNU Lesser
15 ** General Public License version 2.1 requirements will be met:
16 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
17 **
18 ** In addition, as a special exception, Nokia gives you certain additional
19 ** rights. These rights are described in the Nokia Qt LGPL Exception
20 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
21 **
22 ** GNU General Public License Usage
23 ** Alternatively, this file may be used under the terms of the GNU General
24 ** Public License version 3.0 as published by the Free Software Foundation
25 ** and appearing in the file LICENSE.GPL included in the packaging of this
26 ** file. Please review the following information to ensure the GNU General
27 ** Public License version 3.0 requirements will be met:
28 ** http://www.gnu.org/copyleft/gpl.html.
29 **
30 ** Other Usage
31 ** Alternatively, this file may be used in accordance with the terms and
32 ** conditions contained in a signed written agreement between you and Nokia.
33 **
34 **
35 **
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41
42
43 // Just to get Q_OS_SYMBIAN
44 #include <qglobal.h>
45
46 #if defined(_WIN32) && !defined(Q_OS_SYMBIAN)
47 #include <winsock2.h>
48 #else
49 #include <sys/types.h>
50 #include <sys/socket.h>
51 #include <fcntl.h>
52 #include <unistd.h>
53 #define SOCKET int
54 #define INVALID_SOCKET -1
55 #endif
56
57 #include <qplatformdefs.h>
58
59 #include <QtTest/QtTest>
60
61 #include <QAuthenticator>
62 #include <QCoreApplication>
63 #include <QEventLoop>
64 #include <QFile>
65 #include <QHostAddress>
66 #include <QHostInfo>
67 #include <QMap>
68 #ifndef Q_OS_VXWORKS
69 #include <QMessageBox>
70 #include <QPushButton>
71 #endif
72 #include <QPointer>
73 #include <QProcess>
74 #include <QStringList>
75 #include <QTcpServer>
76 #include <QTcpSocket>
77 #ifndef QT_NO_OPENSSL
78 #include <QSslSocket>
79 #endif
80 #include <QTextStream>
81 #include <QThread>
82 #include <QTime>
83 #include <QTimer>
84 #include <QDebug>
85 // RVCT compiles also unused inline methods
86 # include <QNetworkProxy>
87
88 #ifdef Q_OS_LINUX
89 #include <stdio.h>
90 #include <stdlib.h>
91 #include <sys/stat.h>
92 #include <unistd.h>
93 #endif
94
95 #include "private/qhostinfo_p.h"
96
97 #include "../network-settings.h"
98 #include "../../shared/util.h"
99
100 Q_DECLARE_METATYPE(QAbstractSocket::SocketError)
101 Q_DECLARE_METATYPE(QAbstractSocket::SocketState)
102 Q_DECLARE_METATYPE(QNetworkProxy)
103 Q_DECLARE_METATYPE(QList<QNetworkProxy>)
104
105 //TESTED_CLASS=
106 //TESTED_FILES=
107
108 QT_FORWARD_DECLARE_CLASS(QTcpSocket)
109 QT_FORWARD_DECLARE_CLASS(SocketPair)
110
111 class tst_QTcpSocket : public QObject
112 {
113     Q_OBJECT
114
115 public:
116     tst_QTcpSocket();
117     virtual ~tst_QTcpSocket();
118
119     static void enterLoop(int secs)
120     {
121         ++loopLevel;
122         QTestEventLoop::instance().enterLoop(secs);
123         --loopLevel;
124     }
125     static void exitLoop()
126     {
127         // Safe exit - if we aren't in an event loop, don't
128         // exit one.
129         if (loopLevel > 0)
130             QTestEventLoop::instance().exitLoop();
131     }
132     static bool timeout()
133     {
134         return QTestEventLoop::instance().timeout();
135     }
136
137 public slots:
138     void initTestCase_data();
139     void init();
140     void cleanup();
141 private slots:
142     void socketsConstructedBeforeEventLoop();
143     void constructing();
144     void setInvalidSocketDescriptor();
145     void setSocketDescriptor();
146     void socketDescriptor();
147     void blockingIMAP();
148     void nonBlockingIMAP();
149     void hostNotFound();
150     void timeoutConnect_data();
151     void timeoutConnect();
152     void delayedClose();
153     void partialRead();
154     void unget();
155     void readAllAfterClose();
156     void openCloseOpenClose();
157     void connectDisconnectConnectDisconnect();
158     void disconnectWhileConnecting_data();
159     void disconnectWhileConnecting();
160     void disconnectWhileConnectingNoEventLoop_data();
161     void disconnectWhileConnectingNoEventLoop();
162     void disconnectWhileLookingUp_data();
163     void disconnectWhileLookingUp();
164     void downloadBigFile();
165     void readLine();
166     void readLineString();
167     void readChunks();
168     void waitForBytesWritten();
169     void waitForBytesWrittenMinusOne();
170     void waitForReadyRead();
171     void waitForReadyReadMinusOne();
172     void flush();
173     void synchronousApi();
174     void dontCloseOnTimeout();
175     void recursiveReadyRead();
176     void atEnd();
177     void socketInAThread();
178     void socketsInThreads();
179     void waitForReadyReadInASlot();
180     void remoteCloseError();
181     void openMessageBoxInErrorSlot();
182 #ifndef Q_OS_WIN
183     void connectToLocalHostNoService();
184 #endif
185     void waitForConnectedInHostLookupSlot();
186     void waitForConnectedInHostLookupSlot2();
187     void readyReadSignalsAfterWaitForReadyRead();
188 #ifdef Q_OS_LINUX
189     void linuxKernelBugLocalSocket();
190 #endif
191     void abortiveClose();
192     void localAddressEmptyOnBSD();
193     void zeroAndMinusOneReturns();
194     void connectionRefused();
195     void suddenRemoteDisconnect_data();
196     void suddenRemoteDisconnect();
197     void connectToMultiIP();
198     void moveToThread0();
199     void increaseReadBufferSize();
200     void taskQtBug5799ConnectionErrorWaitForConnected();
201     void taskQtBug5799ConnectionErrorEventLoop();
202     void taskQtBug7054TimeoutErrorResetting();
203
204     void invalidProxy_data();
205     void invalidProxy();
206     void proxyFactory_data();
207     void proxyFactory();
208
209     void qtbug14268_peek();
210
211
212 protected slots:
213     void nonBlockingIMAP_hostFound();
214     void nonBlockingIMAP_connected();
215     void nonBlockingIMAP_closed();
216     void nonBlockingIMAP_readyRead();
217     void nonBlockingIMAP_bytesWritten(qint64);
218     void readRegularFile_readyRead();
219     void exitLoopSlot();
220     void downloadBigFileSlot();
221     void recursiveReadyReadSlot();
222     void waitForReadyReadInASlotSlot();
223     void messageBoxSlot();
224     void hostLookupSlot();
225     void abortiveClose_abortSlot();
226     void remoteCloseErrorSlot();
227     void proxyAuthenticationRequired(const QNetworkProxy &, QAuthenticator *auth);
228     void earlySocketBytesSent(qint64 bytes);
229     void earlySocketReadyRead();
230
231 private:
232     QByteArray expectedReplyIMAP();
233     void fetchExpectedReplyIMAP();
234     QTcpSocket *newSocket() const;
235     QTcpSocket *nonBlockingIMAP_socket;
236     QStringList nonBlockingIMAP_data;
237     qint64 nonBlockingIMAP_totalWritten;
238
239     QTcpSocket *tmpSocket;
240     qint64 bytesAvailable;
241     qint64 expectedLength;
242     bool readingBody;
243     QTime timer;
244
245     QByteArray expectedReplyIMAP_cached;
246
247     mutable int proxyAuthCalled;
248
249     bool gotClosedSignal;
250     int numConnections;
251     static int loopLevel;
252
253     SocketPair *earlyConstructedSockets;
254     int earlyBytesWrittenCount;
255     int earlyReadyReadCount;
256 };
257
258 enum ProxyTests {
259     NoProxy = 0x00,
260     Socks5Proxy = 0x01,
261     HttpProxy = 0x02,
262     TypeMask = 0x0f,
263
264     NoAuth = 0x00,
265     AuthBasic = 0x10,
266     AuthNtlm = 0x20,
267     AuthMask = 0xf0
268 };
269
270 int tst_QTcpSocket::loopLevel = 0;
271
272 class SocketPair: public QObject
273 {
274     Q_OBJECT
275 public:
276     QTcpSocket *endPoints[2];
277
278     SocketPair(QObject *parent = 0)
279         : QObject(parent)
280     {
281         endPoints[0] = endPoints[1] = 0;
282     }
283
284     bool create()
285     {
286         QTcpServer server;
287         server.listen();
288
289         QTcpSocket *active = new QTcpSocket(this);
290         active->connectToHost("127.0.0.1", server.serverPort());
291
292         if (!active->waitForConnected(1000))
293             return false;
294
295         if (!server.waitForNewConnection(1000))
296             return false;
297
298         QTcpSocket *passive = server.nextPendingConnection();
299         passive->setParent(this);
300
301         endPoints[0] = active;
302         endPoints[1] = passive;
303         return true;
304     }
305 };
306
307 tst_QTcpSocket::tst_QTcpSocket()
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(earlyConstructedSockets->endPoints[0], SIGNAL(readyRead()), this, SLOT(earlySocketReadyRead()));
317     connect(earlyConstructedSockets->endPoints[1], SIGNAL(bytesWritten(qint64)), this, SLOT(earlySocketBytesSent(qint64)));
318     earlyConstructedSockets->endPoints[1]->write("hello work");
319 }
320
321 tst_QTcpSocket::~tst_QTcpSocket()
322 {
323
324 }
325
326 void tst_QTcpSocket::initTestCase_data()
327 {
328     QTest::addColumn<bool>("setProxy");
329     QTest::addColumn<int>("proxyType");
330     QTest::addColumn<bool>("ssl");
331
332     qDebug() << QtNetworkSettings::serverName();
333     QTest::newRow("WithoutProxy") << false << 0 << false;
334     QTest::newRow("WithSocks5Proxy") << true << int(Socks5Proxy) << false;
335     QTest::newRow("WithSocks5ProxyAuth") << true << int(Socks5Proxy | AuthBasic) << false;
336
337     QTest::newRow("WithHttpProxy") << true << int(HttpProxy) << false;
338     QTest::newRow("WithHttpProxyBasicAuth") << true << int(HttpProxy | AuthBasic) << false;
339 //    QTest::newRow("WithHttpProxyNtlmAuth") << true << int(HttpProxy | AuthNtlm) << false;
340
341 #ifndef QT_NO_OPENSSL
342     QTest::newRow("WithoutProxy SSL") << false << 0 << true;
343     QTest::newRow("WithSocks5Proxy SSL") << true << int(Socks5Proxy) << true;
344     QTest::newRow("WithSocks5AuthProxy SSL") << true << int(Socks5Proxy | AuthBasic) << true;
345
346     QTest::newRow("WithHttpProxy SSL") << true << int(HttpProxy) << true;
347     QTest::newRow("WithHttpProxyBasicAuth SSL") << true << int(HttpProxy | AuthBasic) << true;
348 //    QTest::newRow("WithHttpProxyNtlmAuth SSL") << true << int(HttpProxy | AuthNtlm) << true;
349 #endif
350 }
351
352 void tst_QTcpSocket::init()
353 {
354     QFETCH_GLOBAL(bool, setProxy);
355     if (setProxy) {
356         QFETCH_GLOBAL(int, proxyType);
357         QList<QHostAddress> addresses = QHostInfo::fromName(QtNetworkSettings::serverName()).addresses();
358         QVERIFY2(addresses.count() > 0, "failed to get ip address for test server");
359         QString fluke = addresses.first().toString();
360         QNetworkProxy proxy;
361
362         switch (proxyType) {
363         case Socks5Proxy:
364             proxy = QNetworkProxy(QNetworkProxy::Socks5Proxy, fluke, 1080);
365             break;
366
367         case Socks5Proxy | AuthBasic:
368             proxy = QNetworkProxy(QNetworkProxy::Socks5Proxy, fluke, 1081);
369             break;
370
371         case HttpProxy | NoAuth:
372             proxy = QNetworkProxy(QNetworkProxy::HttpProxy, fluke, 3128);
373             break;
374
375         case HttpProxy | AuthBasic:
376             proxy = QNetworkProxy(QNetworkProxy::HttpProxy, fluke, 3129);
377             break;
378
379         case HttpProxy | AuthNtlm:
380             proxy = QNetworkProxy(QNetworkProxy::HttpProxy, fluke, 3130);
381             break;
382         }
383         QNetworkProxy::setApplicationProxy(proxy);
384     }
385
386     qt_qhostinfo_clear_cache();
387 }
388
389 QTcpSocket *tst_QTcpSocket::newSocket() const
390 {
391     QTcpSocket *socket;
392 #ifndef QT_NO_OPENSSL
393     QFETCH_GLOBAL(bool, ssl);
394     socket = ssl ? new QSslSocket : new QTcpSocket;
395 #else
396     socket = new QTcpSocket;
397 #endif
398
399     proxyAuthCalled = 0;
400     connect(socket, SIGNAL(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)),
401             SLOT(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)),
402             Qt::DirectConnection);
403     return socket;
404 }
405
406 void tst_QTcpSocket::cleanup()
407 {
408     QNetworkProxy::setApplicationProxy(QNetworkProxy::DefaultProxy);
409 }
410
411 void tst_QTcpSocket::proxyAuthenticationRequired(const QNetworkProxy &, QAuthenticator *auth)
412 {
413     ++proxyAuthCalled;
414     auth->setUser("qsockstest");
415     auth->setPassword("password");
416 }
417
418 //----------------------------------------------------------------------------------
419
420 void tst_QTcpSocket::socketsConstructedBeforeEventLoop()
421 {
422     QFETCH_GLOBAL(bool, setProxy);
423     QFETCH_GLOBAL(bool, ssl);
424     if (setProxy || ssl)
425         return;
426     //This test checks that sockets constructed before QCoreApplication::exec() still emit signals
427     //see construction code in the tst_QTcpSocket constructor
428     enterLoop(3);
429     QCOMPARE(earlyBytesWrittenCount, 1);
430     QCOMPARE(earlyReadyReadCount, 1);
431     earlyConstructedSockets->endPoints[0]->close();
432     earlyConstructedSockets->endPoints[1]->close();
433 }
434
435 void tst_QTcpSocket::earlySocketBytesSent(qint64 /* bytes */)
436 {
437     earlyBytesWrittenCount++;
438 }
439
440 void tst_QTcpSocket::earlySocketReadyRead()
441 {
442     earlyReadyReadCount++;
443 }
444
445 //----------------------------------------------------------------------------------
446
447 void tst_QTcpSocket::constructing()
448 {
449     QTcpSocket *socket = newSocket();
450
451     // Check the initial state of the QTcpSocket.
452     QCOMPARE(socket->state(), QTcpSocket::UnconnectedState);
453     QVERIFY(socket->isSequential());
454     QVERIFY(!socket->isOpen());
455     QVERIFY(!socket->isValid());
456     QCOMPARE(socket->socketType(), QTcpSocket::TcpSocket);
457
458     char c;
459     QCOMPARE(socket->getChar(&c), false);
460     QCOMPARE((int) socket->bytesAvailable(), 0);
461     QCOMPARE(socket->canReadLine(), false);
462     QCOMPARE(socket->readLine(), QByteArray());
463     QCOMPARE(socket->socketDescriptor(), -1);
464     QCOMPARE((int) socket->localPort(), 0);
465     QVERIFY(socket->localAddress() == QHostAddress());
466     QCOMPARE((int) socket->peerPort(), 0);
467     QVERIFY(socket->peerAddress() == QHostAddress());
468     QCOMPARE(socket->error(), QTcpSocket::UnknownSocketError);
469     QCOMPARE(socket->errorString(), QString("Unknown error"));
470
471     // Check the state of the socket layer?
472     delete socket;
473 }
474
475 //----------------------------------------------------------------------------------
476
477 void tst_QTcpSocket::setInvalidSocketDescriptor()
478 {
479     QTcpSocket *socket = newSocket();
480     QCOMPARE(socket->socketDescriptor(), -1);
481 #ifdef Q_OS_SYMBIAN
482     QTest::ignoreMessage(QtWarningMsg, "QSymbianSocketEngine::initialize - socket descriptor not found");
483 #endif
484     QVERIFY(!socket->setSocketDescriptor(-5, QTcpSocket::UnconnectedState));
485     QCOMPARE(socket->socketDescriptor(), -1);
486
487     QCOMPARE(socket->error(), QTcpSocket::UnsupportedSocketOperationError);
488
489     delete socket;
490 }
491
492 //----------------------------------------------------------------------------------
493
494 void tst_QTcpSocket::setSocketDescriptor()
495 {
496 #ifdef Q_OS_SYMBIAN
497     QSKIP("adopting open c socket handles is not supported", SkipAll);
498 #else
499     QFETCH_GLOBAL(bool, setProxy);
500     if (setProxy)
501         return;                 // this test doesn't make sense with proxies
502
503 #ifdef Q_OS_WIN
504     // need the dummy to ensure winsock is started
505     QTcpSocket *dummy = newSocket();
506     dummy->connectToHost(QtNetworkSettings::serverName(), 143);
507     QVERIFY(dummy->waitForConnected());
508
509     SOCKET sock = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
510     if (sock == INVALID_SOCKET) {
511         qErrnoWarning(WSAGetLastError(), "INVALID_SOCKET");
512     }
513 #else
514     SOCKET sock = ::socket(AF_INET, SOCK_STREAM, 0);
515
516     // artificially increase the value of sock
517     SOCKET sock2 = ::fcntl(sock, F_DUPFD, sock + 50);
518     ::close(sock);
519     sock = sock2;
520 #endif
521
522     QVERIFY(sock != INVALID_SOCKET);
523     QTcpSocket *socket = newSocket();
524     QVERIFY(socket->setSocketDescriptor(sock, QTcpSocket::UnconnectedState));
525     QCOMPARE(socket->socketDescriptor(), (int)sock);
526
527     socket->connectToHost(QtNetworkSettings::serverName(), 143);
528     QCOMPARE(socket->state(), QTcpSocket::HostLookupState);
529     QCOMPARE(socket->socketDescriptor(), (int)sock);
530     QVERIFY(socket->waitForConnected(10000));
531     // skip this, it has been broken for years, see task 260735
532     // if somebody complains, consider fixing it, but it might break existing applications.
533     QEXPECT_FAIL("", "bug has been around for years, will not fix without need", Continue);
534     QCOMPARE(socket->socketDescriptor(), (int)sock);
535     delete socket;
536 #ifdef Q_OS_WIN
537     delete dummy;
538 #endif
539 #endif
540 }
541
542 //----------------------------------------------------------------------------------
543
544 void tst_QTcpSocket::socketDescriptor()
545 {
546     QTcpSocket *socket = newSocket();
547
548     QCOMPARE(socket->socketDescriptor(), -1);
549     socket->connectToHost(QtNetworkSettings::serverName(), 143);
550     QVERIFY((socket->state() == QAbstractSocket::HostLookupState && socket->socketDescriptor() == -1) ||
551             (socket->state() == QAbstractSocket::ConnectingState && socket->socketDescriptor() != -1));
552     QVERIFY(socket->waitForConnected(10000));
553     QVERIFY(socket->state() == QAbstractSocket::ConnectedState);
554     QVERIFY(socket->socketDescriptor() != -1);
555
556     delete socket;
557 }
558
559 //----------------------------------------------------------------------------------
560
561 void tst_QTcpSocket::blockingIMAP()
562 {
563     QTcpSocket *socket = newSocket();
564
565     // Connect
566     socket->connectToHost(QtNetworkSettings::serverName(), 143);
567     QVERIFY(socket->waitForConnected(10000));
568     QCOMPARE(socket->state(), QTcpSocket::ConnectedState);
569     QVERIFY(socket->isValid());
570
571     // Read greeting
572     QVERIFY(socket->waitForReadyRead(5000));
573     QString s = socket->readLine();
574     // only test if an OK was returned, to make the test compatible between different
575     // IMAP server versions
576     QCOMPARE(s.left(4).toLatin1().constData(), "* OK");
577
578     // Write NOOP
579     QCOMPARE((int) socket->write("1 NOOP\r\n", 8), 8);
580     QCOMPARE((int) socket->write("2 NOOP\r\n", 8), 8);
581
582     if (!socket->canReadLine())
583         QVERIFY(socket->waitForReadyRead(5000));
584
585     // Read response
586     s = socket->readLine();
587     QCOMPARE(s.toLatin1().constData(), "1 OK Completed\r\n");
588
589     // Write a third NOOP to verify that write doesn't clear the read buffer
590     QCOMPARE((int) socket->write("3 NOOP\r\n", 8), 8);
591
592     // Read second response
593     if (!socket->canReadLine())
594         QVERIFY(socket->waitForReadyRead(5000));
595     s = socket->readLine();
596     QCOMPARE(s.toLatin1().constData(), "2 OK Completed\r\n");
597
598     // Read third response
599     if (!socket->canReadLine())
600         QVERIFY(socket->waitForReadyRead(5000));
601     s = socket->readLine();
602     QCOMPARE(s.toLatin1().constData(), "3 OK Completed\r\n");
603
604
605     // Write LOGOUT
606     QCOMPARE((int) socket->write("4 LOGOUT\r\n", 10), 10);
607
608     if (!socket->canReadLine())
609         QVERIFY(socket->waitForReadyRead(5000));
610
611     // Read two lines of respose
612     s = socket->readLine();
613     QCOMPARE(s.toLatin1().constData(), "* BYE LOGOUT received\r\n");
614
615     if (!socket->canReadLine())
616         QVERIFY(socket->waitForReadyRead(5000));
617
618     s = socket->readLine();
619     QCOMPARE(s.toLatin1().constData(), "4 OK Completed\r\n");
620
621     // Close the socket
622     socket->close();
623
624     // Check that it's closed
625     QCOMPARE(socket->state(), QTcpSocket::UnconnectedState);
626
627     delete socket;
628 }
629
630 //----------------------------------------------------------------------------------
631
632 void tst_QTcpSocket::hostNotFound()
633 {
634     QTcpSocket *socket = newSocket();
635
636     socket->connectToHost("nosuchserver.troll.no", 80);
637     QVERIFY(!socket->waitForConnected());
638     QCOMPARE(socket->state(), QTcpSocket::UnconnectedState);
639     QCOMPARE(int(socket->error()), int(QTcpSocket::HostNotFoundError));
640
641     delete socket;
642 }
643
644 //----------------------------------------------------------------------------------
645 void tst_QTcpSocket::timeoutConnect_data()
646 {
647     QTest::addColumn<QString>("address");
648     QTest::newRow("host") << QtNetworkSettings::serverName();
649     QTest::newRow("ip") << QtNetworkSettings::serverIP().toString();
650 }
651
652 void tst_QTcpSocket::timeoutConnect()
653 {
654     QFETCH(QString, address);
655     QTcpSocket *socket = newSocket();
656
657     QElapsedTimer timer;
658     timer.start();
659
660     // Port 1357 is configured to drop packets on the test server
661     socket->connectToHost(address, 1357);
662     QVERIFY(timer.elapsed() < 150);
663     QVERIFY(!socket->waitForConnected(1000)); //200ms is too short when using SOCKS proxy authentication
664     QCOMPARE(socket->state(), QTcpSocket::UnconnectedState);
665     QCOMPARE(int(socket->error()), int(QTcpSocket::SocketTimeoutError));
666
667     timer.start();
668     socket->connectToHost(address, 1357);
669     QVERIFY(timer.elapsed() < 150);
670     QTimer::singleShot(50, &QTestEventLoop::instance(), SLOT(exitLoop()));
671     QTestEventLoop::instance().enterLoop(5);
672     QVERIFY(!QTestEventLoop::instance().timeout());
673     QVERIFY(socket->state() == QTcpSocket::ConnectingState
674             || socket->state() == QTcpSocket::HostLookupState);
675     socket->abort();
676     QCOMPARE(socket->state(), QTcpSocket::UnconnectedState);
677     QCOMPARE(socket->openMode(), QIODevice::NotOpen);
678
679     delete socket;
680 }
681
682 //----------------------------------------------------------------------------------
683
684 void tst_QTcpSocket::nonBlockingIMAP()
685 {
686     QTcpSocket *socket = newSocket();
687     connect(socket, SIGNAL(hostFound()), SLOT(nonBlockingIMAP_hostFound()));
688     connect(socket, SIGNAL(connected()), SLOT(nonBlockingIMAP_connected()));
689     connect(socket, SIGNAL(disconnected()), SLOT(nonBlockingIMAP_closed()));
690     connect(socket, SIGNAL(bytesWritten(qint64)), SLOT(nonBlockingIMAP_bytesWritten(qint64)));
691     connect(socket, SIGNAL(readyRead()), SLOT(nonBlockingIMAP_readyRead()));
692     nonBlockingIMAP_socket = socket;
693
694     // Connect
695     socket->connectToHost(QtNetworkSettings::serverName(), 143);
696     QVERIFY(socket->state() == QTcpSocket::HostLookupState ||
697             socket->state() == QTcpSocket::ConnectingState);
698
699     enterLoop(30);
700     if (timeout()) {
701         QFAIL("Timed out");
702     }
703
704     if (socket->state() == QTcpSocket::ConnectingState) {
705         enterLoop(30);
706         if (timeout()) {
707             QFAIL("Timed out");
708         }
709     }
710
711     QCOMPARE(socket->state(), QTcpSocket::ConnectedState);
712
713     enterLoop(30);
714     if (timeout()) {
715         QFAIL("Timed out");
716     }
717
718     // Read greeting
719     QVERIFY(!nonBlockingIMAP_data.isEmpty());
720     QCOMPARE(nonBlockingIMAP_data.at(0).left(4).toLatin1().constData(), "* OK");
721     nonBlockingIMAP_data.clear();
722
723     nonBlockingIMAP_totalWritten = 0;
724
725     // Write NOOP
726     QCOMPARE((int) socket->write("1 NOOP\r\n", 8), 8);
727
728
729     enterLoop(30);
730     if (timeout()) {
731         QFAIL("Timed out");
732     }
733
734     QVERIFY(nonBlockingIMAP_totalWritten == 8);
735
736
737     enterLoop(30);
738     if (timeout()) {
739         QFAIL("Timed out");
740     }
741
742
743     // Read response
744     QVERIFY(!nonBlockingIMAP_data.isEmpty());
745     QCOMPARE(nonBlockingIMAP_data.at(0).toLatin1().constData(), "1 OK Completed\r\n");
746     nonBlockingIMAP_data.clear();
747
748
749     nonBlockingIMAP_totalWritten = 0;
750
751     // Write LOGOUT
752     QCOMPARE((int) socket->write("2 LOGOUT\r\n", 10), 10);
753
754     enterLoop(30);
755     if (timeout()) {
756         QFAIL("Timed out");
757     }
758
759     QVERIFY(nonBlockingIMAP_totalWritten == 10);
760
761     // Wait for greeting
762     enterLoop(30);
763     if (timeout()) {
764         QFAIL("Timed out");
765     }
766
767     // Read two lines of respose
768     QCOMPARE(nonBlockingIMAP_data.at(0).toLatin1().constData(), "* BYE LOGOUT received\r\n");
769     QCOMPARE(nonBlockingIMAP_data.at(1).toLatin1().constData(), "2 OK Completed\r\n");
770     nonBlockingIMAP_data.clear();
771
772     // Close the socket
773     socket->close();
774
775     // Check that it's closed
776     QCOMPARE(socket->state(), QTcpSocket::UnconnectedState);
777
778     delete socket;
779 }
780
781 void tst_QTcpSocket::nonBlockingIMAP_hostFound()
782 {
783     exitLoop();
784 }
785
786 void tst_QTcpSocket::nonBlockingIMAP_connected()
787 {
788     exitLoop();
789 }
790
791 void tst_QTcpSocket::nonBlockingIMAP_readyRead()
792 {
793     while (nonBlockingIMAP_socket->canReadLine())
794         nonBlockingIMAP_data.append(nonBlockingIMAP_socket->readLine());
795
796     exitLoop();
797 }
798
799 void tst_QTcpSocket::nonBlockingIMAP_bytesWritten(qint64 written)
800 {
801     nonBlockingIMAP_totalWritten += written;
802     exitLoop();
803 }
804
805 void tst_QTcpSocket::nonBlockingIMAP_closed()
806 {
807 }
808
809 //----------------------------------------------------------------------------------
810
811 void tst_QTcpSocket::delayedClose()
812 {
813     QTcpSocket *socket = newSocket();
814     connect(socket, SIGNAL(connected()), SLOT(nonBlockingIMAP_connected()));
815     connect(socket, SIGNAL(disconnected()), SLOT(exitLoopSlot()));
816
817     socket->connectToHost(QtNetworkSettings::serverName(), 143);
818
819     enterLoop(30);
820     if (timeout())
821         QFAIL("Timed out");
822
823     QCOMPARE(socket->state(), QTcpSocket::ConnectedState);
824
825     QCOMPARE((int) socket->write("1 LOGOUT\r\n", 10), 10);
826
827     // Add a huge bulk of data to be written after the logout
828     // command. The server will shut down after receiving the LOGOUT,
829     // so this data will not be read. But our close call should
830     // schedule a delayed close because all the data can not be
831     // written in one go.
832     QCOMPARE((int) socket->write(QByteArray(100000, '\n'), 100000), 100000);
833
834     socket->close();
835
836     QCOMPARE((int) socket->state(), (int) QTcpSocket::ClosingState);
837
838     enterLoop(10);
839     if (timeout())
840         QFAIL("Timed out");
841
842     QCOMPARE(socket->state(), QTcpSocket::UnconnectedState);
843
844     delete socket;
845 }
846
847
848 //----------------------------------------------------------------------------------
849
850 QByteArray tst_QTcpSocket::expectedReplyIMAP()
851 {
852     if (expectedReplyIMAP_cached.isEmpty()) {
853         fetchExpectedReplyIMAP();
854     }
855
856     return expectedReplyIMAP_cached;
857 }
858
859 // Figure out how the current IMAP server responds
860 void tst_QTcpSocket::fetchExpectedReplyIMAP()
861 {
862     QTcpSocket *socket = newSocket();
863     socket->connectToHost(QtNetworkSettings::serverName(), 143);
864     QVERIFY2(socket->waitForConnected(10000), qPrintable(socket->errorString()));
865     QVERIFY2(socket->state() == QTcpSocket::ConnectedState, qPrintable(socket->errorString()));
866
867     QTRY_VERIFY(socket->canReadLine());
868
869     QByteArray greeting = socket->readLine();
870     delete socket;
871
872     QVERIFY2(QtNetworkSettings::compareReplyIMAP(greeting), greeting.constData());
873
874     expectedReplyIMAP_cached = greeting;
875 }
876
877 //----------------------------------------------------------------------------------
878
879 void tst_QTcpSocket::partialRead()
880 {
881     QTcpSocket *socket = newSocket();
882     socket->connectToHost(QtNetworkSettings::serverName(), 143);
883     QVERIFY(socket->waitForConnected(10000));
884     QVERIFY(socket->state() == QTcpSocket::ConnectedState);
885     char buf[512];
886
887     QByteArray greeting = expectedReplyIMAP();
888     QVERIFY(!greeting.isEmpty());
889
890     for (int i = 0; i < 10; i += 2) {
891         while (socket->bytesAvailable() < 2)
892             QVERIFY(socket->waitForReadyRead(5000));
893         QVERIFY(socket->read(buf, 2) == 2);
894         buf[2] = '\0';
895         QCOMPARE((char *)buf, greeting.mid(i, 2).data());
896     }
897
898     delete socket;
899 }
900
901 //----------------------------------------------------------------------------------
902
903 void tst_QTcpSocket::unget()
904 {
905     QTcpSocket *socket = newSocket();
906     socket->connectToHost(QtNetworkSettings::serverName(), 143);
907     QVERIFY(socket->waitForConnected(10000));
908     QVERIFY(socket->state() == QTcpSocket::ConnectedState);
909     char buf[512];
910
911     QByteArray greeting = expectedReplyIMAP();
912     QVERIFY(!greeting.isEmpty());
913
914     for (int i = 0; i < 10; i += 2) {
915         while (socket->bytesAvailable() < 2)
916             QVERIFY(socket->waitForReadyRead(10000));
917         int bA = socket->bytesAvailable();
918         QVERIFY(socket->read(buf, 2) == 2);
919         buf[2] = '\0';
920         QCOMPARE((char *)buf, greeting.mid(i, 2).data());
921         QCOMPARE((int)socket->bytesAvailable(), bA - 2);
922         socket->ungetChar(buf[1]);
923         socket->ungetChar(buf[0]);
924         QCOMPARE((int)socket->bytesAvailable(), bA);
925         QVERIFY(socket->read(buf, 2) == 2);
926         buf[2] = '\0';
927         QCOMPARE((char *)buf, greeting.mid(i, 2).data());
928     }
929
930     delete socket;
931 }
932
933 //----------------------------------------------------------------------------------
934 void tst_QTcpSocket::readRegularFile_readyRead()
935 {
936     exitLoop();
937 }
938
939 //----------------------------------------------------------------------------------
940 void tst_QTcpSocket::readAllAfterClose()
941 {
942     QTcpSocket *socket = newSocket();
943     socket->connectToHost(QtNetworkSettings::serverName(), 143);
944     connect(socket, SIGNAL(readyRead()), SLOT(readRegularFile_readyRead()));
945     enterLoop(10);
946     if (timeout())
947         QFAIL("Network operation timed out");
948
949     socket->close();
950     QByteArray array = socket->readAll();
951     QCOMPARE(array.size(), 0);
952
953     delete socket;
954 }
955
956 //----------------------------------------------------------------------------------
957 void tst_QTcpSocket::openCloseOpenClose()
958 {
959     QTcpSocket *socket = newSocket();
960
961     for (int i = 0; i < 3; ++i) {
962         QCOMPARE(socket->state(), QTcpSocket::UnconnectedState);
963         QCOMPARE(int(socket->openMode()), int(QIODevice::NotOpen));
964         QVERIFY(socket->isSequential());
965         QVERIFY(!socket->isOpen());
966         QVERIFY(socket->socketType() == QTcpSocket::TcpSocket);
967
968         char c;
969         QCOMPARE(socket->getChar(&c), false);
970         QCOMPARE((int) socket->bytesAvailable(), 0);
971         QCOMPARE(socket->canReadLine(), false);
972         QCOMPARE(socket->readLine(), QByteArray());
973         QCOMPARE(socket->socketDescriptor(), -1);
974         QCOMPARE((int) socket->localPort(), 0);
975         QVERIFY(socket->localAddress() == QHostAddress());
976         QCOMPARE((int) socket->peerPort(), 0);
977         QVERIFY(socket->peerAddress() == QHostAddress());
978         QCOMPARE(socket->error(), QTcpSocket::UnknownSocketError);
979         QCOMPARE(socket->errorString(), QString("Unknown error"));
980
981         QVERIFY(socket->state() == QTcpSocket::UnconnectedState);
982
983         socket->connectToHost(QtNetworkSettings::serverName(), 143);
984         QVERIFY(socket->waitForConnected(10000));
985         socket->close();
986     }
987
988     delete socket;
989 }
990
991 //----------------------------------------------------------------------------------
992 void tst_QTcpSocket::connectDisconnectConnectDisconnect()
993 {
994     QTcpSocket *socket = newSocket();
995
996     for (int i = 0; i < 3; ++i) {
997         QCOMPARE(socket->state(), QTcpSocket::UnconnectedState);
998         QVERIFY(socket->socketType() == QTcpSocket::TcpSocket);
999
1000         socket->connectToHost(QtNetworkSettings::serverName(), 143);
1001         QVERIFY(socket->waitForReadyRead(10000));
1002         QCOMPARE(QString::fromLatin1(socket->read(4)), QString("* OK"));
1003
1004         socket->disconnectFromHost();
1005         if (socket->state() != QTcpSocket::UnconnectedState)
1006             QVERIFY(socket->waitForDisconnected(10000));
1007         QCOMPARE(int(socket->openMode()), int(QIODevice::ReadWrite));
1008     }
1009
1010     delete socket;
1011 }
1012
1013 //----------------------------------------------------------------------------------
1014 void tst_QTcpSocket::disconnectWhileConnecting_data()
1015 {
1016     QTest::addColumn<QByteArray>("data");
1017     QTest::addColumn<bool>("closeDirectly");
1018
1019     QTest::newRow("without-data") << QByteArray() << false;
1020     QTest::newRow("without-data+close") << QByteArray() << true;
1021     QTest::newRow("with-data") << QByteArray("Hello, world!") << false;
1022     QTest::newRow("with-data+close") << QByteArray("Hello, world!") << true;
1023
1024     QByteArray bigData(1024*1024, '@');
1025     QTest::newRow("with-big-data") << bigData << false;
1026     QTest::newRow("with-big-data+close") << bigData << true;
1027 }
1028
1029 void tst_QTcpSocket::disconnectWhileConnecting()
1030 {
1031     QFETCH(QByteArray, data);
1032     QFETCH_GLOBAL(bool, setProxy);
1033     if (setProxy)
1034         return; //proxy not useful for localhost test case
1035
1036     QTcpServer server;
1037     QVERIFY(server.listen(QHostAddress::LocalHost));
1038
1039     // proceed to the connect-write-disconnect
1040     QTcpSocket *socket = newSocket();
1041     socket->connectToHost("127.0.0.1", server.serverPort());
1042     if (!data.isEmpty())
1043         socket->write(data);
1044     if (socket->state() == QAbstractSocket::ConnectedState)
1045         QSKIP("localhost connections are immediate, test case is invalid", SkipSingle);
1046
1047     QFETCH(bool, closeDirectly);
1048     if (closeDirectly) {
1049         socket->close();
1050         QCOMPARE(int(socket->openMode()), int(QIODevice::NotOpen));
1051     } else {
1052         socket->disconnectFromHost();
1053     }
1054
1055     connect(socket, SIGNAL(disconnected()), SLOT(exitLoopSlot()));
1056 #ifndef Q_OS_SYMBIAN
1057     enterLoop(10);
1058 #else
1059     enterLoop(30);
1060 #endif
1061     QVERIFY2(!timeout(), "Network timeout");
1062     QVERIFY(socket->state() == QAbstractSocket::UnconnectedState);
1063     if (!closeDirectly) {
1064         QCOMPARE(int(socket->openMode()), int(QIODevice::ReadWrite));
1065         socket->close();
1066     }
1067     QCOMPARE(int(socket->openMode()), int(QIODevice::NotOpen));
1068
1069     // accept the other side and verify that it was sent properly:
1070     QVERIFY(server.hasPendingConnections() || server.waitForNewConnection(0));
1071     QTcpSocket *othersocket = server.nextPendingConnection();
1072     if (othersocket->state() != QAbstractSocket::UnconnectedState)
1073         QVERIFY2(othersocket->waitForDisconnected(10000), "Network timeout");
1074     QVERIFY(othersocket->state() == QAbstractSocket::UnconnectedState);
1075     QCOMPARE(othersocket->readAll(), data);
1076
1077     delete socket;
1078     delete othersocket;
1079 }
1080
1081 //----------------------------------------------------------------------------------
1082 class ReceiverThread: public QThread
1083 {
1084     QTcpServer *server;
1085 public:
1086     int serverPort;
1087     bool ok;
1088     QByteArray receivedData;
1089     volatile bool quit;
1090
1091     ReceiverThread()
1092         : server(0), ok(false), quit(false)
1093     { }
1094
1095     ~ReceiverThread() { }
1096
1097     bool listen()
1098     {
1099         server = new QTcpServer;
1100         if (!server->listen(QHostAddress::LocalHost))
1101             return false;
1102         serverPort = server->serverPort();
1103         server->moveToThread(this);
1104         return true;
1105     }
1106
1107     static void cleanup(void *ptr)
1108     {
1109         ReceiverThread* self = reinterpret_cast<ReceiverThread*>(ptr);
1110         self->quit = true;
1111         self->wait(30000);
1112         delete self;
1113     }
1114
1115 protected:
1116     void run()
1117     {
1118         bool timedOut = false;
1119         while (!quit) {
1120 #ifndef Q_OS_SYMBIAN
1121             if (server->waitForNewConnection(500, &timedOut))
1122 #else
1123             if (server->waitForNewConnection(5000, &timedOut))
1124 #endif
1125                 break;
1126             if (!timedOut)
1127                 return;
1128         }
1129
1130         QTcpSocket *socket = server->nextPendingConnection();
1131         while (!quit) {
1132 #ifndef Q_OS_SYMBIAN
1133             if (socket->waitForDisconnected(500))
1134 #else
1135             if (socket->waitForDisconnected(5000))
1136 #endif
1137                 break;
1138             if (socket->error() != QAbstractSocket::SocketTimeoutError)
1139                 return;
1140         }
1141
1142         if (!quit) {
1143             receivedData = socket->readAll();
1144             ok = true;
1145         }
1146         delete socket;
1147         delete server;
1148         server = 0;
1149     }
1150 };
1151
1152 void tst_QTcpSocket::disconnectWhileConnectingNoEventLoop_data()
1153 {
1154     disconnectWhileConnecting_data();
1155 }
1156
1157 void tst_QTcpSocket::disconnectWhileConnectingNoEventLoop()
1158 {
1159     QFETCH(QByteArray, data);
1160     QFETCH_GLOBAL(bool, setProxy);
1161     if (setProxy)
1162         return; //proxy not useful for localhost test case
1163
1164     QScopedPointer<ReceiverThread, ReceiverThread> thread (new ReceiverThread);
1165     QVERIFY(thread->listen());
1166     thread->start();
1167
1168     // proceed to the connect-write-disconnect
1169     QTcpSocket *socket = newSocket();
1170     socket->connectToHost("127.0.0.1", thread->serverPort);
1171     if (!data.isEmpty())
1172         socket->write(data);
1173     if (socket->state() == QAbstractSocket::ConnectedState) {
1174         QSKIP("localhost connections are immediate, test case is invalid", SkipSingle);
1175     }
1176
1177     QFETCH(bool, closeDirectly);
1178     if (closeDirectly) {
1179         socket->close();
1180         QCOMPARE(int(socket->openMode()), int(QIODevice::NotOpen));
1181     } else {
1182         socket->disconnectFromHost();
1183     }
1184
1185 #ifndef Q_OS_SYMBIAN
1186     QVERIFY2(socket->waitForDisconnected(10000), "Network timeout");
1187 #else
1188     QVERIFY2(socket->waitForDisconnected(30000), "Network timeout");
1189 #endif
1190     QVERIFY(socket->state() == QAbstractSocket::UnconnectedState);
1191     if (!closeDirectly) {
1192         QCOMPARE(int(socket->openMode()), int(QIODevice::ReadWrite));
1193         socket->close();
1194     }
1195     QCOMPARE(int(socket->openMode()), int(QIODevice::NotOpen));
1196     delete socket;
1197
1198     // check if the other side received everything ok
1199     QVERIFY(thread->wait(30000));
1200     QVERIFY(thread->ok);
1201     QCOMPARE(thread->receivedData, data);
1202 }
1203
1204 //----------------------------------------------------------------------------------
1205 void tst_QTcpSocket::disconnectWhileLookingUp_data()
1206 {
1207     QTest::addColumn<bool>("doClose");
1208
1209     QTest::newRow("disconnect") << false;
1210     QTest::newRow("close") << true;
1211 }
1212
1213 void tst_QTcpSocket::disconnectWhileLookingUp()
1214 {
1215     QFETCH_GLOBAL(bool, setProxy);
1216     if (setProxy)
1217         return;                 // we let the proxies do the lookup now
1218
1219     // just connect and disconnect, then make sure nothing weird happened
1220     QTcpSocket *socket = newSocket();
1221     socket->connectToHost(QtNetworkSettings::serverName(), 21);
1222
1223     // check that connect is in progress
1224     QVERIFY(socket->state() != QAbstractSocket::UnconnectedState);
1225
1226     QFETCH(bool, doClose);
1227     if (doClose) {
1228         socket->close();
1229         QVERIFY(socket->openMode() == QIODevice::NotOpen);
1230     } else {
1231         socket->disconnectFromHost();
1232         QVERIFY(socket->openMode() == QIODevice::ReadWrite);
1233     }
1234
1235     // let anything queued happen
1236     QEventLoop loop;
1237 #ifndef Q_OS_SYMBIAN
1238     QTimer::singleShot(50, &loop, SLOT(quit()));
1239 #else
1240     QTimer::singleShot(5000, &loop, SLOT(quit()));
1241 #endif
1242     loop.exec();
1243
1244     // recheck
1245     if (doClose) {
1246         QVERIFY(socket->openMode() == QIODevice::NotOpen);
1247     } else {
1248         QVERIFY(socket->openMode() == QIODevice::ReadWrite);
1249     }
1250
1251     QVERIFY(socket->state() == QAbstractSocket::UnconnectedState);
1252 }
1253
1254 //----------------------------------------------------------------------------------
1255 void tst_QTcpSocket::downloadBigFile()
1256 {
1257     if (tmpSocket)
1258         delete tmpSocket;
1259     tmpSocket = newSocket();
1260
1261     connect(tmpSocket, SIGNAL(connected()), SLOT(exitLoopSlot()));
1262     connect(tmpSocket, SIGNAL(readyRead()), SLOT(downloadBigFileSlot()));
1263     connect(tmpSocket, SIGNAL(disconnected()), SLOT(exitLoopSlot()));
1264
1265     tmpSocket->connectToHost(QtNetworkSettings::serverName(), 80);
1266
1267     enterLoop(30);
1268     if (timeout()) {
1269         delete tmpSocket;
1270         tmpSocket = 0;
1271         QFAIL("Network operation timed out");
1272     }
1273
1274     QByteArray hostName = QtNetworkSettings::serverName().toLatin1();
1275     QVERIFY(tmpSocket->state() == QAbstractSocket::ConnectedState);
1276     QVERIFY(tmpSocket->write("GET /qtest/mediumfile HTTP/1.0\r\n") > 0);
1277     QVERIFY(tmpSocket->write("HOST: ") > 0);
1278     QVERIFY(tmpSocket->write(hostName.data()) > 0);
1279     QVERIFY(tmpSocket->write("\r\n") > 0);
1280     QVERIFY(tmpSocket->write("\r\n") > 0);
1281
1282     bytesAvailable = 0;
1283     expectedLength = 0;
1284     readingBody = false;
1285
1286     QTime stopWatch;
1287     stopWatch.start();
1288
1289     enterLoop(600);
1290     if (timeout()) {
1291         delete tmpSocket;
1292         tmpSocket = 0;
1293         if (bytesAvailable > 0)
1294             qDebug("Slow Connection, only downloaded %ld of %d", long(bytesAvailable), 10000281);
1295         QFAIL("Network operation timed out");
1296     }
1297
1298     QCOMPARE(bytesAvailable, expectedLength);
1299
1300     qDebug("\t\t%.1fMB/%.1fs: %.1fMB/s",
1301            bytesAvailable / (1024.0 * 1024.0),
1302            stopWatch.elapsed() / 1024.0,
1303            (bytesAvailable / (stopWatch.elapsed() / 1000.0)) / (1024 * 1024));
1304
1305     delete tmpSocket;
1306     tmpSocket = 0;
1307 }
1308
1309 //----------------------------------------------------------------------------------
1310 void tst_QTcpSocket::exitLoopSlot()
1311 {
1312     exitLoop();
1313 }
1314
1315 //----------------------------------------------------------------------------------
1316 void tst_QTcpSocket::downloadBigFileSlot()
1317 {
1318     if (!readingBody) {
1319         while (tmpSocket->canReadLine()) {
1320             QByteArray array = tmpSocket->readLine();
1321             if (array.startsWith("Content-Length"))
1322                 expectedLength = array.simplified().split(' ').at(1).toInt();
1323             if (array == "\r\n") {
1324                 readingBody = true;
1325                 break;
1326             }
1327         }
1328     }
1329     if (readingBody) {
1330         bytesAvailable += tmpSocket->readAll().size();
1331         if (bytesAvailable == expectedLength)
1332             exitLoop();
1333     }
1334 }
1335
1336 //----------------------------------------------------------------------------------
1337 void tst_QTcpSocket::readLine()
1338 {
1339     QTcpSocket *socket = newSocket();
1340     socket->connectToHost(QtNetworkSettings::serverName(), 143);
1341     QVERIFY(socket->waitForConnected(5000));
1342
1343     while (!socket->canReadLine())
1344         QVERIFY(socket->waitForReadyRead(10000));
1345
1346     char buffer[1024];
1347
1348     qint64 linelen = socket->readLine(buffer, sizeof(buffer));
1349     QVERIFY(linelen >= 3);
1350     QVERIFY(linelen < 1024);
1351
1352     QByteArray reply = QByteArray::fromRawData(buffer, linelen);
1353     QCOMPARE((int) buffer[linelen-2], (int) '\r');
1354     QCOMPARE((int) buffer[linelen-1], (int) '\n');
1355     QCOMPARE((int) buffer[linelen],   (int) '\0');
1356
1357     QVERIFY2(QtNetworkSettings::compareReplyIMAP(reply), reply.constData());
1358
1359     QCOMPARE(socket->write("1 NOOP\r\n"), qint64(8));
1360
1361     while (socket->bytesAvailable() < 10)
1362         QVERIFY(socket->waitForReadyRead(10000));
1363
1364     QCOMPARE(socket->readLine(buffer, 11), qint64(10));
1365     QCOMPARE((const char *)buffer, "1 OK Compl");
1366
1367     while (socket->bytesAvailable() < 6)
1368         QVERIFY(socket->waitForReadyRead(10000));
1369
1370     QCOMPARE(socket->readLine(buffer, 11), qint64(6));
1371     QCOMPARE((const char *)buffer, "eted\r\n");
1372
1373     QVERIFY(!socket->waitForReadyRead(100));
1374     QCOMPARE(socket->readLine(buffer, sizeof(buffer)), qint64(0));
1375     QVERIFY(socket->error() == QAbstractSocket::SocketTimeoutError
1376             || socket->error() == QAbstractSocket::RemoteHostClosedError);
1377     QCOMPARE(socket->bytesAvailable(), qint64(0));
1378
1379     socket->close();
1380     QCOMPARE(socket->readLine(buffer, sizeof(buffer)), qint64(-1));
1381
1382     delete socket;
1383 }
1384
1385 //----------------------------------------------------------------------------------
1386 void tst_QTcpSocket::readLineString()
1387 {
1388     QTcpSocket *socket = newSocket();
1389     socket->connectToHost(QtNetworkSettings::serverName(), 143);
1390     QVERIFY(socket->waitForReadyRead(10000));
1391
1392     QByteArray arr = socket->readLine();
1393     QVERIFY2(QtNetworkSettings::compareReplyIMAP(arr), arr.constData());
1394
1395     delete socket;
1396 }
1397
1398 //----------------------------------------------------------------------------------
1399 void tst_QTcpSocket::readChunks()
1400 {
1401     QTcpSocket *socket = newSocket();
1402     socket->connectToHost(QtNetworkSettings::serverName(), 143);
1403     QVERIFY(socket->waitForConnected(10000));
1404     QVERIFY(socket->waitForReadyRead(5000));
1405
1406     char buf[4096];
1407     memset(buf, '@', sizeof(buf));
1408     qint64 dataLength = socket->read(buf, sizeof(buf));
1409     QVERIFY(dataLength > 0);
1410
1411     QCOMPARE(buf[dataLength - 2], '\r');
1412     QCOMPARE(buf[dataLength - 1], '\n');
1413     QCOMPARE(buf[dataLength], '@');
1414
1415     delete socket;
1416 }
1417
1418 //----------------------------------------------------------------------------------
1419 void tst_QTcpSocket::waitForBytesWritten()
1420 {
1421     QTcpSocket *socket = newSocket();
1422     socket->connectToHost(QtNetworkSettings::serverName(), 80);
1423     QVERIFY(socket->waitForConnected(10000));
1424
1425     socket->write("GET / HTTP/1.0\r\n\r\n");
1426     qint64 toWrite = socket->bytesToWrite();
1427     QVERIFY(socket->waitForBytesWritten(5000));
1428     QVERIFY(toWrite > socket->bytesToWrite());
1429
1430     delete socket;
1431 }
1432
1433 //----------------------------------------------------------------------------------
1434 void tst_QTcpSocket::waitForBytesWrittenMinusOne()
1435 {
1436     QTcpSocket *socket = newSocket();
1437     socket->connectToHost(QtNetworkSettings::serverName(), 80);
1438     QVERIFY(socket->waitForConnected(10000));
1439
1440     socket->write("GET / HTTP/1.0\r\n\r\n");
1441     qint64 toWrite = socket->bytesToWrite();
1442     QVERIFY(socket->waitForBytesWritten(-1));
1443     QVERIFY(toWrite > socket->bytesToWrite());
1444
1445     delete socket;
1446 }
1447
1448 //----------------------------------------------------------------------------------
1449 void tst_QTcpSocket::waitForReadyRead()
1450 {
1451     QTcpSocket *socket = newSocket();
1452     socket->connectToHost(QtNetworkSettings::serverName(), 80);
1453     socket->write("GET / HTTP/1.0\r\n\r\n");
1454     QVERIFY(socket->waitForReadyRead(5000));
1455     delete socket;
1456 }
1457
1458 //----------------------------------------------------------------------------------
1459 void tst_QTcpSocket::waitForReadyReadMinusOne()
1460 {
1461     QTcpSocket *socket = newSocket();
1462     socket->connectToHost(QtNetworkSettings::serverName(), 80);
1463     socket->write("GET / HTTP/1.0\r\n\r\n");
1464     QVERIFY(socket->waitForReadyRead(-1));
1465     delete socket;
1466 }
1467
1468 //----------------------------------------------------------------------------------
1469 void tst_QTcpSocket::flush()
1470 {
1471     QTcpSocket *socket = newSocket();
1472     socket->flush();
1473
1474     connect(socket, SIGNAL(connected()), SLOT(exitLoopSlot()));
1475     socket->connectToHost(QtNetworkSettings::serverName(), 143);
1476     enterLoop(60);
1477     QVERIFY(socket->isOpen());
1478
1479     socket->write("1 LOGOUT\r\n");
1480     QCOMPARE(socket->bytesToWrite(), qint64(10));
1481     socket->flush();
1482     QCOMPARE(socket->bytesToWrite(), qint64(0));
1483     socket->close();
1484
1485     delete socket;
1486 }
1487
1488 //----------------------------------------------------------------------------------
1489 void tst_QTcpSocket::synchronousApi()
1490 {
1491     QTcpSocket *ftpSocket = newSocket();
1492     ftpSocket->connectToHost(QtNetworkSettings::serverName(), 21);
1493     ftpSocket->write("QUIT\r\n");
1494     QVERIFY(ftpSocket->waitForDisconnected(10000));
1495     QVERIFY(ftpSocket->bytesAvailable() > 0);
1496     QByteArray arr = ftpSocket->readAll();
1497     QVERIFY(arr.size() > 0);
1498     delete ftpSocket;
1499 }
1500
1501 //----------------------------------------------------------------------------------
1502 void tst_QTcpSocket::dontCloseOnTimeout()
1503 {
1504     QTcpServer server;
1505     server.setProxy(QNetworkProxy(QNetworkProxy::NoProxy));
1506     QVERIFY(server.listen());
1507
1508     QHostAddress serverAddress = QHostAddress::LocalHost;
1509     if (!(server.serverAddress() == QHostAddress::Any) && !(server.serverAddress() == QHostAddress::AnyIPv6))
1510         serverAddress = server.serverAddress();
1511
1512     QTcpSocket *socket = newSocket();
1513     socket->connectToHost(serverAddress, server.serverPort());
1514 #ifndef Q_OS_SYMBIAN
1515     QVERIFY(!socket->waitForReadyRead(100));
1516 #else
1517     QVERIFY(!socket->waitForReadyRead(5000));
1518 #endif
1519     QCOMPARE(socket->error(), QTcpSocket::SocketTimeoutError);
1520     QVERIFY(socket->isOpen());
1521
1522 #ifndef Q_OS_SYMBIAN
1523     QVERIFY(!socket->waitForDisconnected(100));
1524 #else
1525     QVERIFY(!socket->waitForDisconnected(5000));
1526 #endif
1527     QCOMPARE(socket->error(), QTcpSocket::SocketTimeoutError);
1528     QVERIFY(socket->isOpen());
1529
1530     delete socket;
1531 }
1532
1533 //----------------------------------------------------------------------------------
1534 void tst_QTcpSocket::recursiveReadyRead()
1535 {
1536     QTcpSocket *smtp = newSocket();
1537     connect(smtp, SIGNAL(connected()), SLOT(exitLoopSlot()));
1538     connect(smtp, SIGNAL(readyRead()), SLOT(recursiveReadyReadSlot()));
1539     tmpSocket = smtp;
1540
1541     QSignalSpy spy(smtp, SIGNAL(readyRead()));
1542
1543     smtp->connectToHost("smtp.trolltech.com", 25);
1544     enterLoop(30);
1545     QVERIFY2(!timeout(),
1546             "Timed out when connecting to smtp.trolltech.com:25");
1547
1548     enterLoop(30);
1549     QVERIFY2(!timeout(),
1550             "Timed out when waiting for the readyRead() signal");
1551
1552     QCOMPARE(spy.count(), 1);
1553
1554     delete smtp;
1555 }
1556
1557 void tst_QTcpSocket::recursiveReadyReadSlot()
1558 {
1559     // make sure the server spits out more data
1560     tmpSocket->write("NOOP\r\n");
1561     tmpSocket->flush();
1562
1563     // indiscriminately enter the event loop and start processing
1564     // events again. but oops! future socket notifications will cause
1565     // undesired recursive behavior. Unless QTcpSocket is smart, which
1566     // it of course is. :-)
1567     QEventLoop loop;
1568     for (int i = 0; i < 100; ++i)
1569         loop.processEvents();
1570
1571     // all we really wanted to do was process some events, then exit
1572     // the loop
1573     exitLoop();
1574 }
1575
1576 //----------------------------------------------------------------------------------
1577 void tst_QTcpSocket::atEnd()
1578 {
1579     QTcpSocket *socket = newSocket();
1580     socket->connectToHost(QtNetworkSettings::serverName(), 21);
1581
1582     QVERIFY(socket->waitForReadyRead(15000));
1583     QTextStream stream(socket);
1584     QVERIFY(!stream.atEnd());
1585     QString greeting = stream.readLine();
1586     QVERIFY(stream.atEnd());
1587
1588     // Test server must use some vsFTPd 2.x.x version
1589     QVERIFY2(greeting.length() == sizeof("220 (vsFTPd 2.x.x)")-1, qPrintable(greeting));
1590     QVERIFY2(greeting.startsWith("220 (vsFTPd 2."), qPrintable(greeting));
1591     QVERIFY2(greeting.endsWith(")"), qPrintable(greeting));
1592
1593     delete socket;
1594 }
1595
1596 class TestThread : public QThread
1597 {
1598     Q_OBJECT
1599
1600 public:
1601     inline QByteArray data() const
1602     {
1603         return socketData;
1604     }
1605
1606 protected:
1607     inline void run()
1608     {
1609 #ifndef QT_NO_OPENSSL
1610         QFETCH_GLOBAL(bool, ssl);
1611         if (ssl)
1612             socket = new QSslSocket;
1613         else
1614 #endif
1615         socket = new QTcpSocket;
1616         connect(socket, SIGNAL(readyRead()), this, SLOT(getData()), Qt::DirectConnection);
1617         connect(socket, SIGNAL(disconnected()), this, SLOT(closed()), Qt::DirectConnection);
1618         connect(socket, SIGNAL(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)),
1619                 SLOT(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)), Qt::DirectConnection);
1620
1621         socket->connectToHost(QtNetworkSettings::serverName(), 21);
1622         socket->write("QUIT\r\n");
1623         exec();
1624
1625         delete socket;
1626     }
1627
1628 private slots:
1629     inline void getData()
1630     {
1631         socketData += socket->readAll();
1632     }
1633
1634     inline void closed()
1635     {
1636         quit();
1637     }
1638     inline void proxyAuthenticationRequired(const QNetworkProxy &, QAuthenticator *auth)
1639     {
1640         auth->setUser("qsockstest");
1641         auth->setPassword("password");
1642     }
1643 private:
1644     int exitCode;
1645     QTcpSocket *socket;
1646     QByteArray socketData;
1647 };
1648
1649 //----------------------------------------------------------------------------------
1650 void tst_QTcpSocket::socketInAThread()
1651 {
1652     for (int i = 0; i < 3; ++i) {
1653         TestThread thread;
1654         thread.start();
1655         QVERIFY(thread.wait(15000));
1656         QByteArray data = thread.data();
1657         QVERIFY2(QtNetworkSettings::compareReplyFtp(data), data.constData());
1658     }
1659 }
1660
1661 //----------------------------------------------------------------------------------
1662 void tst_QTcpSocket::socketsInThreads()
1663 {
1664     for (int i = 0; i < 3; ++i) {
1665         TestThread thread1;
1666         TestThread thread2;
1667         TestThread thread3;
1668
1669         thread1.start();
1670         thread2.start();
1671         thread3.start();
1672
1673         QVERIFY(thread2.wait(15000));
1674         QVERIFY(thread3.wait(15000));
1675         QVERIFY(thread1.wait(15000));
1676
1677         QByteArray data1 = thread1.data();
1678         QByteArray data2 = thread2.data();
1679         QByteArray data3 = thread3.data();
1680
1681         QVERIFY2(QtNetworkSettings::compareReplyFtp(data1), data1.constData());
1682         QVERIFY2(QtNetworkSettings::compareReplyFtp(data2), data2.constData());
1683         QVERIFY2(QtNetworkSettings::compareReplyFtp(data3), data3.constData());
1684     }
1685 }
1686
1687 //----------------------------------------------------------------------------------
1688 void tst_QTcpSocket::waitForReadyReadInASlot()
1689 {
1690     QTcpSocket *socket = newSocket();
1691     tmpSocket = socket;
1692     connect(socket, SIGNAL(connected()), this, SLOT(waitForReadyReadInASlotSlot()));
1693
1694     socket->connectToHost(QtNetworkSettings::serverName(), 80);
1695     socket->write("GET / HTTP/1.0\r\n\r\n");
1696
1697     enterLoop(30);
1698     QVERIFY(!timeout());
1699
1700     delete socket;
1701 }
1702
1703 void tst_QTcpSocket::waitForReadyReadInASlotSlot()
1704 {
1705     QVERIFY(tmpSocket->waitForReadyRead(10000));
1706     exitLoop();
1707 }
1708
1709 class RemoteCloseErrorServer : public QTcpServer
1710 {
1711     Q_OBJECT
1712 public:
1713     RemoteCloseErrorServer()
1714     {
1715         connect(this, SIGNAL(newConnection()),
1716                 this, SLOT(getConnection()));
1717     }
1718
1719 private slots:
1720     void getConnection()
1721     {
1722         tst_QTcpSocket::exitLoop();
1723     }
1724 };
1725
1726 //----------------------------------------------------------------------------------
1727 void tst_QTcpSocket::remoteCloseError()
1728 {
1729     QFETCH_GLOBAL(bool, setProxy);
1730     if (setProxy)
1731         return; //proxy not useful for localhost test case
1732     RemoteCloseErrorServer server;
1733     QVERIFY(server.listen(QHostAddress::LocalHost));
1734
1735     QCoreApplication::instance()->processEvents();
1736
1737     QTcpSocket *clientSocket = newSocket();
1738     connect(clientSocket, SIGNAL(readyRead()), this, SLOT(exitLoopSlot()));
1739
1740     clientSocket->connectToHost(server.serverAddress(), server.serverPort());
1741
1742     enterLoop(30);
1743     QVERIFY(!timeout());
1744
1745     QVERIFY(server.hasPendingConnections());
1746     QTcpSocket *serverSocket = server.nextPendingConnection();
1747     connect(clientSocket, SIGNAL(disconnected()), this, SLOT(exitLoopSlot()));
1748
1749     serverSocket->write("Hello");
1750
1751     enterLoop(30);
1752     QVERIFY(!timeout());
1753
1754     QCOMPARE(clientSocket->bytesAvailable(), qint64(5));
1755
1756     qRegisterMetaType<QAbstractSocket::SocketError>("QAbstractSocket::SocketError");
1757     QSignalSpy errorSpy(clientSocket, SIGNAL(error(QAbstractSocket::SocketError)));
1758     QSignalSpy disconnectedSpy(clientSocket, SIGNAL(disconnected()));
1759
1760     clientSocket->write("World");
1761     serverSocket->disconnectFromHost();
1762
1763     tmpSocket = clientSocket;
1764     connect(clientSocket, SIGNAL(error(QAbstractSocket::SocketError)),
1765             this, SLOT(remoteCloseErrorSlot()));
1766
1767     enterLoop(30);
1768     QVERIFY(!timeout());
1769
1770     QCOMPARE(disconnectedSpy.count(), 1);
1771     QCOMPARE(errorSpy.count(), 1);
1772     QCOMPARE(clientSocket->error(), QAbstractSocket::RemoteHostClosedError);
1773
1774     delete serverSocket;
1775
1776     clientSocket->connectToHost(server.serverAddress(), server.serverPort());
1777
1778     enterLoop(30);
1779     QVERIFY(!timeout());
1780
1781     QVERIFY(server.hasPendingConnections());
1782     serverSocket = server.nextPendingConnection();
1783     serverSocket->disconnectFromHost();
1784
1785     enterLoop(30);
1786     QVERIFY(!timeout());
1787
1788     QCOMPARE(clientSocket->state(), QAbstractSocket::UnconnectedState);
1789
1790     delete clientSocket;
1791 }
1792
1793 void tst_QTcpSocket::remoteCloseErrorSlot()
1794 {
1795     QCOMPARE(tmpSocket->state(), QAbstractSocket::ConnectedState);
1796     static_cast<QTcpSocket *>(sender())->close();
1797 }
1798
1799 void tst_QTcpSocket::messageBoxSlot()
1800 {
1801 #if !defined(Q_OS_VXWORKS) // no gui
1802     QTcpSocket *socket = qobject_cast<QTcpSocket *>(sender());
1803     socket->deleteLater();
1804     QMessageBox box;
1805     QTimer::singleShot(100, &box, SLOT(close()));
1806
1807     // This should not delete the socket
1808     box.exec();
1809
1810     // Fire a non-0 singleshot to leave time for the delete
1811     QTimer::singleShot(250, this, SLOT(exitLoopSlot()));
1812 #endif
1813 }
1814 //----------------------------------------------------------------------------------
1815 void tst_QTcpSocket::openMessageBoxInErrorSlot()
1816 {
1817 #if defined(Q_OS_VXWORKS) // no gui
1818     QSKIP("no default gui available on VxWorks", SkipAll);
1819 #else
1820     QTcpSocket *socket = newSocket();
1821     QPointer<QTcpSocket> p(socket);
1822     connect(socket, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(messageBoxSlot()));
1823
1824     socket->connectToHost("hostnotfoundhostnotfound.troll.no", 9999); // Host not found, fyi
1825     enterLoop(30);
1826     QVERIFY(!p);
1827 #endif
1828 }
1829
1830 //----------------------------------------------------------------------------------
1831 #ifndef Q_OS_WIN
1832 void tst_QTcpSocket::connectToLocalHostNoService()
1833 {
1834     // This test was created after we received a report that claimed
1835     // QTcpSocket would crash if trying to connect to "localhost" on a random
1836     // port with no service listening.
1837     QTcpSocket *socket = newSocket();
1838     socket->connectToHost("localhost", 31415); // no service running here, one suspects
1839
1840     while(socket->state() == QTcpSocket::HostLookupState || socket->state() == QTcpSocket::ConnectingState) {
1841         QTest::qWait(100);
1842     }
1843     QCOMPARE(socket->state(), QTcpSocket::UnconnectedState);
1844     delete socket;
1845 }
1846 #endif
1847
1848 //----------------------------------------------------------------------------------
1849 void tst_QTcpSocket::waitForConnectedInHostLookupSlot()
1850 {
1851     // This test tries to reproduce the problem where waitForConnected() is
1852     // called at a point where the host lookup is already done. QTcpSocket
1853     // will try to abort the "pending lookup", but since it's already done and
1854     // the queued signal is already underway, we will receive the signal after
1855     // waitForConnected() has returned, and control goes back to the event
1856     // loop. When the signal has been received, the connection is torn down,
1857     // then reopened. Yikes. If we reproduce this by calling
1858     // waitForConnected() inside hostLookupSlot(), it will even crash.
1859     tmpSocket = newSocket();
1860     QEventLoop loop;
1861     connect(tmpSocket, SIGNAL(connected()), &loop, SLOT(quit()));
1862     QTimer timer;
1863     connect(&timer, SIGNAL(timeout()), &loop, SLOT(quit()));
1864     QSignalSpy timerSpy(&timer, SIGNAL(timeout()));
1865     timer.start(15000);
1866
1867     connect(tmpSocket, SIGNAL(hostFound()), this, SLOT(hostLookupSlot()));
1868     tmpSocket->connectToHost(QtNetworkSettings::serverName(), 143);
1869
1870     // only execute the loop if not already connected
1871     if (tmpSocket->state() != QAbstractSocket::ConnectedState)
1872         loop.exec();
1873
1874     QCOMPARE(timerSpy.count(), 0);
1875
1876     delete tmpSocket;
1877 }
1878
1879 void tst_QTcpSocket::hostLookupSlot()
1880 {
1881     // This will fail to cancel the pending signal
1882     QVERIFY(tmpSocket->waitForConnected(10000));
1883 }
1884
1885 class Foo : public QObject
1886 {
1887     Q_OBJECT
1888     QTcpSocket *sock;
1889 public:
1890     bool attemptedToConnect;
1891     bool networkTimeout;
1892     int count;
1893
1894     inline Foo(QObject *parent = 0) : QObject(parent)
1895     {
1896         attemptedToConnect = false;
1897         networkTimeout = false;
1898         count = 0;
1899 #ifndef QT_NO_OPENSSL
1900         QFETCH_GLOBAL(bool, ssl);
1901         if (ssl)
1902             sock = new QSslSocket;
1903         else
1904 #endif
1905         sock = new QTcpSocket;
1906         connect(sock, SIGNAL(connected()), this, SLOT(connectedToIt()));
1907         connect(sock, SIGNAL(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)),
1908                 SLOT(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)));
1909     }
1910
1911     inline ~Foo()
1912     {
1913         delete sock;
1914     }
1915
1916 public slots:
1917     inline void connectedToIt()
1918     { count++; }
1919
1920     inline void doIt()
1921     {
1922         attemptedToConnect = true;
1923         sock->connectToHost(QtNetworkSettings::serverName(), 80);
1924
1925 #ifdef Q_OS_MAC
1926         pthread_yield_np();
1927 #elif defined Q_OS_LINUX
1928         pthread_yield();
1929 #endif
1930         if (!sock->waitForConnected()) {
1931             networkTimeout = true;
1932         }
1933         tst_QTcpSocket::exitLoop();
1934     }
1935
1936     inline void exitLoop()
1937     {
1938         tst_QTcpSocket::exitLoop();
1939     }
1940
1941     inline void proxyAuthenticationRequired(const QNetworkProxy &, QAuthenticator *auth)
1942     {
1943         auth->setUser("qsockstest");
1944         auth->setPassword("password");
1945     }
1946 };
1947
1948 //----------------------------------------------------------------------------------
1949 void tst_QTcpSocket::waitForConnectedInHostLookupSlot2()
1950 {
1951 #if defined(Q_OS_WIN) || defined(Q_OS_VXWORKS)
1952     QSKIP("waitForConnectedInHostLookupSlot2 is not run on Windows and VxWorks", SkipAll);
1953 #else
1954
1955     Foo foo;
1956     QPushButton top("Go", 0);
1957     top.show();
1958     connect(&top, SIGNAL(clicked()), &foo, SLOT(doIt()));
1959
1960     QTimer::singleShot(100, &top, SLOT(animateClick()));
1961     QTimer::singleShot(5000, &foo, SLOT(exitLoop()));
1962
1963     enterLoop(30);
1964     if (timeout() || foo.networkTimeout)
1965         QFAIL("Network timeout");
1966
1967     QVERIFY(foo.attemptedToConnect);
1968     QCOMPARE(foo.count, 1);
1969 #endif
1970 }
1971
1972 //----------------------------------------------------------------------------------
1973 void tst_QTcpSocket::readyReadSignalsAfterWaitForReadyRead()
1974 {
1975     QTcpSocket *socket = newSocket();
1976
1977     QSignalSpy readyReadSpy(socket, SIGNAL(readyRead()));
1978
1979     // Connect
1980     socket->connectToHost(QtNetworkSettings::serverName(), 143);
1981
1982     // Wait for the read
1983     QVERIFY(socket->waitForReadyRead(10000));
1984
1985     QCOMPARE(readyReadSpy.count(), 1);
1986
1987     QString s = socket->readLine();
1988     QVERIFY2(QtNetworkSettings::compareReplyIMAP(s.toLatin1()), s.toLatin1().constData());
1989     QCOMPARE(socket->bytesAvailable(), qint64(0));
1990
1991     QCoreApplication::instance()->processEvents();
1992     QCOMPARE(socket->bytesAvailable(), qint64(0));
1993     QCOMPARE(readyReadSpy.count(), 1);
1994
1995     delete socket;
1996 }
1997
1998 class TestThread2 : public QThread
1999 {
2000     Q_OBJECT
2001 public:
2002     void run()
2003     {
2004         QFile fileWriter("fifo");
2005         QVERIFY(fileWriter.open(QFile::WriteOnly));
2006         QCOMPARE(fileWriter.write(QByteArray(32, '@')), qint64(32));
2007         QCOMPARE(fileWriter.write(QByteArray(32, '@')), qint64(32));
2008         QCOMPARE(fileWriter.write(QByteArray(32, '@')), qint64(32));
2009         QCOMPARE(fileWriter.write(QByteArray(32, '@')), qint64(32));
2010     }
2011 };
2012
2013 //----------------------------------------------------------------------------------
2014 #ifdef Q_OS_LINUX
2015 void tst_QTcpSocket::linuxKernelBugLocalSocket()
2016 {
2017     QFile::remove("fifo");
2018     mkfifo("fifo", 0666);
2019
2020     TestThread2 test;
2021     test.start();
2022
2023     QFile fileReader("fifo");
2024     QVERIFY(fileReader.open(QFile::ReadOnly));
2025
2026     test.wait();
2027
2028     QTcpSocket *socket = newSocket();
2029     socket->setSocketDescriptor(fileReader.handle());
2030     QVERIFY(socket->waitForReadyRead(5000));
2031     QCOMPARE(socket->bytesAvailable(), qint64(128));
2032
2033     QFile::remove("fifo");
2034
2035     delete socket;
2036 }
2037 #endif
2038
2039 //----------------------------------------------------------------------------------
2040 void tst_QTcpSocket::abortiveClose()
2041 {
2042     QFETCH_GLOBAL(bool, setProxy);
2043     if (setProxy)
2044         return; //proxy not useful for localhost test case
2045     QTcpServer server;
2046     QVERIFY(server.listen(QHostAddress::LocalHost));
2047     connect(&server, SIGNAL(newConnection()), this, SLOT(exitLoopSlot()));
2048
2049     QTcpSocket *clientSocket = newSocket();
2050     clientSocket->connectToHost(server.serverAddress(), server.serverPort());
2051
2052     enterLoop(10);
2053     QVERIFY(server.hasPendingConnections());
2054
2055     QVERIFY(tmpSocket = server.nextPendingConnection());
2056
2057     qRegisterMetaType<QAbstractSocket::SocketError>("QAbstractSocket::SocketError");
2058     QSignalSpy readyReadSpy(clientSocket, SIGNAL(readyRead()));
2059     QSignalSpy errorSpy(clientSocket, SIGNAL(error(QAbstractSocket::SocketError)));
2060
2061     connect(clientSocket, SIGNAL(disconnected()), this, SLOT(exitLoopSlot()));
2062     QTimer::singleShot(0, this, SLOT(abortiveClose_abortSlot()));
2063
2064     enterLoop(5);
2065
2066     QCOMPARE(readyReadSpy.count(), 0);
2067     QCOMPARE(errorSpy.count(), 1);
2068
2069     QCOMPARE(*static_cast<const int *>(errorSpy.at(0).at(0).constData()),
2070              int(QAbstractSocket::RemoteHostClosedError));
2071
2072     delete clientSocket;
2073 }
2074
2075 void tst_QTcpSocket::abortiveClose_abortSlot()
2076 {
2077     tmpSocket->abort();
2078 }
2079
2080 //----------------------------------------------------------------------------------
2081 void tst_QTcpSocket::localAddressEmptyOnBSD()
2082 {
2083     QFETCH_GLOBAL(bool, setProxy);
2084     if (setProxy)
2085         return; //proxy not useful for localhost test case
2086     QTcpServer server;
2087     QVERIFY(server.listen(QHostAddress::LocalHost));
2088
2089     QTcpSocket *tcpSocket = 0;
2090     // we try 10 times, but note that this doesn't always provoke the bug
2091     for (int i = 0; i < 10; ++i) {
2092         delete tcpSocket;
2093         tcpSocket = newSocket();
2094         tcpSocket->connectToHost(QHostAddress::LocalHost, server.serverPort());
2095         if (!tcpSocket->waitForConnected(0)) {
2096             // to provoke the bug, we need a local socket that connects immediately
2097             // --i;
2098             tcpSocket->abort();
2099             if (tcpSocket->state() != QTcpSocket::UnconnectedState)
2100                 QVERIFY(tcpSocket->waitForDisconnected(-1));
2101             continue;
2102         }
2103         QCOMPARE(tcpSocket->localAddress(), QHostAddress(QHostAddress::LocalHost));
2104     }
2105     delete tcpSocket;
2106 }
2107
2108 //----------------------------------------------------------------------------------
2109 void tst_QTcpSocket::zeroAndMinusOneReturns()
2110 {
2111     QTcpSocket *socket = newSocket();
2112     socket->connectToHost(QtNetworkSettings::serverName(), 80);
2113     socket->write("GET / HTTP/1.0\r\nConnection: keep-alive\r\n\r\n");
2114     QVERIFY(socket->waitForReadyRead(15000));
2115
2116     char c[16];
2117     QVERIFY(socket->getChar(c));
2118     QCOMPARE(socket->read(c, 16), qint64(16));
2119     QVERIFY(socket->readLine(c, 16) > 0);
2120     QVERIFY(!socket->readAll().isEmpty());
2121
2122     // the last operation emptied the read buffer
2123     // all read operations from this point on should fail
2124     // with return 0 because the socket is still open
2125     QVERIFY(socket->readAll().isEmpty());
2126     QCOMPARE(socket->read(c, 16), qint64(0));
2127     QCOMPARE(socket->readLine(c, 16), qint64(0));
2128     QVERIFY(!socket->getChar(c));
2129
2130     socket->write("GET / HTTP/1.0\r\n\r\n");
2131     QVERIFY(socket->waitForDisconnected(15000));
2132     QCOMPARE(socket->error(), QAbstractSocket::RemoteHostClosedError);
2133
2134     QCOMPARE(socket->write("BLUBBER"), qint64(-1));
2135     QVERIFY(socket->getChar(c));
2136     QCOMPARE(socket->read(c, 16), qint64(16));
2137     QVERIFY(socket->readLine(c, 16) > 0);
2138     QVERIFY(!socket->readAll().isEmpty());
2139
2140     // the last operation emptied the read buffer
2141     // all read operations from this point on should fail
2142     // with return -1 because the socket is not connected
2143     QVERIFY(socket->readAll().isEmpty());
2144     QCOMPARE(socket->read(c, 16), qint64(-1));
2145     QCOMPARE(socket->readLine(c, 16), qint64(-1));
2146     QVERIFY(!socket->getChar(c));
2147     QVERIFY(!socket->putChar('a'));
2148
2149     socket->close();
2150
2151     // now the QIODevice is closed, which means getChar complains
2152     QCOMPARE(socket->write("BLUBBER"), qint64(-1));
2153     QCOMPARE(socket->read(c, 16), qint64(-1));
2154     QCOMPARE(socket->readLine(c, 16), qint64(-1));
2155     QVERIFY(!socket->getChar(c));
2156     QVERIFY(!socket->putChar('a'));
2157
2158     delete socket;
2159 }
2160
2161 //----------------------------------------------------------------------------------
2162 void tst_QTcpSocket::connectionRefused()
2163 {
2164     qRegisterMetaType<QAbstractSocket::SocketError>("QAbstractSocket::SocketError");
2165     qRegisterMetaType<QAbstractSocket::SocketState>("QAbstractSocket::SocketState");
2166
2167     QTcpSocket *socket = newSocket();
2168     QSignalSpy stateSpy(socket, SIGNAL(stateChanged(QAbstractSocket::SocketState)));
2169     QSignalSpy errorSpy(socket, SIGNAL(error(QAbstractSocket::SocketError)));
2170     connect(socket, SIGNAL(error(QAbstractSocket::SocketError)),
2171             &QTestEventLoop::instance(), SLOT(exitLoop()));
2172
2173     socket->connectToHost(QtNetworkSettings::serverName(), 144);
2174
2175     enterLoop(10);
2176     disconnect(socket, SIGNAL(error(QAbstractSocket::SocketError)),
2177                &QTestEventLoop::instance(), SLOT(exitLoop()));
2178     QVERIFY2(!timeout(), "Network timeout");
2179
2180     QCOMPARE(socket->state(), QAbstractSocket::UnconnectedState);
2181     QCOMPARE(socket->error(), QAbstractSocket::ConnectionRefusedError);
2182
2183     QCOMPARE(stateSpy.count(), 3);
2184     QCOMPARE(qVariantValue<QAbstractSocket::SocketState>(stateSpy.at(0).at(0)), QAbstractSocket::HostLookupState);
2185     QCOMPARE(qVariantValue<QAbstractSocket::SocketState>(stateSpy.at(1).at(0)), QAbstractSocket::ConnectingState);
2186     QCOMPARE(qVariantValue<QAbstractSocket::SocketState>(stateSpy.at(2).at(0)), QAbstractSocket::UnconnectedState);
2187     QCOMPARE(errorSpy.count(), 1);
2188
2189     delete socket;
2190 }
2191
2192 //----------------------------------------------------------------------------------
2193 void tst_QTcpSocket::suddenRemoteDisconnect_data()
2194 {
2195     QTest::addColumn<QString>("client");
2196     QTest::addColumn<QString>("server");
2197
2198     QTest::newRow("Qt4 Client <-> Qt4 Server") << QString::fromLatin1("qt4client") << QString::fromLatin1("qt4server");
2199 }
2200
2201 void tst_QTcpSocket::suddenRemoteDisconnect()
2202 {
2203 #if defined( Q_OS_SYMBIAN )
2204     QSKIP("Symbian: QProcess IO is not yet supported, fix when supported", SkipAll);
2205 #else
2206     QFETCH(QString, client);
2207     QFETCH(QString, server);
2208
2209     QFETCH_GLOBAL(bool, setProxy);
2210     if (setProxy)
2211         return;
2212     QFETCH_GLOBAL(bool, ssl);
2213     if (ssl)
2214         return;
2215
2216     // Start server
2217     QProcess serverProcess;
2218     serverProcess.setReadChannel(QProcess::StandardError);
2219     serverProcess.start(QString::fromLatin1("stressTest/stressTest %1").arg(server),
2220                         QIODevice::ReadWrite | QIODevice::Text);
2221     while (!serverProcess.canReadLine())
2222         QVERIFY(serverProcess.waitForReadyRead(10000));
2223     QCOMPARE(serverProcess.readLine().data(), (server.toLatin1() + "\n").data());
2224
2225     // Start client
2226     QProcess clientProcess;
2227     clientProcess.setReadChannel(QProcess::StandardError);
2228     clientProcess.start(QString::fromLatin1("stressTest/stressTest %1").arg(client),
2229                         QIODevice::ReadWrite | QIODevice::Text);
2230     while (!clientProcess.canReadLine())
2231         QVERIFY(clientProcess.waitForReadyRead(10000));
2232     QCOMPARE(clientProcess.readLine().data(), (client.toLatin1() + "\n").data());
2233
2234     // Let them play for a while
2235     qDebug("Running stress test for 5 seconds");
2236     QEventLoop loop;
2237     connect(&serverProcess, SIGNAL(finished(int)), &loop, SLOT(quit()));
2238     connect(&clientProcess, SIGNAL(finished(int)), &loop, SLOT(quit()));
2239     QTime stopWatch;
2240     stopWatch.start();
2241     QTimer::singleShot(20000, &loop, SLOT(quit()));
2242
2243     while ((serverProcess.state() == QProcess::Running
2244            || clientProcess.state() == QProcess::Running) && stopWatch.elapsed() < 20000)
2245         loop.exec();
2246
2247     QVERIFY(stopWatch.elapsed() < 20000);
2248
2249     // Check that both exited normally.
2250     QCOMPARE(clientProcess.readAll().constData(), "SUCCESS\n");
2251     QCOMPARE(serverProcess.readAll().constData(), "SUCCESS\n");
2252 #endif
2253 }
2254
2255 //----------------------------------------------------------------------------------
2256 void tst_QTcpSocket::connectToMultiIP()
2257 {
2258         QSKIP("TODO: setup DNS in the new network", SkipAll);
2259
2260 #if defined(Q_OS_VXWORKS)
2261     QSKIP("VxSim in standard config doesn't even run a DNS resolver", SkipAll);
2262 #else
2263     QFETCH_GLOBAL(bool, ssl);
2264     if (ssl)
2265         return;
2266     QFETCH_GLOBAL(bool, setProxy);
2267     if (setProxy)
2268         QSKIP("This test takes too long if we also add the proxies.", SkipSingle);
2269
2270     qDebug("Please wait, this test can take a while...");
2271
2272     QTcpSocket *socket = newSocket();
2273     // rationale: this domain resolves to 3 A-records, 2 of them are
2274     // invalid. QTcpSocket should never spend more than 30 seconds per IP, and
2275     // 30s*2 = 60s.
2276     QTime stopWatch;
2277     stopWatch.start();
2278     socket->connectToHost("multi.dev.troll.no", 80);
2279     QVERIFY(socket->waitForConnected(60500));
2280     QVERIFY(stopWatch.elapsed() < 70000);
2281     socket->abort();
2282
2283     stopWatch.restart();
2284     socket->connectToHost("multi.dev.troll.no", 81);
2285     QVERIFY(!socket->waitForConnected(2000));
2286     QVERIFY(stopWatch.elapsed() < 2000);
2287     QCOMPARE(socket->error(), QAbstractSocket::SocketTimeoutError);
2288
2289     delete socket;
2290 #endif
2291 }
2292
2293 //----------------------------------------------------------------------------------
2294 void tst_QTcpSocket::moveToThread0()
2295 {
2296     QFETCH_GLOBAL(int, proxyType);
2297     if (proxyType & AuthMask)
2298         return;
2299
2300     {
2301         // Case 1: Moved after connecting, before waiting for connection.
2302         QTcpSocket *socket = newSocket();;
2303         socket->connectToHost(QtNetworkSettings::serverName(), 143);
2304         socket->moveToThread(0);
2305         QVERIFY(socket->waitForConnected(5000));
2306         socket->write("XXX LOGOUT\r\n");
2307         QVERIFY(socket->waitForBytesWritten(5000));
2308         QVERIFY(socket->waitForDisconnected());
2309         delete socket;
2310     }
2311     {
2312         // Case 2: Moved before connecting
2313         QTcpSocket *socket = newSocket();
2314         socket->moveToThread(0);
2315         socket->connectToHost(QtNetworkSettings::serverName(), 143);
2316         QVERIFY(socket->waitForConnected(5000));
2317         socket->write("XXX LOGOUT\r\n");
2318         QVERIFY(socket->waitForBytesWritten(5000));
2319         QVERIFY(socket->waitForDisconnected());
2320         delete socket;
2321     }
2322     {
2323         // Case 3: Moved after writing, while waiting for bytes to be written.
2324         QTcpSocket *socket = newSocket();
2325         socket->connectToHost(QtNetworkSettings::serverName(), 143);
2326         QVERIFY(socket->waitForConnected(5000));
2327         socket->write("XXX LOGOUT\r\n");
2328         socket->moveToThread(0);
2329         QVERIFY(socket->waitForBytesWritten(5000));
2330         QVERIFY(socket->waitForDisconnected());
2331         delete socket;
2332     }
2333     {
2334         // Case 4: Moved after writing, while waiting for response.
2335         QTcpSocket *socket = newSocket();
2336         socket->connectToHost(QtNetworkSettings::serverName(), 143);
2337         QVERIFY(socket->waitForConnected(5000));
2338         socket->write("XXX LOGOUT\r\n");
2339         QVERIFY(socket->waitForBytesWritten(5000));
2340         socket->moveToThread(0);
2341         QVERIFY(socket->waitForDisconnected());
2342         delete socket;
2343     }
2344 }
2345
2346 void tst_QTcpSocket::increaseReadBufferSize()
2347 {
2348     QFETCH_GLOBAL(bool, setProxy);
2349     if (setProxy)
2350         return; //proxy not useful for localhost test case
2351     QTcpServer server;
2352     QTcpSocket *active = newSocket();
2353     connect(active, SIGNAL(readyRead()), SLOT(exitLoopSlot()));
2354
2355     // connect two sockets to each other:
2356     QVERIFY(server.listen(QHostAddress::LocalHost));
2357     active->connectToHost("127.0.0.1", server.serverPort());
2358     QVERIFY(active->waitForConnected(5000));
2359     QVERIFY(server.waitForNewConnection(5000));
2360
2361     QTcpSocket *passive = server.nextPendingConnection();
2362     QVERIFY(passive);
2363
2364     // now write 512 bytes of data on one end
2365     QByteArray data(512, 'a');
2366     passive->write(data);
2367     QVERIFY2(passive->waitForBytesWritten(5000), "Network timeout");
2368
2369     // set the read buffer size to less than what was written and iterate:
2370     active->setReadBufferSize(256);
2371     enterLoop(10);
2372     QVERIFY2(!timeout(), "Network timeout");
2373     QCOMPARE(active->bytesAvailable(), active->readBufferSize());
2374
2375     // increase the buffer size and iterate again:
2376     active->setReadBufferSize(384);
2377     enterLoop(10);
2378     QVERIFY2(!timeout(), "Network timeout");
2379     QCOMPARE(active->bytesAvailable(), active->readBufferSize());
2380
2381     // once more, but now it should read everything there was to read
2382     active->setReadBufferSize(1024);
2383     enterLoop(10);
2384     QVERIFY2(!timeout(), "Network timeout");
2385     QCOMPARE(active->bytesAvailable(), qint64(data.size()));
2386
2387     // drain it and compare
2388     QCOMPARE(active->readAll(), data);
2389
2390     // now one more test by setting the buffer size to unlimited:
2391     passive->write(data);
2392     QVERIFY2(passive->waitForBytesWritten(5000), "Network timeout");
2393     active->setReadBufferSize(256);
2394     enterLoop(10);
2395     QVERIFY2(!timeout(), "Network timeout");
2396     QCOMPARE(active->bytesAvailable(), active->readBufferSize());
2397     active->setReadBufferSize(0);
2398     enterLoop(10);
2399     QVERIFY2(!timeout(), "Network timeout");
2400     QCOMPARE(active->bytesAvailable(), qint64(data.size()));
2401     QCOMPARE(active->readAll(), data);
2402
2403     delete active;
2404 }
2405
2406 void tst_QTcpSocket::taskQtBug5799ConnectionErrorWaitForConnected()
2407 {
2408     QFETCH_GLOBAL(bool, setProxy);
2409     if (setProxy)
2410         return;
2411
2412     // check that we get a proper error connecting to port 12346
2413     // use waitForConnected, e.g. this should use a synchronous select() on the OS level
2414
2415     QTcpSocket socket;
2416     socket.connectToHost(QtNetworkSettings::serverName(), 12346);
2417     QTime timer;
2418     timer.start();
2419     socket.waitForConnected(10000);
2420     QVERIFY2(timer.elapsed() < 9900, "Connection to closed port timed out instead of refusing, something is wrong");
2421     QVERIFY2(socket.state() == QAbstractSocket::UnconnectedState, "Socket connected unexpectedly!");
2422     QVERIFY2(socket.error() == QAbstractSocket::ConnectionRefusedError,
2423              QString("Could not reach server: %1").arg(socket.errorString()).toLocal8Bit());
2424 }
2425
2426 void tst_QTcpSocket::taskQtBug5799ConnectionErrorEventLoop()
2427 {
2428     QFETCH_GLOBAL(bool, setProxy);
2429     if (setProxy)
2430         return;
2431
2432     // check that we get a proper error connecting to port 12346
2433     // This testcase uses an event loop
2434     QTcpSocket socket;
2435     connect(&socket, SIGNAL(error(QAbstractSocket::SocketError)), &QTestEventLoop::instance(), SLOT(exitLoop()));
2436     socket.connectToHost(QtNetworkSettings::serverName(), 12346);
2437
2438     QTestEventLoop::instance().enterLoop(10);
2439     QVERIFY2(!QTestEventLoop::instance().timeout(), "Connection to closed port timed out instead of refusing, something is wrong");
2440     QVERIFY2(socket.state() == QAbstractSocket::UnconnectedState, "Socket connected unexpectedly!");
2441     QVERIFY2(socket.error() == QAbstractSocket::ConnectionRefusedError,
2442              QString("Could not reach server: %1").arg(socket.errorString()).toLocal8Bit());
2443 }
2444
2445 void tst_QTcpSocket::taskQtBug7054TimeoutErrorResetting()
2446 {
2447     QTcpSocket *socket = newSocket();
2448
2449     socket->connectToHost(QtNetworkSettings::serverName(), 443);
2450     QVERIFY(socket->waitForConnected(5*1000));
2451     QVERIFY(socket->error() == QAbstractSocket::UnknownSocketError);
2452
2453     // We connected to the HTTPS port. Wait two seconds to receive data. We will receive
2454     // nothing because we would need to start the SSL handshake
2455     QVERIFY(!socket->waitForReadyRead(2*1000));
2456     QVERIFY(socket->error() == QAbstractSocket::SocketTimeoutError);
2457
2458     // Now write some crap to make the server disconnect us. 4 lines are enough.
2459     socket->write("a\r\nb\r\nc\r\nd\r\n");
2460     socket->waitForBytesWritten(2*1000);
2461
2462     // we try to waitForReadyRead another time, but this time instead of a timeout we
2463     // should get a better error since the server disconnected us
2464     QVERIFY(!socket->waitForReadyRead(2*1000));
2465     // It must NOT be the SocketTimeoutError that had been set before
2466     QVERIFY(socket->error() == QAbstractSocket::RemoteHostClosedError);
2467 }
2468
2469 void tst_QTcpSocket::invalidProxy_data()
2470 {
2471     QTest::addColumn<int>("type");
2472     QTest::addColumn<QString>("host");
2473     QTest::addColumn<int>("port");
2474     QTest::addColumn<bool>("failsAtConnect");
2475     QTest::addColumn<int>("expectedError");
2476
2477     QString fluke = QHostInfo::fromName(QtNetworkSettings::serverName()).addresses().first().toString();
2478     QTest::newRow("ftp-proxy") << int(QNetworkProxy::FtpCachingProxy) << fluke << 21 << true
2479                                << int(QAbstractSocket::UnsupportedSocketOperationError);
2480     QTest::newRow("http-caching-proxy") << int(QNetworkProxy::HttpCachingProxy) << fluke << 3128 << true
2481                                         << int(QAbstractSocket::UnsupportedSocketOperationError);
2482     QTest::newRow("no-such-host-socks5") << int(QNetworkProxy::Socks5Proxy)
2483                                          << "this-host-will-never-exist.troll.no" << 1080 << false
2484                                          << int(QAbstractSocket::ProxyNotFoundError);
2485     QTest::newRow("no-such-host-http") << int(QNetworkProxy::HttpProxy)
2486                                        << "this-host-will-never-exist.troll.no" << 3128 << false
2487                                        << int(QAbstractSocket::ProxyNotFoundError);
2488 #if !defined(Q_OS_SYMBIAN)
2489     QTest::newRow("http-on-socks5") << int(QNetworkProxy::HttpProxy) << fluke << 1080 << false
2490                                     << int(QAbstractSocket::ProxyConnectionClosedError);
2491     QTest::newRow("socks5-on-http") << int(QNetworkProxy::Socks5Proxy) << fluke << 3128 << false
2492                                     << int(QAbstractSocket::SocketTimeoutError);
2493 #endif
2494 }
2495
2496 void tst_QTcpSocket::invalidProxy()
2497 {
2498     QFETCH_GLOBAL(bool, setProxy);
2499     if (setProxy)
2500         return;
2501
2502     QFETCH(int, type);
2503     QFETCH(QString, host);
2504     QFETCH(int, port);
2505     QFETCH(bool, failsAtConnect);
2506     QNetworkProxy::ProxyType proxyType = QNetworkProxy::ProxyType(type);
2507     QNetworkProxy proxy(proxyType, host, port);
2508
2509     QTcpSocket *socket = newSocket();
2510     socket->setProxy(proxy);
2511     socket->connectToHost(QHostInfo::fromName(QtNetworkSettings::serverName()).addresses().first().toString(), 80);
2512
2513     if (failsAtConnect) {
2514         QCOMPARE(socket->state(), QAbstractSocket::UnconnectedState);
2515     } else {
2516         QCOMPARE(socket->state(), QAbstractSocket::ConnectingState);
2517         QVERIFY(!socket->waitForConnected(5000));
2518     }
2519     QVERIFY(!socket->errorString().isEmpty());
2520
2521     // note: the following test is not a hard failure.
2522     // Sometimes, error codes change for the better
2523     QTEST(int(socket->error()), "expectedError");
2524
2525     delete socket;
2526 }
2527
2528 // copied from tst_qnetworkreply.cpp
2529 class MyProxyFactory: public QNetworkProxyFactory
2530 {
2531 public:
2532     int callCount;
2533     QList<QNetworkProxy> toReturn;
2534     QNetworkProxyQuery lastQuery;
2535     inline MyProxyFactory() { clear(); }
2536
2537     inline void clear()
2538     {
2539         callCount = 0;
2540         toReturn = QList<QNetworkProxy>() << QNetworkProxy::DefaultProxy;
2541         lastQuery = QNetworkProxyQuery();
2542     }
2543
2544     virtual QList<QNetworkProxy> queryProxy(const QNetworkProxyQuery &query)
2545     {
2546         lastQuery = query;
2547         ++callCount;
2548         return toReturn;
2549     }
2550 };
2551
2552 void tst_QTcpSocket::proxyFactory_data()
2553 {
2554     QTest::addColumn<QList<QNetworkProxy> >("proxyList");
2555     QTest::addColumn<QNetworkProxy>("proxyUsed");
2556     QTest::addColumn<bool>("failsAtConnect");
2557     QTest::addColumn<int>("expectedError");
2558
2559     QList<QNetworkProxy> proxyList;
2560
2561     // tests that do connect
2562
2563     proxyList << QNetworkProxy(QNetworkProxy::HttpProxy, QtNetworkSettings::serverName(), 3129);
2564     QTest::newRow("http")
2565         << proxyList << proxyList.at(0)
2566         << false << int(QAbstractSocket::UnknownSocketError);
2567
2568     proxyList.clear();
2569     proxyList << QNetworkProxy(QNetworkProxy::Socks5Proxy, QtNetworkSettings::serverName(), 1081);
2570     QTest::newRow("socks5")
2571         << proxyList << proxyList.at(0)
2572         << false << int(QAbstractSocket::UnknownSocketError);
2573
2574     proxyList.clear();
2575     proxyList << QNetworkProxy(QNetworkProxy::HttpCachingProxy, QtNetworkSettings::serverName(), 3129)
2576               << QNetworkProxy(QNetworkProxy::Socks5Proxy, QtNetworkSettings::serverName(), 1081);
2577     QTest::newRow("cachinghttp+socks5")
2578         << proxyList << proxyList.at(1)
2579         << false << int(QAbstractSocket::UnknownSocketError);
2580
2581     proxyList.clear();
2582     proxyList << QNetworkProxy(QNetworkProxy::FtpCachingProxy, QtNetworkSettings::serverName(), 2121)
2583               << QNetworkProxy(QNetworkProxy::HttpCachingProxy, QtNetworkSettings::serverName(), 3129)
2584               << QNetworkProxy(QNetworkProxy::Socks5Proxy, QtNetworkSettings::serverName(), 1081);
2585     QTest::newRow("ftp+cachinghttp+socks5")
2586         << proxyList << proxyList.at(2)
2587         << false << int(QAbstractSocket::UnknownSocketError);
2588
2589     // tests that fail to connect
2590     proxyList.clear();
2591     proxyList << QNetworkProxy(QNetworkProxy::HttpCachingProxy, QtNetworkSettings::serverName(), 3129);
2592     QTest::newRow("cachinghttp")
2593         << proxyList << QNetworkProxy()
2594         << true << int(QAbstractSocket::UnsupportedSocketOperationError);
2595
2596     proxyList.clear();
2597     proxyList << QNetworkProxy(QNetworkProxy::FtpCachingProxy, QtNetworkSettings::serverName(), 2121);
2598     QTest::newRow("ftp")
2599         << proxyList << QNetworkProxy()
2600         << true << int(QAbstractSocket::UnsupportedSocketOperationError);
2601
2602     proxyList.clear();
2603     proxyList << QNetworkProxy(QNetworkProxy::FtpCachingProxy, QtNetworkSettings::serverName(), 2121)
2604               << QNetworkProxy(QNetworkProxy::HttpCachingProxy, QtNetworkSettings::serverName(), 3129);
2605     QTest::newRow("ftp+cachinghttp")
2606         << proxyList << QNetworkProxy()
2607         << true << int(QAbstractSocket::UnsupportedSocketOperationError);
2608 }
2609
2610 void tst_QTcpSocket::proxyFactory()
2611 {
2612     QFETCH_GLOBAL(bool, setProxy);
2613     if (setProxy)
2614         return;
2615
2616     QFETCH(QList<QNetworkProxy>, proxyList);
2617     QFETCH(QNetworkProxy, proxyUsed);
2618     QFETCH(bool, failsAtConnect);
2619
2620     MyProxyFactory *factory = new MyProxyFactory;
2621     factory->toReturn = proxyList;
2622     QNetworkProxyFactory::setApplicationProxyFactory(factory);
2623
2624     QTcpSocket *socket = newSocket();
2625     QString host = QtNetworkSettings::serverName();
2626     socket->connectToHost(host, 80);
2627
2628     // Verify that the factory was called properly
2629     QCOMPARE(factory->callCount, 1);
2630     QCOMPARE(factory->lastQuery, QNetworkProxyQuery(host, 80));
2631
2632     if (failsAtConnect) {
2633         QCOMPARE(socket->state(), QAbstractSocket::UnconnectedState);
2634     } else {
2635         QCOMPARE(socket->state(), QAbstractSocket::ConnectingState);
2636         QVERIFY(socket->waitForConnected(5000));
2637         QCOMPARE(proxyAuthCalled, 1);
2638     }
2639     QVERIFY(!socket->errorString().isEmpty());
2640
2641     // note: the following test is not a hard failure.
2642     // Sometimes, error codes change for the better
2643     QTEST(int(socket->error()), "expectedError");
2644
2645     delete socket;
2646 }
2647
2648 // there is a similar test inside tst_qtcpserver that uses the event loop instead
2649 void tst_QTcpSocket::qtbug14268_peek()
2650 {
2651     QFETCH_GLOBAL(bool, setProxy);
2652     if (setProxy)
2653         return;
2654
2655     SocketPair socketPair;
2656     QVERIFY(socketPair.create());
2657     QTcpSocket *outgoing = socketPair.endPoints[0];
2658     QTcpSocket *incoming = socketPair.endPoints[1];
2659
2660     QVERIFY(incoming->state() == QTcpSocket::ConnectedState);
2661     QVERIFY(outgoing->state() == QTcpSocket::ConnectedState);
2662
2663     outgoing->write("abc\n");
2664     QVERIFY(outgoing->waitForBytesWritten(2000));
2665     QVERIFY(incoming->waitForReadyRead(2000));
2666     QVERIFY(incoming->peek(128*1024) == QByteArray("abc\n"));
2667
2668     outgoing->write("def\n");
2669     QVERIFY(outgoing->waitForBytesWritten(2000));
2670     QVERIFY(incoming->waitForReadyRead(2000));
2671     QVERIFY(incoming->peek(128*1024) == QByteArray("abc\ndef\n"));
2672
2673     outgoing->write("ghi\n");
2674     QVERIFY(outgoing->waitForBytesWritten(2000));
2675     QVERIFY(incoming->waitForReadyRead(2000));
2676     QVERIFY(incoming->peek(128*1024) == QByteArray("abc\ndef\nghi\n"));
2677
2678     QVERIFY(incoming->read(128*1024) == QByteArray("abc\ndef\nghi\n"));
2679 }
2680
2681
2682
2683 QTEST_MAIN(tst_QTcpSocket)
2684 #include "tst_qtcpsocket.moc"