summaryrefslogtreecommitdiffstats
path: root/tests/auto/network/socket
diff options
context:
space:
mode:
Diffstat (limited to 'tests/auto/network/socket')
-rw-r--r--tests/auto/network/socket/platformsocketengine/.gitignore1
-rw-r--r--tests/auto/network/socket/platformsocketengine/platformsocketengine.pri19
-rw-r--r--tests/auto/network/socket/platformsocketengine/platformsocketengine.pro16
-rw-r--r--tests/auto/network/socket/platformsocketengine/tst_platformsocketengine.cpp763
-rw-r--r--tests/auto/network/socket/qabstractsocket/.gitignore1
-rw-r--r--tests/auto/network/socket/qabstractsocket/qabstractsocket.pro11
-rw-r--r--tests/auto/network/socket/qabstractsocket/tst_qabstractsocket.cpp109
-rw-r--r--tests/auto/network/socket/qhttpsocketengine/.gitignore1
-rw-r--r--tests/auto/network/socket/qhttpsocketengine/qhttpsocketengine.pro13
-rw-r--r--tests/auto/network/socket/qhttpsocketengine/tst_qhttpsocketengine.cpp748
-rw-r--r--tests/auto/network/socket/qlocalsocket/.gitignore2
-rw-r--r--tests/auto/network/socket/qlocalsocket/example/client/client.pro10
-rw-r--r--tests/auto/network/socket/qlocalsocket/example/client/main.cpp84
-rw-r--r--tests/auto/network/socket/qlocalsocket/example/example.pro3
-rw-r--r--tests/auto/network/socket/qlocalsocket/example/server/main.cpp97
-rw-r--r--tests/auto/network/socket/qlocalsocket/example/server/server.pro13
-rw-r--r--tests/auto/network/socket/qlocalsocket/lackey/lackey.pro16
-rw-r--r--tests/auto/network/socket/qlocalsocket/lackey/main.cpp296
-rwxr-xr-xtests/auto/network/socket/qlocalsocket/lackey/scripts/client.js35
-rw-r--r--tests/auto/network/socket/qlocalsocket/lackey/scripts/server.js19
-rw-r--r--tests/auto/network/socket/qlocalsocket/qlocalsocket.pro4
-rw-r--r--tests/auto/network/socket/qlocalsocket/test/test.pro50
-rw-r--r--tests/auto/network/socket/qlocalsocket/tst_qlocalsocket.cpp1120
-rw-r--r--tests/auto/network/socket/qsocks5socketengine/.gitignore1
-rw-r--r--tests/auto/network/socket/qsocks5socketengine/qsocks5socketengine.pro17
-rw-r--r--tests/auto/network/socket/qsocks5socketengine/tst_qsocks5socketengine.cpp963
-rw-r--r--tests/auto/network/socket/qtcpserver/.gitignore3
-rw-r--r--tests/auto/network/socket/qtcpserver/crashingServer/crashingServer.pro9
-rw-r--r--tests/auto/network/socket/qtcpserver/crashingServer/main.cpp70
-rw-r--r--tests/auto/network/socket/qtcpserver/qtcpserver.pro4
-rw-r--r--tests/auto/network/socket/qtcpserver/test/test.pro37
-rw-r--r--tests/auto/network/socket/qtcpserver/tst_qtcpserver.cpp817
-rw-r--r--tests/auto/network/socket/qtcpsocket/.gitignore3
-rw-r--r--tests/auto/network/socket/qtcpsocket/qtcpsocket.pro8
-rw-r--r--tests/auto/network/socket/qtcpsocket/stressTest/Test.cpp146
-rw-r--r--tests/auto/network/socket/qtcpsocket/stressTest/Test.h95
-rw-r--r--tests/auto/network/socket/qtcpsocket/stressTest/main.cpp67
-rw-r--r--tests/auto/network/socket/qtcpsocket/stressTest/stressTest.pro12
-rw-r--r--tests/auto/network/socket/qtcpsocket/test/test.pro33
-rw-r--r--tests/auto/network/socket/qtcpsocket/tst_qtcpsocket.cpp2684
-rw-r--r--tests/auto/network/socket/qudpsocket/.gitignore2
-rw-r--r--tests/auto/network/socket/qudpsocket/clientserver/clientserver.pro8
-rw-r--r--tests/auto/network/socket/qudpsocket/clientserver/main.cpp170
-rw-r--r--tests/auto/network/socket/qudpsocket/qudpsocket.pro4
-rw-r--r--tests/auto/network/socket/qudpsocket/test/test.pro28
-rw-r--r--tests/auto/network/socket/qudpsocket/tst_qudpsocket.cpp1356
-rw-r--r--tests/auto/network/socket/qudpsocket/udpServer/main.cpp90
-rw-r--r--tests/auto/network/socket/qudpsocket/udpServer/udpServer.pro7
-rw-r--r--tests/auto/network/socket/socket.pro17
49 files changed, 10082 insertions, 0 deletions
diff --git a/tests/auto/network/socket/platformsocketengine/.gitignore b/tests/auto/network/socket/platformsocketengine/.gitignore
new file mode 100644
index 0000000000..afe93891ff
--- /dev/null
+++ b/tests/auto/network/socket/platformsocketengine/.gitignore
@@ -0,0 +1 @@
+tst_platformsocketengine
diff --git a/tests/auto/network/socket/platformsocketengine/platformsocketengine.pri b/tests/auto/network/socket/platformsocketengine/platformsocketengine.pri
new file mode 100644
index 0000000000..15f31fdbb5
--- /dev/null
+++ b/tests/auto/network/socket/platformsocketengine/platformsocketengine.pri
@@ -0,0 +1,19 @@
+QT += network
+
+QNETWORK_SRC = $$QT_SOURCE_TREE/src/network
+
+INCLUDEPATH += $$QNETWORK_SRC
+
+win32 {
+ wince*: {
+ LIBS += -lws2
+ } else {
+ LIBS += -lws2_32
+ }
+}
+
+unix:contains(QT_CONFIG, reduce_exports) {
+ SOURCES += $$QNETWORK_SRC/socket/qnativesocketengine_unix.cpp
+ SOURCES += $$QNETWORK_SRC/socket/qnativesocketengine.cpp
+ SOURCES += $$QNETWORK_SRC/socket/qabstractsocketengine.cpp
+}
diff --git a/tests/auto/network/socket/platformsocketengine/platformsocketengine.pro b/tests/auto/network/socket/platformsocketengine/platformsocketengine.pro
new file mode 100644
index 0000000000..99ae358a93
--- /dev/null
+++ b/tests/auto/network/socket/platformsocketengine/platformsocketengine.pro
@@ -0,0 +1,16 @@
+load(qttest_p4)
+SOURCES += tst_platformsocketengine.cpp
+
+include(../platformsocketengine/platformsocketengine.pri)
+
+requires(contains(QT_CONFIG,private_tests))
+
+MOC_DIR=tmp
+
+QT = core-private network-private
+
+symbian {
+ TARGET.CAPABILITY = NetworkServices
+ INCLUDEPATH += $$OS_LAYER_SYSTEMINCLUDE
+ LIBS += -lesock
+}
diff --git a/tests/auto/network/socket/platformsocketengine/tst_platformsocketengine.cpp b/tests/auto/network/socket/platformsocketengine/tst_platformsocketengine.cpp
new file mode 100644
index 0000000000..9e93108fc7
--- /dev/null
+++ b/tests/auto/network/socket/platformsocketengine/tst_platformsocketengine.cpp
@@ -0,0 +1,763 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+
+#include <QtTest/QTest>
+
+#ifdef Q_OS_WIN
+#include <winsock2.h>
+#endif
+
+#include <qcoreapplication.h>
+
+
+#include <qdatastream.h>
+
+#include <qhostaddress.h>
+#include <qdatetime.h>
+
+#ifdef Q_OS_UNIX
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#endif
+
+#include <stddef.h>
+
+#ifdef Q_OS_SYMBIAN
+#include <QNetworkConfigurationManager>
+#include <QNetworkConfiguration>
+#include <QNetworkSession>
+#include <QScopedPointer>
+#define PLATFORMSOCKETENGINE QSymbianSocketEngine
+#define PLATFORMSOCKETENGINESTRING "QSymbianSocketEngine"
+#include <private/qsymbiansocketengine_p.h>
+#include <private/qcore_symbian_p.h>
+#else
+#define PLATFORMSOCKETENGINE QNativeSocketEngine
+#define PLATFORMSOCKETENGINESTRING "QNativeSocketEngine"
+#include <private/qnativesocketengine_p.h>
+#endif
+
+#include <qstringlist.h>
+
+#include "../../../network-settings.h"
+
+//TESTED_FILES=network/qnativesocketengine.cpp network/qnativesocketengine_p.h network/qnativesocketengine_unix.cpp
+
+class tst_PlatformSocketEngine : public QObject
+{
+ Q_OBJECT
+
+public:
+ tst_PlatformSocketEngine();
+ virtual ~tst_PlatformSocketEngine();
+
+
+public slots:
+ void init();
+ void cleanup();
+private slots:
+ void construction();
+ void simpleConnectToIMAP();
+ void udpLoopbackTest();
+ void udpIPv6LoopbackTest();
+ void broadcastTest();
+ void serverTest();
+ void udpLoopbackPerformance();
+ void tcpLoopbackPerformance();
+ void readWriteBufferSize();
+ void bind();
+ void networkError();
+ void setSocketDescriptor();
+ void invalidSend();
+ void receiveUrgentData();
+ void tooManySockets();
+};
+
+tst_PlatformSocketEngine::tst_PlatformSocketEngine()
+{
+ Q_SET_DEFAULT_IAP
+}
+
+tst_PlatformSocketEngine::~tst_PlatformSocketEngine()
+{
+}
+
+void tst_PlatformSocketEngine::init()
+{
+}
+
+void tst_PlatformSocketEngine::cleanup()
+{
+}
+
+//---------------------------------------------------------------------------
+void tst_PlatformSocketEngine::construction()
+{
+ PLATFORMSOCKETENGINE socketDevice;
+
+ QVERIFY(!socketDevice.isValid());
+
+ // Initialize device
+ QVERIFY(socketDevice.initialize(QAbstractSocket::TcpSocket, QAbstractSocket::IPv4Protocol));
+ QVERIFY(socketDevice.isValid());
+ QVERIFY(socketDevice.protocol() == QAbstractSocket::IPv4Protocol);
+ QVERIFY(socketDevice.socketType() == QAbstractSocket::TcpSocket);
+ QVERIFY(socketDevice.state() == QAbstractSocket::UnconnectedState);
+ QVERIFY(socketDevice.socketDescriptor() != -1);
+ QVERIFY(socketDevice.localAddress() == QHostAddress());
+ QVERIFY(socketDevice.localPort() == 0);
+ QVERIFY(socketDevice.peerAddress() == QHostAddress());
+ QVERIFY(socketDevice.peerPort() == 0);
+ QVERIFY(socketDevice.error() == QAbstractSocket::UnknownSocketError);
+
+ QTest::ignoreMessage(QtWarningMsg, PLATFORMSOCKETENGINESTRING "::bytesAvailable() was called in QAbstractSocket::UnconnectedState");
+ QVERIFY(socketDevice.bytesAvailable() == 0);
+
+ QTest::ignoreMessage(QtWarningMsg, PLATFORMSOCKETENGINESTRING "::hasPendingDatagrams() was called in QAbstractSocket::UnconnectedState");
+ QVERIFY(!socketDevice.hasPendingDatagrams());
+}
+
+//---------------------------------------------------------------------------
+void tst_PlatformSocketEngine::simpleConnectToIMAP()
+{
+ PLATFORMSOCKETENGINE socketDevice;
+
+ // Initialize device
+ QVERIFY(socketDevice.initialize(QAbstractSocket::TcpSocket, QAbstractSocket::IPv4Protocol));
+ QVERIFY(socketDevice.state() == QAbstractSocket::UnconnectedState);
+
+ const bool isConnected = socketDevice.connectToHost(QtNetworkSettings::serverIP(), 143);
+ if (!isConnected) {
+ QVERIFY(socketDevice.state() == QAbstractSocket::ConnectingState);
+ QVERIFY(socketDevice.waitForWrite());
+ QVERIFY(socketDevice.state() == QAbstractSocket::ConnectedState);
+ }
+ QVERIFY(socketDevice.state() == QAbstractSocket::ConnectedState);
+ QVERIFY(socketDevice.peerAddress() == QtNetworkSettings::serverIP());
+
+ // Wait for the greeting
+ QVERIFY(socketDevice.waitForRead());
+
+ // Read the greeting
+ qint64 available = socketDevice.bytesAvailable();
+ QVERIFY(available > 0);
+ QByteArray array;
+ array.resize(available);
+ QVERIFY(socketDevice.read(array.data(), array.size()) == available);
+
+ // Check that the greeting is what we expect it to be
+ QVERIFY2(QtNetworkSettings::compareReplyIMAP(array), array.constData());
+
+ // Write a logout message
+ QByteArray array2 = "ZZZ LOGOUT\r\n";
+ QVERIFY(socketDevice.write(array2.data(),
+ array2.size()) == array2.size());
+
+ // Wait for the response
+ QVERIFY(socketDevice.waitForRead());
+
+ available = socketDevice.bytesAvailable();
+ QVERIFY(available > 0);
+ array.resize(available);
+ QVERIFY(socketDevice.read(array.data(), array.size()) == available);
+
+ // Check that the greeting is what we expect it to be
+ QCOMPARE(array.constData(),
+ "* BYE LOGOUT received\r\n"
+ "ZZZ OK Completed\r\n");
+
+ // Wait for the response
+ QVERIFY(socketDevice.waitForRead());
+ char c;
+ QVERIFY(socketDevice.read(&c, sizeof(c)) == -1);
+ QVERIFY(socketDevice.error() == QAbstractSocket::RemoteHostClosedError);
+ QVERIFY(socketDevice.state() == QAbstractSocket::UnconnectedState);
+}
+
+//---------------------------------------------------------------------------
+void tst_PlatformSocketEngine::udpLoopbackTest()
+{
+ PLATFORMSOCKETENGINE udpSocket;
+
+ // Initialize device #1
+ QVERIFY(udpSocket.initialize(QAbstractSocket::UdpSocket));
+ QVERIFY(udpSocket.isValid());
+ QVERIFY(udpSocket.socketDescriptor() != -1);
+ QVERIFY(udpSocket.protocol() == QAbstractSocket::IPv4Protocol);
+ QVERIFY(udpSocket.socketType() == QAbstractSocket::UdpSocket);
+ QVERIFY(udpSocket.state() == QAbstractSocket::UnconnectedState);
+
+ // Bind #1 to localhost
+ QVERIFY(udpSocket.bind(QHostAddress("127.0.0.1"), 0));
+ QVERIFY(udpSocket.state() == QAbstractSocket::BoundState);
+ quint16 port = udpSocket.localPort();
+ QVERIFY(port != 0);
+
+ // Initialize device #2
+ PLATFORMSOCKETENGINE udpSocket2;
+ QVERIFY(udpSocket2.initialize(QAbstractSocket::UdpSocket));
+
+ // Connect device #2 to #1
+ QVERIFY(udpSocket2.connectToHost(QHostAddress("127.0.0.1"), port));
+ QVERIFY(udpSocket2.state() == QAbstractSocket::ConnectedState);
+
+ // Write a message to #1
+ QByteArray message1 = "hei der";
+ QVERIFY(udpSocket2.write(message1.data(),
+ message1.size()) == message1.size());
+
+ // Read the message from #2
+ QVERIFY(udpSocket.waitForRead());
+ QVERIFY(udpSocket.hasPendingDatagrams());
+ qint64 available = udpSocket.pendingDatagramSize();
+ QVERIFY(available > 0);
+ QByteArray answer;
+ answer.resize(available);
+ QHostAddress senderAddress;
+ quint16 senderPort = 0;
+ QVERIFY(udpSocket.readDatagram(answer.data(), answer.size(),
+ &senderAddress,
+ &senderPort) == message1.size());
+ QVERIFY(senderAddress == QHostAddress("127.0.0.1"));
+ QVERIFY(senderPort != 0);
+}
+
+//---------------------------------------------------------------------------
+void tst_PlatformSocketEngine::udpIPv6LoopbackTest()
+{
+ PLATFORMSOCKETENGINE udpSocket;
+
+ // Initialize device #1
+ bool init = udpSocket.initialize(QAbstractSocket::UdpSocket, QAbstractSocket::IPv6Protocol);
+
+ if (!init) {
+ QVERIFY(udpSocket.error() == QAbstractSocket::UnsupportedSocketOperationError);
+ } else {
+ QVERIFY(udpSocket.protocol() == QAbstractSocket::IPv6Protocol);
+
+ // Bind #1 to localhost
+ QVERIFY(udpSocket.bind(QHostAddress("::1"), 0));
+ QVERIFY(udpSocket.state() == QAbstractSocket::BoundState);
+ quint16 port = udpSocket.localPort();
+ QVERIFY(port != 0);
+
+ // Initialize device #2
+ PLATFORMSOCKETENGINE udpSocket2;
+ QVERIFY(udpSocket2.initialize(QAbstractSocket::UdpSocket, QAbstractSocket::IPv6Protocol));
+
+ // Connect device #2 to #1
+ QVERIFY(udpSocket2.connectToHost(QHostAddress("::1"), port));
+ QVERIFY(udpSocket2.state() == QAbstractSocket::ConnectedState);
+
+ // Write a message to #1
+ QByteArray message1 = "hei der";
+ QVERIFY(udpSocket2.write(message1.data(),
+ message1.size()) == message1.size());
+
+ // Read the message from #2
+ QVERIFY(udpSocket.waitForRead());
+ QVERIFY(udpSocket.hasPendingDatagrams());
+ qint64 available = udpSocket.pendingDatagramSize();
+ QVERIFY(available > 0);
+ QByteArray answer;
+ answer.resize(available);
+ QHostAddress senderAddress;
+ quint16 senderPort = 0;
+ QVERIFY(udpSocket.readDatagram(answer.data(), answer.size(),
+ &senderAddress,
+ &senderPort) == message1.size());
+ QVERIFY(senderAddress == QHostAddress("::1"));
+ QVERIFY(senderPort != 0);
+ }
+}
+
+//---------------------------------------------------------------------------
+void tst_PlatformSocketEngine::broadcastTest()
+{
+#ifdef Q_OS_SYMBIAN
+ //broadcast isn't supported on loopback connections, but is on WLAN
+#ifndef QT_NO_BEARERMANAGEMENT
+ QScopedPointer<QNetworkConfigurationManager> netConfMan(new QNetworkConfigurationManager());
+ QNetworkConfiguration networkConfiguration(netConfMan->defaultConfiguration());
+ QScopedPointer<QNetworkSession> networkSession(new QNetworkSession(networkConfiguration));
+ if (!networkSession->isOpen()) {
+ networkSession->open();
+ bool ok = networkSession->waitForOpened(30000);
+ qDebug() << networkSession->isOpen() << networkSession->error() << networkSession->errorString();
+ QVERIFY(ok);
+ }
+#endif
+#endif
+#ifdef Q_OS_AIX
+ QSKIP("Broadcast does not work on darko", SkipAll);
+#endif
+ PLATFORMSOCKETENGINE broadcastSocket;
+
+ // Initialize a regular Udp socket
+ QVERIFY(broadcastSocket.initialize(QAbstractSocket::UdpSocket));
+
+ // Bind to any port on all interfaces
+ QVERIFY(broadcastSocket.bind(QHostAddress::Any, 0));
+ QVERIFY(broadcastSocket.state() == QAbstractSocket::BoundState);
+ quint16 port = broadcastSocket.localPort();
+ QVERIFY(port > 0);
+
+ // Broadcast an inappropriate troll message
+ QByteArray trollMessage
+ = "MOOT wtf is a MOOT? talk english not your sutpiD ENGLISH.";
+ qint64 written = broadcastSocket.writeDatagram(trollMessage.data(),
+ trollMessage.size(),
+ QHostAddress::Broadcast,
+ port);
+
+#ifdef Q_OS_SYMBIAN
+ //On symbian, broadcasts return 0 bytes written if none of the interfaces support it.
+ //Notably the loopback interfaces do not. (though they do support multicast!?)
+ if (written == 0)
+ QEXPECT_FAIL("", "No active interface supports broadcast", Abort);
+#endif
+ QCOMPARE((int)written, trollMessage.size());
+
+ // Wait until we receive it ourselves
+#if defined(Q_OS_FREEBSD)
+ QEXPECT_FAIL("", "Broadcasting to 255.255.255.255 does not work on FreeBSD", Abort);
+#endif
+ QVERIFY(broadcastSocket.waitForRead());
+ QVERIFY(broadcastSocket.hasPendingDatagrams());
+
+ qlonglong available = broadcastSocket.pendingDatagramSize();
+ QByteArray response;
+ response.resize(available);
+ QVERIFY(broadcastSocket.readDatagram(response.data(), response.size())
+ == response.size());
+ QCOMPARE(response, trollMessage);
+
+}
+
+//---------------------------------------------------------------------------
+void tst_PlatformSocketEngine::serverTest()
+{
+ PLATFORMSOCKETENGINE server;
+
+ // Initialize a Tcp socket
+ QVERIFY(server.initialize(QAbstractSocket::TcpSocket));
+
+ // Bind to any port on all interfaces
+ QVERIFY(server.bind(QHostAddress("0.0.0.0"), 0));
+ QVERIFY(server.state() == QAbstractSocket::BoundState);
+ quint16 port = server.localPort();
+
+ // Listen for incoming connections
+ QVERIFY(server.listen());
+ QVERIFY(server.state() == QAbstractSocket::ListeningState);
+
+ // Initialize a Tcp socket
+ PLATFORMSOCKETENGINE client;
+ QVERIFY(client.initialize(QAbstractSocket::TcpSocket));
+ if (!client.connectToHost(QHostAddress("127.0.0.1"), port)) {
+ QVERIFY(client.state() == QAbstractSocket::ConnectingState);
+ QVERIFY(client.waitForWrite());
+ QVERIFY(client.state() == QAbstractSocket::ConnectedState);
+ }
+
+ // The server accepts the connection
+ int socketDescriptor = server.accept();
+ QVERIFY(socketDescriptor > 0);
+
+ // A socket device is initialized on the server side, passing the
+ // socket descriptor from accept(). It's pre-connected.
+ PLATFORMSOCKETENGINE serverSocket;
+ QVERIFY(serverSocket.initialize(socketDescriptor));
+ QVERIFY(serverSocket.state() == QAbstractSocket::ConnectedState);
+
+ // The server socket sends a greeting to the clietn
+ QByteArray greeting = "Greetings!";
+ QVERIFY(serverSocket.write(greeting.data(),
+ greeting.size()) == greeting.size());
+
+ // The client waits for the greeting to arrive
+ QVERIFY(client.waitForRead());
+ qint64 available = client.bytesAvailable();
+ QVERIFY(available > 0);
+
+ // The client reads the greeting and checks that it's correct
+ QByteArray response;
+ response.resize(available);
+ QVERIFY(client.read(response.data(),
+ response.size()) == response.size());
+ QCOMPARE(response, greeting);
+}
+
+//---------------------------------------------------------------------------
+void tst_PlatformSocketEngine::udpLoopbackPerformance()
+{
+#ifdef SYMBIAN_WINSOCK_CONNECTIVITY
+ QSKIP("Not working on Emulator without WinPCAP", SkipAll);
+#endif
+ PLATFORMSOCKETENGINE udpSocket;
+
+ // Initialize device #1
+ QVERIFY(udpSocket.initialize(QAbstractSocket::UdpSocket));
+ QVERIFY(udpSocket.isValid());
+ QVERIFY(udpSocket.socketDescriptor() != -1);
+ QVERIFY(udpSocket.protocol() == QAbstractSocket::IPv4Protocol);
+ QVERIFY(udpSocket.socketType() == QAbstractSocket::UdpSocket);
+ QVERIFY(udpSocket.state() == QAbstractSocket::UnconnectedState);
+
+ // Bind #1 to localhost
+ QVERIFY(udpSocket.bind(QHostAddress("127.0.0.1"), 0));
+ QVERIFY(udpSocket.state() == QAbstractSocket::BoundState);
+ quint16 port = udpSocket.localPort();
+ QVERIFY(port != 0);
+
+ // Initialize device #2
+ PLATFORMSOCKETENGINE udpSocket2;
+ QVERIFY(udpSocket2.initialize(QAbstractSocket::UdpSocket));
+
+ // Connect device #2 to #1
+ QVERIFY(udpSocket2.connectToHost(QHostAddress("127.0.0.1"), port));
+ QVERIFY(udpSocket2.state() == QAbstractSocket::ConnectedState);
+
+ const int messageSize = 8192;
+ QByteArray message1(messageSize, '@');
+ QByteArray answer(messageSize, '@');
+
+ QHostAddress localhost = QHostAddress::LocalHost;
+
+ qlonglong readBytes = 0;
+ QTime timer;
+ timer.start();
+ while (timer.elapsed() < 5000) {
+ udpSocket2.write(message1.data(), message1.size());
+ udpSocket.waitForRead();
+ while (udpSocket.hasPendingDatagrams()) {
+ readBytes += (qlonglong) udpSocket.readDatagram(answer.data(),
+ answer.size());
+ }
+ }
+
+ qDebug("\t\t%.1fMB/%.1fs: %.1fMB/s",
+ readBytes / (1024.0 * 1024.0),
+ timer.elapsed() / 1024.0,
+ (readBytes / (timer.elapsed() / 1000.0)) / (1024 * 1024));
+}
+
+//---------------------------------------------------------------------------
+void tst_PlatformSocketEngine::tcpLoopbackPerformance()
+{
+ PLATFORMSOCKETENGINE server;
+
+ // Initialize a Tcp socket
+ QVERIFY(server.initialize(QAbstractSocket::TcpSocket));
+
+ // Bind to any port on all interfaces
+ QVERIFY(server.bind(QHostAddress("0.0.0.0"), 0));
+ QVERIFY(server.state() == QAbstractSocket::BoundState);
+ quint16 port = server.localPort();
+
+ // Listen for incoming connections
+ QVERIFY(server.listen());
+ QVERIFY(server.state() == QAbstractSocket::ListeningState);
+
+ // Initialize a Tcp socket
+ PLATFORMSOCKETENGINE client;
+ QVERIFY(client.initialize(QAbstractSocket::TcpSocket));
+
+ // Connect to our server
+ if (!client.connectToHost(QHostAddress("127.0.0.1"), port)) {
+ QVERIFY(client.state() == QAbstractSocket::ConnectingState);
+ QVERIFY(client.waitForWrite());
+ QVERIFY(client.state() == QAbstractSocket::ConnectedState);
+ }
+
+ // The server accepts the connection
+ int socketDescriptor = server.accept();
+ QVERIFY(socketDescriptor > 0);
+
+ // A socket device is initialized on the server side, passing the
+ // socket descriptor from accept(). It's pre-connected.
+ PLATFORMSOCKETENGINE serverSocket;
+ QVERIFY(serverSocket.initialize(socketDescriptor));
+ QVERIFY(serverSocket.state() == QAbstractSocket::ConnectedState);
+
+#if defined (Q_OS_SYMBIAN) && defined (__WINS__)
+ const int messageSize = 1024 * 16;
+#else
+ const int messageSize = 1024 * 256;
+#endif
+ QByteArray message1(messageSize, '@');
+ QByteArray answer(messageSize, '@');
+
+ QTime timer;
+ timer.start();
+ qlonglong readBytes = 0;
+ while (timer.elapsed() < 5000) {
+ qlonglong written = serverSocket.write(message1.data(), message1.size());
+ while (written > 0) {
+ client.waitForRead();
+ if (client.bytesAvailable() > 0) {
+ qlonglong readNow = client.read(answer.data(), answer.size());
+ written -= readNow;
+ readBytes += readNow;
+ }
+ }
+ }
+
+ qDebug("\t\t%.1fMB/%.1fs: %.1fMB/s",
+ readBytes / (1024.0 * 1024.0),
+ timer.elapsed() / 1024.0,
+ (readBytes / (timer.elapsed() / 1000.0)) / (1024 * 1024));
+}
+
+//---------------------------------------------------------------------------
+void tst_PlatformSocketEngine::readWriteBufferSize()
+{
+ PLATFORMSOCKETENGINE device;
+
+ QVERIFY(device.initialize(QAbstractSocket::TcpSocket));
+
+ qint64 bufferSize = device.receiveBufferSize();
+ QVERIFY(bufferSize != -1);
+ device.setReceiveBufferSize(bufferSize + 1);
+#if defined(Q_OS_WINCE)
+ QEXPECT_FAIL(0, "Not supported by default on WinCE", Continue);
+#endif
+ QVERIFY(device.receiveBufferSize() > bufferSize);
+
+ bufferSize = device.sendBufferSize();
+ QVERIFY(bufferSize != -1);
+ device.setSendBufferSize(bufferSize + 1);
+ QVERIFY(device.sendBufferSize() > bufferSize);
+
+}
+
+//---------------------------------------------------------------------------
+void tst_PlatformSocketEngine::tooManySockets()
+{
+#if defined Q_OS_WIN
+ QSKIP("Certain windows machines suffocate and spend too much time in this test.", SkipAll);
+#endif
+ QList<PLATFORMSOCKETENGINE *> sockets;
+ PLATFORMSOCKETENGINE *socketLayer = 0;
+ for (;;) {
+ socketLayer = new PLATFORMSOCKETENGINE;
+ sockets.append(socketLayer);
+
+ if (!socketLayer->initialize(QAbstractSocket::TcpSocket, QAbstractSocket::IPv4Protocol))
+ break;
+ }
+
+ QCOMPARE(socketLayer->error(), QAbstractSocket::SocketResourceError);
+
+ qDeleteAll(sockets);
+}
+
+//---------------------------------------------------------------------------
+void tst_PlatformSocketEngine::bind()
+{
+#if !defined Q_OS_WIN && !defined Q_OS_SYMBIAN
+ PLATFORMSOCKETENGINE binder;
+ QVERIFY(binder.initialize(QAbstractSocket::TcpSocket, QAbstractSocket::IPv4Protocol));
+ QVERIFY(!binder.bind(QHostAddress::Any, 82));
+ QVERIFY(binder.error() == QAbstractSocket::SocketAccessError);
+#endif
+
+ PLATFORMSOCKETENGINE binder2;
+ QVERIFY(binder2.initialize(QAbstractSocket::TcpSocket, QAbstractSocket::IPv4Protocol));
+ QVERIFY(binder2.bind(QHostAddress::Any, 31180));
+
+ PLATFORMSOCKETENGINE binder3;
+ QVERIFY(binder3.initialize(QAbstractSocket::TcpSocket, QAbstractSocket::IPv4Protocol));
+ QVERIFY(!binder3.bind(QHostAddress::Any, 31180));
+
+#ifdef SYMBIAN_WINSOCK_CONNECTIVITY
+ qDebug("On Symbian Emulator (WinSock) we get EADDRNOTAVAIL instead of EADDRINUSE");
+ QVERIFY(binder3.error() == QAbstractSocket::SocketAddressNotAvailableError);
+#else
+ QVERIFY(binder3.error() == QAbstractSocket::AddressInUseError);
+#endif
+}
+
+//---------------------------------------------------------------------------
+void tst_PlatformSocketEngine::networkError()
+{
+ PLATFORMSOCKETENGINE client;
+
+ QVERIFY(client.initialize(QAbstractSocket::TcpSocket, QAbstractSocket::IPv4Protocol));
+
+ const bool isConnected = client.connectToHost(QtNetworkSettings::serverIP(), 143);
+ if (!isConnected) {
+ QVERIFY(client.state() == QAbstractSocket::ConnectingState);
+ QVERIFY(client.waitForWrite());
+ QVERIFY(client.state() == QAbstractSocket::ConnectedState);
+ }
+ QVERIFY(client.state() == QAbstractSocket::ConnectedState);
+
+ // An unexpected network error!
+#ifdef Q_OS_WIN
+ // could use shutdown to produce different errors
+ ::closesocket(client.socketDescriptor());
+#elif defined(Q_OS_SYMBIAN)
+ RSocket sock;
+ QVERIFY(QSymbianSocketManager::instance().lookupSocket(client.socketDescriptor(), sock));
+ TRequestStatus stat;
+ sock.Shutdown(RSocket::EImmediate, stat);
+ User::WaitForRequest(stat);
+#else
+ ::close(client.socketDescriptor());
+#endif
+
+ QVERIFY(client.read(0, 0) == -1);
+}
+
+//---------------------------------------------------------------------------
+void tst_PlatformSocketEngine::setSocketDescriptor()
+{
+ PLATFORMSOCKETENGINE socket1;
+ QVERIFY(socket1.initialize(QAbstractSocket::TcpSocket));
+
+ PLATFORMSOCKETENGINE socket2;
+ QVERIFY(socket2.initialize(socket1.socketDescriptor()));
+}
+
+//---------------------------------------------------------------------------
+void tst_PlatformSocketEngine::invalidSend()
+{
+ PLATFORMSOCKETENGINE socket;
+ QVERIFY(socket.initialize(QAbstractSocket::TcpSocket));
+
+ QTest::ignoreMessage(QtWarningMsg, PLATFORMSOCKETENGINESTRING "::writeDatagram() was"
+ " called by a socket other than QAbstractSocket::UdpSocket");
+ QCOMPARE(socket.writeDatagram("hei", 3, QHostAddress::LocalHost, 143),
+ (qlonglong) -1);
+}
+
+//---------------------------------------------------------------------------
+void tst_PlatformSocketEngine::receiveUrgentData()
+{
+ PLATFORMSOCKETENGINE server;
+
+ QVERIFY(server.initialize(QAbstractSocket::TcpSocket));
+
+ // Bind to any port on all interfaces
+ QVERIFY(server.bind(QHostAddress("0.0.0.0"), 0));
+ QVERIFY(server.state() == QAbstractSocket::BoundState);
+ quint16 port = server.localPort();
+
+ QVERIFY(server.listen());
+ QVERIFY(server.state() == QAbstractSocket::ListeningState);
+
+ PLATFORMSOCKETENGINE client;
+ QVERIFY(client.initialize(QAbstractSocket::TcpSocket));
+
+ if (!client.connectToHost(QHostAddress("127.0.0.1"), port)) {
+ QVERIFY(client.state() == QAbstractSocket::ConnectingState);
+ QVERIFY(client.waitForWrite());
+ QVERIFY(client.state() == QAbstractSocket::ConnectedState);
+ }
+
+ int socketDescriptor = server.accept();
+ QVERIFY(socketDescriptor > 0);
+
+ PLATFORMSOCKETENGINE serverSocket;
+ QVERIFY(serverSocket.initialize(socketDescriptor));
+ QVERIFY(serverSocket.state() == QAbstractSocket::ConnectedState);
+
+ char msg;
+ int available;
+ QByteArray response;
+
+#if defined Q_OS_HPUX
+ QSKIP("Native OOB data test doesn't work on HP-UX.", SkipAll);
+#elif defined (Q_OS_WINCE)
+ QSKIP("Native OOB data test doesn't work on WinCE.", SkipAll);
+#endif
+
+ // The server sends an urgent message
+ msg = 'Q';
+#if defined(Q_OS_SYMBIAN)
+ RSocket sock;
+ QVERIFY(QSymbianSocketManager::instance().lookupSocket(socketDescriptor, sock));
+ TRequestStatus stat;
+ TSockXfrLength len;
+ sock.Send(TPtrC8((TUint8*)&msg,1), KSockWriteUrgent, stat, len);
+ User::WaitForRequest(stat);
+ QVERIFY(stat == KErrNone);
+ QCOMPARE(len(), 1);
+#else
+ QCOMPARE(int(::send(socketDescriptor, &msg, sizeof(msg), MSG_OOB)), 1);
+#endif
+
+ // The client receives the urgent message
+ QVERIFY(client.waitForRead());
+ available = client.bytesAvailable();
+ QCOMPARE(available, 1);
+ response.resize(available);
+ QCOMPARE(client.read(response.data(), response.size()), qint64(1));
+ QCOMPARE(response.at(0), msg);
+
+ // The client sends an urgent message
+ msg = 'T';
+ int clientDescriptor = client.socketDescriptor();
+#if defined(Q_OS_SYMBIAN)
+ QVERIFY(QSymbianSocketManager::instance().lookupSocket(clientDescriptor, sock));
+ sock.Send(TPtrC8((TUint8*)&msg,1), KSockWriteUrgent, stat, len);
+ User::WaitForRequest(stat);
+ QVERIFY(stat == KErrNone);
+ QCOMPARE(len(), 1);
+#else
+ QCOMPARE(int(::send(clientDescriptor, &msg, sizeof(msg), MSG_OOB)), 1);
+#endif
+
+ // The server receives the urgent message
+ QVERIFY(serverSocket.waitForRead());
+ available = serverSocket.bytesAvailable();
+ QCOMPARE(available, 1);
+ response.resize(available);
+ QCOMPARE(serverSocket.read(response.data(), response.size()), qint64(1));
+ QCOMPARE(response.at(0), msg);
+
+}
+
+QTEST_MAIN(tst_PlatformSocketEngine)
+#include "tst_platformsocketengine.moc"
diff --git a/tests/auto/network/socket/qabstractsocket/.gitignore b/tests/auto/network/socket/qabstractsocket/.gitignore
new file mode 100644
index 0000000000..b962a1a54b
--- /dev/null
+++ b/tests/auto/network/socket/qabstractsocket/.gitignore
@@ -0,0 +1 @@
+tst_qabstractsocket
diff --git a/tests/auto/network/socket/qabstractsocket/qabstractsocket.pro b/tests/auto/network/socket/qabstractsocket/qabstractsocket.pro
new file mode 100644
index 0000000000..814a7d2600
--- /dev/null
+++ b/tests/auto/network/socket/qabstractsocket/qabstractsocket.pro
@@ -0,0 +1,11 @@
+############################################################
+# Project file for autotest for file qabstractsocket.h
+############################################################
+
+load(qttest_p4)
+QT = core network
+
+SOURCES += tst_qabstractsocket.cpp
+
+symbian: TARGET.CAPABILITY = NetworkServices
+
diff --git a/tests/auto/network/socket/qabstractsocket/tst_qabstractsocket.cpp b/tests/auto/network/socket/qabstractsocket/tst_qabstractsocket.cpp
new file mode 100644
index 0000000000..309215d5ea
--- /dev/null
+++ b/tests/auto/network/socket/qabstractsocket/tst_qabstractsocket.cpp
@@ -0,0 +1,109 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+
+#include <QtTest/QtTest>
+
+#include <qcoreapplication.h>
+#include <qdebug.h>
+#include <qabstractsocket.h>
+
+//TESTED_CLASS=
+//TESTED_FILES=
+
+class tst_QAbstractSocket : public QObject
+{
+Q_OBJECT
+
+public:
+ tst_QAbstractSocket();
+ virtual ~tst_QAbstractSocket();
+
+private slots:
+ void getSetCheck();
+};
+
+tst_QAbstractSocket::tst_QAbstractSocket()
+{
+}
+
+tst_QAbstractSocket::~tst_QAbstractSocket()
+{
+}
+
+class MyAbstractSocket : public QAbstractSocket
+{
+public:
+ MyAbstractSocket() : QAbstractSocket(QAbstractSocket::TcpSocket, 0) {}
+ void setLocalPort(quint16 port) { QAbstractSocket::setLocalPort(port); }
+ void setPeerPort(quint16 port) { QAbstractSocket::setPeerPort(port); }
+};
+
+// Testing get/set functions
+void tst_QAbstractSocket::getSetCheck()
+{
+ MyAbstractSocket obj1;
+ // qint64 QAbstractSocket::readBufferSize()
+ // void QAbstractSocket::setReadBufferSize(qint64)
+ obj1.setReadBufferSize(qint64(0));
+ QCOMPARE(qint64(0), obj1.readBufferSize());
+ obj1.setReadBufferSize((Q_INT64_C(-9223372036854775807) - 1));
+ QCOMPARE((Q_INT64_C(-9223372036854775807) - 1), obj1.readBufferSize());
+ obj1.setReadBufferSize(Q_INT64_C(9223372036854775807));
+ QCOMPARE(Q_INT64_C(9223372036854775807), obj1.readBufferSize());
+
+ // quint16 QAbstractSocket::localPort()
+ // void QAbstractSocket::setLocalPort(quint16)
+ obj1.setLocalPort(quint16(0));
+ QCOMPARE(quint16(0), obj1.localPort());
+ obj1.setLocalPort(quint16(0xffff));
+ QCOMPARE(quint16(0xffff), obj1.localPort());
+
+ // quint16 QAbstractSocket::peerPort()
+ // void QAbstractSocket::setPeerPort(quint16)
+ obj1.setPeerPort(quint16(0));
+ QCOMPARE(quint16(0), obj1.peerPort());
+ obj1.setPeerPort(quint16(0xffff));
+ QCOMPARE(quint16(0xffff), obj1.peerPort());
+}
+
+QTEST_MAIN(tst_QAbstractSocket)
+#include "tst_qabstractsocket.moc"
diff --git a/tests/auto/network/socket/qhttpsocketengine/.gitignore b/tests/auto/network/socket/qhttpsocketengine/.gitignore
new file mode 100644
index 0000000000..c3eb6526ba
--- /dev/null
+++ b/tests/auto/network/socket/qhttpsocketengine/.gitignore
@@ -0,0 +1 @@
+tst_qhttpsocketengine
diff --git a/tests/auto/network/socket/qhttpsocketengine/qhttpsocketengine.pro b/tests/auto/network/socket/qhttpsocketengine/qhttpsocketengine.pro
new file mode 100644
index 0000000000..f26abbe8d9
--- /dev/null
+++ b/tests/auto/network/socket/qhttpsocketengine/qhttpsocketengine.pro
@@ -0,0 +1,13 @@
+load(qttest_p4)
+SOURCES += tst_qhttpsocketengine.cpp
+
+
+include(../platformsocketengine/platformsocketengine.pri)
+
+MOC_DIR=tmp
+
+QT = core-private network-private
+
+symbian: TARGET.CAPABILITY = NetworkServices
+
+
diff --git a/tests/auto/network/socket/qhttpsocketengine/tst_qhttpsocketengine.cpp b/tests/auto/network/socket/qhttpsocketengine/tst_qhttpsocketengine.cpp
new file mode 100644
index 0000000000..5a90abea0e
--- /dev/null
+++ b/tests/auto/network/socket/qhttpsocketengine/tst_qhttpsocketengine.cpp
@@ -0,0 +1,748 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+
+#include <QtTest/QTest>
+#include <QtTest/QTestEventLoop>
+#include <QtCore/QQueue>
+#include <QtCore/QString>
+#include <QtCore/QCoreApplication>
+
+#include <private/qhttpsocketengine_p.h>
+#include <qhostinfo.h>
+#include <qhostaddress.h>
+#include <qtcpsocket.h>
+#include <qhttp.h>
+#include <qdebug.h>
+#include <qtcpserver.h>
+
+#include "../../../network-settings.h"
+
+class tst_QHttpSocketEngine : public QObject
+{
+ Q_OBJECT
+
+public:
+ tst_QHttpSocketEngine();
+ virtual ~tst_QHttpSocketEngine();
+
+
+public slots:
+ void init();
+ void cleanup();
+private slots:
+ void construction();
+ void errorTest_data();
+ void errorTest();
+ void simpleConnectToIMAP();
+ void simpleErrorsAndStates();
+
+ void tcpSocketBlockingTest();
+ void tcpSocketNonBlockingTest();
+ void downloadBigFile();
+ // void tcpLoopbackPerformance();
+ void passwordAuth();
+
+protected slots:
+ void tcpSocketNonBlocking_hostFound();
+ void tcpSocketNonBlocking_connected();
+ void tcpSocketNonBlocking_closed();
+ void tcpSocketNonBlocking_readyRead();
+ void tcpSocketNonBlocking_bytesWritten(qint64);
+ void exitLoopSlot();
+ void downloadBigFileSlot();
+
+private:
+ QTcpSocket *tcpSocketNonBlocking_socket;
+ QStringList tcpSocketNonBlocking_data;
+ qint64 tcpSocketNonBlocking_totalWritten;
+ QTcpSocket *tmpSocket;
+ qint64 bytesAvailable;
+};
+
+class MiniHttpServer: public QTcpServer
+{
+ Q_OBJECT
+ QTcpSocket *client;
+ QList<QByteArray> dataToTransmit;
+
+public:
+ QByteArray receivedData;
+
+ MiniHttpServer(const QList<QByteArray> &data) : client(0), dataToTransmit(data)
+ {
+ listen();
+ connect(this, SIGNAL(newConnection()), this, SLOT(doAccept()));
+ }
+
+public slots:
+ void doAccept()
+ {
+ client = nextPendingConnection();
+ connect(client, SIGNAL(readyRead()), this, SLOT(sendData()));
+ }
+
+ void sendData()
+ {
+ receivedData += client->readAll();
+ int idx = client->property("dataTransmitionIdx").toInt();
+ if (receivedData.contains("\r\n\r\n") ||
+ receivedData.contains("\n\n")) {
+ if (idx < dataToTransmit.length())
+ client->write(dataToTransmit.at(idx++));
+ if (idx == dataToTransmit.length()) {
+ client->disconnectFromHost();
+ disconnect(client, 0, this, 0);
+ client = 0;
+ } else {
+ client->setProperty("dataTransmitionIdx", idx);
+ }
+ }
+ }
+};
+
+tst_QHttpSocketEngine::tst_QHttpSocketEngine()
+{
+ Q_SET_DEFAULT_IAP
+}
+
+tst_QHttpSocketEngine::~tst_QHttpSocketEngine()
+{
+}
+
+
+void tst_QHttpSocketEngine::init()
+{
+ tmpSocket = 0;
+ bytesAvailable = 0;
+}
+
+void tst_QHttpSocketEngine::cleanup()
+{
+}
+
+//---------------------------------------------------------------------------
+void tst_QHttpSocketEngine::construction()
+{
+ QHttpSocketEngine socketDevice;
+
+ QVERIFY(!socketDevice.isValid());
+
+ // Initialize device
+ QVERIFY(socketDevice.initialize(QAbstractSocket::TcpSocket, QAbstractSocket::IPv4Protocol));
+ QVERIFY(socketDevice.isValid());
+ QVERIFY(socketDevice.protocol() == QAbstractSocket::IPv4Protocol);
+ QVERIFY(socketDevice.socketType() == QAbstractSocket::TcpSocket);
+ QVERIFY(socketDevice.state() == QAbstractSocket::UnconnectedState);
+ // QVERIFY(socketDevice.socketDescriptor() != -1);
+ QVERIFY(socketDevice.localAddress() == QHostAddress());
+ QVERIFY(socketDevice.localPort() == 0);
+ QVERIFY(socketDevice.peerAddress() == QHostAddress());
+ QVERIFY(socketDevice.peerPort() == 0);
+ QVERIFY(socketDevice.error() == QAbstractSocket::UnknownSocketError);
+
+ //QTest::ignoreMessage(QtWarningMsg, "QSocketLayer::bytesAvailable() was called in QAbstractSocket::UnconnectedState");
+ QVERIFY(socketDevice.bytesAvailable() == 0);
+
+ //QTest::ignoreMessage(QtWarningMsg, "QSocketLayer::hasPendingDatagrams() was called in QAbstractSocket::UnconnectedState");
+ QVERIFY(!socketDevice.hasPendingDatagrams());
+}
+
+//---------------------------------------------------------------------------
+void tst_QHttpSocketEngine::errorTest_data()
+{
+ QTest::addColumn<QString>("hostname");
+ QTest::addColumn<int>("port");
+ QTest::addColumn<QString>("username");
+ QTest::addColumn<QString>("response");
+ QTest::addColumn<int>("expectedError");
+
+ QQueue<QByteArray> responses;
+ QTest::newRow("proxy-host-not-found") << "this-host-does-not-exist." << 1080 << QString()
+ << QString()
+ << int(QAbstractSocket::ProxyNotFoundError);
+ QTest::newRow("proxy-connection-refused") << QtNetworkSettings::serverName() << 2 << QString()
+ << QString()
+ << int(QAbstractSocket::ProxyConnectionRefusedError);
+
+ QTest::newRow("garbage1") << QString() << 0 << QString()
+ << "This is not HTTP\r\n\r\n"
+ << int(QAbstractSocket::ProxyProtocolError);
+
+ QTest::newRow("garbage2") << QString() << 0 << QString()
+ << "This is not HTTP"
+ << int(QAbstractSocket::ProxyConnectionClosedError);
+
+ QTest::newRow("garbage3") << QString() << 0 << QString()
+ << ""
+ << int(QAbstractSocket::ProxyConnectionClosedError);
+
+ QTest::newRow("forbidden") << QString() << 0 << QString()
+ << "HTTP/1.0 403 Forbidden\r\n\r\n"
+ << int(QAbstractSocket::SocketAccessError);
+
+ QTest::newRow("method-not-allowed") << QString() << 0 << QString()
+ << "HTTP/1.0 405 Method Not Allowed\r\n\r\n"
+ << int(QAbstractSocket::SocketAccessError);
+
+ QTest::newRow("proxy-authentication-too-short")
+ << QString() << 0 << "foo"
+ << "HTTP/1.0 407 Proxy Authentication Required\r\n\r\n"
+ << int(QAbstractSocket::ProxyProtocolError);
+
+ QTest::newRow("proxy-authentication-invalid-method")
+ << QString() << 0 << "foo"
+ << "HTTP/1.0 407 Proxy Authentication Required\r\n"
+ "Proxy-Authenticate: Frobnicator\r\n\r\n"
+ << int(QAbstractSocket::ProxyProtocolError);
+
+ QTest::newRow("proxy-authentication-required")
+ << QString() << 0 << "foo"
+ << "HTTP/1.0 407 Proxy Authentication Required\r\n"
+ "Proxy-Connection: close\r\n"
+ "Proxy-Authenticate: Basic, realm=wonderland\r\n\r\n"
+ << int(QAbstractSocket::ProxyAuthenticationRequiredError);
+
+ QTest::newRow("proxy-authentication-required2")
+ << QString() << 0 << "foo"
+ << "HTTP/1.0 407 Proxy Authentication Required\r\n"
+ "Proxy-Connection: keep-alive\r\n"
+ "Proxy-Authenticate: Basic, realm=wonderland\r\n\r\n"
+ "\1"
+ "HTTP/1.0 407 Proxy Authentication Required\r\n"
+ "Proxy-Authenticate: Basic, realm=wonderland\r\n\r\n"
+ << int(QAbstractSocket::ProxyAuthenticationRequiredError);
+
+ QTest::newRow("proxy-authentication-required-noclose")
+ << QString() << 0 << "foo"
+ << "HTTP/1.0 407 Proxy Authentication Required\r\n"
+ "Proxy-Authenticate: Basic\r\n"
+ "\r\n"
+ << int(QAbstractSocket::ProxyAuthenticationRequiredError);
+
+ QTest::newRow("connection-refused") << QString() << 0 << QString()
+ << "HTTP/1.0 503 Service Unavailable\r\n\r\n"
+ << int(QAbstractSocket::ConnectionRefusedError);
+
+ QTest::newRow("host-not-found") << QString() << 0 << QString()
+ << "HTTP/1.0 404 Not Found\r\n\r\n"
+ << int(QAbstractSocket::HostNotFoundError);
+
+ QTest::newRow("weird-http-reply") << QString() << 0 << QString()
+ << "HTTP/1.0 206 Partial Content\r\n\r\n"
+ << int(QAbstractSocket::ProxyProtocolError);
+}
+
+void tst_QHttpSocketEngine::errorTest()
+{
+ QFETCH(QString, hostname);
+ QFETCH(int, port);
+ QFETCH(QString, username);
+ QFETCH(QString, response);
+ QFETCH(int, expectedError);
+
+ MiniHttpServer server(response.toLatin1().split('\1'));
+
+ if (hostname.isEmpty()) {
+ hostname = "127.0.0.1";
+ port = server.serverPort();
+ }
+ QTcpSocket socket;
+ socket.setProxy(QNetworkProxy(QNetworkProxy::HttpProxy, hostname, port, username, username));
+ socket.connectToHost("0.1.2.3", 12345);
+
+ connect(&socket, SIGNAL(error(QAbstractSocket::SocketError)),
+ &QTestEventLoop::instance(), SLOT(exitLoop()));
+ QTestEventLoop::instance().enterLoop(5);
+ QVERIFY(!QTestEventLoop::instance().timeout());
+
+ QCOMPARE(int(socket.error()), expectedError);
+}
+
+//---------------------------------------------------------------------------
+void tst_QHttpSocketEngine::simpleConnectToIMAP()
+{
+ QHttpSocketEngine socketDevice;
+
+ // Initialize device
+ QVERIFY(socketDevice.initialize(QAbstractSocket::TcpSocket, QAbstractSocket::IPv4Protocol));
+ QVERIFY(socketDevice.state() == QAbstractSocket::UnconnectedState);
+
+ socketDevice.setProxy(QNetworkProxy(QNetworkProxy::HttpProxy, QtNetworkSettings::serverName(), 3128));
+
+ QVERIFY(!socketDevice.connectToHost(QtNetworkSettings::serverIP(), 143));
+ QVERIFY(socketDevice.state() == QAbstractSocket::ConnectingState);
+ QVERIFY(socketDevice.waitForWrite());
+ QVERIFY(socketDevice.state() == QAbstractSocket::ConnectedState);
+ QVERIFY(socketDevice.peerAddress() == QtNetworkSettings::serverIP());
+ QVERIFY(!socketDevice.localAddress().isNull());
+ QVERIFY(socketDevice.localPort() > 0);
+
+ // Wait for the greeting
+ QVERIFY(socketDevice.waitForRead());
+
+ // Read the greeting
+ qint64 available = socketDevice.bytesAvailable();
+ QVERIFY(available > 0);
+ QByteArray array;
+ array.resize(available);
+ QVERIFY(socketDevice.read(array.data(), array.size()) == available);
+
+ // Check that the greeting is what we expect it to be
+ QVERIFY2(QtNetworkSettings::compareReplyIMAP(array), array.constData());
+
+
+ // Write a logout message
+ QByteArray array2 = "XXXX LOGOUT\r\n";
+ QVERIFY(socketDevice.write(array2.data(),
+ array2.size()) == array2.size());
+
+ // Wait for the response
+ QVERIFY(socketDevice.waitForRead());
+
+ available = socketDevice.bytesAvailable();
+ QVERIFY(available > 0);
+ array.resize(available);
+ QVERIFY(socketDevice.read(array.data(), array.size()) == available);
+
+ // Check that the greeting is what we expect it to be
+ QCOMPARE(array.constData(), "* BYE LOGOUT received\r\nXXXX OK Completed\r\n");
+
+ // Wait for the response
+ QVERIFY(socketDevice.waitForRead());
+ char c;
+ QCOMPARE(socketDevice.read(&c, sizeof(c)), (qint64) -1);
+ QVERIFY(socketDevice.error() == QAbstractSocket::RemoteHostClosedError);
+ QVERIFY(socketDevice.state() == QAbstractSocket::UnconnectedState);
+}
+
+//---------------------------------------------------------------------------
+void tst_QHttpSocketEngine::simpleErrorsAndStates()
+{
+ {
+ QHttpSocketEngine socketDevice;
+
+ // Initialize device
+ QVERIFY(socketDevice.initialize(QAbstractSocket::TcpSocket, QAbstractSocket::IPv4Protocol));
+
+ socketDevice.setProxy(QNetworkProxy(QNetworkProxy::HttpProxy, QtNetworkSettings::serverName(), 3128));
+
+ QVERIFY(socketDevice.state() == QAbstractSocket::UnconnectedState);
+ QVERIFY(!socketDevice.connectToHost(QHostAddress(QtNetworkSettings::serverName()), 8088));
+ QVERIFY(socketDevice.state() == QAbstractSocket::ConnectingState);
+ if (socketDevice.waitForWrite(15000)) {
+ QVERIFY(socketDevice.state() == QAbstractSocket::ConnectedState ||
+ socketDevice.state() == QAbstractSocket::UnconnectedState);
+ } else {
+ QVERIFY(socketDevice.error() == QAbstractSocket::SocketTimeoutError);
+ }
+ }
+
+}
+
+/*
+//---------------------------------------------------------------------------
+void tst_QHttpSocketEngine::tcpLoopbackPerformance()
+{
+ QTcpServer server;
+
+ // Bind to any port on all interfaces
+ QVERIFY(server.bind(QHostAddress("0.0.0.0"), 0));
+ QVERIFY(server.state() == QAbstractSocket::BoundState);
+ quint16 port = server.localPort();
+
+ // Listen for incoming connections
+ QVERIFY(server.listen());
+ QVERIFY(server.state() == QAbstractSocket::ListeningState);
+
+ // Initialize a Tcp socket
+ QHttpSocketEngine client;
+ QVERIFY(client.initialize(QAbstractSocket::TcpSocket));
+
+ client.setProxy(QHostAddress("80.232.37.158"), 1081);
+
+ // Connect to our server
+ if (!client.connectToHost(QHostAddress("127.0.0.1"), port)) {
+ QVERIFY(client.waitForWrite());
+ QVERIFY(client.connectToHost(QHostAddress("127.0.0.1"), port));
+ }
+
+ // The server accepts the connectio
+ int socketDescriptor = server.accept();
+ QVERIFY(socketDescriptor > 0);
+
+ // A socket device is initialized on the server side, passing the
+ // socket descriptor from accept(). It's pre-connected.
+ QSocketLayer serverSocket;
+ QVERIFY(serverSocket.initialize(socketDescriptor));
+ QVERIFY(serverSocket.state() == QAbstractSocket::ConnectedState);
+
+ const int messageSize = 1024 * 256;
+ QByteArray message1(messageSize, '@');
+ QByteArray answer(messageSize, '@');
+
+ QTime timer;
+ timer.start();
+ qlonglong readBytes = 0;
+ while (timer.elapsed() < 5000) {
+ qlonglong written = serverSocket.write(message1.data(), message1.size());
+ while (written > 0) {
+ client.waitForRead();
+ if (client.bytesAvailable() > 0) {
+ qlonglong readNow = client.read(answer.data(), answer.size());
+ written -= readNow;
+ readBytes += readNow;
+ }
+ }
+ }
+
+ qDebug("\t\t%.1fMB/%.1fs: %.1fMB/s",
+ readBytes / (1024.0 * 1024.0),
+ timer.elapsed() / 1024.0,
+ (readBytes / (timer.elapsed() / 1000.0)) / (1024 * 1024));
+}
+*/
+
+
+
+void tst_QHttpSocketEngine::tcpSocketBlockingTest()
+{
+ QHttpSocketEngineHandler http;
+
+ QTcpSocket socket;
+
+ // Connect
+ socket.connectToHost(QtNetworkSettings::serverName(), 143);
+ QVERIFY(socket.waitForConnected());
+ QCOMPARE(socket.state(), QTcpSocket::ConnectedState);
+
+ // Read greeting
+ QVERIFY(socket.waitForReadyRead(5000));
+ QString s = socket.readLine();
+ QVERIFY2(QtNetworkSettings::compareReplyIMAP(s.toLatin1()), qPrintable(s));
+
+ // Write NOOP
+ QCOMPARE((int) socket.write("1 NOOP\r\n", 8), 8);
+
+ if (!socket.canReadLine())
+ QVERIFY(socket.waitForReadyRead(5000));
+
+ // Read response
+ s = socket.readLine();
+ QCOMPARE(s.toLatin1().constData(), "1 OK Completed\r\n");
+
+ // Write LOGOUT
+ QCOMPARE((int) socket.write("2 LOGOUT\r\n", 10), 10);
+
+ if (!socket.canReadLine())
+ QVERIFY(socket.waitForReadyRead(5000));
+
+ // Read two lines of respose
+ s = socket.readLine();
+ QCOMPARE(s.toLatin1().constData(), "* BYE LOGOUT received\r\n");
+
+ if (!socket.canReadLine())
+ QVERIFY(socket.waitForReadyRead(5000));
+
+ s = socket.readLine();
+ QCOMPARE(s.toLatin1().constData(), "2 OK Completed\r\n");
+
+ // Close the socket
+ socket.close();
+
+ // Check that it's closed
+ QCOMPARE(socket.state(), QTcpSocket::UnconnectedState);
+}
+
+//----------------------------------------------------------------------------------
+
+void tst_QHttpSocketEngine::tcpSocketNonBlockingTest()
+{
+ QHttpSocketEngineHandler http;
+
+ QTcpSocket socket;
+ connect(&socket, SIGNAL(hostFound()), SLOT(tcpSocketNonBlocking_hostFound()));
+ connect(&socket, SIGNAL(connected()), SLOT(tcpSocketNonBlocking_connected()));
+ connect(&socket, SIGNAL(disconnected()), SLOT(tcpSocketNonBlocking_closed()));
+ connect(&socket, SIGNAL(bytesWritten(qint64)), SLOT(tcpSocketNonBlocking_bytesWritten(qint64)));
+ connect(&socket, SIGNAL(readyRead()), SLOT(tcpSocketNonBlocking_readyRead()));
+ tcpSocketNonBlocking_socket = &socket;
+
+ // Connect
+ socket.connectToHost(QtNetworkSettings::serverName(), 143);
+ QVERIFY(socket.state() == QTcpSocket::HostLookupState ||
+ socket.state() == QTcpSocket::ConnectingState);
+
+ QTestEventLoop::instance().enterLoop(30);
+ if (QTestEventLoop::instance().timeout()) {
+ QFAIL("Timed out");
+ }
+
+ if (socket.state() == QTcpSocket::ConnectingState) {
+ QTestEventLoop::instance().enterLoop(30);
+ if (QTestEventLoop::instance().timeout()) {
+ QFAIL("Timed out");
+ }
+ }
+
+ QCOMPARE(socket.state(), QTcpSocket::ConnectedState);
+
+ QTestEventLoop::instance().enterLoop(30);
+ if (QTestEventLoop::instance().timeout()) {
+ QFAIL("Timed out");
+ }
+
+ // Read greeting
+ QVERIFY(!tcpSocketNonBlocking_data.isEmpty());
+ QByteArray data = tcpSocketNonBlocking_data.at(0).toLatin1();
+ QVERIFY2(QtNetworkSettings::compareReplyIMAP(data), data.constData());
+
+
+ tcpSocketNonBlocking_data.clear();
+
+ tcpSocketNonBlocking_totalWritten = 0;
+
+ // Write NOOP
+ QCOMPARE((int) socket.write("1 NOOP\r\n", 8), 8);
+
+
+ QTestEventLoop::instance().enterLoop(30);
+ if (QTestEventLoop::instance().timeout()) {
+ QFAIL("Timed out");
+ }
+
+ QVERIFY(tcpSocketNonBlocking_totalWritten == 8);
+
+
+ QTestEventLoop::instance().enterLoop(30);
+ if (QTestEventLoop::instance().timeout()) {
+ QFAIL("Timed out");
+ }
+
+
+ // Read response
+ QVERIFY(!tcpSocketNonBlocking_data.isEmpty());
+ QCOMPARE(tcpSocketNonBlocking_data.at(0).toLatin1().constData(), "1 OK Completed\r\n");
+ tcpSocketNonBlocking_data.clear();
+
+
+ tcpSocketNonBlocking_totalWritten = 0;
+
+ // Write LOGOUT
+ QCOMPARE((int) socket.write("2 LOGOUT\r\n", 10), 10);
+
+ QTestEventLoop::instance().enterLoop(30);
+ if (QTestEventLoop::instance().timeout()) {
+ QFAIL("Timed out");
+ }
+
+ QVERIFY(tcpSocketNonBlocking_totalWritten == 10);
+
+ // Wait for greeting
+ QTestEventLoop::instance().enterLoop(30);
+ if (QTestEventLoop::instance().timeout()) {
+ QFAIL("Timed out");
+ }
+
+ // Read two lines of respose
+ QCOMPARE(tcpSocketNonBlocking_data.at(0).toLatin1().constData(), "* BYE LOGOUT received\r\n");
+ QCOMPARE(tcpSocketNonBlocking_data.at(1).toLatin1().constData(), "2 OK Completed\r\n");
+ tcpSocketNonBlocking_data.clear();
+
+ // Close the socket
+ socket.close();
+
+ // Check that it's closed
+ QCOMPARE(socket.state(), QTcpSocket::UnconnectedState);
+}
+
+void tst_QHttpSocketEngine::tcpSocketNonBlocking_hostFound()
+{
+ QTestEventLoop::instance().exitLoop();
+}
+
+void tst_QHttpSocketEngine::tcpSocketNonBlocking_connected()
+{
+ QTestEventLoop::instance().exitLoop();
+}
+
+void tst_QHttpSocketEngine::tcpSocketNonBlocking_readyRead()
+{
+ while (tcpSocketNonBlocking_socket->canReadLine())
+ tcpSocketNonBlocking_data.append(tcpSocketNonBlocking_socket->readLine());
+
+ QTestEventLoop::instance().exitLoop();
+}
+
+void tst_QHttpSocketEngine::tcpSocketNonBlocking_bytesWritten(qint64 written)
+{
+ tcpSocketNonBlocking_totalWritten += written;
+ QTestEventLoop::instance().exitLoop();
+}
+
+void tst_QHttpSocketEngine::tcpSocketNonBlocking_closed()
+{
+}
+
+//----------------------------------------------------------------------------------
+
+void tst_QHttpSocketEngine::downloadBigFile()
+{
+ QHttpSocketEngineHandler http;
+
+ if (tmpSocket)
+ delete tmpSocket;
+ tmpSocket = new QTcpSocket;
+
+ connect(tmpSocket, SIGNAL(connected()), SLOT(exitLoopSlot()));
+ connect(tmpSocket, SIGNAL(readyRead()), SLOT(downloadBigFileSlot()));
+
+ tmpSocket->connectToHost(QtNetworkSettings::serverName(), 80);
+
+ QTestEventLoop::instance().enterLoop(30);
+ if (QTestEventLoop::instance().timeout())
+ QFAIL("Network operation timed out");
+
+ QByteArray hostName = QtNetworkSettings::serverName().toLatin1();
+ QVERIFY(tmpSocket->state() == QAbstractSocket::ConnectedState);
+ QVERIFY(tmpSocket->write("GET /qtest/mediumfile HTTP/1.0\r\n") > 0);
+ QVERIFY(tmpSocket->write("Host: ") > 0);
+ QVERIFY(tmpSocket->write(hostName.data()) > 0);
+ QVERIFY(tmpSocket->write("\r\n") > 0);
+ QVERIFY(tmpSocket->write("\r\n") > 0);
+
+ bytesAvailable = 0;
+
+ QTime stopWatch;
+ stopWatch.start();
+
+#if defined(Q_OS_WINCE) || defined(Q_OS_SYMBIAN)
+ QTestEventLoop::instance().enterLoop(240);
+#else
+ QTestEventLoop::instance().enterLoop(60);
+#endif
+ if (QTestEventLoop::instance().timeout())
+ QFAIL("Network operation timed out");
+
+ QVERIFY(bytesAvailable >= 10000000);
+
+ QVERIFY(tmpSocket->state() == QAbstractSocket::ConnectedState);
+
+ qDebug("\t\t%.1fMB/%.1fs: %.1fMB/s",
+ bytesAvailable / (1024.0 * 1024.0),
+ stopWatch.elapsed() / 1024.0,
+ (bytesAvailable / (stopWatch.elapsed() / 1000.0)) / (1024 * 1024));
+
+ delete tmpSocket;
+ tmpSocket = 0;
+}
+
+void tst_QHttpSocketEngine::exitLoopSlot()
+{
+ QTestEventLoop::instance().exitLoop();
+}
+
+
+void tst_QHttpSocketEngine::downloadBigFileSlot()
+{
+ bytesAvailable += tmpSocket->readAll().size();
+ if (bytesAvailable >= 10000000)
+ QTestEventLoop::instance().exitLoop();
+}
+
+void tst_QHttpSocketEngine::passwordAuth()
+{
+ QHttpSocketEngine socketDevice;
+
+ // Initialize device
+ QVERIFY(socketDevice.initialize(QAbstractSocket::TcpSocket, QAbstractSocket::IPv4Protocol));
+ QVERIFY(socketDevice.state() == QAbstractSocket::UnconnectedState);
+
+ socketDevice.setProxy(QNetworkProxy(QNetworkProxy::HttpProxy, QtNetworkSettings::serverName(), 3128, "qsockstest", "password"));
+
+ QVERIFY(!socketDevice.connectToHost(QtNetworkSettings::serverIP(), 143));
+ QVERIFY(socketDevice.state() == QAbstractSocket::ConnectingState);
+ QVERIFY(socketDevice.waitForWrite());
+ QVERIFY(socketDevice.state() == QAbstractSocket::ConnectedState);
+ QVERIFY(socketDevice.peerAddress() == QtNetworkSettings::serverIP());
+
+ // Wait for the greeting
+ QVERIFY(socketDevice.waitForRead());
+
+ // Read the greeting
+ qint64 available = socketDevice.bytesAvailable();
+ QVERIFY(available > 0);
+ QByteArray array;
+ array.resize(available);
+ QVERIFY(socketDevice.read(array.data(), array.size()) == available);
+
+ // Check that the greeting is what we expect it to be
+ QVERIFY2(QtNetworkSettings::compareReplyIMAP(array), array.constData());
+
+
+ // Write a logout message
+ QByteArray array2 = "XXXX LOGOUT\r\n";
+ QVERIFY(socketDevice.write(array2.data(),
+ array2.size()) == array2.size());
+
+ // Wait for the response
+ QVERIFY(socketDevice.waitForRead());
+
+ available = socketDevice.bytesAvailable();
+ QVERIFY(available > 0);
+ array.resize(available);
+ QVERIFY(socketDevice.read(array.data(), array.size()) == available);
+
+ // Check that the greeting is what we expect it to be
+ QCOMPARE(array.constData(), "* BYE LOGOUT received\r\nXXXX OK Completed\r\n");
+
+ // Wait for the response
+ QVERIFY(socketDevice.waitForRead());
+ char c;
+ QVERIFY(socketDevice.read(&c, sizeof(c)) == -1);
+ QVERIFY(socketDevice.error() == QAbstractSocket::RemoteHostClosedError);
+ QVERIFY(socketDevice.state() == QAbstractSocket::UnconnectedState);
+}
+
+//----------------------------------------------------------------------------------
+
+QTEST_MAIN(tst_QHttpSocketEngine)
+#include "tst_qhttpsocketengine.moc"
diff --git a/tests/auto/network/socket/qlocalsocket/.gitignore b/tests/auto/network/socket/qlocalsocket/.gitignore
new file mode 100644
index 0000000000..b45c266ce3
--- /dev/null
+++ b/tests/auto/network/socket/qlocalsocket/.gitignore
@@ -0,0 +1,2 @@
+tst_qlocalsocket
+lackey/lackey.exe
diff --git a/tests/auto/network/socket/qlocalsocket/example/client/client.pro b/tests/auto/network/socket/qlocalsocket/example/client/client.pro
new file mode 100644
index 0000000000..84f20d6ec0
--- /dev/null
+++ b/tests/auto/network/socket/qlocalsocket/example/client/client.pro
@@ -0,0 +1,10 @@
+TEMPLATE = app
+TARGET =
+DEPENDPATH += .
+INCLUDEPATH += .
+CONFIG += console
+QT = core network
+
+SOURCES += main.cpp
+
+
diff --git a/tests/auto/network/socket/qlocalsocket/example/client/main.cpp b/tests/auto/network/socket/qlocalsocket/example/client/main.cpp
new file mode 100644
index 0000000000..acf5cbc388
--- /dev/null
+++ b/tests/auto/network/socket/qlocalsocket/example/client/main.cpp
@@ -0,0 +1,84 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+
+#include <string.h>
+#include <qstring.h>
+#include <qdebug.h>
+
+#include "qlocalsocket.h"
+
+#define SOCK_PATH "echo_socket"
+
+int main(void)
+{
+ QLocalSocket socket;
+ socket.connectToServer(SOCK_PATH);
+ socket.open(QIODevice::ReadWrite);
+
+ printf("Connected.\n");
+ char str[100];
+ while(printf("> "), fgets(str, 100, stdin), !feof(stdin)) {
+ if (socket.write(str, strlen(str)) == -1) {
+ perror("send");
+ return EXIT_FAILURE;
+ }
+
+ int t;
+ if ((t = socket.read(str, 100)) > 0) {
+ str[t] = '\0';
+ printf("echo> %s", str);
+ } else {
+ if (t < 0)
+ perror("recv");
+ else
+ printf("Server closed connection.\n");
+ return EXIT_FAILURE;
+ }
+ }
+
+ return EXIT_SUCCESS;
+}
+
diff --git a/tests/auto/network/socket/qlocalsocket/example/example.pro b/tests/auto/network/socket/qlocalsocket/example/example.pro
new file mode 100644
index 0000000000..8c678cd05a
--- /dev/null
+++ b/tests/auto/network/socket/qlocalsocket/example/example.pro
@@ -0,0 +1,3 @@
+TEMPLATE = subdirs
+SUBDIRS = client server
+
diff --git a/tests/auto/network/socket/qlocalsocket/example/server/main.cpp b/tests/auto/network/socket/qlocalsocket/example/server/main.cpp
new file mode 100644
index 0000000000..0d3de3a2e1
--- /dev/null
+++ b/tests/auto/network/socket/qlocalsocket/example/server/main.cpp
@@ -0,0 +1,97 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+
+#include "qlocalserver.h"
+#include "qlocalsocket.h"
+
+#include <qcoreapplication.h>
+#include <qdebug.h>
+
+class EchoServer : public QLocalServer
+{
+public:
+ void incomingConnection(int socketDescriptor) {
+ QLocalServer::incomingConnection(socketDescriptor);
+ QLocalSocket *socket = nextPendingConnection();
+ socket->open(QIODevice::ReadWrite);
+
+ qDebug() << "server connection";
+
+ do {
+ const int Timeout = 5 * 1000;
+ while (!socket->canReadLine()) {
+ if (!socket->waitForReadyRead(Timeout)) {
+ return;
+ }
+ }
+ char str[100];
+ int n = socket->readLine(str, 100);
+ if (n < 0) {
+ perror("recv");
+ break;
+ }
+ if (n == 0)
+ break;
+ qDebug() << "Read" << str;
+ if ("exit" == str)
+ qApp->quit();
+
+ if (socket->write(str, 100) < 0) {
+ perror("send");
+ break;
+ }
+ } while (true);
+ }
+};
+
+#define SOCK_PATH "echo_socket"
+
+int main(int argc, char *argv[])
+{
+ QCoreApplication application(argc, argv);
+
+ EchoServer echoServer;
+ echoServer.listen(SOCK_PATH);
+
+ return application.exec();
+}
+
diff --git a/tests/auto/network/socket/qlocalsocket/example/server/server.pro b/tests/auto/network/socket/qlocalsocket/example/server/server.pro
new file mode 100644
index 0000000000..bfd14d2bb7
--- /dev/null
+++ b/tests/auto/network/socket/qlocalsocket/example/server/server.pro
@@ -0,0 +1,13 @@
+TEMPLATE = app
+TARGET =
+DEPENDPATH += .
+INCLUDEPATH += .
+
+CONFIG += console
+
+QT = core network
+
+# Input
+SOURCES += main.cpp
+
+
diff --git a/tests/auto/network/socket/qlocalsocket/lackey/lackey.pro b/tests/auto/network/socket/qlocalsocket/lackey/lackey.pro
new file mode 100644
index 0000000000..2573222c8b
--- /dev/null
+++ b/tests/auto/network/socket/qlocalsocket/lackey/lackey.pro
@@ -0,0 +1,16 @@
+#include(../src/src.pri)
+
+QT = core script network testlib
+
+DESTDIR = ./
+
+win32: CONFIG += console
+mac:CONFIG -= app_bundle
+
+DEFINES += QLOCALSERVER_DEBUG
+DEFINES += QLOCALSOCKET_DEBUG
+
+SOURCES += main.cpp
+TARGET = lackey
+
+symbian:TARGET.CAPABILITY = ALL -TCB
diff --git a/tests/auto/network/socket/qlocalsocket/lackey/main.cpp b/tests/auto/network/socket/qlocalsocket/lackey/main.cpp
new file mode 100644
index 0000000000..f7b2ff10b3
--- /dev/null
+++ b/tests/auto/network/socket/qlocalsocket/lackey/main.cpp
@@ -0,0 +1,296 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+
+#include <qscriptengine.h>
+ #include <QFile>
+#include <QTest>
+
+#include <qlocalsocket.h>
+#include <qlocalserver.h>
+
+class QScriptLocalSocket : public QObject
+{
+ Q_OBJECT
+ Q_PROPERTY(QString serverName WRITE connectToServer READ serverName)
+
+public:
+ QScriptLocalSocket(QObject *parent = 0) : QObject(parent)
+ {
+ lc = new QLocalSocket(this);
+ }
+
+public slots:
+ QString serverName()
+ {
+ return lc->serverName();
+ }
+
+ void connectToServer(const QString &name) {
+ lc->connectToServer(name);
+ }
+
+ void sleep(int x) const
+ {
+ QTest::qSleep(x);
+ }
+
+ bool isConnected() {
+ return (lc->state() == QLocalSocket::ConnectedState);
+ }
+
+ void open() {
+ lc->open(QIODevice::ReadWrite);
+ }
+
+ bool waitForConnected() {
+ return lc->waitForConnected(100000);
+ }
+ void waitForReadyRead() {
+ lc->waitForReadyRead();
+ }
+
+ void write(const QString &string) {
+ QTextStream out(lc);
+ out << string << endl;
+ }
+
+ bool waitForBytesWritten(int t = 3000) {
+ return lc->waitForBytesWritten(t);
+ }
+
+ QString readLine() {
+ QTextStream in(lc);
+ return in.readLine();
+ }
+
+ QString errorString() {
+ return lc->errorString();
+ }
+
+ void close() {
+ lc->close();
+ }
+
+public:
+ QLocalSocket *lc;
+};
+
+class QScriptLocalServer : public QLocalServer
+{
+ Q_OBJECT
+ Q_PROPERTY(int maxPendingConnections WRITE setMaxPendingConnections READ maxPendingConnections)
+ Q_PROPERTY(QString name WRITE listen READ serverName)
+ Q_PROPERTY(bool listening READ isListening)
+
+public:
+ QScriptLocalServer(QObject *parent = 0) : QLocalServer(parent)
+ {
+ }
+
+public slots:
+ bool listen(const QString &name) {
+ if (!QLocalServer::listen(name)) {
+ if (serverError() == QAbstractSocket::AddressInUseError) {
+ QFile::remove(serverName());
+ return QLocalServer::listen(name);
+ }
+ return false;
+ }
+ return true;
+ }
+
+ QScriptLocalSocket *nextConnection() {
+ QLocalSocket *other = nextPendingConnection();
+ QScriptLocalSocket *s = new QScriptLocalSocket(this);
+ delete s->lc;
+ s->lc = other;
+ return s;
+ }
+
+ bool waitForNewConnection() {
+ return QLocalServer::waitForNewConnection(30000);
+ }
+
+ QString errorString() {
+ return QLocalServer::errorString();
+ }
+
+
+};
+
+template <typename T>
+static QScriptValue _q_ScriptValueFromQObject(QScriptEngine *engine, T* const &in)
+{
+ return engine->newQObject(in);
+}
+template <typename T>
+static void _q_ScriptValueToQObject(const QScriptValue &v, T* &out)
+{ out = qobject_cast<T*>(v.toQObject());
+}
+template <typename T>
+static int _q_ScriptRegisterQObjectMetaType(QScriptEngine *engine, const QScriptValue &prototype)
+{
+ return qScriptRegisterMetaType<T*>(engine, _q_ScriptValueFromQObject<T>, _q_ScriptValueToQObject<T>, prototype);
+}
+
+QT_BEGIN_NAMESPACE
+Q_SCRIPT_DECLARE_QMETAOBJECT(QScriptLocalSocket, QObject*);
+Q_SCRIPT_DECLARE_QMETAOBJECT(QScriptLocalServer, QObject*);
+QT_END_NAMESPACE
+
+static void interactive(QScriptEngine &eng)
+{
+ QTextStream qin(stdin, QFile::ReadOnly);
+
+ const char *qscript_prompt = "qs> ";
+ const char *dot_prompt = ".... ";
+ const char *prompt = qscript_prompt;
+
+ QString code;
+
+ forever {
+ QString line;
+
+ printf("%s", prompt);
+ fflush(stdout);
+
+ line = qin.readLine();
+ if (line.isNull())
+ break;
+
+ code += line;
+ code += QLatin1Char('\n');
+
+ if (line.trimmed().isEmpty()) {
+ continue;
+
+ } else if (! eng.canEvaluate(code)) {
+ prompt = dot_prompt;
+
+ } else {
+ QScriptValue result = eng.evaluate(code);
+ code.clear();
+ prompt = qscript_prompt;
+ if (!result.isUndefined())
+ fprintf(stderr, "%s\n", qPrintable(result.toString()));
+ }
+ }
+}
+Q_DECLARE_METATYPE(QScriptLocalSocket*)
+Q_DECLARE_METATYPE(QScriptLocalServer*)
+int main(int argc, char *argv[])
+{
+ QCoreApplication app(argc, argv);
+ QScriptEngine eng;
+ QScriptValue globalObject = eng.globalObject();
+
+ _q_ScriptRegisterQObjectMetaType<QScriptLocalServer>(&eng, QScriptValue());
+
+ QScriptValue lss = qScriptValueFromQMetaObject<QScriptLocalServer>(&eng);
+ eng.globalObject().setProperty("QScriptLocalServer", lss);
+
+ _q_ScriptRegisterQObjectMetaType<QScriptLocalSocket>(&eng, QScriptValue());
+
+ QScriptValue lsc = qScriptValueFromQMetaObject<QScriptLocalSocket>(&eng);
+ eng.globalObject().setProperty("QScriptLocalSocket", lsc);
+
+ if (! *++argv) {
+ interactive(eng);
+ return EXIT_SUCCESS;
+ }
+
+ QStringList arguments;
+ for (int i = 0; i < argc - 1; ++i)
+ arguments << QString::fromLocal8Bit(argv[i]);
+
+ while (!arguments.isEmpty()) {
+ QString fn = arguments.takeFirst();
+
+ if (fn == QLatin1String("-i")) {
+ interactive(eng);
+ break;
+ }
+
+ QString contents;
+
+ if (fn == QLatin1String("-")) {
+ QTextStream stream(stdin, QFile::ReadOnly);
+ contents = stream.readAll();
+ } else {
+ QFile file(fn);
+ if (!file.exists()) {
+ fprintf(stderr, "%s doesn't exists\n", qPrintable(fn));
+ return EXIT_FAILURE;
+ }
+ if (file.open(QFile::ReadOnly)) {
+ QTextStream stream(&file);
+ contents = stream.readAll();
+ file.close();
+ }
+ }
+
+ if (contents.isEmpty())
+ continue;
+
+ if (contents[0] == '#') {
+ contents.prepend("//");
+ QScriptValue args = eng.newArray();
+ args.setProperty("0", QScriptValue(&eng, fn));
+ int i = 1;
+ while (!arguments.isEmpty())
+ args.setProperty(i++, QScriptValue(&eng, arguments.takeFirst()));
+ eng.currentContext()->activationObject().setProperty("args", args);
+ }
+ QScriptValue r = eng.evaluate(contents);
+ if (eng.hasUncaughtException()) {
+ int line = eng.uncaughtExceptionLineNumber();
+ fprintf(stderr, "%d: %s\n\t%s\n\n", line, qPrintable(fn), qPrintable(r.toString()));
+ return EXIT_FAILURE;
+ }
+ if (r.isNumber())
+ return r.toInt32();
+ }
+
+ return EXIT_SUCCESS;
+}
+
+#include "main.moc"
diff --git a/tests/auto/network/socket/qlocalsocket/lackey/scripts/client.js b/tests/auto/network/socket/qlocalsocket/lackey/scripts/client.js
new file mode 100755
index 0000000000..76cc0b97ad
--- /dev/null
+++ b/tests/auto/network/socket/qlocalsocket/lackey/scripts/client.js
@@ -0,0 +1,35 @@
+#/bin/qscript
+function QVERIFY(x, socket) {
+ if (!(x)) {
+ throw(socket.errorString());
+ }
+}
+
+var socket = new QScriptLocalSocket;
+var tries = 0;
+do {
+ socket.serverName = "qlocalsocket_autotest";
+ if ((socket.errorString() != "QLocalSocket::connectToServer: Invalid name")
+ && (socket.errorString() != "QLocalSocket::connectToServer: Connection refused"))
+ break;
+ socket.sleep(1);
+ ++tries;
+ print("isConnected:", socket.isConnected());
+} while ((socket.errorString() == "QLocalSocket::connectToServer: Invalid name"
+ || (socket.errorString() == "QlocalSocket::connectToServer: Connection refused"))
+ && tries < 5000);
+if (tries == 5000) {
+ print("too many tries, exiting");
+} else {
+socket.waitForConnected();
+//print("isConnected:", socket.isConnected());
+if (!socket.isConnected())
+ print("Not Connected:", socket.errorString());
+socket.waitForReadyRead();
+var text = socket.readLine();
+var testLine = "test";
+QVERIFY((text == testLine), socket);
+QVERIFY((socket.errorString() == "Unknown error"), socket);
+socket.close();
+//print("client: exiting", text);
+}
diff --git a/tests/auto/network/socket/qlocalsocket/lackey/scripts/server.js b/tests/auto/network/socket/qlocalsocket/lackey/scripts/server.js
new file mode 100644
index 0000000000..98a83bc9dd
--- /dev/null
+++ b/tests/auto/network/socket/qlocalsocket/lackey/scripts/server.js
@@ -0,0 +1,19 @@
+#/bin/qscript
+function QVERIFY(x, server) {
+ if (!(x)) {
+ throw(server.errorString());
+ }
+}
+var server = new QScriptLocalServer;
+QVERIFY(server.listen("qlocalsocket_autotest"), server);
+var done = args[1];
+var testLine = "test";
+while (done > 0) {
+ QVERIFY(server.waitForNewConnection(), server);
+ var serverSocket = server.nextConnection();
+ serverSocket.write(testLine);
+ QVERIFY(serverSocket.waitForBytesWritten(), serverSocket);
+ QVERIFY(serverSocket.errorString() == ""
+ ||serverSocket.errorString() == "Unknown error", serverSocket);
+ --done;
+}
diff --git a/tests/auto/network/socket/qlocalsocket/qlocalsocket.pro b/tests/auto/network/socket/qlocalsocket/qlocalsocket.pro
new file mode 100644
index 0000000000..931c1e0602
--- /dev/null
+++ b/tests/auto/network/socket/qlocalsocket/qlocalsocket.pro
@@ -0,0 +1,4 @@
+TEMPLATE = subdirs
+SUBDIRS = test # lackey should be moved to the QtScript module
+!wince*:!symbian: SUBDIRS += example
+symbian: TARGET.CAPABILITY = NetworkServices
diff --git a/tests/auto/network/socket/qlocalsocket/test/test.pro b/tests/auto/network/socket/qlocalsocket/test/test.pro
new file mode 100644
index 0000000000..b2755b5411
--- /dev/null
+++ b/tests/auto/network/socket/qlocalsocket/test/test.pro
@@ -0,0 +1,50 @@
+load(qttest_p4)
+
+DEFINES += QLOCALSERVER_DEBUG
+DEFINES += QLOCALSOCKET_DEBUG
+
+symbian {
+ # nothing
+} else:wince* {
+ DEFINES += QT_LOCALSOCKET_TCP
+ DEFINES += SRCDIR=\\\"../\\\"
+} else {
+ DEFINES += SRCDIR=\\\"$$PWD/../\\\"
+}
+
+QT = core network
+
+SOURCES += ../tst_qlocalsocket.cpp
+
+TARGET = tst_qlocalsocket
+CONFIG(debug_and_release) {
+ CONFIG(debug, debug|release) {
+ DESTDIR = ../debug
+ } else {
+ DESTDIR = ../release
+ }
+} else {
+ DESTDIR = ..
+}
+
+wince* {
+ additionalFiles.files = ../lackey/lackey.exe
+ additionalFiles.path = lackey
+}
+
+symbian {
+ additionalFiles.files = lackey.exe
+ additionalFiles.path = \\sys\\bin
+ TARGET.UID3 = 0xE0340005
+ DEFINES += SYMBIAN_SRCDIR_UID=$$lower($$replace(TARGET.UID3,"0x",""))
+}
+
+wince*|symbian {
+ scriptFiles.files = ../lackey/scripts/*.js
+ scriptFiles.path = lackey/scripts
+ DEPLOYMENT += additionalFiles scriptFiles
+ QT += script # for easy deployment of QtScript
+
+ requires(contains(QT_CONFIG,script))
+}
+
diff --git a/tests/auto/network/socket/qlocalsocket/tst_qlocalsocket.cpp b/tests/auto/network/socket/qlocalsocket/tst_qlocalsocket.cpp
new file mode 100644
index 0000000000..57daa92f82
--- /dev/null
+++ b/tests/auto/network/socket/qlocalsocket/tst_qlocalsocket.cpp
@@ -0,0 +1,1120 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+
+#include <QtTest/QtTest>
+
+#include <qtextstream.h>
+#include <QtNetwork/qlocalsocket.h>
+#include <QtNetwork/qlocalserver.h>
+#include "../../../../shared/util.h"
+
+#ifdef Q_OS_SYMBIAN
+ #include <unistd.h>
+#endif
+//TESTED_CLASS=QLocalServer, QLocalSocket
+//TESTED_FILES=network/socket/qlocalserver.cpp network/socket/qlocalsocket.cpp
+#ifdef Q_OS_SYMBIAN
+ #define STRINGIFY(x) #x
+ #define TOSTRING(x) STRINGIFY(x)
+ #define SRCDIR "C:/Private/" TOSTRING(SYMBIAN_SRCDIR_UID) "/"
+#endif
+Q_DECLARE_METATYPE(QLocalSocket::LocalSocketError)
+Q_DECLARE_METATYPE(QLocalSocket::LocalSocketState)
+
+class tst_QLocalSocket : public QObject
+{
+ Q_OBJECT
+
+public:
+ tst_QLocalSocket();
+ virtual ~tst_QLocalSocket();
+
+public Q_SLOTS:
+ void init();
+ void cleanup();
+
+private slots:
+ // basics
+ void server_basic();
+ void server_connectionsCount();
+ void socket_basic();
+
+ void listen_data();
+ void listen();
+
+ void listenAndConnect_data();
+ void listenAndConnect();
+
+ void sendData_data();
+ void sendData();
+
+ void readBufferOverflow();
+
+ void fullPath();
+
+ void hitMaximumConnections_data();
+ void hitMaximumConnections();
+
+ void setSocketDescriptor();
+
+ void threadedConnection_data();
+ void threadedConnection();
+
+ void processConnection_data();
+ void processConnection();
+
+ void longPath();
+ void waitForDisconnect();
+ void waitForDisconnectByServer();
+
+ void removeServer();
+
+ void recycleServer();
+
+ void multiConnect();
+ void writeOnlySocket();
+ void writeToClientAndDisconnect();
+ void debug();
+ void bytesWrittenSignal();
+ void syncDisconnectNotify();
+ void asyncDisconnectNotify();
+
+#ifdef Q_OS_SYMBIAN
+private:
+ void unlink(QString serverName);
+#endif
+};
+
+tst_QLocalSocket::tst_QLocalSocket()
+{
+ if (!QFile::exists("lackey/lackey"
+#ifdef Q_OS_WIN
+ ".exe"
+#endif
+ ))
+ qWarning() << "lackey executable doesn't exists!";
+}
+
+tst_QLocalSocket::~tst_QLocalSocket()
+{
+}
+
+void tst_QLocalSocket::init()
+{
+ qRegisterMetaType<QLocalSocket::LocalSocketState>("QLocalSocket::LocalSocketState");
+ qRegisterMetaType<QLocalSocket::LocalSocketError>("QLocalSocket::LocalSocketError");
+}
+
+void tst_QLocalSocket::cleanup()
+{
+}
+
+class LocalServer : public QLocalServer
+{
+ Q_OBJECT
+
+public:
+ LocalServer() : QLocalServer()
+ {
+ connect(this, SIGNAL(newConnection()), this, SLOT(slotNewConnection()));
+ }
+
+ bool listen(const QString &name)
+ {
+ removeServer(name);
+ return QLocalServer::listen(name);
+ }
+
+ QList<int> hits;
+
+protected:
+ void incomingConnection(quintptr socketDescriptor)
+ {
+ hits.append(socketDescriptor);
+ QLocalServer::incomingConnection(socketDescriptor);
+ }
+
+private slots:
+ void slotNewConnection() {
+ QVERIFY(!hits.isEmpty());
+ QVERIFY(hasPendingConnections());
+ }
+};
+
+class LocalSocket : public QLocalSocket
+{
+ Q_OBJECT
+
+public:
+ LocalSocket(QObject *parent = 0) : QLocalSocket(parent)
+ {
+ connect(this, SIGNAL(connected()),
+ this, SLOT(slotConnected()));
+ connect(this, SIGNAL(disconnected()),
+ this, SLOT(slotDisconnected()));
+ connect(this, SIGNAL(error(QLocalSocket::LocalSocketError)),
+ this, SLOT(slotError(QLocalSocket::LocalSocketError)));
+ connect(this, SIGNAL(stateChanged(QLocalSocket::LocalSocketState)),
+ this, SLOT(slotStateChanged(QLocalSocket::LocalSocketState)));
+ connect(this, SIGNAL(readyRead()),
+ this, SLOT(slotReadyRead()));
+ }
+
+private slots:
+ void slotConnected()
+ {
+ QCOMPARE(state(), QLocalSocket::ConnectedState);
+ }
+ void slotDisconnected()
+ {
+ QCOMPARE(state(), QLocalSocket::UnconnectedState);
+ }
+ void slotError(QLocalSocket::LocalSocketError newError)
+ {
+ QVERIFY(errorString() != "Unknown error");
+ QCOMPARE(error(), newError);
+ }
+ void slotStateChanged(QLocalSocket::LocalSocketState newState)
+ {
+ QCOMPARE(state(), newState);
+ }
+ void slotReadyRead()
+ {
+ QVERIFY(bytesAvailable() > 0);
+ }
+};
+
+// basic test make sure no segfaults and check default values
+void tst_QLocalSocket::server_basic()
+{
+ LocalServer server;
+ QSignalSpy spyNewConnection(&server, SIGNAL(newConnection()));
+ server.close();
+ QCOMPARE(server.errorString(), QString());
+ QCOMPARE(server.hasPendingConnections(), false);
+ QCOMPARE(server.isListening(), false);
+ QCOMPARE(server.maxPendingConnections(), 30);
+ QCOMPARE(server.nextPendingConnection(), (QLocalSocket*)0);
+ QCOMPARE(server.serverName(), QString());
+ QCOMPARE(server.fullServerName(), QString());
+ QCOMPARE(server.serverError(), QAbstractSocket::UnknownSocketError);
+ server.setMaxPendingConnections(20);
+ bool timedOut = true;
+ QCOMPARE(server.waitForNewConnection(3000, &timedOut), false);
+ QVERIFY(!timedOut);
+ QCOMPARE(server.listen(QString()), false);
+
+ QCOMPARE(server.hits.count(), 0);
+ QCOMPARE(spyNewConnection.count(), 0);
+}
+
+void tst_QLocalSocket::server_connectionsCount()
+{
+ LocalServer server;
+ server.setMaxPendingConnections(10);
+ QCOMPARE(server.maxPendingConnections(), 10);
+}
+
+// basic test make sure no segfaults and check default values
+void tst_QLocalSocket::socket_basic()
+{
+ LocalSocket socket;
+ QSignalSpy spyConnected(&socket, SIGNAL(connected()));
+ QSignalSpy spyDisconnected(&socket, SIGNAL(disconnected()));
+ QSignalSpy spyError(&socket, SIGNAL(error(QLocalSocket::LocalSocketError)));
+ QSignalSpy spyStateChanged(&socket, SIGNAL(stateChanged(QLocalSocket::LocalSocketState)));
+ QSignalSpy spyReadyRead(&socket, SIGNAL(readyRead()));
+
+ QCOMPARE(socket.serverName(), QString());
+ QCOMPARE(socket.fullServerName(), QString());
+ socket.abort();
+ QVERIFY(socket.bytesAvailable() == 0);
+ QVERIFY(socket.bytesToWrite() == 0);
+ QCOMPARE(socket.canReadLine(), false);
+ socket.close();
+ socket.disconnectFromServer();
+ QCOMPARE(QLocalSocket::UnknownSocketError, socket.error());
+ QVERIFY(socket.errorString() != QString());
+ QCOMPARE(socket.flush(), false);
+ QCOMPARE(socket.isValid(), false);
+ QVERIFY(socket.readBufferSize() == 0);
+ socket.setReadBufferSize(0);
+ //QCOMPARE(socket.socketDescriptor(), -1);
+ QCOMPARE(socket.state(), QLocalSocket::UnconnectedState);
+ QCOMPARE(socket.waitForConnected(0), false);
+ QCOMPARE(socket.waitForDisconnected(0), false);
+ QCOMPARE(socket.waitForReadyRead(0), false);
+
+ QCOMPARE(spyConnected.count(), 0);
+ QCOMPARE(spyDisconnected.count(), 0);
+ QCOMPARE(spyError.count(), 0);
+ QCOMPARE(spyStateChanged.count(), 0);
+ QCOMPARE(spyReadyRead.count(), 0);
+}
+
+void tst_QLocalSocket::listen_data()
+{
+ QTest::addColumn<QString>("name");
+ QTest::addColumn<bool>("canListen");
+ QTest::addColumn<bool>("close");
+ QTest::newRow("null") << QString() << false << false;
+ QTest::newRow("tst_localsocket") << "tst_localsocket" << true << true;
+ QTest::newRow("tst_localsocket") << "tst_localsocket" << true << false;
+}
+
+// start a server that listens, but don't connect a socket, make sure everything is in order
+void tst_QLocalSocket::listen()
+{
+ LocalServer server;
+ QSignalSpy spyNewConnection(&server, SIGNAL(newConnection()));
+
+ QFETCH(QString, name);
+#ifdef Q_OS_SYMBIAN
+ unlink(name);
+#endif
+ QFETCH(bool, canListen);
+ QFETCH(bool, close);
+ QVERIFY2((server.listen(name) == canListen), server.errorString().toLatin1().constData());
+
+ // test listening
+ QCOMPARE(server.serverName(), name);
+ QVERIFY(server.fullServerName().contains(name));
+ QCOMPARE(server.isListening(), canListen);
+ QCOMPARE(server.hasPendingConnections(), false);
+ QCOMPARE(server.nextPendingConnection(), (QLocalSocket*)0);
+ QCOMPARE(server.hits.count(), 0);
+ QCOMPARE(spyNewConnection.count(), 0);
+ if (canListen) {
+ QVERIFY(server.errorString() == QString());
+ QCOMPARE(server.serverError(), QAbstractSocket::UnknownSocketError);
+ // already isListening
+ QVERIFY(!server.listen(name));
+ } else {
+ QVERIFY(server.errorString() != QString());
+ QCOMPARE(server.serverError(), QAbstractSocket::HostNotFoundError);
+ }
+ QCOMPARE(server.maxPendingConnections(), 30);
+ bool timedOut = false;
+ QCOMPARE(server.waitForNewConnection(3000, &timedOut), false);
+ QCOMPARE(timedOut, canListen);
+ if (close)
+ server.close();
+}
+
+void tst_QLocalSocket::listenAndConnect_data()
+{
+ QTest::addColumn<QString>("name");
+ QTest::addColumn<bool>("canListen");
+ QTest::addColumn<int>("connections");
+ for (int i = 0; i < 3; ++i) {
+ int connections = i;
+ if (i == 2)
+ connections = 5;
+ QTest::newRow(QString("null %1").arg(i).toLatin1()) << QString() << false << connections;
+ QTest::newRow(QString("tst_localsocket %1").arg(i).toLatin1()) << "tst_localsocket" << true << connections;
+ }
+}
+
+void tst_QLocalSocket::listenAndConnect()
+{
+ LocalServer server;
+ QSignalSpy spyNewConnection(&server, SIGNAL(newConnection()));
+
+ QFETCH(QString, name);
+ QFETCH(bool, canListen);
+#ifdef Q_OS_SYMBIAN
+ unlink(name);
+#endif
+ QCOMPARE(server.listen(name), canListen);
+ QTest::qWait(1000);
+ //QVERIFY(!server.errorString().isEmpty());
+ QCOMPARE(server.serverError(),
+ canListen ? QAbstractSocket::UnknownSocketError : QAbstractSocket::HostNotFoundError);
+
+ // test creating connection(s)
+ QFETCH(int, connections);
+ QList<QLocalSocket*> sockets;
+ for (int i = 0; i < connections; ++i) {
+ LocalSocket *socket = new LocalSocket;
+
+ QSignalSpy spyConnected(socket, SIGNAL(connected()));
+ QSignalSpy spyDisconnected(socket, SIGNAL(disconnected()));
+ QSignalSpy spyError(socket, SIGNAL(error(QLocalSocket::LocalSocketError)));
+ QSignalSpy spyStateChanged(socket, SIGNAL(stateChanged(QLocalSocket::LocalSocketState)));
+ QSignalSpy spyReadyRead(socket, SIGNAL(readyRead()));
+
+ socket->connectToServer(name);
+#if defined(QT_LOCALSOCKET_TCP)
+ QTest::qWait(250);
+#endif
+
+ QCOMPARE(socket->serverName(), name);
+ QVERIFY(socket->fullServerName().contains(name));
+ sockets.append(socket);
+ if (canListen) {
+ QVERIFY(socket->waitForConnected());
+ QVERIFY(socket->isValid());
+ QCOMPARE(socket->errorString(), QString("Unknown error"));
+ QCOMPARE(socket->error(), QLocalSocket::UnknownSocketError);
+ QCOMPARE(socket->state(), QLocalSocket::ConnectedState);
+ //QVERIFY(socket->socketDescriptor() != -1);
+ QCOMPARE(spyError.count(), 0);
+ } else {
+ QVERIFY(socket->errorString() != QString());
+ QVERIFY(socket->error() != QLocalSocket::UnknownSocketError);
+ QCOMPARE(socket->state(), QLocalSocket::UnconnectedState);
+ //QVERIFY(socket->socketDescriptor() == -1);
+ QCOMPARE(qVariantValue<QLocalSocket::LocalSocketError>(spyError.first()[0]),
+ QLocalSocket::ServerNotFoundError);
+ }
+
+ QVERIFY(socket->bytesAvailable() == 0);
+ QVERIFY(socket->bytesToWrite() == 0);
+ QCOMPARE(socket->canReadLine(), false);
+ QCOMPARE(socket->flush(), false);
+ QCOMPARE(socket->isValid(), canListen);
+ QCOMPARE(socket->readBufferSize(), (qint64)0);
+ QCOMPARE(socket->waitForConnected(0), canListen);
+ QCOMPARE(socket->waitForReadyRead(0), false);
+
+ QTRY_COMPARE(spyConnected.count(), canListen ? 1 : 0);
+ QCOMPARE(spyDisconnected.count(), 0);
+
+ // error signals
+ QVERIFY(spyError.count() >= 0);
+ if (canListen) {
+ if (spyError.count() > 0)
+ QCOMPARE(qVariantValue<QLocalSocket::LocalSocketError>(spyError.first()[0]),
+ QLocalSocket::SocketTimeoutError);
+ } else {
+ QCOMPARE(qVariantValue<QLocalSocket::LocalSocketError>(spyError.first()[0]),
+ QLocalSocket::ServerNotFoundError);
+ }
+
+ // Check first and last state
+ QCOMPARE(qVariantValue<QLocalSocket::LocalSocketState>(spyStateChanged.first()[0]),
+ QLocalSocket::ConnectingState);
+#if 0
+ for (int j = 0; j < spyStateChanged.count(); ++j) {
+ QLocalSocket::LocalSocketState s;
+ s = qVariantValue<QLocalSocket::LocalSocketState>(spyStateChanged.at(j).at(0));
+ qDebug() << s;
+ }
+#endif
+ if (canListen)
+ QCOMPARE(qVariantValue<QLocalSocket::LocalSocketState>(spyStateChanged.last()[0]),
+ QLocalSocket::ConnectedState);
+ QCOMPARE(spyStateChanged.count(), 2);
+ QCOMPARE(spyReadyRead.count(), 0);
+
+ bool timedOut = true;
+ QCOMPARE(server.waitForNewConnection(3000, &timedOut), canListen);
+ QVERIFY(!timedOut);
+ QCOMPARE(server.hasPendingConnections(), canListen);
+ QCOMPARE(server.isListening(), canListen);
+ // NOTE: socket disconnecting is not tested here
+
+ // server checks post connection
+ if (canListen) {
+ QCOMPARE(server.serverName(), name);
+ QVERIFY(server.fullServerName().contains(name));
+ QVERIFY(server.nextPendingConnection() != (QLocalSocket*)0);
+ QTRY_COMPARE(server.hits.count(), i + 1);
+ QCOMPARE(spyNewConnection.count(), i + 1);
+ QVERIFY(server.errorString() == QString());
+ QCOMPARE(server.serverError(), QAbstractSocket::UnknownSocketError);
+ } else {
+ QVERIFY(server.serverName().isEmpty());
+ QVERIFY(server.fullServerName().isEmpty());
+ QVERIFY(server.nextPendingConnection() == (QLocalSocket*)0);
+ QCOMPARE(spyNewConnection.count(), 0);
+ QCOMPARE(server.hits.count(), 0);
+ QVERIFY(server.errorString() != QString());
+ QCOMPARE(server.serverError(), QAbstractSocket::HostNotFoundError);
+ }
+ }
+ qDeleteAll(sockets.begin(), sockets.end());
+
+ server.close();
+
+ QCOMPARE(server.hits.count(), (canListen ? connections : 0));
+ QCOMPARE(spyNewConnection.count(), (canListen ? connections : 0));
+}
+
+void tst_QLocalSocket::sendData_data()
+{
+ listenAndConnect_data();
+}
+
+void tst_QLocalSocket::sendData()
+{
+ QFETCH(QString, name);
+#ifdef Q_OS_SYMBIAN
+ unlink(name);
+#endif
+ QFETCH(bool, canListen);
+
+ LocalServer server;
+ QSignalSpy spy(&server, SIGNAL(newConnection()));
+
+ QCOMPARE(server.listen(name), canListen);
+
+ LocalSocket socket;
+ QSignalSpy spyConnected(&socket, SIGNAL(connected()));
+ QSignalSpy spyDisconnected(&socket, SIGNAL(disconnected()));
+ QSignalSpy spyError(&socket, SIGNAL(error(QLocalSocket::LocalSocketError)));
+ QSignalSpy spyStateChanged(&socket, SIGNAL(stateChanged(QLocalSocket::LocalSocketState)));
+ QSignalSpy spyReadyRead(&socket, SIGNAL(readyRead()));
+
+ // test creating a connection
+ socket.connectToServer(name);
+ bool timedOut = true;
+
+ QCOMPARE(server.waitForNewConnection(3000, &timedOut), canListen);
+
+#if defined(QT_LOCALSOCKET_TCP)
+ QTest::qWait(250);
+#endif
+ QVERIFY(!timedOut);
+ QCOMPARE(spyConnected.count(), canListen ? 1 : 0);
+ QCOMPARE(socket.state(), canListen ? QLocalSocket::ConnectedState : QLocalSocket::UnconnectedState);
+
+ // test sending/receiving data
+ if (server.hasPendingConnections()) {
+ QString testLine = "test";
+#ifdef Q_OS_SYMBIAN
+ for (int i = 0; i < 25 * 1024; ++i)
+#else
+ for (int i = 0; i < 50000; ++i)
+#endif
+ testLine += "a";
+ QLocalSocket *serverSocket = server.nextPendingConnection();
+ QVERIFY(serverSocket);
+ QCOMPARE(serverSocket->state(), QLocalSocket::ConnectedState);
+ QTextStream out(serverSocket);
+ QTextStream in(&socket);
+ out << testLine << endl;
+ bool wrote = serverSocket->waitForBytesWritten(3000);
+
+ if (!socket.canReadLine())
+ QVERIFY(socket.waitForReadyRead());
+
+ QVERIFY(socket.bytesAvailable() >= 0);
+ QCOMPARE(socket.bytesToWrite(), (qint64)0);
+ QCOMPARE(socket.flush(), false);
+ QCOMPARE(socket.isValid(), canListen);
+ QCOMPARE(socket.readBufferSize(), (qint64)0);
+ QCOMPARE(spyReadyRead.count(), 1);
+
+ QVERIFY(testLine.startsWith(in.readLine()));
+
+ QVERIFY(wrote || serverSocket->waitForBytesWritten(1000));
+
+ QCOMPARE(serverSocket->errorString(), QString("Unknown error"));
+ QCOMPARE(socket.errorString(), QString("Unknown error"));
+ }
+
+ socket.disconnectFromServer();
+ QCOMPARE(spyConnected.count(), canListen ? 1 : 0);
+ QCOMPARE(spyDisconnected.count(), canListen ? 1 : 0);
+ QCOMPARE(spyError.count(), canListen ? 0 : 1);
+ QCOMPARE(spyStateChanged.count(), canListen ? 4 : 2);
+ QCOMPARE(spyReadyRead.count(), canListen ? 1 : 0);
+
+ server.close();
+
+ QCOMPARE(server.hits.count(), (canListen ? 1 : 0));
+ QCOMPARE(spy.count(), (canListen ? 1 : 0));
+}
+
+void tst_QLocalSocket::readBufferOverflow()
+{
+ const int readBufferSize = 128;
+ const int dataBufferSize = readBufferSize * 2;
+ const QString serverName = QLatin1String("myPreciousTestServer");
+ LocalServer server;
+ server.listen(serverName);
+ QVERIFY(server.isListening());
+
+ LocalSocket client;
+ client.setReadBufferSize(readBufferSize);
+ client.connectToServer(serverName);
+
+ bool timedOut = true;
+ QVERIFY(server.waitForNewConnection(3000, &timedOut));
+ QVERIFY(!timedOut);
+
+ QCOMPARE(client.state(), QLocalSocket::ConnectedState);
+ QVERIFY(server.hasPendingConnections());
+
+ QLocalSocket* serverSocket = server.nextPendingConnection();
+ char buffer[dataBufferSize];
+ memset(buffer, 0, dataBufferSize);
+ serverSocket->write(buffer, dataBufferSize);
+ serverSocket->waitForBytesWritten();
+
+ // wait until the first 128 bytes are ready to read
+ QVERIFY(client.waitForReadyRead());
+ QCOMPARE(client.read(buffer, readBufferSize), qint64(readBufferSize));
+ // wait until the second 128 bytes are ready to read
+ QVERIFY(client.waitForReadyRead());
+ QCOMPARE(client.read(buffer, readBufferSize), qint64(readBufferSize));
+ // no more bytes available
+ QVERIFY(client.bytesAvailable() == 0);
+}
+
+// QLocalSocket/Server can take a name or path, check that it works as expected
+void tst_QLocalSocket::fullPath()
+{
+ QLocalServer server;
+ QString name = "qlocalsocket_pathtest";
+#if defined(Q_OS_SYMBIAN)
+ QString path = "";
+#elif defined(QT_LOCALSOCKET_TCP)
+ QString path = "QLocalServer";
+#elif defined(Q_OS_WIN)
+ QString path = "\\\\.\\pipe\\";
+#else
+ QString path = "/tmp";
+#endif
+ QString serverName = path + '/' + name;
+ QVERIFY2(server.listen(serverName), server.errorString().toLatin1().constData());
+ QCOMPARE(server.serverName(), serverName);
+ QCOMPARE(server.fullServerName(), serverName);
+
+ LocalSocket socket;
+ socket.connectToServer(serverName);
+
+ QCOMPARE(socket.serverName(), serverName);
+ QCOMPARE(socket.fullServerName(), serverName);
+ socket.disconnectFromServer();
+#ifdef QT_LOCALSOCKET_TCP
+ QTest::qWait(250);
+#endif
+ QCOMPARE(socket.serverName(), QString());
+ QCOMPARE(socket.fullServerName(), QString());
+}
+
+void tst_QLocalSocket::hitMaximumConnections_data()
+{
+ QTest::addColumn<int>("max");
+ QTest::newRow("none") << 0;
+ QTest::newRow("1") << 1;
+ QTest::newRow("3") << 3;
+}
+
+void tst_QLocalSocket::hitMaximumConnections()
+{
+ QFETCH(int, max);
+ LocalServer server;
+ QString name = "tst_localsocket";
+#ifdef Q_OS_SYMBIAN
+ unlink(name);
+#endif
+ server.setMaxPendingConnections(max);
+ QVERIFY2(server.listen(name), server.errorString().toLatin1().constData());
+ int connections = server.maxPendingConnections() + 1;
+ QList<QLocalSocket*> sockets;
+ for (int i = 0; i < connections; ++i) {
+ LocalSocket *socket = new LocalSocket;
+ sockets.append(socket);
+ socket->connectToServer(name);
+ }
+ bool timedOut = true;
+ QVERIFY(server.waitForNewConnection(3000, &timedOut));
+ QVERIFY(!timedOut);
+ QVERIFY(server.hits.count() > 0);
+ qDeleteAll(sockets.begin(), sockets.end());
+}
+
+// check that state and mode are kept
+void tst_QLocalSocket::setSocketDescriptor()
+{
+ LocalSocket socket;
+ quintptr minusOne = -1;
+ socket.setSocketDescriptor(minusOne, QLocalSocket::ConnectingState, QIODevice::Append);
+ QCOMPARE(socket.socketDescriptor(), minusOne);
+ QCOMPARE(socket.state(), QLocalSocket::ConnectingState);
+ QVERIFY((socket.openMode() & QIODevice::Append) != 0);
+}
+
+class Client : public QThread
+{
+
+public:
+ void run()
+ {
+ QString testLine = "test";
+ LocalSocket socket;
+ QSignalSpy spyReadyRead(&socket, SIGNAL(readyRead()));
+ socket.connectToServer("qlocalsocket_threadtest");
+ QVERIFY(socket.waitForConnected(1000));
+
+ // We should *not* have this signal yet!
+ QCOMPARE(spyReadyRead.count(), 0);
+ socket.waitForReadyRead();
+ QCOMPARE(spyReadyRead.count(), 1);
+ QTextStream in(&socket);
+ QCOMPARE(in.readLine(), testLine);
+ socket.close();
+ }
+};
+
+class Server : public QThread
+{
+
+public:
+ int clients;
+ QMutex mutex;
+ QWaitCondition wc;
+ void run()
+ {
+ QString testLine = "test";
+ LocalServer server;
+ server.setMaxPendingConnections(10);
+ QVERIFY2(server.listen("qlocalsocket_threadtest"),
+ server.errorString().toLatin1().constData());
+ mutex.lock();
+ wc.wakeAll();
+ mutex.unlock();
+ int done = clients;
+ while (done > 0) {
+ bool timedOut = true;
+ QVERIFY(server.waitForNewConnection(7000, &timedOut));
+ QVERIFY(!timedOut);
+ QLocalSocket *serverSocket = server.nextPendingConnection();
+ QVERIFY(serverSocket);
+ QTextStream out(serverSocket);
+ out << testLine << endl;
+ QCOMPARE(serverSocket->state(), QLocalSocket::ConnectedState);
+ QVERIFY2(serverSocket->waitForBytesWritten(), serverSocket->errorString().toLatin1().constData());
+ QCOMPARE(serverSocket->errorString(), QString("Unknown error"));
+ --done;
+ delete serverSocket;
+ }
+ QCOMPARE(server.hits.count(), clients);
+ }
+};
+
+void tst_QLocalSocket::threadedConnection_data()
+{
+ QTest::addColumn<int>("threads");
+ QTest::newRow("1 client") << 1;
+ QTest::newRow("2 clients") << 2;
+ QTest::newRow("5 clients") << 5;
+#ifndef Q_OS_WINCE
+ QTest::newRow("10 clients") << 10;
+ QTest::newRow("20 clients") << 20;
+#endif
+}
+
+void tst_QLocalSocket::threadedConnection()
+{
+#ifdef Q_OS_SYMBIAN
+ unlink("qlocalsocket_threadtest");
+#endif
+
+ QFETCH(int, threads);
+ Server server;
+#if defined(Q_OS_SYMBIAN)
+ server.setStackSize(0x14000);
+#endif
+ server.clients = threads;
+ server.mutex.lock();
+ server.start();
+ server.wc.wait(&server.mutex);
+
+ QList<Client*> clients;
+ for (int i = 0; i < threads; ++i) {
+ clients.append(new Client());
+#if defined(Q_OS_SYMBIAN)
+ clients.last()->setStackSize(0x14000);
+#endif
+ clients.last()->start();
+ }
+
+ server.wait();
+ while (!clients.isEmpty()) {
+ QVERIFY(clients.first()->wait(3000));
+ delete clients.takeFirst();
+ }
+}
+
+void tst_QLocalSocket::processConnection_data()
+{
+ QTest::addColumn<int>("processes");
+ QTest::newRow("1 client") << 1;
+#ifndef Q_OS_WIN
+ QTest::newRow("2 clients") << 2;
+ QTest::newRow("5 clients") << 5;
+#endif
+ QTest::newRow("30 clients") << 30;
+}
+
+/*!
+ Create external processes that produce and consume.
+ */
+void tst_QLocalSocket::processConnection()
+{
+#if defined(QT_NO_PROCESS) || defined(Q_CC_NOKIAX86)
+ QSKIP("Qt was compiled with QT_NO_PROCESS", SkipAll);
+#else
+ QFETCH(int, processes);
+ QStringList serverArguments = QStringList() << SRCDIR "lackey/scripts/server.js" << QString::number(processes);
+ QProcess producer;
+ producer.setProcessChannelMode(QProcess::ForwardedChannels);
+#ifdef Q_WS_QWS
+ serverArguments << "-qws";
+#endif
+ QList<QProcess*> consumers;
+ producer.start("lackey/lackey", serverArguments);
+ QVERIFY(producer.waitForStarted(-1));
+ QTest::qWait(2000);
+ for (int i = 0; i < processes; ++i) {
+ QStringList arguments = QStringList() << SRCDIR "lackey/scripts/client.js";
+#ifdef Q_WS_QWS
+ arguments << "-qws";
+#endif
+ QProcess *p = new QProcess;
+ p->setProcessChannelMode(QProcess::ForwardedChannels);
+ consumers.append(p);
+ p->start("lackey/lackey", arguments);
+ }
+
+ while (!consumers.isEmpty()) {
+ consumers.first()->waitForFinished(20000);
+ QCOMPARE(consumers.first()->exitStatus(), QProcess::NormalExit);
+ QCOMPARE(consumers.first()->exitCode(), 0);
+ QProcess *consumer = consumers.takeFirst();
+ consumer->terminate();
+ delete consumer;
+ }
+ producer.waitForFinished(15000);
+#endif
+}
+
+void tst_QLocalSocket::longPath()
+{
+#ifndef Q_OS_WIN
+ QString name;
+ for (int i = 0; i < 256; ++i)
+ name += 'a';
+ LocalServer server;
+ QVERIFY(!server.listen(name));
+
+ LocalSocket socket;
+ socket.connectToServer(name);
+ QCOMPARE(socket.state(), QLocalSocket::UnconnectedState);
+#endif
+}
+
+void tst_QLocalSocket::waitForDisconnect()
+{
+ QString name = "tst_localsocket";
+#ifdef Q_OS_SYMBIAN
+ unlink(name);
+#endif
+ LocalServer server;
+ QVERIFY(server.listen(name));
+ LocalSocket socket;
+ socket.connectToServer(name);
+ QVERIFY(socket.waitForConnected(3000));
+ QVERIFY(server.waitForNewConnection(3000));
+ QLocalSocket *serverSocket = server.nextPendingConnection();
+ QVERIFY(serverSocket);
+ socket.disconnectFromServer();
+ QTime timer;
+ timer.start();
+ QVERIFY(serverSocket->waitForDisconnected(3000));
+ QVERIFY(timer.elapsed() < 2000);
+}
+
+void tst_QLocalSocket::waitForDisconnectByServer()
+{
+ QString name = "tst_localsocket";
+ LocalServer server;
+ QVERIFY(server.listen(name));
+ LocalSocket socket;
+ QSignalSpy spy(&socket, SIGNAL(disconnected()));
+ QVERIFY(spy.isValid());
+ socket.connectToServer(name);
+ QVERIFY(socket.waitForConnected(3000));
+ QVERIFY(server.waitForNewConnection(3000));
+ QLocalSocket *serverSocket = server.nextPendingConnection();
+ QVERIFY(serverSocket);
+ serverSocket->close();
+ QVERIFY(serverSocket->state() == QLocalSocket::UnconnectedState);
+ QVERIFY(socket.waitForDisconnected(3000));
+ QCOMPARE(spy.count(), 1);
+}
+
+void tst_QLocalSocket::removeServer()
+{
+ // this is a hostile takeover, but recovering from a crash results in the same
+ QLocalServer server, server2;
+ QVERIFY(QLocalServer::removeServer("cleanuptest"));
+ QVERIFY(server.listen("cleanuptest"));
+#ifndef Q_OS_WIN
+ // on Windows, there can be several sockets listening on the same pipe
+ // on Unix, there can only be one socket instance
+ QVERIFY(! server2.listen("cleanuptest"));
+#endif
+ QVERIFY(QLocalServer::removeServer("cleanuptest"));
+ QVERIFY(server2.listen("cleanuptest"));
+}
+
+void tst_QLocalSocket::recycleServer()
+{
+#ifdef Q_OS_SYMBIAN
+ unlink("recycletest1");
+#endif
+
+ QLocalServer server;
+ QLocalSocket client;
+
+ QVERIFY(server.listen("recycletest1"));
+ client.connectToServer("recycletest1");
+ QVERIFY(client.waitForConnected(201));
+ QVERIFY(server.waitForNewConnection(201));
+ QVERIFY(server.nextPendingConnection() != 0);
+
+ server.close();
+ client.disconnectFromServer();
+ qApp->processEvents();
+
+ QVERIFY(server.listen("recycletest2"));
+ client.connectToServer("recycletest2");
+ QVERIFY(client.waitForConnected(202));
+ QVERIFY(server.waitForNewConnection(202));
+ QVERIFY(server.nextPendingConnection() != 0);
+}
+
+void tst_QLocalSocket::multiConnect()
+{
+ QLocalServer server;
+ QLocalSocket client1;
+ QLocalSocket client2;
+ QLocalSocket client3;
+
+ QVERIFY(server.listen("multiconnect"));
+
+ client1.connectToServer("multiconnect");
+ client2.connectToServer("multiconnect");
+ client3.connectToServer("multiconnect");
+
+ QVERIFY(client1.waitForConnected(201));
+ QVERIFY(client2.waitForConnected(202));
+ QVERIFY(client3.waitForConnected(203));
+
+ QVERIFY(server.waitForNewConnection(201));
+ QVERIFY(server.nextPendingConnection() != 0);
+ QVERIFY(server.waitForNewConnection(202));
+ QVERIFY(server.nextPendingConnection() != 0);
+ QVERIFY(server.waitForNewConnection(203));
+ QVERIFY(server.nextPendingConnection() != 0);
+}
+
+void tst_QLocalSocket::writeOnlySocket()
+{
+ QLocalServer server;
+#ifdef Q_OS_SYMBIAN
+ unlink("writeOnlySocket");
+#endif
+ QVERIFY(server.listen("writeOnlySocket"));
+
+ QLocalSocket client;
+ client.connectToServer("writeOnlySocket", QIODevice::WriteOnly);
+ QVERIFY(client.waitForConnected());
+#if defined(Q_OS_SYMBIAN)
+ QTest::qWait(250);
+#endif
+ QVERIFY(server.waitForNewConnection(200));
+ QLocalSocket* serverSocket = server.nextPendingConnection();
+ QVERIFY(serverSocket);
+
+ QCOMPARE(client.bytesAvailable(), qint64(0));
+ QCOMPARE(client.state(), QLocalSocket::ConnectedState);
+}
+
+void tst_QLocalSocket::writeToClientAndDisconnect()
+{
+#ifdef Q_OS_SYMBIAN
+ unlink("writeAndDisconnectServer");
+#endif
+
+ QLocalServer server;
+ QLocalSocket client;
+ QSignalSpy readChannelFinishedSpy(&client, SIGNAL(readChannelFinished()));
+
+ QVERIFY(server.listen("writeAndDisconnectServer"));
+ client.connectToServer("writeAndDisconnectServer");
+ QVERIFY(client.waitForConnected(200));
+ QVERIFY(server.waitForNewConnection(200));
+ QLocalSocket* clientSocket = server.nextPendingConnection();
+ QVERIFY(clientSocket);
+
+ char buffer[100];
+ memset(buffer, 0, sizeof(buffer));
+ QCOMPARE(clientSocket->write(buffer, sizeof(buffer)), (qint64)sizeof(buffer));
+ clientSocket->waitForBytesWritten();
+ clientSocket->close();
+ server.close();
+
+ QTRY_COMPARE(readChannelFinishedSpy.count(), 1);
+ QCOMPARE(client.read(buffer, sizeof(buffer)), (qint64)sizeof(buffer));
+ client.waitForDisconnected();
+ QCOMPARE(client.state(), QLocalSocket::UnconnectedState);
+}
+
+void tst_QLocalSocket::debug()
+{
+ // Make sure this compiles
+ qDebug() << QLocalSocket::ConnectionRefusedError << QLocalSocket::UnconnectedState;
+}
+
+class WriteThread : public QThread
+{
+Q_OBJECT
+public:
+ void run() {
+ QLocalSocket socket;
+ socket.connectToServer("qlocalsocket_readyread");
+
+ if (!socket.waitForConnected(3000))
+ exec();
+ connect(&socket, SIGNAL(bytesWritten(qint64)),
+ this, SLOT(bytesWritten(qint64)), Qt::QueuedConnection);
+ socket.write("testing\n");
+ exec();
+ }
+public slots:
+ void bytesWritten(qint64) {
+ exit();
+ }
+
+private:
+};
+
+/*
+ Tests the emission of the bytesWritten(qint64)
+ signal.
+
+ Create a thread that will write to a socket.
+ If the bytesWritten(qint64) signal is generated,
+ the slot connected to it will exit the thread,
+ indicating test success.
+
+*/
+void tst_QLocalSocket::bytesWrittenSignal()
+{
+ QLocalServer server;
+ QVERIFY(server.listen("qlocalsocket_readyread"));
+ WriteThread writeThread;
+ writeThread.start();
+ bool timedOut = false;
+ QVERIFY(server.waitForNewConnection(3000, &timedOut));
+ QVERIFY(!timedOut);
+ QTest::qWait(2000);
+ QVERIFY(writeThread.wait(2000));
+}
+
+void tst_QLocalSocket::syncDisconnectNotify()
+{
+#ifdef Q_OS_SYMBIAN
+ unlink("syncDisconnectNotify");
+#endif
+
+ QLocalServer server;
+ QVERIFY(server.listen("syncDisconnectNotify"));
+ QLocalSocket client;
+ client.connectToServer("syncDisconnectNotify");
+ QVERIFY(server.waitForNewConnection());
+ QLocalSocket* serverSocket = server.nextPendingConnection();
+ QVERIFY(serverSocket);
+ delete serverSocket;
+ QCOMPARE(client.waitForReadyRead(), false);
+}
+
+void tst_QLocalSocket::asyncDisconnectNotify()
+{
+#ifdef Q_OS_SYMBIAN
+ unlink("asyncDisconnectNotify");
+#endif
+
+ QLocalServer server;
+ QVERIFY(server.listen("asyncDisconnectNotify"));
+ QLocalSocket client;
+ QSignalSpy disconnectedSpy(&client, SIGNAL(disconnected()));
+ client.connectToServer("asyncDisconnectNotify");
+ QVERIFY(server.waitForNewConnection());
+ QLocalSocket* serverSocket = server.nextPendingConnection();
+ QVERIFY(serverSocket);
+ delete serverSocket;
+ QTRY_VERIFY(!disconnectedSpy.isEmpty());
+}
+
+#ifdef Q_OS_SYMBIAN
+void tst_QLocalSocket::unlink(QString name)
+{
+ if(name.length() == 0)
+ return;
+
+ QString fullName;
+ // determine the full server path
+ if (name.startsWith(QLatin1Char('/'))) {
+ fullName = name;
+ } else {
+ fullName = QDir::cleanPath(QDir::tempPath());
+ fullName += QLatin1Char('/') + name;
+ fullName = QDir::toNativeSeparators(fullName);
+ }
+
+ int result = ::unlink(fullName.toUtf8().data());
+
+ if(result != 0) {
+ qWarning() << "Unlinking " << fullName << " failed with " << strerror(errno);
+ }
+}
+#endif
+QTEST_MAIN(tst_QLocalSocket)
+#include "tst_qlocalsocket.moc"
+
diff --git a/tests/auto/network/socket/qsocks5socketengine/.gitignore b/tests/auto/network/socket/qsocks5socketengine/.gitignore
new file mode 100644
index 0000000000..7d64805f3c
--- /dev/null
+++ b/tests/auto/network/socket/qsocks5socketengine/.gitignore
@@ -0,0 +1 @@
+tst_qsocks5socketengine
diff --git a/tests/auto/network/socket/qsocks5socketengine/qsocks5socketengine.pro b/tests/auto/network/socket/qsocks5socketengine/qsocks5socketengine.pro
new file mode 100644
index 0000000000..3a144aeacf
--- /dev/null
+++ b/tests/auto/network/socket/qsocks5socketengine/qsocks5socketengine.pro
@@ -0,0 +1,17 @@
+load(qttest_p4)
+SOURCES += tst_qsocks5socketengine.cpp
+
+
+include(../platformsocketengine/platformsocketengine.pri)
+
+
+MOC_DIR=tmp
+
+QT = core-private network-private
+
+# Symbian toolchain does not support correct include semantics
+symbian:INCLUDEPATH+=..\\..\\..\\include\\QtNetwork\\private
+symbian: TARGET.CAPABILITY = NetworkServices
+
+
+requires(contains(QT_CONFIG,private_tests))
diff --git a/tests/auto/network/socket/qsocks5socketengine/tst_qsocks5socketengine.cpp b/tests/auto/network/socket/qsocks5socketengine/tst_qsocks5socketengine.cpp
new file mode 100644
index 0000000000..2678816482
--- /dev/null
+++ b/tests/auto/network/socket/qsocks5socketengine/tst_qsocks5socketengine.cpp
@@ -0,0 +1,963 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+
+#include <QtTest/QTest>
+#include <QtTest/QTestEventLoop>
+
+#include <QtCore/QQueue>
+#include <QtCore/QString>
+#include <QtCore/QCoreApplication>
+#include <QtCore/QMetaType>
+
+#include <private/qsocks5socketengine_p.h>
+#include <qhostinfo.h>
+#include <qhostaddress.h>
+#include <qtcpsocket.h>
+#include <qhttp.h>
+#include <qauthenticator.h>
+#include <qdebug.h>
+#include <qtcpserver.h>
+#include <qmetatype.h>
+#include <qdebug.h>
+
+#include "../../../network-settings.h"
+
+Q_DECLARE_METATYPE(QQueue<QByteArray>)
+
+class tst_QSocks5SocketEngine : public QObject, public QAbstractSocketEngineReceiver
+{
+ Q_OBJECT
+
+public:
+ tst_QSocks5SocketEngine();
+ virtual ~tst_QSocks5SocketEngine();
+
+
+public slots:
+ void init();
+ void cleanup();
+private slots:
+ void construction();
+ void errorTest_data();
+ void errorTest();
+ void simpleConnectToIMAP();
+ void simpleErrorsAndStates();
+ void udpTest();
+ void serverTest();
+ void tcpSocketBlockingTest();
+ void tcpSocketNonBlockingTest();
+ void downloadBigFile();
+ // void tcpLoopbackPerformance();
+ void passwordAuth();
+ void passwordAuth2();
+
+protected slots:
+ void tcpSocketNonBlocking_hostFound();
+ void tcpSocketNonBlocking_connected();
+ void tcpSocketNonBlocking_closed();
+ void tcpSocketNonBlocking_readyRead();
+ void tcpSocketNonBlocking_bytesWritten(qint64);
+ void exitLoopSlot();
+ void downloadBigFileSlot();
+ void proxyAuthenticationRequired(const QNetworkProxy &proxy, QAuthenticator *auth);
+
+private:
+ void readNotification() { }
+ void writeNotification() { }
+ void exceptionNotification() { }
+ void connectionNotification() { }
+ QTcpSocket *tcpSocketNonBlocking_socket;
+ QStringList tcpSocketNonBlocking_data;
+ qint64 tcpSocketNonBlocking_totalWritten;
+ QTcpSocket *tmpSocket;
+ qint64 bytesAvailable;
+};
+
+class MiniSocks5Server: public QTcpServer
+{
+ Q_OBJECT
+public:
+ QQueue<QByteArray> responses;
+
+ MiniSocks5Server(const QQueue<QByteArray> r)
+ : responses(r)
+ {
+ listen();
+ connect(this, SIGNAL(newConnection()), SLOT(handleNewConnection()));
+ }
+
+private slots:
+ void handleNewConnection()
+ {
+ QTcpSocket *client = nextPendingConnection();
+ connect(client, SIGNAL(readyRead()), SLOT(handleClientCommand()));
+ client->setProperty("pendingResponses", qVariantFromValue(responses));
+ }
+
+ void handleClientCommand()
+ {
+ // WARNING
+ // this assumes that the client command is received in its entirety
+ // should be ok, since SOCKSv5 commands are rather small
+ QTcpSocket *client = static_cast<QTcpSocket *>(sender());
+ QQueue<QByteArray> pendingResponses =
+ qvariant_cast<QQueue<QByteArray> >(client->property("pendingResponses"));
+ if (pendingResponses.isEmpty())
+ client->disconnectFromHost();
+ else
+ client->write(pendingResponses.dequeue());
+ client->setProperty("pendingResponses", qVariantFromValue(pendingResponses));
+ }
+};
+
+tst_QSocks5SocketEngine::tst_QSocks5SocketEngine()
+{
+ Q_SET_DEFAULT_IAP
+}
+
+tst_QSocks5SocketEngine::~tst_QSocks5SocketEngine()
+{
+}
+
+void tst_QSocks5SocketEngine::init()
+{
+ tmpSocket = 0;
+ bytesAvailable = 0;
+}
+
+void tst_QSocks5SocketEngine::cleanup()
+{
+}
+
+//---------------------------------------------------------------------------
+void tst_QSocks5SocketEngine::construction()
+{
+ QSocks5SocketEngine socketDevice;
+
+ QVERIFY(!socketDevice.isValid());
+
+ // Initialize device
+ QVERIFY(socketDevice.initialize(QAbstractSocket::TcpSocket, QAbstractSocket::IPv4Protocol));
+ QVERIFY(socketDevice.isValid());
+ QVERIFY(socketDevice.protocol() == QAbstractSocket::IPv4Protocol);
+ QVERIFY(socketDevice.socketType() == QAbstractSocket::TcpSocket);
+ QVERIFY(socketDevice.state() == QAbstractSocket::UnconnectedState);
+ // QVERIFY(socketDevice.socketDescriptor() != -1);
+ QVERIFY(socketDevice.localAddress() == QHostAddress());
+ QVERIFY(socketDevice.localPort() == 0);
+ QVERIFY(socketDevice.peerAddress() == QHostAddress());
+ QVERIFY(socketDevice.peerPort() == 0);
+ QVERIFY(socketDevice.error() == QAbstractSocket::UnknownSocketError);
+
+ //QTest::ignoreMessage(QtWarningMsg, "QSocketLayer::bytesAvailable() was called in QAbstractSocket::UnconnectedState");
+ QVERIFY(socketDevice.bytesAvailable() == 0);
+
+ //QTest::ignoreMessage(QtWarningMsg, "QSocketLayer::hasPendingDatagrams() was called in QAbstractSocket::UnconnectedState");
+ QVERIFY(!socketDevice.hasPendingDatagrams());
+}
+
+//---------------------------------------------------------------------------
+void tst_QSocks5SocketEngine::errorTest_data()
+{
+ QTest::addColumn<QString>("hostname");
+ QTest::addColumn<int>("port");
+ QTest::addColumn<QString>("username");
+ QTest::addColumn<QQueue<QByteArray> >("responses");
+ QTest::addColumn<int>("expectedError");
+
+ QQueue<QByteArray> responses;
+ QTest::newRow("proxy-host-not-found") << "this-host-does-not-exist." << 1080 << QString()
+ << responses
+ << int(QAbstractSocket::ProxyNotFoundError);
+ QTest::newRow("proxy-connection-refused") << "127.0.0.1" << 2 << QString()
+ << responses
+ << int(QAbstractSocket::ProxyConnectionRefusedError);
+
+#define REPLY(name, contents) \
+ static const char raw_ ## name [] = contents; \
+ const QByteArray name = QByteArray::fromRawData(raw_ ## name, sizeof raw_ ## name - 1)
+
+ REPLY(garbage, "\4\4\4\4");
+ // authentication method replies
+ REPLY(noAuthentication, "\5\0");
+ REPLY(passwordAuthentication, "\5\2");
+ REPLY(garbageAuthentication, "\5\177");
+ REPLY(noAcceptableAuthentication, "\5\377");
+ // authentication replies
+ REPLY(authenticationAccepted, "\5\0");
+ REPLY(authenticationNotAccepted, "\5\1");
+ // connection replies
+ REPLY(connectionAccepted, "\5\0\0\4\177\0\0\1\0\100");
+ REPLY(connectionNotAllowed, "\5\2\0");
+ REPLY(networkUnreachable, "\5\3\0");
+ REPLY(hostUnreachable, "\5\4\0");
+ REPLY(connectionRefused, "\5\5\0");
+
+#undef REPLY
+
+ responses << garbage;
+ QTest::newRow("garbage1") << QString() << 0 << QString() << responses
+ << int(QAbstractSocket::ProxyProtocolError);
+
+ responses.clear();
+ responses << noAuthentication << garbage;
+ QTest::newRow("garbage2") << QString() << 0 << QString() << responses
+ << int(QAbstractSocket::ProxyProtocolError);
+
+ responses.clear();
+ responses << garbageAuthentication;
+ QTest::newRow("unknown-auth-method") << QString() << 0 << QString()
+ << responses
+ << int(QAbstractSocket::SocketAccessError);
+
+ responses.clear();
+ responses << noAcceptableAuthentication;
+ QTest::newRow("no-acceptable-authentication") << QString() << 0 << QString()
+ << responses
+ << int(QAbstractSocket::ProxyAuthenticationRequiredError);
+
+ responses.clear();
+ responses << passwordAuthentication << authenticationNotAccepted;
+ QTest::newRow("authentication-required") << QString() << 0 << "foo"
+ << responses
+ << int(QAbstractSocket::ProxyAuthenticationRequiredError);
+
+ responses.clear();
+ responses << noAuthentication << connectionNotAllowed;
+ QTest::newRow("connection-not-allowed") << QString() << 0 << QString()
+ << responses
+ << int(QAbstractSocket::SocketAccessError);
+
+ responses.clear();
+ responses << noAuthentication << networkUnreachable;
+ QTest::newRow("network-unreachable") << QString() << 0 << QString()
+ << responses
+ << int(QAbstractSocket::NetworkError);
+
+ responses.clear();
+ responses << noAuthentication << hostUnreachable;
+ QTest::newRow("host-unreachable") << QString() << 0 << QString()
+ << responses
+ << int(QAbstractSocket::HostNotFoundError);
+
+ responses.clear();
+ responses << noAuthentication << connectionRefused;
+ QTest::newRow("connection-refused") << QString() << 0 << QString()
+ << responses
+ << int(QAbstractSocket::ConnectionRefusedError);
+}
+
+void tst_QSocks5SocketEngine::errorTest()
+{
+ QFETCH(QString, hostname);
+ QFETCH(int, port);
+ QFETCH(QString, username);
+ QFETCH(QQueue<QByteArray>, responses);
+ QFETCH(int, expectedError);
+
+ MiniSocks5Server server(responses);
+
+ if (hostname.isEmpty()) {
+ hostname = "127.0.0.1";
+ port = server.serverPort();
+ }
+ QTcpSocket socket;
+ socket.setProxy(QNetworkProxy(QNetworkProxy::Socks5Proxy, hostname, port, username, username));
+ socket.connectToHost("0.1.2.3", 12345);
+
+ connect(&socket, SIGNAL(error(QAbstractSocket::SocketError)),
+ &QTestEventLoop::instance(), SLOT(exitLoop()));
+ QTestEventLoop::instance().enterLoop(10);
+ QVERIFY(!QTestEventLoop::instance().timeout());
+
+ QCOMPARE(int(socket.error()), expectedError);
+}
+
+//---------------------------------------------------------------------------
+void tst_QSocks5SocketEngine::simpleConnectToIMAP()
+{
+ QSocks5SocketEngine socketDevice;
+
+ // Initialize device
+ QVERIFY(socketDevice.initialize(QAbstractSocket::TcpSocket, QAbstractSocket::IPv4Protocol));
+ QVERIFY(socketDevice.state() == QAbstractSocket::UnconnectedState);
+
+ socketDevice.setProxy(QNetworkProxy(QNetworkProxy::Socks5Proxy, QtNetworkSettings::serverName(), 1080));
+
+ QVERIFY(!socketDevice.connectToHost(QtNetworkSettings::serverIP(), 143));
+ QVERIFY(socketDevice.state() == QAbstractSocket::ConnectingState);
+ QVERIFY(socketDevice.waitForWrite());
+ QVERIFY(socketDevice.state() == QAbstractSocket::ConnectedState);
+ QVERIFY(socketDevice.peerAddress() == QtNetworkSettings::serverIP());
+
+ // Wait for the greeting
+ QVERIFY(socketDevice.waitForRead());
+
+ // Read the greeting
+ qint64 available = socketDevice.bytesAvailable();
+ QVERIFY(available > 0);
+ QByteArray array;
+ array.resize(available);
+ QVERIFY(socketDevice.read(array.data(), array.size()) == available);
+
+ // Check that the greeting is what we expect it to be
+ QVERIFY2(QtNetworkSettings::compareReplyIMAP(array), array.constData());
+
+ // Write a logout message
+ QByteArray array2 = "XXXX LOGOUT\r\n";
+ QVERIFY(socketDevice.write(array2.data(),
+ array2.size()) == array2.size());
+
+ // Wait for the response
+ QVERIFY(socketDevice.waitForRead());
+
+ available = socketDevice.bytesAvailable();
+ QVERIFY(available > 0);
+ array.resize(available);
+ QVERIFY(socketDevice.read(array.data(), array.size()) == available);
+
+ // Check that the greeting is what we expect it to be
+ QCOMPARE(array.constData(), "* BYE LOGOUT received\r\nXXXX OK Completed\r\n");
+
+ // Wait for the response
+ QVERIFY(socketDevice.waitForRead());
+ char c;
+ QVERIFY(socketDevice.read(&c, sizeof(c)) == -1);
+ QVERIFY(socketDevice.error() == QAbstractSocket::RemoteHostClosedError);
+ QVERIFY(socketDevice.state() == QAbstractSocket::UnconnectedState);
+}
+
+//---------------------------------------------------------------------------
+void tst_QSocks5SocketEngine::simpleErrorsAndStates()
+{
+ {
+ QSocks5SocketEngine socketDevice;
+
+ // Initialize device
+ QVERIFY(socketDevice.initialize(QAbstractSocket::TcpSocket, QAbstractSocket::IPv4Protocol));
+
+ socketDevice.setProxy(QNetworkProxy(QNetworkProxy::Socks5Proxy, QtNetworkSettings::serverName(), 1080));
+
+ QVERIFY(socketDevice.state() == QAbstractSocket::UnconnectedState);
+ QVERIFY(!socketDevice.connectToHost(QHostInfo::fromName(QtNetworkSettings::serverName()).addresses().first(), 8088));
+ QVERIFY(socketDevice.state() == QAbstractSocket::ConnectingState);
+ if (socketDevice.waitForWrite(15000)) {
+ QVERIFY(socketDevice.state() == QAbstractSocket::UnconnectedState ||
+ socketDevice.state() == QAbstractSocket::ConnectedState);
+ } else {
+ QVERIFY(socketDevice.error() == QAbstractSocket::SocketTimeoutError);
+ }
+ }
+
+}
+
+/*
+//---------------------------------------------------------------------------
+void tst_QSocks5SocketEngine::tcpLoopbackPerformance()
+{
+ QTcpServer server;
+
+ // Bind to any port on all interfaces
+ QVERIFY(server.bind(QHostAddress("0.0.0.0"), 0));
+ QVERIFY(server.state() == QAbstractSocket::BoundState);
+ quint16 port = server.localPort();
+
+ // Listen for incoming connections
+ QVERIFY(server.listen());
+ QVERIFY(server.state() == QAbstractSocket::ListeningState);
+
+ // Initialize a Tcp socket
+ QSocks5SocketEngine client;
+ QVERIFY(client.initialize(QAbstractSocket::TcpSocket));
+
+ client.setProxy(QHostAddress("80.232.37.158"), 1081);
+
+ // Connect to our server
+ if (!client.connectToHost(QHostAddress("127.0.0.1"), port)) {
+ QVERIFY(client.waitForWrite());
+ QVERIFY(client.connectToHost(QHostAddress("127.0.0.1"), port));
+ }
+
+ // The server accepts the connectio
+ int socketDescriptor = server.accept();
+ QVERIFY(socketDescriptor > 0);
+
+ // A socket device is initialized on the server side, passing the
+ // socket descriptor from accept(). It's pre-connected.
+ QSocketLayer serverSocket;
+ QVERIFY(serverSocket.initialize(socketDescriptor));
+ QVERIFY(serverSocket.state() == QAbstractSocket::ConnectedState);
+
+ const int messageSize = 1024 * 256;
+ QByteArray message1(messageSize, '@');
+ QByteArray answer(messageSize, '@');
+
+ QTime timer;
+ timer.start();
+ qlonglong readBytes = 0;
+ while (timer.elapsed() < 5000) {
+ qlonglong written = serverSocket.write(message1.data(), message1.size());
+ while (written > 0) {
+ client.waitForRead();
+ if (client.bytesAvailable() > 0) {
+ qlonglong readNow = client.read(answer.data(), answer.size());
+ written -= readNow;
+ readBytes += readNow;
+ }
+ }
+ }
+
+ qDebug("\t\t%.1fMB/%.1fs: %.1fMB/s",
+ readBytes / (1024.0 * 1024.0),
+ timer.elapsed() / 1024.0,
+ (readBytes / (timer.elapsed() / 1000.0)) / (1024 * 1024));
+}
+*/
+
+//---------------------------------------------------------------------------
+void tst_QSocks5SocketEngine::serverTest()
+{
+ QSocks5SocketEngine server;
+
+ // Initialize a Tcp socket
+ QVERIFY(server.initialize(QAbstractSocket::TcpSocket));
+
+ QNetworkProxy proxy(QNetworkProxy::Socks5Proxy, QtNetworkSettings::serverName(), 1080);
+
+ server.setProxy(proxy);
+
+ // Bind to any port on all interfaces
+ QVERIFY(server.bind(QHostAddress("0.0.0.0"), 0));
+ QVERIFY(server.state() == QAbstractSocket::BoundState);
+
+ // Listen for incoming connections
+ QVERIFY(server.listen());
+ QVERIFY(server.state() == QAbstractSocket::ListeningState);
+
+ // Initialize a Tcp socket
+ QSocks5SocketEngine client;
+ QVERIFY(client.initialize(QAbstractSocket::TcpSocket));
+
+ client.setProxy(proxy);
+
+ // QTest::wait(100000); // ### timing problem on win32
+
+
+ // Connect to our server
+ if (!client.connectToHost(server.localAddress(), server.localPort())) {
+ QVERIFY(client.waitForWrite());
+ // QTest::wait(100); // ### timing problem on win32
+ QVERIFY(client.state() == QAbstractSocket::ConnectedState);
+ //QTest::wait(100);
+ }
+
+ QVERIFY(server.waitForRead());
+
+ // The server accepts the connection
+ int socketDescriptor = server.accept();
+ QVERIFY(socketDescriptor > 0);
+
+ // A socket device is initialized on the server side, passing the
+ // socket descriptor from accept(). It's pre-connected.
+
+ QSocks5SocketEngine serverSocket;
+ QVERIFY(serverSocket.initialize(socketDescriptor));
+ QVERIFY(serverSocket.state() == QAbstractSocket::ConnectedState);
+
+ QVERIFY(serverSocket.localAddress() == client.peerAddress());
+ QVERIFY(serverSocket.localPort() == client.peerPort());
+ // this seems depends on the socks server implementation, especially
+ // when connecting /to/ the socks server /through/ the same socks server
+ //QVERIFY(serverSocket.peerAddress() == client.localAddress());
+ //QVERIFY(serverSocket.peerPort() == client.localPort());
+
+ // The server socket sends a greeting to the client
+ QByteArray greeting = "Greetings!";
+ QVERIFY(serverSocket.write(greeting.data(),
+ greeting.size()) == greeting.size());
+
+ // The client waits for the greeting to arrive
+ QVERIFY(client.waitForRead());
+ qint64 available = client.bytesAvailable();
+ QVERIFY(available > 0);
+
+ // The client reads the greeting and checks that it's correct
+ QByteArray response;
+ response.resize(available);
+ QVERIFY(client.read(response.data(),
+ response.size()) == response.size());
+ QCOMPARE(response, greeting);
+}
+
+
+//---------------------------------------------------------------------------
+void tst_QSocks5SocketEngine::udpTest()
+{
+#ifdef SYMBIAN_WINSOCK_CONNECTIVITY
+ QSKIP("UDP works bads on non WinPCAP emulator setting", SkipAll);
+#endif
+
+ QSocks5SocketEngine udpSocket;
+
+ // Initialize device #1
+ QVERIFY(udpSocket.initialize(QAbstractSocket::UdpSocket));
+ QVERIFY(udpSocket.isValid());
+
+ QNetworkProxy proxy(QNetworkProxy::Socks5Proxy, QtNetworkSettings::serverName(), 1080);
+
+ udpSocket.setProxy(proxy);
+
+ QVERIFY(udpSocket.protocol() == QAbstractSocket::IPv4Protocol);
+ QVERIFY(udpSocket.socketType() == QAbstractSocket::UdpSocket);
+ QVERIFY(udpSocket.state() == QAbstractSocket::UnconnectedState);
+
+ // Bind #1
+ QVERIFY(udpSocket.bind(QHostAddress("0.0.0.0"), 0));
+ QVERIFY(udpSocket.state() == QAbstractSocket::BoundState);
+ QVERIFY(udpSocket.localPort() != 0);
+
+ // Initialize device #2
+ QSocks5SocketEngine udpSocket2;
+ QVERIFY(udpSocket2.initialize(QAbstractSocket::UdpSocket));
+
+ udpSocket2.setProxy(proxy);
+
+ // Connect device #2 to #1
+ QVERIFY(udpSocket2.connectToHost(udpSocket.localAddress(), udpSocket.localPort()));
+ QVERIFY(udpSocket2.state() == QAbstractSocket::ConnectedState);
+
+ // Write a message to #1
+ QByteArray message1 = "hei der";
+ QVERIFY(udpSocket2.write(message1.data(),
+ message1.size()) == message1.size());
+
+ // Read the message from #2
+ QVERIFY(udpSocket.waitForRead());
+ QVERIFY(udpSocket.hasPendingDatagrams());
+ qint64 available = udpSocket.pendingDatagramSize();
+ QVERIFY(available > 0);
+ QByteArray answer;
+ answer.resize(available);
+ QHostAddress senderAddress;
+ quint16 senderPort = 0;
+ QVERIFY(udpSocket.readDatagram(answer.data(), answer.size(),
+ &senderAddress,
+ &senderPort) == message1.size());
+ QVERIFY(senderAddress == udpSocket2.localAddress());
+ QVERIFY(senderPort == udpSocket2.localPort());
+}
+
+void tst_QSocks5SocketEngine::tcpSocketBlockingTest()
+{
+ QSocks5SocketEngineHandler socks5;
+
+ QTcpSocket socket;
+
+ // Connect
+ socket.connectToHost(QtNetworkSettings::serverName(), 143);
+ QVERIFY(socket.waitForConnected());
+ QCOMPARE(socket.state(), QTcpSocket::ConnectedState);
+
+ // Read greeting
+ QVERIFY(socket.waitForReadyRead(5000));
+ QString s = socket.readLine();
+ QVERIFY2(QtNetworkSettings::compareReplyIMAP(s.toLatin1()), s.toLatin1().constData());
+
+ // Write NOOP
+ QCOMPARE((int) socket.write("1 NOOP\r\n", 8), 8);
+
+ if (!socket.canReadLine())
+ QVERIFY(socket.waitForReadyRead(5000));
+
+ // Read response
+ s = socket.readLine();
+ QCOMPARE(s.toLatin1().constData(), "1 OK Completed\r\n");
+
+ // Write LOGOUT
+ QCOMPARE((int) socket.write("2 LOGOUT\r\n", 10), 10);
+
+ if (!socket.canReadLine())
+ QVERIFY(socket.waitForReadyRead(5000));
+
+ // Read two lines of respose
+ s = socket.readLine();
+ QCOMPARE(s.toLatin1().constData(), "* BYE LOGOUT received\r\n");
+
+ if (!socket.canReadLine())
+ QVERIFY(socket.waitForReadyRead(5000));
+
+ s = socket.readLine();
+ QCOMPARE(s.toLatin1().constData(), "2 OK Completed\r\n");
+
+ // Close the socket
+ socket.close();
+
+ // Check that it's closed
+ QCOMPARE(socket.state(), QTcpSocket::UnconnectedState);
+}
+
+//----------------------------------------------------------------------------------
+
+void tst_QSocks5SocketEngine::tcpSocketNonBlockingTest()
+{
+ QSocks5SocketEngineHandler socks5;
+
+ QTcpSocket socket;
+ connect(&socket, SIGNAL(hostFound()), SLOT(tcpSocketNonBlocking_hostFound()));
+ connect(&socket, SIGNAL(connected()), SLOT(tcpSocketNonBlocking_connected()));
+ connect(&socket, SIGNAL(disconnected()), SLOT(tcpSocketNonBlocking_closed()));
+ connect(&socket, SIGNAL(bytesWritten(qint64)), SLOT(tcpSocketNonBlocking_bytesWritten(qint64)));
+ connect(&socket, SIGNAL(readyRead()), SLOT(tcpSocketNonBlocking_readyRead()));
+ tcpSocketNonBlocking_socket = &socket;
+
+ // Connect
+ socket.connectToHost(QtNetworkSettings::serverName(), 143);
+ QVERIFY(socket.state() == QTcpSocket::HostLookupState ||
+ socket.state() == QTcpSocket::ConnectingState);
+
+ QTestEventLoop::instance().enterLoop(30);
+ if (QTestEventLoop::instance().timeout()) {
+ QFAIL("Timed out");
+ }
+
+ if (socket.state() == QTcpSocket::ConnectingState) {
+ QTestEventLoop::instance().enterLoop(30);
+ if (QTestEventLoop::instance().timeout()) {
+ QFAIL("Timed out");
+ }
+ }
+
+ QCOMPARE(socket.state(), QTcpSocket::ConnectedState);
+
+ QTestEventLoop::instance().enterLoop(30);
+ if (QTestEventLoop::instance().timeout()) {
+ QFAIL("Timed out");
+ }
+
+ // Read greeting
+ QVERIFY(!tcpSocketNonBlocking_data.isEmpty());
+ QByteArray data = tcpSocketNonBlocking_data.at(0).toLatin1();
+ QVERIFY2(QtNetworkSettings::compareReplyIMAP(data), data.constData());
+
+ tcpSocketNonBlocking_data.clear();
+
+ tcpSocketNonBlocking_totalWritten = 0;
+
+ // Write NOOP
+ QCOMPARE((int) socket.write("1 NOOP\r\n", 8), 8);
+
+
+ QTestEventLoop::instance().enterLoop(30);
+ if (QTestEventLoop::instance().timeout()) {
+ QFAIL("Timed out");
+ }
+
+ QVERIFY(tcpSocketNonBlocking_totalWritten == 8);
+
+
+ QTestEventLoop::instance().enterLoop(30);
+ if (QTestEventLoop::instance().timeout()) {
+ QFAIL("Timed out");
+ }
+
+ // Read response
+ QVERIFY(!tcpSocketNonBlocking_data.isEmpty());
+ QCOMPARE(tcpSocketNonBlocking_data.at(0).toLatin1().constData(), "1 OK Completed\r\n");
+ tcpSocketNonBlocking_data.clear();
+
+
+ tcpSocketNonBlocking_totalWritten = 0;
+
+ // Write LOGOUT
+ QCOMPARE((int) socket.write("2 LOGOUT\r\n", 10), 10);
+
+ QTestEventLoop::instance().enterLoop(30);
+ if (QTestEventLoop::instance().timeout()) {
+ QFAIL("Timed out");
+ }
+
+ QVERIFY(tcpSocketNonBlocking_totalWritten == 10);
+
+ // Wait for greeting
+ QTestEventLoop::instance().enterLoop(30);
+ if (QTestEventLoop::instance().timeout()) {
+ QFAIL("Timed out");
+ }
+
+ // Read two lines of respose
+ QCOMPARE(tcpSocketNonBlocking_data.at(0).toLatin1().constData(), "* BYE LOGOUT received\r\n");
+ QCOMPARE(tcpSocketNonBlocking_data.at(1).toLatin1().constData(), "2 OK Completed\r\n");
+ tcpSocketNonBlocking_data.clear();
+
+ // Close the socket
+ socket.close();
+
+ // Check that it's closed
+ QCOMPARE(socket.state(), QTcpSocket::UnconnectedState);
+}
+
+void tst_QSocks5SocketEngine::tcpSocketNonBlocking_hostFound()
+{
+ QTestEventLoop::instance().exitLoop();
+}
+
+void tst_QSocks5SocketEngine::tcpSocketNonBlocking_connected()
+{
+ QTestEventLoop::instance().exitLoop();
+}
+
+void tst_QSocks5SocketEngine::tcpSocketNonBlocking_readyRead()
+{
+ while (tcpSocketNonBlocking_socket->canReadLine())
+ tcpSocketNonBlocking_data.append(tcpSocketNonBlocking_socket->readLine());
+
+ QTestEventLoop::instance().exitLoop();
+}
+
+void tst_QSocks5SocketEngine::tcpSocketNonBlocking_bytesWritten(qint64 written)
+{
+ tcpSocketNonBlocking_totalWritten += written;
+ QTestEventLoop::instance().exitLoop();
+}
+
+void tst_QSocks5SocketEngine::tcpSocketNonBlocking_closed()
+{
+}
+
+//----------------------------------------------------------------------------------
+
+void tst_QSocks5SocketEngine::downloadBigFile()
+{
+ QSocks5SocketEngineHandler socks5;
+
+ if (tmpSocket)
+ delete tmpSocket;
+ tmpSocket = new QTcpSocket;
+
+ connect(tmpSocket, SIGNAL(connected()), SLOT(exitLoopSlot()));
+ connect(tmpSocket, SIGNAL(readyRead()), SLOT(downloadBigFileSlot()));
+
+ tmpSocket->connectToHost(QtNetworkSettings::serverName(), 80);
+
+ QTestEventLoop::instance().enterLoop(30);
+ if (QTestEventLoop::instance().timeout())
+ QFAIL("Network operation timed out");
+
+ QByteArray hostName = QtNetworkSettings::serverName().toLatin1();
+ QVERIFY(tmpSocket->state() == QAbstractSocket::ConnectedState);
+ QVERIFY(tmpSocket->write("GET /qtest/mediumfile HTTP/1.0\r\n") > 0);
+ QVERIFY(tmpSocket->write("HOST: ") > 0);
+ QVERIFY(tmpSocket->write(hostName.data()) > 0);
+ QVERIFY(tmpSocket->write("\r\n") > 0);
+ QVERIFY(tmpSocket->write("\r\n") > 0);
+
+ bytesAvailable = 0;
+
+ QTime stopWatch;
+ stopWatch.start();
+
+#if !defined(Q_OS_WINCE) && !defined(Q_OS_SYMBIAN)
+ QTestEventLoop::instance().enterLoop(60);
+#else
+ QTestEventLoop::instance().enterLoop(180);
+#endif
+ if (QTestEventLoop::instance().timeout())
+ QFAIL("Network operation timed out");
+
+ QCOMPARE(bytesAvailable, qint64(10000000));
+
+ QVERIFY(tmpSocket->state() == QAbstractSocket::ConnectedState);
+
+ /*qDebug("\t\t%.1fMB/%.1fs: %.1fMB/s",
+ bytesAvailable / (1024.0 * 1024.0),
+ stopWatch.elapsed() / 1024.0,
+ (bytesAvailable / (stopWatch.elapsed() / 1000.0)) / (1024 * 1024));*/
+
+ delete tmpSocket;
+ tmpSocket = 0;
+}
+
+void tst_QSocks5SocketEngine::exitLoopSlot()
+{
+ QTestEventLoop::instance().exitLoop();
+}
+
+
+void tst_QSocks5SocketEngine::downloadBigFileSlot()
+{
+ QByteArray tmp=tmpSocket->readAll();
+ int correction=tmp.indexOf((char)0,0); //skip header
+ if (correction==-1) correction=0;
+ bytesAvailable += (tmp.size()-correction);
+ if (bytesAvailable >= 10000000)
+ QTestEventLoop::instance().exitLoop();
+}
+
+void tst_QSocks5SocketEngine::passwordAuth()
+{
+ QSocks5SocketEngine socketDevice;
+
+ // Initialize device
+ QVERIFY(socketDevice.initialize(QAbstractSocket::TcpSocket, QAbstractSocket::IPv4Protocol));
+ QVERIFY(socketDevice.state() == QAbstractSocket::UnconnectedState);
+
+ socketDevice.setProxy(QNetworkProxy(QNetworkProxy::Socks5Proxy, QtNetworkSettings::serverName(), 1080, "qsockstest", "password"));
+
+ // Connect to imap.trolltech.com's IP
+ QVERIFY(!socketDevice.connectToHost(QtNetworkSettings::serverIP(), 143));
+ QVERIFY(socketDevice.state() == QAbstractSocket::ConnectingState);
+ QVERIFY(socketDevice.waitForWrite());
+ if (!socketDevice.connectToHost(QtNetworkSettings::serverIP(), 143)) {
+ qDebug("%d, %s", socketDevice.error(), socketDevice.errorString().toLatin1().constData());
+ }
+ QVERIFY(socketDevice.state() == QAbstractSocket::ConnectedState);
+ QVERIFY(socketDevice.peerAddress() == QtNetworkSettings::serverIP());
+
+ // Wait for the greeting
+ QVERIFY(socketDevice.waitForRead());
+
+ // Read the greeting
+ qint64 available = socketDevice.bytesAvailable();
+ QVERIFY(available > 0);
+ QByteArray array;
+ array.resize(available);
+ QVERIFY(socketDevice.read(array.data(), array.size()) == available);
+
+ // Check that the greeting is what we expect it to be
+ QVERIFY2(QtNetworkSettings::compareReplyIMAP(array), array.constData());
+
+ // Write a logout message
+ QByteArray array2 = "XXXX LOGOUT\r\n";
+ QVERIFY(socketDevice.write(array2.data(),
+ array2.size()) == array2.size());
+
+ // Wait for the response
+ QVERIFY(socketDevice.waitForRead());
+
+ available = socketDevice.bytesAvailable();
+ QVERIFY(available > 0);
+ array.resize(available);
+ QVERIFY(socketDevice.read(array.data(), array.size()) == available);
+
+ // Check that the greeting is what we expect it to be
+ QCOMPARE(array.constData(), "* BYE LOGOUT received\r\nXXXX OK Completed\r\n");
+
+ // Wait for the response
+ QVERIFY(socketDevice.waitForRead());
+ char c;
+ QVERIFY(socketDevice.read(&c, sizeof(c)) == -1);
+ QVERIFY(socketDevice.error() == QAbstractSocket::RemoteHostClosedError);
+ QVERIFY(socketDevice.state() == QAbstractSocket::UnconnectedState);
+}
+
+//----------------------------------------------------------------------------------
+
+void tst_QSocks5SocketEngine::proxyAuthenticationRequired(const QNetworkProxy &,
+ QAuthenticator *auth)
+{
+ auth->setUser("qsockstest");
+ auth->setPassword("password");
+}
+
+void tst_QSocks5SocketEngine::passwordAuth2()
+{
+ QSocks5SocketEngine socketDevice;
+
+ // Initialize device
+ QVERIFY(socketDevice.initialize(QAbstractSocket::TcpSocket, QAbstractSocket::IPv4Protocol));
+ QVERIFY(socketDevice.state() == QAbstractSocket::UnconnectedState);
+
+ socketDevice.setProxy(QNetworkProxy(QNetworkProxy::Socks5Proxy, QtNetworkSettings::serverName(), 1081));
+ socketDevice.setReceiver(this);
+
+ QVERIFY(!socketDevice.connectToHost(QtNetworkSettings::serverIP(), 143));
+ QVERIFY(socketDevice.state() == QAbstractSocket::ConnectingState);
+ while (socketDevice.state() == QAbstractSocket::ConnectingState) {
+ QVERIFY(socketDevice.waitForWrite());
+ socketDevice.connectToHost(QtNetworkSettings::serverIP(), 143);
+ }
+ if (socketDevice.state() != QAbstractSocket::ConnectedState)
+ qDebug("%d, %s", socketDevice.error(), socketDevice.errorString().toLatin1().constData());
+ QVERIFY(socketDevice.state() == QAbstractSocket::ConnectedState);
+ QVERIFY(socketDevice.peerAddress() == QtNetworkSettings::serverIP());
+
+ // Wait for the greeting
+ QVERIFY(socketDevice.waitForRead());
+
+ // Read the greeting
+ qint64 available = socketDevice.bytesAvailable();
+ QVERIFY(available > 0);
+ QByteArray array;
+ array.resize(available);
+ QVERIFY(socketDevice.read(array.data(), array.size()) == available);
+
+ // Check that the greeting is what we expect it to be
+ QVERIFY2(QtNetworkSettings::compareReplyIMAP(array), array.constData());
+
+ // Write a logout message
+ QByteArray array2 = "XXXX LOGOUT\r\n";
+ QVERIFY(socketDevice.write(array2.data(),
+ array2.size()) == array2.size());
+
+ // Wait for the response
+ QVERIFY(socketDevice.waitForRead());
+
+ available = socketDevice.bytesAvailable();
+ QVERIFY(available > 0);
+ array.resize(available);
+ QVERIFY(socketDevice.read(array.data(), array.size()) == available);
+
+ // Check that the greeting is what we expect it to be
+ QCOMPARE(array.constData(), "* BYE LOGOUT received\r\nXXXX OK Completed\r\n");
+
+ // Wait for the response
+ QVERIFY(socketDevice.waitForRead());
+ char c;
+ QVERIFY(socketDevice.read(&c, sizeof(c)) == -1);
+ QVERIFY(socketDevice.error() == QAbstractSocket::RemoteHostClosedError);
+ QVERIFY(socketDevice.state() == QAbstractSocket::UnconnectedState);
+}
+
+//----------------------------------------------------------------------------------
+
+QTEST_MAIN(tst_QSocks5SocketEngine)
+#include "tst_qsocks5socketengine.moc"
diff --git a/tests/auto/network/socket/qtcpserver/.gitignore b/tests/auto/network/socket/qtcpserver/.gitignore
new file mode 100644
index 0000000000..c00e0a4ca9
--- /dev/null
+++ b/tests/auto/network/socket/qtcpserver/.gitignore
@@ -0,0 +1,3 @@
+tst_qtcpserver
+crashingServer/crashingServer
+crashingServer/crashingServer.exe
diff --git a/tests/auto/network/socket/qtcpserver/crashingServer/crashingServer.pro b/tests/auto/network/socket/qtcpserver/crashingServer/crashingServer.pro
new file mode 100644
index 0000000000..700e9520ec
--- /dev/null
+++ b/tests/auto/network/socket/qtcpserver/crashingServer/crashingServer.pro
@@ -0,0 +1,9 @@
+SOURCES += main.cpp
+QT = core network
+CONFIG -= app_bundle
+DESTDIR = ./
+
+# This means the auto test works on some machines for MinGW. No dialog stalls
+# the application.
+win32-g++*:CONFIG += console
+symbian: TARGET.CAPABILITY += NetworkServices ReadUserData
diff --git a/tests/auto/network/socket/qtcpserver/crashingServer/main.cpp b/tests/auto/network/socket/qtcpserver/crashingServer/main.cpp
new file mode 100644
index 0000000000..35da65f671
--- /dev/null
+++ b/tests/auto/network/socket/qtcpserver/crashingServer/main.cpp
@@ -0,0 +1,70 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+
+#include <QtCore>
+#include <QtNetwork>
+
+int main(int argc, char *argv[])
+{
+ QCoreApplication app(argc, argv);
+
+ QTcpServer server;
+ if (!server.listen(QHostAddress::LocalHost, 49199)) {
+ qDebug("Failed to listen: %s", server.errorString().toLatin1().constData());
+ return 1;
+ }
+
+#if defined(Q_OS_WINCE) || defined(Q_OS_SYMBIAN)
+ QFile file(QLatin1String("/test_signal.txt"));
+ file.open(QIODevice::WriteOnly);
+ file.write("Listening\n");
+ file.flush();
+ file.close();
+#else
+ printf("Listening\n");
+ fflush(stdout);
+#endif
+
+ server.waitForNewConnection(5000);
+ qFatal("Crash");
+ return 0;
+}
diff --git a/tests/auto/network/socket/qtcpserver/qtcpserver.pro b/tests/auto/network/socket/qtcpserver/qtcpserver.pro
new file mode 100644
index 0000000000..e123cfe73b
--- /dev/null
+++ b/tests/auto/network/socket/qtcpserver/qtcpserver.pro
@@ -0,0 +1,4 @@
+TEMPLATE = subdirs
+SUBDIRS = test crashingServer
+
+
diff --git a/tests/auto/network/socket/qtcpserver/test/test.pro b/tests/auto/network/socket/qtcpserver/test/test.pro
new file mode 100644
index 0000000000..65e1d82613
--- /dev/null
+++ b/tests/auto/network/socket/qtcpserver/test/test.pro
@@ -0,0 +1,37 @@
+load(qttest_p4)
+SOURCES += ../tst_qtcpserver.cpp
+
+win32: {
+wince*: {
+ LIBS += -lws2
+ crashApp.files = ../crashingServer/crashingServer.exe
+ crashApp.path = crashingServer
+ DEPLOYMENT += crashApp
+} else {
+ LIBS += -lws2_32
+}
+}
+
+symbian {
+ crashApp.files = $$QT_BUILD_TREE/examples/widgets/wiggly/$${BUILD_DIR}/crashingServer.exe
+ crashApp.path = .
+ DEPLOYMENT += crashApp
+ TARGET.CAPABILITY += NetworkServices ReadUserData
+}
+
+TARGET = ../tst_qtcpserver
+
+win32 {
+ CONFIG(debug, debug|release) {
+ TARGET = ../../debug/tst_qtcpserver
+} else {
+ TARGET = ../../release/tst_qtcpserver
+ }
+}
+
+QT = core network
+
+MOC_DIR=tmp
+
+
+
diff --git a/tests/auto/network/socket/qtcpserver/tst_qtcpserver.cpp b/tests/auto/network/socket/qtcpserver/tst_qtcpserver.cpp
new file mode 100644
index 0000000000..ca28a9c7c8
--- /dev/null
+++ b/tests/auto/network/socket/qtcpserver/tst_qtcpserver.cpp
@@ -0,0 +1,817 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+// Just to get Q_OS_SYMBIAN
+#include <qglobal.h>
+#if defined(_WIN32) && !defined(Q_OS_SYMBIAN)
+#include <winsock2.h>
+#else
+#include <sys/types.h>
+#include <sys/socket.h>
+#define SOCKET int
+#define INVALID_SOCKET -1
+#endif
+
+#include <QtTest/QtTest>
+
+#ifndef Q_OS_WIN
+#include <unistd.h>
+#include <sys/ioctl.h>
+#endif
+
+#include <qcoreapplication.h>
+#include <qtcpsocket.h>
+#include <qtcpserver.h>
+#include <qhostaddress.h>
+#include <qprocess.h>
+#include <qstringlist.h>
+#include <qplatformdefs.h>
+#include <qhostinfo.h>
+
+#include <QNetworkProxy>
+Q_DECLARE_METATYPE(QNetworkProxy)
+Q_DECLARE_METATYPE(QList<QNetworkProxy>)
+
+#include <QNetworkSession>
+#include <QNetworkConfiguration>
+#include <QNetworkConfigurationManager>
+#include "../../../network-settings.h"
+
+//TESTED_CLASS=
+//TESTED_FILES=
+
+class tst_QTcpServer : public QObject
+{
+ Q_OBJECT
+
+public:
+ tst_QTcpServer();
+ virtual ~tst_QTcpServer();
+
+
+public slots:
+ void initTestCase_data();
+ void initTestCase();
+ void init();
+ void cleanup();
+private slots:
+ void getSetCheck();
+ void constructing();
+ void clientServerLoop();
+ void ipv6Server();
+ void dualStack_data();
+ void dualStack();
+ void ipv6ServerMapped();
+ void crashTests();
+ void maxPendingConnections();
+ void listenError();
+ void waitForConnectionTest();
+ void setSocketDescriptor();
+ void listenWhileListening();
+ void addressReusable();
+ void setNewSocketDescriptorBlocking();
+ void invalidProxy_data();
+ void invalidProxy();
+ void proxyFactory_data();
+ void proxyFactory();
+
+ void qtbug14268_peek();
+
+private:
+#ifndef QT_NO_BEARERMANAGEMENT
+ QNetworkSession *networkSession;
+#endif
+};
+
+// Testing get/set functions
+void tst_QTcpServer::getSetCheck()
+{
+ QTcpServer obj1;
+ // int QTcpServer::maxPendingConnections()
+ // void QTcpServer::setMaxPendingConnections(int)
+ obj1.setMaxPendingConnections(0);
+ QCOMPARE(0, obj1.maxPendingConnections());
+ obj1.setMaxPendingConnections(INT_MIN);
+ QCOMPARE(INT_MIN, obj1.maxPendingConnections());
+ obj1.setMaxPendingConnections(INT_MAX);
+ QCOMPARE(INT_MAX, obj1.maxPendingConnections());
+}
+
+tst_QTcpServer::tst_QTcpServer()
+{
+ Q_SET_DEFAULT_IAP
+}
+
+tst_QTcpServer::~tst_QTcpServer()
+{
+}
+
+void tst_QTcpServer::initTestCase_data()
+{
+ QTest::addColumn<bool>("setProxy");
+ QTest::addColumn<int>("proxyType");
+
+ QTest::newRow("WithoutProxy") << false << 0;
+ QTest::newRow("WithSocks5Proxy") << true << int(QNetworkProxy::Socks5Proxy);
+}
+
+void tst_QTcpServer::initTestCase()
+{
+#ifndef QT_NO_BEARERMANAGEMENT
+ QNetworkConfigurationManager man;
+ networkSession = new QNetworkSession(man.defaultConfiguration(), this);
+ networkSession->open();
+ QVERIFY(networkSession->waitForOpened());
+#endif
+}
+
+void tst_QTcpServer::init()
+{
+ QFETCH_GLOBAL(bool, setProxy);
+ if (setProxy) {
+ QFETCH_GLOBAL(int, proxyType);
+ if (proxyType == QNetworkProxy::Socks5Proxy) {
+ QNetworkProxy::setApplicationProxy(QNetworkProxy(QNetworkProxy::Socks5Proxy, QtNetworkSettings::serverName(), 1080));
+ }
+ }
+}
+
+void tst_QTcpServer::cleanup()
+{
+ QNetworkProxy::setApplicationProxy(QNetworkProxy::DefaultProxy);
+}
+
+//----------------------------------------------------------------------------------
+
+void tst_QTcpServer::constructing()
+{
+ QTcpServer socket;
+
+ // Check the initial state of the QTcpSocket.
+ QCOMPARE(socket.isListening(), false);
+ QCOMPARE((int)socket.serverPort(), 0);
+ QCOMPARE(socket.serverAddress(), QHostAddress());
+ QCOMPARE(socket.maxPendingConnections(), 30);
+ QCOMPARE(socket.hasPendingConnections(), false);
+ QCOMPARE(socket.socketDescriptor(), -1);
+ QCOMPARE(socket.serverError(), QAbstractSocket::UnknownSocketError);
+
+ // Check the state of the socket layer?
+}
+
+//----------------------------------------------------------------------------------
+void tst_QTcpServer::clientServerLoop()
+{
+ QTcpServer server;
+
+ QSignalSpy spy(&server, SIGNAL(newConnection()));
+
+ QVERIFY(!server.isListening());
+ QVERIFY(!server.hasPendingConnections());
+ QVERIFY(server.listen(QHostAddress::Any, 11423));
+ QVERIFY(server.isListening());
+
+ QTcpSocket client;
+
+ QHostAddress serverAddress = QHostAddress::LocalHost;
+ if (!(server.serverAddress() == QHostAddress::Any) && !(server.serverAddress() == QHostAddress::AnyIPv6))
+ serverAddress = server.serverAddress();
+
+ client.connectToHost(serverAddress, server.serverPort());
+ QVERIFY(client.waitForConnected(5000));
+
+ QVERIFY(server.waitForNewConnection(5000));
+ QVERIFY(server.hasPendingConnections());
+
+ QCOMPARE(spy.count(), 1);
+
+ QTcpSocket *serverSocket = server.nextPendingConnection();
+ QVERIFY(serverSocket != 0);
+
+ QVERIFY(serverSocket->write("Greetings, client!\n", 19) == 19);
+ serverSocket->flush();
+
+ QVERIFY(client.waitForReadyRead(5000));
+ QByteArray arr = client.readAll();
+ QCOMPARE(arr.constData(), "Greetings, client!\n");
+
+ QVERIFY(client.write("Well, hello to you!\n", 20) == 20);
+ client.flush();
+
+ QVERIFY(serverSocket->waitForReadyRead(5000));
+ arr = serverSocket->readAll();
+ QCOMPARE(arr.constData(), "Well, hello to you!\n");
+}
+
+//----------------------------------------------------------------------------------
+void tst_QTcpServer::ipv6Server()
+{
+ //### need to enter the event loop for the server to get the connection ?? ( windows)
+ QTcpServer server;
+ if (!server.listen(QHostAddress::LocalHostIPv6, 8944)) {
+ QVERIFY(server.serverError() == QAbstractSocket::UnsupportedSocketOperationError);
+ return;
+ }
+
+ QVERIFY(server.serverPort() == 8944);
+ QVERIFY(server.serverAddress() == QHostAddress::LocalHostIPv6);
+
+ QTcpSocket client;
+ client.connectToHost("::1", 8944);
+ QVERIFY(client.waitForConnected(5000));
+
+ QVERIFY(server.waitForNewConnection());
+ QVERIFY(server.hasPendingConnections());
+
+ QTcpSocket *serverSocket = 0;
+ QVERIFY((serverSocket = server.nextPendingConnection()));
+ serverSocket->close();
+ delete serverSocket;
+}
+
+Q_DECLARE_METATYPE(QHostAddress);
+
+void tst_QTcpServer::dualStack_data()
+{
+ QTest::addColumn<QHostAddress>("bindAddress");
+ QTest::addColumn<bool>("v4ok");
+ QTest::addColumn<bool>("v6ok");
+ QTest::newRow("any") << QHostAddress(QHostAddress::Any) << true << true;
+ QTest::newRow("anyIPv4") << QHostAddress(QHostAddress::AnyIPv4) << true << false;
+ QTest::newRow("anyIPv6") << QHostAddress(QHostAddress::AnyIPv6) << false << true;
+}
+
+void tst_QTcpServer::dualStack()
+{
+ QFETCH_GLOBAL(bool, setProxy);
+ if (setProxy)
+ QSKIP("test server proxy doesn't support ipv6", SkipSingle);
+ QFETCH(QHostAddress, bindAddress);
+ QFETCH(bool, v4ok);
+ QFETCH(bool, v6ok);
+
+ QTcpServer server;
+ QVERIFY(server.listen(bindAddress));
+
+ QTcpSocket v4client;
+ v4client.connectToHost(QHostAddress::LocalHost, server.serverPort());
+
+ QTcpSocket v6client;
+ v6client.connectToHost(QHostAddress::LocalHostIPv6, server.serverPort());
+
+ QCOMPARE(v4client.waitForConnected(5000), v4ok);
+ QCOMPARE(v6client.waitForConnected(5000), v6ok);
+}
+
+//----------------------------------------------------------------------------------
+void tst_QTcpServer::ipv6ServerMapped()
+{
+ QFETCH_GLOBAL(bool, setProxy);
+ if (setProxy)
+ return;
+
+ QTcpServer server;
+ QVERIFY(server.listen(QHostAddress::LocalHost));
+
+ // let's try the normal case
+ QTcpSocket client1;
+ client1.connectToHost("127.0.0.1", server.serverPort());
+ QVERIFY(server.waitForNewConnection(5000));
+ delete server.nextPendingConnection();
+
+ // let's try the mapped one in the nice format
+ QTcpSocket client2;
+ client2.connectToHost("::ffff:127.0.0.1", server.serverPort());
+ QVERIFY(server.waitForNewConnection(5000));
+ delete server.nextPendingConnection();
+
+ // let's try the mapped in hex format
+ QTcpSocket client3;
+ client3.connectToHost("::ffff:7F00:0001", server.serverPort());
+ QVERIFY(server.waitForNewConnection(5000));
+ delete server.nextPendingConnection();
+
+ // However connecting to the v6 localhost should not work
+ QTcpSocket client4;
+ client4.connectToHost("::1", server.serverPort());
+ QVERIFY(!server.waitForNewConnection(5000));
+}
+
+//----------------------------------------------------------------------------------
+void tst_QTcpServer::crashTests()
+{
+ QTcpServer server;
+ server.close();
+ QVERIFY(server.listen());
+}
+
+//----------------------------------------------------------------------------------
+void tst_QTcpServer::maxPendingConnections()
+{
+ QFETCH_GLOBAL(bool, setProxy);
+ if (setProxy) {
+ QFETCH_GLOBAL(int, proxyType);
+ if (proxyType == QNetworkProxy::Socks5Proxy) {
+ QSKIP("With socks5 only 1 connection is allowed ever", SkipAll);
+ }
+ }
+ //### sees to fail sometimes ... a timing issue with the test on windows
+ QTcpServer server;
+ server.setMaxPendingConnections(2);
+
+ QTcpSocket socket1;
+ QTcpSocket socket2;
+ QTcpSocket socket3;
+
+ QVERIFY(server.listen());
+
+ socket1.connectToHost(QHostAddress::LocalHost, server.serverPort());
+ socket2.connectToHost(QHostAddress::LocalHost, server.serverPort());
+ socket3.connectToHost(QHostAddress::LocalHost, server.serverPort());
+
+ QVERIFY(server.waitForNewConnection(5000));
+
+ QVERIFY(server.hasPendingConnections());
+ QVERIFY(server.nextPendingConnection());
+ QVERIFY(server.hasPendingConnections());
+ QVERIFY(server.nextPendingConnection());
+ QVERIFY(!server.hasPendingConnections());
+ QCOMPARE(server.nextPendingConnection(), (QTcpSocket*)0);
+
+ QVERIFY(server.waitForNewConnection(5000));
+
+ QVERIFY(server.hasPendingConnections());
+ QVERIFY(server.nextPendingConnection());
+}
+
+//----------------------------------------------------------------------------------
+void tst_QTcpServer::listenError()
+{
+ QFETCH_GLOBAL(bool, setProxy);
+ if (setProxy) {
+ QFETCH_GLOBAL(int, proxyType);
+ if (proxyType == QNetworkProxy::Socks5Proxy) {
+ QSKIP("With socks5 we can not make hard requirements on the address or port", SkipAll);
+ }
+ }
+ QTcpServer server;
+ QVERIFY(!server.listen(QHostAddress("1.2.3.4"), 0));
+ QCOMPARE(server.serverError(), QAbstractSocket::SocketAddressNotAvailableError);
+ QCOMPARE(server.errorString().toLatin1().constData(), "The address is not available");
+}
+
+class ThreadConnector : public QThread
+{
+public:
+ ThreadConnector(const QHostAddress &host, quint16 port)
+ : host(host), port(port)
+ { }
+
+ ~ThreadConnector()
+ {
+ wait();
+ }
+
+protected:
+ void run()
+ {
+ sleep(2);
+
+ QTcpSocket socket;
+ socket.connectToHost(host, port);
+
+ QEventLoop loop;
+ QTimer::singleShot(5000, &loop, SLOT(quit()));
+ loop.exec();
+ }
+
+private:
+ QHostAddress host;
+ quint16 port;
+};
+
+//----------------------------------------------------------------------------------
+void tst_QTcpServer::waitForConnectionTest()
+{
+
+ QFETCH_GLOBAL(bool, setProxy);
+ if (setProxy) {
+ QFETCH_GLOBAL(int, proxyType);
+ if (proxyType == QNetworkProxy::Socks5Proxy) {
+ QSKIP("Localhost servers don't work well with SOCKS5", SkipAll);
+ }
+ }
+
+ QTcpSocket findLocalIpSocket;
+ findLocalIpSocket.connectToHost(QtNetworkSettings::serverName(), 143);
+ QVERIFY(findLocalIpSocket.waitForConnected(5000));
+
+ QTcpServer server;
+ bool timeout = false;
+ QVERIFY(server.listen(findLocalIpSocket.localAddress()));
+ QVERIFY(!server.waitForNewConnection(1000, &timeout));
+ QCOMPARE(server.serverError(), QAbstractSocket::SocketTimeoutError);
+ QVERIFY(timeout);
+
+ ThreadConnector connector(findLocalIpSocket.localAddress(), server.serverPort());
+ connector.start();
+
+#if defined(Q_OS_WINCE) || defined(Q_OS_SYMBIAN)
+ QVERIFY(server.waitForNewConnection(9000, &timeout));
+#else
+ QVERIFY(server.waitForNewConnection(3000, &timeout));
+#endif
+ QVERIFY(!timeout);
+}
+
+//----------------------------------------------------------------------------------
+void tst_QTcpServer::setSocketDescriptor()
+{
+ QTcpServer server;
+#ifdef Q_OS_SYMBIAN
+ QTest::ignoreMessage(QtWarningMsg, "QSymbianSocketEngine::initialize - socket descriptor not found");
+#endif
+ QVERIFY(!server.setSocketDescriptor(42));
+ QCOMPARE(server.serverError(), QAbstractSocket::UnsupportedSocketOperationError);
+#ifndef Q_OS_SYMBIAN
+ //adopting Open C sockets is not supported, neither is adopting externally created RSocket
+#ifdef Q_OS_WIN
+ // ensure winsock is started
+ WSADATA wsaData;
+ QVERIFY(WSAStartup(MAKEWORD(2,0), &wsaData) == NO_ERROR);
+#endif
+
+ SOCKET sock = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+
+ QVERIFY(sock != INVALID_SOCKET);
+
+ sockaddr_in sin;
+ memset(&sin, 0, sizeof(sockaddr_in));
+ sin.sin_family = AF_INET;
+ sin.sin_port = 0;
+ sin.sin_addr.s_addr = 0x00000000;
+ QVERIFY(::bind(sock, (sockaddr*)&sin, sizeof(sockaddr_in)) == 0);
+ QVERIFY(::listen(sock, 10) == 0);
+ QVERIFY(server.setSocketDescriptor(sock));
+
+#ifdef Q_OS_WIN
+ WSACleanup();
+#endif
+#endif
+}
+
+//----------------------------------------------------------------------------------
+void tst_QTcpServer::listenWhileListening()
+{
+ QTcpServer server;
+ QVERIFY(server.listen());
+ QTest::ignoreMessage(QtWarningMsg, "QTcpServer::listen() called when already listening");
+ QVERIFY(!server.listen());
+}
+
+//----------------------------------------------------------------------------------
+
+class SeverWithBlockingSockets : public QTcpServer
+{
+public:
+ SeverWithBlockingSockets()
+ : ok(false) { }
+
+ bool ok;
+
+protected:
+ void incomingConnection(int socketDescriptor)
+ {
+ // how a user woulddo it (qabstractsocketengine is not public)
+ unsigned long arg = 0;
+#if defined(Q_OS_SYMBIAN)
+ arg = fcntl(socketDescriptor, F_GETFL, NULL);
+ arg &= (~O_NONBLOCK);
+ ok = ::fcntl(socketDescriptor, F_SETFL, arg) != -1;
+#elif defined(Q_OS_WIN)
+ ok = ::ioctlsocket(socketDescriptor, FIONBIO, &arg) == 0;
+ ::closesocket(socketDescriptor);
+#else
+ ok = ::ioctl(socketDescriptor, FIONBIO, &arg) == 0;
+ ::close(socketDescriptor);
+#endif
+ }
+};
+
+void tst_QTcpServer::addressReusable()
+{
+#if defined(Q_OS_SYMBIAN) && defined(Q_CC_NOKIAX86)
+ QSKIP("Symbian: Emulator does not support process launching", SkipAll );
+#endif
+
+#if defined(QT_NO_PROCESS)
+ QSKIP("Qt was compiled with QT_NO_PROCESS", SkipAll);
+#else
+
+ QFETCH_GLOBAL(bool, setProxy);
+ if (setProxy) {
+ QFETCH_GLOBAL(int, proxyType);
+ if (proxyType == QNetworkProxy::Socks5Proxy) {
+ QSKIP("With socks5 this test does not make senans at the momment", SkipAll);
+ }
+ }
+#if defined(Q_OS_WINCE) || defined(Q_OS_SYMBIAN)
+ QString signalName = QString::fromLatin1("/test_signal.txt");
+ QFile::remove(signalName);
+ // The crashingServer process will crash once it gets a connection.
+ QProcess process;
+ process.start("crashingServer/crashingServer");
+ int waitCount = 5;
+ while (waitCount-- && !QFile::exists(signalName))
+ QTest::qWait(1000);
+ QVERIFY(QFile::exists(signalName));
+ QFile::remove(signalName);
+#else
+ // The crashingServer process will crash once it gets a connection.
+ QProcess process;
+ process.start("crashingServer/crashingServer");
+ QVERIFY(process.waitForReadyRead(5000));
+#endif
+
+ QTcpSocket socket;
+ socket.connectToHost(QHostAddress::LocalHost, 49199);
+ QVERIFY(socket.waitForConnected(5000));
+
+ QVERIFY(process.waitForFinished(30000));
+
+ // Give the system some time.
+ QTest::qSleep(10);
+
+ QTcpServer server;
+ QVERIFY(server.listen(QHostAddress::LocalHost, 49199));
+#endif
+}
+
+void tst_QTcpServer::setNewSocketDescriptorBlocking()
+{
+#ifdef Q_OS_SYMBIAN
+ QSKIP("open C ioctls on Qt sockets not supported", SkipAll);
+#else
+ QFETCH_GLOBAL(bool, setProxy);
+ if (setProxy) {
+ QFETCH_GLOBAL(int, proxyType);
+ if (proxyType == QNetworkProxy::Socks5Proxy) {
+ QSKIP("With socks5 we can not make the socket descripter blocking", SkipAll);
+ }
+ }
+ SeverWithBlockingSockets server;
+ QVERIFY(server.listen());
+
+ QTcpSocket socket;
+ socket.connectToHost(QHostAddress::LocalHost, server.serverPort());
+ QVERIFY(server.waitForNewConnection(5000));
+ QVERIFY(server.ok);
+#endif
+}
+
+void tst_QTcpServer::invalidProxy_data()
+{
+ QTest::addColumn<int>("type");
+ QTest::addColumn<QString>("host");
+ QTest::addColumn<int>("port");
+ QTest::addColumn<int>("expectedError");
+
+ QString fluke = QHostInfo::fromName(QtNetworkSettings::serverName()).addresses().first().toString();
+ QTest::newRow("ftp-proxy") << int(QNetworkProxy::FtpCachingProxy) << fluke << 143
+ << int(QAbstractSocket::UnsupportedSocketOperationError);
+ QTest::newRow("http-proxy") << int(QNetworkProxy::HttpProxy) << fluke << 3128
+ << int(QAbstractSocket::UnsupportedSocketOperationError);
+
+ QTest::newRow("no-such-host") << int(QNetworkProxy::Socks5Proxy)
+ << "this-host-will-never-exist.troll.no" << 1080
+ << int(QAbstractSocket::ProxyNotFoundError);
+ QTest::newRow("socks5-on-http") << int(QNetworkProxy::Socks5Proxy) << fluke << 3128
+ << int(QAbstractSocket::SocketTimeoutError);
+}
+
+void tst_QTcpServer::invalidProxy()
+{
+ QFETCH_GLOBAL(bool, setProxy);
+ if (setProxy)
+ return;
+
+ QFETCH(int, type);
+ QFETCH(QString, host);
+ QFETCH(int, port);
+ QNetworkProxy::ProxyType proxyType = QNetworkProxy::ProxyType(type);
+ QNetworkProxy proxy(proxyType, host, port);
+
+ QTcpServer server;
+ server.setProxy(proxy);
+ bool listenResult = server.listen();
+
+ QVERIFY(!listenResult);
+ QVERIFY(!server.errorString().isEmpty());
+
+ // note: the following test is not a hard failure.
+ // Sometimes, error codes change for the better
+ QTEST(int(server.serverError()), "expectedError");
+}
+
+// copied from tst_qnetworkreply.cpp
+class MyProxyFactory: public QNetworkProxyFactory
+{
+public:
+ int callCount;
+ QList<QNetworkProxy> toReturn;
+ QNetworkProxyQuery lastQuery;
+ inline MyProxyFactory() { clear(); }
+
+ inline void clear()
+ {
+ callCount = 0;
+ toReturn = QList<QNetworkProxy>() << QNetworkProxy::DefaultProxy;
+ lastQuery = QNetworkProxyQuery();
+ }
+
+ virtual QList<QNetworkProxy> queryProxy(const QNetworkProxyQuery &query)
+ {
+ lastQuery = query;
+ ++callCount;
+ return toReturn;
+ }
+};
+
+void tst_QTcpServer::proxyFactory_data()
+{
+ QTest::addColumn<QList<QNetworkProxy> >("proxyList");
+ QTest::addColumn<QNetworkProxy>("proxyUsed");
+ QTest::addColumn<bool>("fails");
+ QTest::addColumn<int>("expectedError");
+
+ QList<QNetworkProxy> proxyList;
+
+ // tests that do get to listen
+
+ proxyList << QNetworkProxy(QNetworkProxy::Socks5Proxy, QtNetworkSettings::serverName(), 1080);
+ QTest::newRow("socks5")
+ << proxyList << proxyList.at(0)
+ << false << int(QAbstractSocket::UnknownSocketError);
+
+ proxyList.clear();
+ proxyList << QNetworkProxy(QNetworkProxy::HttpCachingProxy, QtNetworkSettings::serverName(), 3128)
+ << QNetworkProxy(QNetworkProxy::Socks5Proxy, QtNetworkSettings::serverName(), 1080);
+ QTest::newRow("cachinghttp+socks5")
+ << proxyList << proxyList.at(1)
+ << false << int(QAbstractSocket::UnknownSocketError);
+
+ proxyList.clear();
+ proxyList << QNetworkProxy(QNetworkProxy::FtpCachingProxy, QtNetworkSettings::serverName(), 2121)
+ << QNetworkProxy(QNetworkProxy::HttpCachingProxy, QtNetworkSettings::serverName(), 3128)
+ << QNetworkProxy(QNetworkProxy::Socks5Proxy, QtNetworkSettings::serverName(), 1080);
+ QTest::newRow("ftp+cachinghttp+socks5")
+ << proxyList << proxyList.at(2)
+ << false << int(QAbstractSocket::UnknownSocketError);
+
+ // tests that fail to listen
+ proxyList.clear();
+ proxyList << QNetworkProxy(QNetworkProxy::HttpProxy, QtNetworkSettings::serverName(), 3128);
+ QTest::newRow("http")
+ << proxyList << proxyList.at(0)
+ << true << int(QAbstractSocket::UnsupportedSocketOperationError);
+
+ proxyList.clear();
+ proxyList << QNetworkProxy(QNetworkProxy::HttpCachingProxy, QtNetworkSettings::serverName(), 3128);
+ QTest::newRow("cachinghttp")
+ << proxyList << QNetworkProxy()
+ << true << int(QAbstractSocket::UnsupportedSocketOperationError);
+
+ proxyList.clear();
+ proxyList << QNetworkProxy(QNetworkProxy::FtpCachingProxy, QtNetworkSettings::serverName(), 2121);
+ QTest::newRow("ftp")
+ << proxyList << QNetworkProxy()
+ << true << int(QAbstractSocket::UnsupportedSocketOperationError);
+
+ proxyList.clear();
+ proxyList << QNetworkProxy(QNetworkProxy::FtpCachingProxy, QtNetworkSettings::serverName(), 2121)
+ << QNetworkProxy(QNetworkProxy::HttpCachingProxy, QtNetworkSettings::serverName(), 3128);
+ QTest::newRow("ftp+cachinghttp")
+ << proxyList << QNetworkProxy()
+ << true << int(QAbstractSocket::UnsupportedSocketOperationError);
+}
+
+void tst_QTcpServer::proxyFactory()
+{
+ QFETCH_GLOBAL(bool, setProxy);
+ if (setProxy)
+ return;
+
+ QFETCH(QList<QNetworkProxy>, proxyList);
+ QFETCH(QNetworkProxy, proxyUsed);
+ QFETCH(bool, fails);
+
+ MyProxyFactory *factory = new MyProxyFactory;
+ factory->toReturn = proxyList;
+ QNetworkProxyFactory::setApplicationProxyFactory(factory);
+
+ QTcpServer server;
+ bool listenResult = server.listen();
+
+ // Verify that the factory was called properly
+ QCOMPARE(factory->callCount, 1);
+ QCOMPARE(factory->lastQuery, QNetworkProxyQuery(0, QString(), QNetworkProxyQuery::TcpServer));
+
+ QCOMPARE(listenResult, !fails);
+ QCOMPARE(server.errorString().isEmpty(), !fails);
+
+ // note: the following test is not a hard failure.
+ // Sometimes, error codes change for the better
+ QTEST(int(server.serverError()), "expectedError");
+}
+
+class Qtbug14268Helper : public QObject
+{
+ Q_OBJECT
+public:
+ QByteArray lastDataPeeked;
+public slots:
+ void newConnection() {
+ QTcpServer* server=static_cast<QTcpServer*>(sender());
+ QTcpSocket* s=server->nextPendingConnection();
+ connect(s,SIGNAL(readyRead()),this,SLOT(onServerReadyRead()));
+ }
+ void onServerReadyRead() {
+ QTcpSocket* clientSocket=static_cast<QTcpSocket*>(sender());
+ lastDataPeeked = clientSocket->peek(128*1024).toHex();
+ QTestEventLoop::instance().exitLoop();
+ }
+};
+
+// there is a similar test inside tst_qtcpsocket that uses the waitFor* functions instead
+void tst_QTcpServer::qtbug14268_peek()
+{
+ QFETCH_GLOBAL(bool, setProxy);
+ if (setProxy)
+ return;
+
+ QTcpServer server;
+ server.listen();
+
+ Qtbug14268Helper helper;
+ QObject::connect(&server, SIGNAL(newConnection()), &helper, SLOT(newConnection()));
+
+ QTcpSocket client;
+ client.connectToHost(QHostAddress::LocalHost, server.serverPort());
+ QVERIFY(client.waitForConnected(2000));
+
+ client.write("abc\n");
+ QTestEventLoop::instance().enterLoop(5);
+ QVERIFY(!QTestEventLoop::instance().timeout());
+ QVERIFY(helper.lastDataPeeked == QByteArray("6162630a"));
+
+ client.write("def\n");
+ QTestEventLoop::instance().enterLoop(5);
+ QVERIFY(!QTestEventLoop::instance().timeout());
+ QVERIFY(helper.lastDataPeeked == QByteArray("6162630a6465660a"));
+
+ client.write("ghi\n");
+ QTestEventLoop::instance().enterLoop(5);
+ QVERIFY(!QTestEventLoop::instance().timeout());
+ QVERIFY(helper.lastDataPeeked == QByteArray("6162630a6465660a6768690a"));
+}
+
+QTEST_MAIN(tst_QTcpServer)
+#include "tst_qtcpserver.moc"
diff --git a/tests/auto/network/socket/qtcpsocket/.gitignore b/tests/auto/network/socket/qtcpsocket/.gitignore
new file mode 100644
index 0000000000..d456ab15d0
--- /dev/null
+++ b/tests/auto/network/socket/qtcpsocket/.gitignore
@@ -0,0 +1,3 @@
+tst_qtcpsocket
+stressTest/stressTest
+crashingServer/crashingServer
diff --git a/tests/auto/network/socket/qtcpsocket/qtcpsocket.pro b/tests/auto/network/socket/qtcpsocket/qtcpsocket.pro
new file mode 100644
index 0000000000..5dfff5bb88
--- /dev/null
+++ b/tests/auto/network/socket/qtcpsocket/qtcpsocket.pro
@@ -0,0 +1,8 @@
+TEMPLATE = subdirs
+
+
+!wince*: SUBDIRS = test stressTest
+wince*|symbian|vxworks* : SUBDIRS = test
+
+
+requires(contains(QT_CONFIG,private_tests))
diff --git a/tests/auto/network/socket/qtcpsocket/stressTest/Test.cpp b/tests/auto/network/socket/qtcpsocket/stressTest/Test.cpp
new file mode 100644
index 0000000000..995fc0528c
--- /dev/null
+++ b/tests/auto/network/socket/qtcpsocket/stressTest/Test.cpp
@@ -0,0 +1,146 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+// Qt
+#include <QByteArray>
+#include <QCoreApplication>
+#include <QDataStream>
+#include <QTimer>
+
+// Test
+#include "Test.h"
+
+//------------------------------------------------------------------------------
+My4Socket::My4Socket(QObject *parent)
+ : QTcpSocket(parent), safeShutDown(false)
+{
+ connect(this, SIGNAL(readyRead()), this, SLOT(read()));
+ connect(this, SIGNAL(disconnected()), this, SLOT(closed()));
+}
+
+//------------------------------------------------------------------------------
+void My4Socket::read(void)
+{
+ QDataStream in(this);
+
+ quint32 num, reply;
+
+ while (bytesAvailable()) {
+ in >> num;
+ if (num == 42) {
+ safeShutDown = true;
+ qDebug("SUCCESS");
+ QCoreApplication::instance()->quit();
+ return;
+ }
+ reply = num + 1;
+ if (reply == 42)
+ ++reply;
+ }
+
+ // Reply with a bigger number
+ sendTest(reply);
+}
+
+//------------------------------------------------------------------------------
+void My4Socket::closed(void)
+{
+ if (!safeShutDown)
+ qDebug("FAILED");
+ QCoreApplication::instance()->quit();
+}
+
+//------------------------------------------------------------------------------
+void My4Socket::sendTest(quint32 num)
+{
+ QByteArray block;
+ QDataStream out(&block, QIODevice::WriteOnly);
+ out << num;
+
+ write(block, block.size());
+}
+
+//------------------------------------------------------------------------------
+My4Server::My4Server(QObject *parent)
+ : QTcpServer(parent)
+{
+ if (listen(QHostAddress::Any, 7700))
+ qDebug("qt4server");
+ QTimer::singleShot(5000, this, SLOT(stopServer()));
+}
+
+//------------------------------------------------------------------------------
+void My4Server::incomingConnection(int socketId)
+{
+ m_socket = new My4Socket(this);
+ m_socket->setSocketDescriptor(socketId);
+}
+
+//------------------------------------------------------------------------------
+void My4Server::stopServer()
+{
+ if (m_socket) {
+ qDebug("SUCCESS");
+ m_socket->safeShutDown = true;
+ m_socket->sendTest(42);
+ } else {
+ QCoreApplication::instance()->quit();
+ }
+}
+
+//------------------------------------------------------------------------------
+Test::Test(Type type)
+{
+ switch (type) {
+ case Qt4Client: {
+ qDebug("qt4client");
+ My4Socket *s = new My4Socket(this);
+ s->connectToHost("localhost", 7700);
+ s->sendTest(1);
+ break;
+ }
+ case Qt4Server: {
+ new My4Server(this);
+ break;
+ }
+ default:
+ break;
+ }
+}
diff --git a/tests/auto/network/socket/qtcpsocket/stressTest/Test.h b/tests/auto/network/socket/qtcpsocket/stressTest/Test.h
new file mode 100644
index 0000000000..5440e7ffa9
--- /dev/null
+++ b/tests/auto/network/socket/qtcpsocket/stressTest/Test.h
@@ -0,0 +1,95 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#ifndef TEST_H
+#define TEST_H
+
+//------------------------------------------------------------------------------
+
+#include <QTcpServer>
+#include <QTcpSocket>
+
+//------------------------------------------------------------------------------
+class My4Socket : public QTcpSocket
+{
+ Q_OBJECT
+public:
+ My4Socket(QObject *parent);
+
+ void sendTest(quint32 num);
+ bool safeShutDown;
+
+private slots:
+ void read();
+ void closed();
+};
+
+//------------------------------------------------------------------------------
+class My4Server : public QTcpServer
+{
+ Q_OBJECT
+public:
+ My4Server(QObject *parent = 0);
+
+protected:
+ void incomingConnection(int socket);
+
+private slots:
+ void stopServer();
+
+private:
+ My4Socket *m_socket;
+};
+
+//------------------------------------------------------------------------------
+class Test : public QObject
+{
+ Q_OBJECT
+
+public:
+ enum Type {
+ Qt4Client,
+ Qt4Server,
+ };
+ Test(Type type);
+};
+
+//------------------------------------------------------------------------------
+#endif // TEST_H
diff --git a/tests/auto/network/socket/qtcpsocket/stressTest/main.cpp b/tests/auto/network/socket/qtcpsocket/stressTest/main.cpp
new file mode 100644
index 0000000000..76ce7bd820
--- /dev/null
+++ b/tests/auto/network/socket/qtcpsocket/stressTest/main.cpp
@@ -0,0 +1,67 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#include "Test.h"
+
+#include <QCoreApplication>
+#include <QStringList>
+
+int main(int argc, char **argv)
+{
+ QCoreApplication app(argc, argv);
+
+ QString arg;
+ if (app.arguments().size() > 1)
+ arg = app.arguments().at(1).toLower().trimmed();
+
+ Test::Type type;
+ if (arg == QLatin1String("qt4client"))
+ type = Test::Qt4Client;
+ else if (arg == QLatin1String("qt4server"))
+ type = Test::Qt4Server;
+ else {
+ qDebug("usage: ./stressTest <qt4client|qt4server>");
+ return 0;
+ }
+
+ Test test(type);
+
+ return app.exec();
+}
diff --git a/tests/auto/network/socket/qtcpsocket/stressTest/stressTest.pro b/tests/auto/network/socket/qtcpsocket/stressTest/stressTest.pro
new file mode 100644
index 0000000000..f6215f80a0
--- /dev/null
+++ b/tests/auto/network/socket/qtcpsocket/stressTest/stressTest.pro
@@ -0,0 +1,12 @@
+HEADERS += Test.h
+SOURCES += main.cpp Test.cpp
+QT += network
+
+CONFIG -= app_bundle
+CONFIG += console
+DESTDIR = ./
+MOC_DIR = .moc/
+TMP_DIR = .tmp/
+
+symbian: TARGET.CAPABILITY = NetworkServices
+
diff --git a/tests/auto/network/socket/qtcpsocket/test/test.pro b/tests/auto/network/socket/qtcpsocket/test/test.pro
new file mode 100644
index 0000000000..61bfaad1a1
--- /dev/null
+++ b/tests/auto/network/socket/qtcpsocket/test/test.pro
@@ -0,0 +1,33 @@
+load(qttest_p4)
+
+QT += widgets
+QT += core-private network-private
+SOURCES += ../tst_qtcpsocket.cpp
+win32: {
+wince*: {
+ LIBS += -lws2
+} else {
+ LIBS += -lws2_32
+}
+}
+QT += network
+vxworks:QT -= gui
+
+symbian: {
+ TARGET.EPOCHEAPSIZE="0x100 0x3000000"
+ TARGET.CAPABILITY = NetworkServices ReadUserData
+}
+
+TARGET = tst_qtcpsocket
+
+win32 {
+ CONFIG(debug, debug|release) {
+ DESTDIR = ../debug
+} else {
+ DESTDIR = ../release
+ }
+} else {
+ DESTDIR = ../
+}
+
+CONFIG+=insignificant_test # unstable, QTBUG-21043
diff --git a/tests/auto/network/socket/qtcpsocket/tst_qtcpsocket.cpp b/tests/auto/network/socket/qtcpsocket/tst_qtcpsocket.cpp
new file mode 100644
index 0000000000..bae3f7c2f5
--- /dev/null
+++ b/tests/auto/network/socket/qtcpsocket/tst_qtcpsocket.cpp
@@ -0,0 +1,2684 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+
+// Just to get Q_OS_SYMBIAN
+#include <qglobal.h>
+
+#if defined(_WIN32) && !defined(Q_OS_SYMBIAN)
+#include <winsock2.h>
+#else
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <fcntl.h>
+#include <unistd.h>
+#define SOCKET int
+#define INVALID_SOCKET -1
+#endif
+
+#include <qplatformdefs.h>
+
+#include <QtTest/QtTest>
+
+#include <QAuthenticator>
+#include <QCoreApplication>
+#include <QEventLoop>
+#include <QFile>
+#include <QHostAddress>
+#include <QHostInfo>
+#include <QMap>
+#ifndef Q_OS_VXWORKS
+#include <QMessageBox>
+#include <QPushButton>
+#endif
+#include <QPointer>
+#include <QProcess>
+#include <QStringList>
+#include <QTcpServer>
+#include <QTcpSocket>
+#ifndef QT_NO_OPENSSL
+#include <QSslSocket>
+#endif
+#include <QTextStream>
+#include <QThread>
+#include <QTime>
+#include <QTimer>
+#include <QDebug>
+// RVCT compiles also unused inline methods
+# include <QNetworkProxy>
+
+#ifdef Q_OS_LINUX
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#endif
+
+#include "private/qhostinfo_p.h"
+
+#include "../../../network-settings.h"
+#include "../../../../shared/util.h"
+
+Q_DECLARE_METATYPE(QAbstractSocket::SocketError)
+Q_DECLARE_METATYPE(QAbstractSocket::SocketState)
+Q_DECLARE_METATYPE(QNetworkProxy)
+Q_DECLARE_METATYPE(QList<QNetworkProxy>)
+
+//TESTED_CLASS=
+//TESTED_FILES=
+
+QT_FORWARD_DECLARE_CLASS(QTcpSocket)
+QT_FORWARD_DECLARE_CLASS(SocketPair)
+
+class tst_QTcpSocket : public QObject
+{
+ Q_OBJECT
+
+public:
+ tst_QTcpSocket();
+ virtual ~tst_QTcpSocket();
+
+ static void enterLoop(int secs)
+ {
+ ++loopLevel;
+ QTestEventLoop::instance().enterLoop(secs);
+ --loopLevel;
+ }
+ static void exitLoop()
+ {
+ // Safe exit - if we aren't in an event loop, don't
+ // exit one.
+ if (loopLevel > 0)
+ QTestEventLoop::instance().exitLoop();
+ }
+ static bool timeout()
+ {
+ return QTestEventLoop::instance().timeout();
+ }
+
+public slots:
+ void initTestCase_data();
+ void init();
+ void cleanup();
+private slots:
+ void socketsConstructedBeforeEventLoop();
+ void constructing();
+ void setInvalidSocketDescriptor();
+ void setSocketDescriptor();
+ void socketDescriptor();
+ void blockingIMAP();
+ void nonBlockingIMAP();
+ void hostNotFound();
+ void timeoutConnect_data();
+ void timeoutConnect();
+ void delayedClose();
+ void partialRead();
+ void unget();
+ void readAllAfterClose();
+ void openCloseOpenClose();
+ void connectDisconnectConnectDisconnect();
+ void disconnectWhileConnecting_data();
+ void disconnectWhileConnecting();
+ void disconnectWhileConnectingNoEventLoop_data();
+ void disconnectWhileConnectingNoEventLoop();
+ void disconnectWhileLookingUp_data();
+ void disconnectWhileLookingUp();
+ void downloadBigFile();
+ void readLine();
+ void readLineString();
+ void readChunks();
+ void waitForBytesWritten();
+ void waitForBytesWrittenMinusOne();
+ void waitForReadyRead();
+ void waitForReadyReadMinusOne();
+ void flush();
+ void synchronousApi();
+ void dontCloseOnTimeout();
+ void recursiveReadyRead();
+ void atEnd();
+ void socketInAThread();
+ void socketsInThreads();
+ void waitForReadyReadInASlot();
+ void remoteCloseError();
+ void openMessageBoxInErrorSlot();
+#ifndef Q_OS_WIN
+ void connectToLocalHostNoService();
+#endif
+ void waitForConnectedInHostLookupSlot();
+ void waitForConnectedInHostLookupSlot2();
+ void readyReadSignalsAfterWaitForReadyRead();
+#ifdef Q_OS_LINUX
+ void linuxKernelBugLocalSocket();
+#endif
+ void abortiveClose();
+ void localAddressEmptyOnBSD();
+ void zeroAndMinusOneReturns();
+ void connectionRefused();
+ void suddenRemoteDisconnect_data();
+ void suddenRemoteDisconnect();
+ void connectToMultiIP();
+ void moveToThread0();
+ void increaseReadBufferSize();
+ void taskQtBug5799ConnectionErrorWaitForConnected();
+ void taskQtBug5799ConnectionErrorEventLoop();
+ void taskQtBug7054TimeoutErrorResetting();
+
+ void invalidProxy_data();
+ void invalidProxy();
+ void proxyFactory_data();
+ void proxyFactory();
+
+ void qtbug14268_peek();
+
+
+protected slots:
+ void nonBlockingIMAP_hostFound();
+ void nonBlockingIMAP_connected();
+ void nonBlockingIMAP_closed();
+ void nonBlockingIMAP_readyRead();
+ void nonBlockingIMAP_bytesWritten(qint64);
+ void readRegularFile_readyRead();
+ void exitLoopSlot();
+ void downloadBigFileSlot();
+ void recursiveReadyReadSlot();
+ void waitForReadyReadInASlotSlot();
+ void messageBoxSlot();
+ void hostLookupSlot();
+ void abortiveClose_abortSlot();
+ void remoteCloseErrorSlot();
+ void proxyAuthenticationRequired(const QNetworkProxy &, QAuthenticator *auth);
+ void earlySocketBytesSent(qint64 bytes);
+ void earlySocketReadyRead();
+
+private:
+ QByteArray expectedReplyIMAP();
+ void fetchExpectedReplyIMAP();
+ QTcpSocket *newSocket() const;
+ QTcpSocket *nonBlockingIMAP_socket;
+ QStringList nonBlockingIMAP_data;
+ qint64 nonBlockingIMAP_totalWritten;
+
+ QTcpSocket *tmpSocket;
+ qint64 bytesAvailable;
+ qint64 expectedLength;
+ bool readingBody;
+ QTime timer;
+
+ QByteArray expectedReplyIMAP_cached;
+
+ mutable int proxyAuthCalled;
+
+ bool gotClosedSignal;
+ int numConnections;
+ static int loopLevel;
+
+ SocketPair *earlyConstructedSockets;
+ int earlyBytesWrittenCount;
+ int earlyReadyReadCount;
+};
+
+enum ProxyTests {
+ NoProxy = 0x00,
+ Socks5Proxy = 0x01,
+ HttpProxy = 0x02,
+ TypeMask = 0x0f,
+
+ NoAuth = 0x00,
+ AuthBasic = 0x10,
+ AuthNtlm = 0x20,
+ AuthMask = 0xf0
+};
+
+int tst_QTcpSocket::loopLevel = 0;
+
+class SocketPair: public QObject
+{
+ Q_OBJECT
+public:
+ QTcpSocket *endPoints[2];
+
+ SocketPair(QObject *parent = 0)
+ : QObject(parent)
+ {
+ endPoints[0] = endPoints[1] = 0;
+ }
+
+ bool create()
+ {
+ QTcpServer server;
+ server.listen();
+
+ QTcpSocket *active = new QTcpSocket(this);
+ active->connectToHost("127.0.0.1", server.serverPort());
+
+ if (!active->waitForConnected(1000))
+ return false;
+
+ if (!server.waitForNewConnection(1000))
+ return false;
+
+ QTcpSocket *passive = server.nextPendingConnection();
+ passive->setParent(this);
+
+ endPoints[0] = active;
+ endPoints[1] = passive;
+ return true;
+ }
+};
+
+tst_QTcpSocket::tst_QTcpSocket()
+{
+ tmpSocket = 0;
+
+ //This code relates to the socketsConstructedBeforeEventLoop test case
+ earlyConstructedSockets = new SocketPair;
+ QVERIFY(earlyConstructedSockets->create());
+ earlyBytesWrittenCount = 0;
+ earlyReadyReadCount = 0;
+ connect(earlyConstructedSockets->endPoints[0], SIGNAL(readyRead()), this, SLOT(earlySocketReadyRead()));
+ connect(earlyConstructedSockets->endPoints[1], SIGNAL(bytesWritten(qint64)), this, SLOT(earlySocketBytesSent(qint64)));
+ earlyConstructedSockets->endPoints[1]->write("hello work");
+}
+
+tst_QTcpSocket::~tst_QTcpSocket()
+{
+
+}
+
+void tst_QTcpSocket::initTestCase_data()
+{
+ QTest::addColumn<bool>("setProxy");
+ QTest::addColumn<int>("proxyType");
+ QTest::addColumn<bool>("ssl");
+
+ qDebug() << QtNetworkSettings::serverName();
+ QTest::newRow("WithoutProxy") << false << 0 << false;
+ QTest::newRow("WithSocks5Proxy") << true << int(Socks5Proxy) << false;
+ QTest::newRow("WithSocks5ProxyAuth") << true << int(Socks5Proxy | AuthBasic) << false;
+
+ QTest::newRow("WithHttpProxy") << true << int(HttpProxy) << false;
+ QTest::newRow("WithHttpProxyBasicAuth") << true << int(HttpProxy | AuthBasic) << false;
+// QTest::newRow("WithHttpProxyNtlmAuth") << true << int(HttpProxy | AuthNtlm) << false;
+
+#ifndef QT_NO_OPENSSL
+ QTest::newRow("WithoutProxy SSL") << false << 0 << true;
+ QTest::newRow("WithSocks5Proxy SSL") << true << int(Socks5Proxy) << true;
+ QTest::newRow("WithSocks5AuthProxy SSL") << true << int(Socks5Proxy | AuthBasic) << true;
+
+ QTest::newRow("WithHttpProxy SSL") << true << int(HttpProxy) << true;
+ QTest::newRow("WithHttpProxyBasicAuth SSL") << true << int(HttpProxy | AuthBasic) << true;
+// QTest::newRow("WithHttpProxyNtlmAuth SSL") << true << int(HttpProxy | AuthNtlm) << true;
+#endif
+}
+
+void tst_QTcpSocket::init()
+{
+ QFETCH_GLOBAL(bool, setProxy);
+ if (setProxy) {
+ QFETCH_GLOBAL(int, proxyType);
+ QList<QHostAddress> addresses = QHostInfo::fromName(QtNetworkSettings::serverName()).addresses();
+ QVERIFY2(addresses.count() > 0, "failed to get ip address for test server");
+ QString fluke = addresses.first().toString();
+ QNetworkProxy proxy;
+
+ switch (proxyType) {
+ case Socks5Proxy:
+ proxy = QNetworkProxy(QNetworkProxy::Socks5Proxy, fluke, 1080);
+ break;
+
+ case Socks5Proxy | AuthBasic:
+ proxy = QNetworkProxy(QNetworkProxy::Socks5Proxy, fluke, 1081);
+ break;
+
+ case HttpProxy | NoAuth:
+ proxy = QNetworkProxy(QNetworkProxy::HttpProxy, fluke, 3128);
+ break;
+
+ case HttpProxy | AuthBasic:
+ proxy = QNetworkProxy(QNetworkProxy::HttpProxy, fluke, 3129);
+ break;
+
+ case HttpProxy | AuthNtlm:
+ proxy = QNetworkProxy(QNetworkProxy::HttpProxy, fluke, 3130);
+ break;
+ }
+ QNetworkProxy::setApplicationProxy(proxy);
+ }
+
+ qt_qhostinfo_clear_cache();
+}
+
+QTcpSocket *tst_QTcpSocket::newSocket() const
+{
+ QTcpSocket *socket;
+#ifndef QT_NO_OPENSSL
+ QFETCH_GLOBAL(bool, ssl);
+ socket = ssl ? new QSslSocket : new QTcpSocket;
+#else
+ socket = new QTcpSocket;
+#endif
+
+ proxyAuthCalled = 0;
+ connect(socket, SIGNAL(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)),
+ SLOT(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)),
+ Qt::DirectConnection);
+ return socket;
+}
+
+void tst_QTcpSocket::cleanup()
+{
+ QNetworkProxy::setApplicationProxy(QNetworkProxy::DefaultProxy);
+}
+
+void tst_QTcpSocket::proxyAuthenticationRequired(const QNetworkProxy &, QAuthenticator *auth)
+{
+ ++proxyAuthCalled;
+ auth->setUser("qsockstest");
+ auth->setPassword("password");
+}
+
+//----------------------------------------------------------------------------------
+
+void tst_QTcpSocket::socketsConstructedBeforeEventLoop()
+{
+ QFETCH_GLOBAL(bool, setProxy);
+ QFETCH_GLOBAL(bool, ssl);
+ if (setProxy || ssl)
+ return;
+ //This test checks that sockets constructed before QCoreApplication::exec() still emit signals
+ //see construction code in the tst_QTcpSocket constructor
+ enterLoop(3);
+ QCOMPARE(earlyBytesWrittenCount, 1);
+ QCOMPARE(earlyReadyReadCount, 1);
+ earlyConstructedSockets->endPoints[0]->close();
+ earlyConstructedSockets->endPoints[1]->close();
+}
+
+void tst_QTcpSocket::earlySocketBytesSent(qint64 /* bytes */)
+{
+ earlyBytesWrittenCount++;
+}
+
+void tst_QTcpSocket::earlySocketReadyRead()
+{
+ earlyReadyReadCount++;
+}
+
+//----------------------------------------------------------------------------------
+
+void tst_QTcpSocket::constructing()
+{
+ QTcpSocket *socket = newSocket();
+
+ // Check the initial state of the QTcpSocket.
+ QCOMPARE(socket->state(), QTcpSocket::UnconnectedState);
+ QVERIFY(socket->isSequential());
+ QVERIFY(!socket->isOpen());
+ QVERIFY(!socket->isValid());
+ QCOMPARE(socket->socketType(), QTcpSocket::TcpSocket);
+
+ char c;
+ QCOMPARE(socket->getChar(&c), false);
+ QCOMPARE((int) socket->bytesAvailable(), 0);
+ QCOMPARE(socket->canReadLine(), false);
+ QCOMPARE(socket->readLine(), QByteArray());
+ QCOMPARE(socket->socketDescriptor(), -1);
+ QCOMPARE((int) socket->localPort(), 0);
+ QVERIFY(socket->localAddress() == QHostAddress());
+ QCOMPARE((int) socket->peerPort(), 0);
+ QVERIFY(socket->peerAddress() == QHostAddress());
+ QCOMPARE(socket->error(), QTcpSocket::UnknownSocketError);
+ QCOMPARE(socket->errorString(), QString("Unknown error"));
+
+ // Check the state of the socket layer?
+ delete socket;
+}
+
+//----------------------------------------------------------------------------------
+
+void tst_QTcpSocket::setInvalidSocketDescriptor()
+{
+ QTcpSocket *socket = newSocket();
+ QCOMPARE(socket->socketDescriptor(), -1);
+#ifdef Q_OS_SYMBIAN
+ QTest::ignoreMessage(QtWarningMsg, "QSymbianSocketEngine::initialize - socket descriptor not found");
+#endif
+ QVERIFY(!socket->setSocketDescriptor(-5, QTcpSocket::UnconnectedState));
+ QCOMPARE(socket->socketDescriptor(), -1);
+
+ QCOMPARE(socket->error(), QTcpSocket::UnsupportedSocketOperationError);
+
+ delete socket;
+}
+
+//----------------------------------------------------------------------------------
+
+void tst_QTcpSocket::setSocketDescriptor()
+{
+#ifdef Q_OS_SYMBIAN
+ QSKIP("adopting open c socket handles is not supported", SkipAll);
+#else
+ QFETCH_GLOBAL(bool, setProxy);
+ if (setProxy)
+ return; // this test doesn't make sense with proxies
+
+#ifdef Q_OS_WIN
+ // need the dummy to ensure winsock is started
+ QTcpSocket *dummy = newSocket();
+ dummy->connectToHost(QtNetworkSettings::serverName(), 143);
+ QVERIFY(dummy->waitForConnected());
+
+ SOCKET sock = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+ if (sock == INVALID_SOCKET) {
+ qErrnoWarning(WSAGetLastError(), "INVALID_SOCKET");
+ }
+#else
+ SOCKET sock = ::socket(AF_INET, SOCK_STREAM, 0);
+
+ // artificially increase the value of sock
+ SOCKET sock2 = ::fcntl(sock, F_DUPFD, sock + 50);
+ ::close(sock);
+ sock = sock2;
+#endif
+
+ QVERIFY(sock != INVALID_SOCKET);
+ QTcpSocket *socket = newSocket();
+ QVERIFY(socket->setSocketDescriptor(sock, QTcpSocket::UnconnectedState));
+ QCOMPARE(socket->socketDescriptor(), (int)sock);
+
+ socket->connectToHost(QtNetworkSettings::serverName(), 143);
+ QCOMPARE(socket->state(), QTcpSocket::HostLookupState);
+ QCOMPARE(socket->socketDescriptor(), (int)sock);
+ QVERIFY(socket->waitForConnected(10000));
+ // skip this, it has been broken for years, see task 260735
+ // if somebody complains, consider fixing it, but it might break existing applications.
+ QEXPECT_FAIL("", "bug has been around for years, will not fix without need", Continue);
+ QCOMPARE(socket->socketDescriptor(), (int)sock);
+ delete socket;
+#ifdef Q_OS_WIN
+ delete dummy;
+#endif
+#endif
+}
+
+//----------------------------------------------------------------------------------
+
+void tst_QTcpSocket::socketDescriptor()
+{
+ QTcpSocket *socket = newSocket();
+
+ QCOMPARE(socket->socketDescriptor(), -1);
+ socket->connectToHost(QtNetworkSettings::serverName(), 143);
+ QVERIFY((socket->state() == QAbstractSocket::HostLookupState && socket->socketDescriptor() == -1) ||
+ (socket->state() == QAbstractSocket::ConnectingState && socket->socketDescriptor() != -1));
+ QVERIFY(socket->waitForConnected(10000));
+ QVERIFY(socket->state() == QAbstractSocket::ConnectedState);
+ QVERIFY(socket->socketDescriptor() != -1);
+
+ delete socket;
+}
+
+//----------------------------------------------------------------------------------
+
+void tst_QTcpSocket::blockingIMAP()
+{
+ QTcpSocket *socket = newSocket();
+
+ // Connect
+ socket->connectToHost(QtNetworkSettings::serverName(), 143);
+ QVERIFY(socket->waitForConnected(10000));
+ QCOMPARE(socket->state(), QTcpSocket::ConnectedState);
+ QVERIFY(socket->isValid());
+
+ // Read greeting
+ QVERIFY(socket->waitForReadyRead(5000));
+ QString s = socket->readLine();
+ // only test if an OK was returned, to make the test compatible between different
+ // IMAP server versions
+ QCOMPARE(s.left(4).toLatin1().constData(), "* OK");
+
+ // Write NOOP
+ QCOMPARE((int) socket->write("1 NOOP\r\n", 8), 8);
+ QCOMPARE((int) socket->write("2 NOOP\r\n", 8), 8);
+
+ if (!socket->canReadLine())
+ QVERIFY(socket->waitForReadyRead(5000));
+
+ // Read response
+ s = socket->readLine();
+ QCOMPARE(s.toLatin1().constData(), "1 OK Completed\r\n");
+
+ // Write a third NOOP to verify that write doesn't clear the read buffer
+ QCOMPARE((int) socket->write("3 NOOP\r\n", 8), 8);
+
+ // Read second response
+ if (!socket->canReadLine())
+ QVERIFY(socket->waitForReadyRead(5000));
+ s = socket->readLine();
+ QCOMPARE(s.toLatin1().constData(), "2 OK Completed\r\n");
+
+ // Read third response
+ if (!socket->canReadLine())
+ QVERIFY(socket->waitForReadyRead(5000));
+ s = socket->readLine();
+ QCOMPARE(s.toLatin1().constData(), "3 OK Completed\r\n");
+
+
+ // Write LOGOUT
+ QCOMPARE((int) socket->write("4 LOGOUT\r\n", 10), 10);
+
+ if (!socket->canReadLine())
+ QVERIFY(socket->waitForReadyRead(5000));
+
+ // Read two lines of respose
+ s = socket->readLine();
+ QCOMPARE(s.toLatin1().constData(), "* BYE LOGOUT received\r\n");
+
+ if (!socket->canReadLine())
+ QVERIFY(socket->waitForReadyRead(5000));
+
+ s = socket->readLine();
+ QCOMPARE(s.toLatin1().constData(), "4 OK Completed\r\n");
+
+ // Close the socket
+ socket->close();
+
+ // Check that it's closed
+ QCOMPARE(socket->state(), QTcpSocket::UnconnectedState);
+
+ delete socket;
+}
+
+//----------------------------------------------------------------------------------
+
+void tst_QTcpSocket::hostNotFound()
+{
+ QTcpSocket *socket = newSocket();
+
+ socket->connectToHost("nosuchserver.troll.no", 80);
+ QVERIFY(!socket->waitForConnected());
+ QCOMPARE(socket->state(), QTcpSocket::UnconnectedState);
+ QCOMPARE(int(socket->error()), int(QTcpSocket::HostNotFoundError));
+
+ delete socket;
+}
+
+//----------------------------------------------------------------------------------
+void tst_QTcpSocket::timeoutConnect_data()
+{
+ QTest::addColumn<QString>("address");
+ QTest::newRow("host") << QtNetworkSettings::serverName();
+ QTest::newRow("ip") << QtNetworkSettings::serverIP().toString();
+}
+
+void tst_QTcpSocket::timeoutConnect()
+{
+ QFETCH(QString, address);
+ QTcpSocket *socket = newSocket();
+
+ QElapsedTimer timer;
+ timer.start();
+
+ // Port 1357 is configured to drop packets on the test server
+ socket->connectToHost(address, 1357);
+ QVERIFY(timer.elapsed() < 150);
+ QVERIFY(!socket->waitForConnected(1000)); //200ms is too short when using SOCKS proxy authentication
+ QCOMPARE(socket->state(), QTcpSocket::UnconnectedState);
+ QCOMPARE(int(socket->error()), int(QTcpSocket::SocketTimeoutError));
+
+ timer.start();
+ socket->connectToHost(address, 1357);
+ QVERIFY(timer.elapsed() < 150);
+ QTimer::singleShot(50, &QTestEventLoop::instance(), SLOT(exitLoop()));
+ QTestEventLoop::instance().enterLoop(5);
+ QVERIFY(!QTestEventLoop::instance().timeout());
+ QVERIFY(socket->state() == QTcpSocket::ConnectingState
+ || socket->state() == QTcpSocket::HostLookupState);
+ socket->abort();
+ QCOMPARE(socket->state(), QTcpSocket::UnconnectedState);
+ QCOMPARE(socket->openMode(), QIODevice::NotOpen);
+
+ delete socket;
+}
+
+//----------------------------------------------------------------------------------
+
+void tst_QTcpSocket::nonBlockingIMAP()
+{
+ QTcpSocket *socket = newSocket();
+ connect(socket, SIGNAL(hostFound()), SLOT(nonBlockingIMAP_hostFound()));
+ connect(socket, SIGNAL(connected()), SLOT(nonBlockingIMAP_connected()));
+ connect(socket, SIGNAL(disconnected()), SLOT(nonBlockingIMAP_closed()));
+ connect(socket, SIGNAL(bytesWritten(qint64)), SLOT(nonBlockingIMAP_bytesWritten(qint64)));
+ connect(socket, SIGNAL(readyRead()), SLOT(nonBlockingIMAP_readyRead()));
+ nonBlockingIMAP_socket = socket;
+
+ // Connect
+ socket->connectToHost(QtNetworkSettings::serverName(), 143);
+ QVERIFY(socket->state() == QTcpSocket::HostLookupState ||
+ socket->state() == QTcpSocket::ConnectingState);
+
+ enterLoop(30);
+ if (timeout()) {
+ QFAIL("Timed out");
+ }
+
+ if (socket->state() == QTcpSocket::ConnectingState) {
+ enterLoop(30);
+ if (timeout()) {
+ QFAIL("Timed out");
+ }
+ }
+
+ QCOMPARE(socket->state(), QTcpSocket::ConnectedState);
+
+ enterLoop(30);
+ if (timeout()) {
+ QFAIL("Timed out");
+ }
+
+ // Read greeting
+ QVERIFY(!nonBlockingIMAP_data.isEmpty());
+ QCOMPARE(nonBlockingIMAP_data.at(0).left(4).toLatin1().constData(), "* OK");
+ nonBlockingIMAP_data.clear();
+
+ nonBlockingIMAP_totalWritten = 0;
+
+ // Write NOOP
+ QCOMPARE((int) socket->write("1 NOOP\r\n", 8), 8);
+
+
+ enterLoop(30);
+ if (timeout()) {
+ QFAIL("Timed out");
+ }
+
+ QVERIFY(nonBlockingIMAP_totalWritten == 8);
+
+
+ enterLoop(30);
+ if (timeout()) {
+ QFAIL("Timed out");
+ }
+
+
+ // Read response
+ QVERIFY(!nonBlockingIMAP_data.isEmpty());
+ QCOMPARE(nonBlockingIMAP_data.at(0).toLatin1().constData(), "1 OK Completed\r\n");
+ nonBlockingIMAP_data.clear();
+
+
+ nonBlockingIMAP_totalWritten = 0;
+
+ // Write LOGOUT
+ QCOMPARE((int) socket->write("2 LOGOUT\r\n", 10), 10);
+
+ enterLoop(30);
+ if (timeout()) {
+ QFAIL("Timed out");
+ }
+
+ QVERIFY(nonBlockingIMAP_totalWritten == 10);
+
+ // Wait for greeting
+ enterLoop(30);
+ if (timeout()) {
+ QFAIL("Timed out");
+ }
+
+ // Read two lines of respose
+ QCOMPARE(nonBlockingIMAP_data.at(0).toLatin1().constData(), "* BYE LOGOUT received\r\n");
+ QCOMPARE(nonBlockingIMAP_data.at(1).toLatin1().constData(), "2 OK Completed\r\n");
+ nonBlockingIMAP_data.clear();
+
+ // Close the socket
+ socket->close();
+
+ // Check that it's closed
+ QCOMPARE(socket->state(), QTcpSocket::UnconnectedState);
+
+ delete socket;
+}
+
+void tst_QTcpSocket::nonBlockingIMAP_hostFound()
+{
+ exitLoop();
+}
+
+void tst_QTcpSocket::nonBlockingIMAP_connected()
+{
+ exitLoop();
+}
+
+void tst_QTcpSocket::nonBlockingIMAP_readyRead()
+{
+ while (nonBlockingIMAP_socket->canReadLine())
+ nonBlockingIMAP_data.append(nonBlockingIMAP_socket->readLine());
+
+ exitLoop();
+}
+
+void tst_QTcpSocket::nonBlockingIMAP_bytesWritten(qint64 written)
+{
+ nonBlockingIMAP_totalWritten += written;
+ exitLoop();
+}
+
+void tst_QTcpSocket::nonBlockingIMAP_closed()
+{
+}
+
+//----------------------------------------------------------------------------------
+
+void tst_QTcpSocket::delayedClose()
+{
+ QTcpSocket *socket = newSocket();
+ connect(socket, SIGNAL(connected()), SLOT(nonBlockingIMAP_connected()));
+ connect(socket, SIGNAL(disconnected()), SLOT(exitLoopSlot()));
+
+ socket->connectToHost(QtNetworkSettings::serverName(), 143);
+
+ enterLoop(30);
+ if (timeout())
+ QFAIL("Timed out");
+
+ QCOMPARE(socket->state(), QTcpSocket::ConnectedState);
+
+ QCOMPARE((int) socket->write("1 LOGOUT\r\n", 10), 10);
+
+ // Add a huge bulk of data to be written after the logout
+ // command. The server will shut down after receiving the LOGOUT,
+ // so this data will not be read. But our close call should
+ // schedule a delayed close because all the data can not be
+ // written in one go.
+ QCOMPARE((int) socket->write(QByteArray(100000, '\n'), 100000), 100000);
+
+ socket->close();
+
+ QCOMPARE((int) socket->state(), (int) QTcpSocket::ClosingState);
+
+ enterLoop(10);
+ if (timeout())
+ QFAIL("Timed out");
+
+ QCOMPARE(socket->state(), QTcpSocket::UnconnectedState);
+
+ delete socket;
+}
+
+
+//----------------------------------------------------------------------------------
+
+QByteArray tst_QTcpSocket::expectedReplyIMAP()
+{
+ if (expectedReplyIMAP_cached.isEmpty()) {
+ fetchExpectedReplyIMAP();
+ }
+
+ return expectedReplyIMAP_cached;
+}
+
+// Figure out how the current IMAP server responds
+void tst_QTcpSocket::fetchExpectedReplyIMAP()
+{
+ QTcpSocket *socket = newSocket();
+ socket->connectToHost(QtNetworkSettings::serverName(), 143);
+ QVERIFY2(socket->waitForConnected(10000), qPrintable(socket->errorString()));
+ QVERIFY2(socket->state() == QTcpSocket::ConnectedState, qPrintable(socket->errorString()));
+
+ QTRY_VERIFY(socket->canReadLine());
+
+ QByteArray greeting = socket->readLine();
+ delete socket;
+
+ QVERIFY2(QtNetworkSettings::compareReplyIMAP(greeting), greeting.constData());
+
+ expectedReplyIMAP_cached = greeting;
+}
+
+//----------------------------------------------------------------------------------
+
+void tst_QTcpSocket::partialRead()
+{
+ QTcpSocket *socket = newSocket();
+ socket->connectToHost(QtNetworkSettings::serverName(), 143);
+ QVERIFY(socket->waitForConnected(10000));
+ QVERIFY(socket->state() == QTcpSocket::ConnectedState);
+ char buf[512];
+
+ QByteArray greeting = expectedReplyIMAP();
+ QVERIFY(!greeting.isEmpty());
+
+ for (int i = 0; i < 10; i += 2) {
+ while (socket->bytesAvailable() < 2)
+ QVERIFY(socket->waitForReadyRead(5000));
+ QVERIFY(socket->read(buf, 2) == 2);
+ buf[2] = '\0';
+ QCOMPARE((char *)buf, greeting.mid(i, 2).data());
+ }
+
+ delete socket;
+}
+
+//----------------------------------------------------------------------------------
+
+void tst_QTcpSocket::unget()
+{
+ QTcpSocket *socket = newSocket();
+ socket->connectToHost(QtNetworkSettings::serverName(), 143);
+ QVERIFY(socket->waitForConnected(10000));
+ QVERIFY(socket->state() == QTcpSocket::ConnectedState);
+ char buf[512];
+
+ QByteArray greeting = expectedReplyIMAP();
+ QVERIFY(!greeting.isEmpty());
+
+ for (int i = 0; i < 10; i += 2) {
+ while (socket->bytesAvailable() < 2)
+ QVERIFY(socket->waitForReadyRead(10000));
+ int bA = socket->bytesAvailable();
+ QVERIFY(socket->read(buf, 2) == 2);
+ buf[2] = '\0';
+ QCOMPARE((char *)buf, greeting.mid(i, 2).data());
+ QCOMPARE((int)socket->bytesAvailable(), bA - 2);
+ socket->ungetChar(buf[1]);
+ socket->ungetChar(buf[0]);
+ QCOMPARE((int)socket->bytesAvailable(), bA);
+ QVERIFY(socket->read(buf, 2) == 2);
+ buf[2] = '\0';
+ QCOMPARE((char *)buf, greeting.mid(i, 2).data());
+ }
+
+ delete socket;
+}
+
+//----------------------------------------------------------------------------------
+void tst_QTcpSocket::readRegularFile_readyRead()
+{
+ exitLoop();
+}
+
+//----------------------------------------------------------------------------------
+void tst_QTcpSocket::readAllAfterClose()
+{
+ QTcpSocket *socket = newSocket();
+ socket->connectToHost(QtNetworkSettings::serverName(), 143);
+ connect(socket, SIGNAL(readyRead()), SLOT(readRegularFile_readyRead()));
+ enterLoop(10);
+ if (timeout())
+ QFAIL("Network operation timed out");
+
+ socket->close();
+ QByteArray array = socket->readAll();
+ QCOMPARE(array.size(), 0);
+
+ delete socket;
+}
+
+//----------------------------------------------------------------------------------
+void tst_QTcpSocket::openCloseOpenClose()
+{
+ QTcpSocket *socket = newSocket();
+
+ for (int i = 0; i < 3; ++i) {
+ QCOMPARE(socket->state(), QTcpSocket::UnconnectedState);
+ QCOMPARE(int(socket->openMode()), int(QIODevice::NotOpen));
+ QVERIFY(socket->isSequential());
+ QVERIFY(!socket->isOpen());
+ QVERIFY(socket->socketType() == QTcpSocket::TcpSocket);
+
+ char c;
+ QCOMPARE(socket->getChar(&c), false);
+ QCOMPARE((int) socket->bytesAvailable(), 0);
+ QCOMPARE(socket->canReadLine(), false);
+ QCOMPARE(socket->readLine(), QByteArray());
+ QCOMPARE(socket->socketDescriptor(), -1);
+ QCOMPARE((int) socket->localPort(), 0);
+ QVERIFY(socket->localAddress() == QHostAddress());
+ QCOMPARE((int) socket->peerPort(), 0);
+ QVERIFY(socket->peerAddress() == QHostAddress());
+ QCOMPARE(socket->error(), QTcpSocket::UnknownSocketError);
+ QCOMPARE(socket->errorString(), QString("Unknown error"));
+
+ QVERIFY(socket->state() == QTcpSocket::UnconnectedState);
+
+ socket->connectToHost(QtNetworkSettings::serverName(), 143);
+ QVERIFY(socket->waitForConnected(10000));
+ socket->close();
+ }
+
+ delete socket;
+}
+
+//----------------------------------------------------------------------------------
+void tst_QTcpSocket::connectDisconnectConnectDisconnect()
+{
+ QTcpSocket *socket = newSocket();
+
+ for (int i = 0; i < 3; ++i) {
+ QCOMPARE(socket->state(), QTcpSocket::UnconnectedState);
+ QVERIFY(socket->socketType() == QTcpSocket::TcpSocket);
+
+ socket->connectToHost(QtNetworkSettings::serverName(), 143);
+ QVERIFY(socket->waitForReadyRead(10000));
+ QCOMPARE(QString::fromLatin1(socket->read(4)), QString("* OK"));
+
+ socket->disconnectFromHost();
+ if (socket->state() != QTcpSocket::UnconnectedState)
+ QVERIFY(socket->waitForDisconnected(10000));
+ QCOMPARE(int(socket->openMode()), int(QIODevice::ReadWrite));
+ }
+
+ delete socket;
+}
+
+//----------------------------------------------------------------------------------
+void tst_QTcpSocket::disconnectWhileConnecting_data()
+{
+ QTest::addColumn<QByteArray>("data");
+ QTest::addColumn<bool>("closeDirectly");
+
+ QTest::newRow("without-data") << QByteArray() << false;
+ QTest::newRow("without-data+close") << QByteArray() << true;
+ QTest::newRow("with-data") << QByteArray("Hello, world!") << false;
+ QTest::newRow("with-data+close") << QByteArray("Hello, world!") << true;
+
+ QByteArray bigData(1024*1024, '@');
+ QTest::newRow("with-big-data") << bigData << false;
+ QTest::newRow("with-big-data+close") << bigData << true;
+}
+
+void tst_QTcpSocket::disconnectWhileConnecting()
+{
+ QFETCH(QByteArray, data);
+ QFETCH_GLOBAL(bool, setProxy);
+ if (setProxy)
+ return; //proxy not useful for localhost test case
+
+ QTcpServer server;
+ QVERIFY(server.listen(QHostAddress::LocalHost));
+
+ // proceed to the connect-write-disconnect
+ QTcpSocket *socket = newSocket();
+ socket->connectToHost("127.0.0.1", server.serverPort());
+ if (!data.isEmpty())
+ socket->write(data);
+ if (socket->state() == QAbstractSocket::ConnectedState)
+ QSKIP("localhost connections are immediate, test case is invalid", SkipSingle);
+
+ QFETCH(bool, closeDirectly);
+ if (closeDirectly) {
+ socket->close();
+ QCOMPARE(int(socket->openMode()), int(QIODevice::NotOpen));
+ } else {
+ socket->disconnectFromHost();
+ }
+
+ connect(socket, SIGNAL(disconnected()), SLOT(exitLoopSlot()));
+#ifndef Q_OS_SYMBIAN
+ enterLoop(10);
+#else
+ enterLoop(30);
+#endif
+ QVERIFY2(!timeout(), "Network timeout");
+ QVERIFY(socket->state() == QAbstractSocket::UnconnectedState);
+ if (!closeDirectly) {
+ QCOMPARE(int(socket->openMode()), int(QIODevice::ReadWrite));
+ socket->close();
+ }
+ QCOMPARE(int(socket->openMode()), int(QIODevice::NotOpen));
+
+ // accept the other side and verify that it was sent properly:
+ QVERIFY(server.hasPendingConnections() || server.waitForNewConnection(0));
+ QTcpSocket *othersocket = server.nextPendingConnection();
+ if (othersocket->state() != QAbstractSocket::UnconnectedState)
+ QVERIFY2(othersocket->waitForDisconnected(10000), "Network timeout");
+ QVERIFY(othersocket->state() == QAbstractSocket::UnconnectedState);
+ QCOMPARE(othersocket->readAll(), data);
+
+ delete socket;
+ delete othersocket;
+}
+
+//----------------------------------------------------------------------------------
+class ReceiverThread: public QThread
+{
+ QTcpServer *server;
+public:
+ int serverPort;
+ bool ok;
+ QByteArray receivedData;
+ volatile bool quit;
+
+ ReceiverThread()
+ : server(0), ok(false), quit(false)
+ { }
+
+ ~ReceiverThread() { }
+
+ bool listen()
+ {
+ server = new QTcpServer;
+ if (!server->listen(QHostAddress::LocalHost))
+ return false;
+ serverPort = server->serverPort();
+ server->moveToThread(this);
+ return true;
+ }
+
+ static void cleanup(void *ptr)
+ {
+ ReceiverThread* self = reinterpret_cast<ReceiverThread*>(ptr);
+ self->quit = true;
+ self->wait(30000);
+ delete self;
+ }
+
+protected:
+ void run()
+ {
+ bool timedOut = false;
+ while (!quit) {
+#ifndef Q_OS_SYMBIAN
+ if (server->waitForNewConnection(500, &timedOut))
+#else
+ if (server->waitForNewConnection(5000, &timedOut))
+#endif
+ break;
+ if (!timedOut)
+ return;
+ }
+
+ QTcpSocket *socket = server->nextPendingConnection();
+ while (!quit) {
+#ifndef Q_OS_SYMBIAN
+ if (socket->waitForDisconnected(500))
+#else
+ if (socket->waitForDisconnected(5000))
+#endif
+ break;
+ if (socket->error() != QAbstractSocket::SocketTimeoutError)
+ return;
+ }
+
+ if (!quit) {
+ receivedData = socket->readAll();
+ ok = true;
+ }
+ delete socket;
+ delete server;
+ server = 0;
+ }
+};
+
+void tst_QTcpSocket::disconnectWhileConnectingNoEventLoop_data()
+{
+ disconnectWhileConnecting_data();
+}
+
+void tst_QTcpSocket::disconnectWhileConnectingNoEventLoop()
+{
+ QFETCH(QByteArray, data);
+ QFETCH_GLOBAL(bool, setProxy);
+ if (setProxy)
+ return; //proxy not useful for localhost test case
+
+ QScopedPointer<ReceiverThread, ReceiverThread> thread (new ReceiverThread);
+ QVERIFY(thread->listen());
+ thread->start();
+
+ // proceed to the connect-write-disconnect
+ QTcpSocket *socket = newSocket();
+ socket->connectToHost("127.0.0.1", thread->serverPort);
+ if (!data.isEmpty())
+ socket->write(data);
+ if (socket->state() == QAbstractSocket::ConnectedState) {
+ QSKIP("localhost connections are immediate, test case is invalid", SkipSingle);
+ }
+
+ QFETCH(bool, closeDirectly);
+ if (closeDirectly) {
+ socket->close();
+ QCOMPARE(int(socket->openMode()), int(QIODevice::NotOpen));
+ } else {
+ socket->disconnectFromHost();
+ }
+
+#ifndef Q_OS_SYMBIAN
+ QVERIFY2(socket->waitForDisconnected(10000), "Network timeout");
+#else
+ QVERIFY2(socket->waitForDisconnected(30000), "Network timeout");
+#endif
+ QVERIFY(socket->state() == QAbstractSocket::UnconnectedState);
+ if (!closeDirectly) {
+ QCOMPARE(int(socket->openMode()), int(QIODevice::ReadWrite));
+ socket->close();
+ }
+ QCOMPARE(int(socket->openMode()), int(QIODevice::NotOpen));
+ delete socket;
+
+ // check if the other side received everything ok
+ QVERIFY(thread->wait(30000));
+ QVERIFY(thread->ok);
+ QCOMPARE(thread->receivedData, data);
+}
+
+//----------------------------------------------------------------------------------
+void tst_QTcpSocket::disconnectWhileLookingUp_data()
+{
+ QTest::addColumn<bool>("doClose");
+
+ QTest::newRow("disconnect") << false;
+ QTest::newRow("close") << true;
+}
+
+void tst_QTcpSocket::disconnectWhileLookingUp()
+{
+ QFETCH_GLOBAL(bool, setProxy);
+ if (setProxy)
+ return; // we let the proxies do the lookup now
+
+ // just connect and disconnect, then make sure nothing weird happened
+ QTcpSocket *socket = newSocket();
+ socket->connectToHost(QtNetworkSettings::serverName(), 21);
+
+ // check that connect is in progress
+ QVERIFY(socket->state() != QAbstractSocket::UnconnectedState);
+
+ QFETCH(bool, doClose);
+ if (doClose) {
+ socket->close();
+ QVERIFY(socket->openMode() == QIODevice::NotOpen);
+ } else {
+ socket->disconnectFromHost();
+ QVERIFY(socket->openMode() == QIODevice::ReadWrite);
+ }
+
+ // let anything queued happen
+ QEventLoop loop;
+#ifndef Q_OS_SYMBIAN
+ QTimer::singleShot(50, &loop, SLOT(quit()));
+#else
+ QTimer::singleShot(5000, &loop, SLOT(quit()));
+#endif
+ loop.exec();
+
+ // recheck
+ if (doClose) {
+ QVERIFY(socket->openMode() == QIODevice::NotOpen);
+ } else {
+ QVERIFY(socket->openMode() == QIODevice::ReadWrite);
+ }
+
+ QVERIFY(socket->state() == QAbstractSocket::UnconnectedState);
+}
+
+//----------------------------------------------------------------------------------
+void tst_QTcpSocket::downloadBigFile()
+{
+ if (tmpSocket)
+ delete tmpSocket;
+ tmpSocket = newSocket();
+
+ connect(tmpSocket, SIGNAL(connected()), SLOT(exitLoopSlot()));
+ connect(tmpSocket, SIGNAL(readyRead()), SLOT(downloadBigFileSlot()));
+ connect(tmpSocket, SIGNAL(disconnected()), SLOT(exitLoopSlot()));
+
+ tmpSocket->connectToHost(QtNetworkSettings::serverName(), 80);
+
+ enterLoop(30);
+ if (timeout()) {
+ delete tmpSocket;
+ tmpSocket = 0;
+ QFAIL("Network operation timed out");
+ }
+
+ QByteArray hostName = QtNetworkSettings::serverName().toLatin1();
+ QVERIFY(tmpSocket->state() == QAbstractSocket::ConnectedState);
+ QVERIFY(tmpSocket->write("GET /qtest/mediumfile HTTP/1.0\r\n") > 0);
+ QVERIFY(tmpSocket->write("HOST: ") > 0);
+ QVERIFY(tmpSocket->write(hostName.data()) > 0);
+ QVERIFY(tmpSocket->write("\r\n") > 0);
+ QVERIFY(tmpSocket->write("\r\n") > 0);
+
+ bytesAvailable = 0;
+ expectedLength = 0;
+ readingBody = false;
+
+ QTime stopWatch;
+ stopWatch.start();
+
+ enterLoop(600);
+ if (timeout()) {
+ delete tmpSocket;
+ tmpSocket = 0;
+ if (bytesAvailable > 0)
+ qDebug("Slow Connection, only downloaded %ld of %d", long(bytesAvailable), 10000281);
+ QFAIL("Network operation timed out");
+ }
+
+ QCOMPARE(bytesAvailable, expectedLength);
+
+ qDebug("\t\t%.1fMB/%.1fs: %.1fMB/s",
+ bytesAvailable / (1024.0 * 1024.0),
+ stopWatch.elapsed() / 1024.0,
+ (bytesAvailable / (stopWatch.elapsed() / 1000.0)) / (1024 * 1024));
+
+ delete tmpSocket;
+ tmpSocket = 0;
+}
+
+//----------------------------------------------------------------------------------
+void tst_QTcpSocket::exitLoopSlot()
+{
+ exitLoop();
+}
+
+//----------------------------------------------------------------------------------
+void tst_QTcpSocket::downloadBigFileSlot()
+{
+ if (!readingBody) {
+ while (tmpSocket->canReadLine()) {
+ QByteArray array = tmpSocket->readLine();
+ if (array.startsWith("Content-Length"))
+ expectedLength = array.simplified().split(' ').at(1).toInt();
+ if (array == "\r\n") {
+ readingBody = true;
+ break;
+ }
+ }
+ }
+ if (readingBody) {
+ bytesAvailable += tmpSocket->readAll().size();
+ if (bytesAvailable == expectedLength)
+ exitLoop();
+ }
+}
+
+//----------------------------------------------------------------------------------
+void tst_QTcpSocket::readLine()
+{
+ QTcpSocket *socket = newSocket();
+ socket->connectToHost(QtNetworkSettings::serverName(), 143);
+ QVERIFY(socket->waitForConnected(5000));
+
+ while (!socket->canReadLine())
+ QVERIFY(socket->waitForReadyRead(10000));
+
+ char buffer[1024];
+
+ qint64 linelen = socket->readLine(buffer, sizeof(buffer));
+ QVERIFY(linelen >= 3);
+ QVERIFY(linelen < 1024);
+
+ QByteArray reply = QByteArray::fromRawData(buffer, linelen);
+ QCOMPARE((int) buffer[linelen-2], (int) '\r');
+ QCOMPARE((int) buffer[linelen-1], (int) '\n');
+ QCOMPARE((int) buffer[linelen], (int) '\0');
+
+ QVERIFY2(QtNetworkSettings::compareReplyIMAP(reply), reply.constData());
+
+ QCOMPARE(socket->write("1 NOOP\r\n"), qint64(8));
+
+ while (socket->bytesAvailable() < 10)
+ QVERIFY(socket->waitForReadyRead(10000));
+
+ QCOMPARE(socket->readLine(buffer, 11), qint64(10));
+ QCOMPARE((const char *)buffer, "1 OK Compl");
+
+ while (socket->bytesAvailable() < 6)
+ QVERIFY(socket->waitForReadyRead(10000));
+
+ QCOMPARE(socket->readLine(buffer, 11), qint64(6));
+ QCOMPARE((const char *)buffer, "eted\r\n");
+
+ QVERIFY(!socket->waitForReadyRead(100));
+ QCOMPARE(socket->readLine(buffer, sizeof(buffer)), qint64(0));
+ QVERIFY(socket->error() == QAbstractSocket::SocketTimeoutError
+ || socket->error() == QAbstractSocket::RemoteHostClosedError);
+ QCOMPARE(socket->bytesAvailable(), qint64(0));
+
+ socket->close();
+ QCOMPARE(socket->readLine(buffer, sizeof(buffer)), qint64(-1));
+
+ delete socket;
+}
+
+//----------------------------------------------------------------------------------
+void tst_QTcpSocket::readLineString()
+{
+ QTcpSocket *socket = newSocket();
+ socket->connectToHost(QtNetworkSettings::serverName(), 143);
+ QVERIFY(socket->waitForReadyRead(10000));
+
+ QByteArray arr = socket->readLine();
+ QVERIFY2(QtNetworkSettings::compareReplyIMAP(arr), arr.constData());
+
+ delete socket;
+}
+
+//----------------------------------------------------------------------------------
+void tst_QTcpSocket::readChunks()
+{
+ QTcpSocket *socket = newSocket();
+ socket->connectToHost(QtNetworkSettings::serverName(), 143);
+ QVERIFY(socket->waitForConnected(10000));
+ QVERIFY(socket->waitForReadyRead(5000));
+
+ char buf[4096];
+ memset(buf, '@', sizeof(buf));
+ qint64 dataLength = socket->read(buf, sizeof(buf));
+ QVERIFY(dataLength > 0);
+
+ QCOMPARE(buf[dataLength - 2], '\r');
+ QCOMPARE(buf[dataLength - 1], '\n');
+ QCOMPARE(buf[dataLength], '@');
+
+ delete socket;
+}
+
+//----------------------------------------------------------------------------------
+void tst_QTcpSocket::waitForBytesWritten()
+{
+ QTcpSocket *socket = newSocket();
+ socket->connectToHost(QtNetworkSettings::serverName(), 80);
+ QVERIFY(socket->waitForConnected(10000));
+
+ socket->write("GET / HTTP/1.0\r\n\r\n");
+ qint64 toWrite = socket->bytesToWrite();
+ QVERIFY(socket->waitForBytesWritten(5000));
+ QVERIFY(toWrite > socket->bytesToWrite());
+
+ delete socket;
+}
+
+//----------------------------------------------------------------------------------
+void tst_QTcpSocket::waitForBytesWrittenMinusOne()
+{
+ QTcpSocket *socket = newSocket();
+ socket->connectToHost(QtNetworkSettings::serverName(), 80);
+ QVERIFY(socket->waitForConnected(10000));
+
+ socket->write("GET / HTTP/1.0\r\n\r\n");
+ qint64 toWrite = socket->bytesToWrite();
+ QVERIFY(socket->waitForBytesWritten(-1));
+ QVERIFY(toWrite > socket->bytesToWrite());
+
+ delete socket;
+}
+
+//----------------------------------------------------------------------------------
+void tst_QTcpSocket::waitForReadyRead()
+{
+ QTcpSocket *socket = newSocket();
+ socket->connectToHost(QtNetworkSettings::serverName(), 80);
+ socket->write("GET / HTTP/1.0\r\n\r\n");
+ QVERIFY(socket->waitForReadyRead(5000));
+ delete socket;
+}
+
+//----------------------------------------------------------------------------------
+void tst_QTcpSocket::waitForReadyReadMinusOne()
+{
+ QTcpSocket *socket = newSocket();
+ socket->connectToHost(QtNetworkSettings::serverName(), 80);
+ socket->write("GET / HTTP/1.0\r\n\r\n");
+ QVERIFY(socket->waitForReadyRead(-1));
+ delete socket;
+}
+
+//----------------------------------------------------------------------------------
+void tst_QTcpSocket::flush()
+{
+ QTcpSocket *socket = newSocket();
+ socket->flush();
+
+ connect(socket, SIGNAL(connected()), SLOT(exitLoopSlot()));
+ socket->connectToHost(QtNetworkSettings::serverName(), 143);
+ enterLoop(60);
+ QVERIFY(socket->isOpen());
+
+ socket->write("1 LOGOUT\r\n");
+ QCOMPARE(socket->bytesToWrite(), qint64(10));
+ socket->flush();
+ QCOMPARE(socket->bytesToWrite(), qint64(0));
+ socket->close();
+
+ delete socket;
+}
+
+//----------------------------------------------------------------------------------
+void tst_QTcpSocket::synchronousApi()
+{
+ QTcpSocket *ftpSocket = newSocket();
+ ftpSocket->connectToHost(QtNetworkSettings::serverName(), 21);
+ ftpSocket->write("QUIT\r\n");
+ QVERIFY(ftpSocket->waitForDisconnected(10000));
+ QVERIFY(ftpSocket->bytesAvailable() > 0);
+ QByteArray arr = ftpSocket->readAll();
+ QVERIFY(arr.size() > 0);
+ delete ftpSocket;
+}
+
+//----------------------------------------------------------------------------------
+void tst_QTcpSocket::dontCloseOnTimeout()
+{
+ QTcpServer server;
+ server.setProxy(QNetworkProxy(QNetworkProxy::NoProxy));
+ QVERIFY(server.listen());
+
+ QHostAddress serverAddress = QHostAddress::LocalHost;
+ if (!(server.serverAddress() == QHostAddress::AnyIPv4) && !(server.serverAddress() == QHostAddress::AnyIPv6))
+ serverAddress = server.serverAddress();
+
+ QTcpSocket *socket = newSocket();
+ socket->connectToHost(serverAddress, server.serverPort());
+#ifndef Q_OS_SYMBIAN
+ QVERIFY(!socket->waitForReadyRead(100));
+#else
+ QVERIFY(!socket->waitForReadyRead(5000));
+#endif
+ QCOMPARE(socket->error(), QTcpSocket::SocketTimeoutError);
+ QVERIFY(socket->isOpen());
+
+#ifndef Q_OS_SYMBIAN
+ QVERIFY(!socket->waitForDisconnected(100));
+#else
+ QVERIFY(!socket->waitForDisconnected(5000));
+#endif
+ QCOMPARE(socket->error(), QTcpSocket::SocketTimeoutError);
+ QVERIFY(socket->isOpen());
+
+ delete socket;
+}
+
+//----------------------------------------------------------------------------------
+void tst_QTcpSocket::recursiveReadyRead()
+{
+ QTcpSocket *smtp = newSocket();
+ connect(smtp, SIGNAL(connected()), SLOT(exitLoopSlot()));
+ connect(smtp, SIGNAL(readyRead()), SLOT(recursiveReadyReadSlot()));
+ tmpSocket = smtp;
+
+ QSignalSpy spy(smtp, SIGNAL(readyRead()));
+
+ smtp->connectToHost("smtp.trolltech.com", 25);
+ enterLoop(30);
+ QVERIFY2(!timeout(),
+ "Timed out when connecting to smtp.trolltech.com:25");
+
+ enterLoop(30);
+ QVERIFY2(!timeout(),
+ "Timed out when waiting for the readyRead() signal");
+
+ QCOMPARE(spy.count(), 1);
+
+ delete smtp;
+}
+
+void tst_QTcpSocket::recursiveReadyReadSlot()
+{
+ // make sure the server spits out more data
+ tmpSocket->write("NOOP\r\n");
+ tmpSocket->flush();
+
+ // indiscriminately enter the event loop and start processing
+ // events again. but oops! future socket notifications will cause
+ // undesired recursive behavior. Unless QTcpSocket is smart, which
+ // it of course is. :-)
+ QEventLoop loop;
+ for (int i = 0; i < 100; ++i)
+ loop.processEvents();
+
+ // all we really wanted to do was process some events, then exit
+ // the loop
+ exitLoop();
+}
+
+//----------------------------------------------------------------------------------
+void tst_QTcpSocket::atEnd()
+{
+ QTcpSocket *socket = newSocket();
+ socket->connectToHost(QtNetworkSettings::serverName(), 21);
+
+ QVERIFY(socket->waitForReadyRead(15000));
+ QTextStream stream(socket);
+ QVERIFY(!stream.atEnd());
+ QString greeting = stream.readLine();
+ QVERIFY(stream.atEnd());
+
+ // Test server must use some vsFTPd 2.x.x version
+ QVERIFY2(greeting.length() == sizeof("220 (vsFTPd 2.x.x)")-1, qPrintable(greeting));
+ QVERIFY2(greeting.startsWith("220 (vsFTPd 2."), qPrintable(greeting));
+ QVERIFY2(greeting.endsWith(")"), qPrintable(greeting));
+
+ delete socket;
+}
+
+class TestThread : public QThread
+{
+ Q_OBJECT
+
+public:
+ inline QByteArray data() const
+ {
+ return socketData;
+ }
+
+protected:
+ inline void run()
+ {
+#ifndef QT_NO_OPENSSL
+ QFETCH_GLOBAL(bool, ssl);
+ if (ssl)
+ socket = new QSslSocket;
+ else
+#endif
+ socket = new QTcpSocket;
+ connect(socket, SIGNAL(readyRead()), this, SLOT(getData()), Qt::DirectConnection);
+ connect(socket, SIGNAL(disconnected()), this, SLOT(closed()), Qt::DirectConnection);
+ connect(socket, SIGNAL(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)),
+ SLOT(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)), Qt::DirectConnection);
+
+ socket->connectToHost(QtNetworkSettings::serverName(), 21);
+ socket->write("QUIT\r\n");
+ exec();
+
+ delete socket;
+ }
+
+private slots:
+ inline void getData()
+ {
+ socketData += socket->readAll();
+ }
+
+ inline void closed()
+ {
+ quit();
+ }
+ inline void proxyAuthenticationRequired(const QNetworkProxy &, QAuthenticator *auth)
+ {
+ auth->setUser("qsockstest");
+ auth->setPassword("password");
+ }
+private:
+ int exitCode;
+ QTcpSocket *socket;
+ QByteArray socketData;
+};
+
+//----------------------------------------------------------------------------------
+void tst_QTcpSocket::socketInAThread()
+{
+ for (int i = 0; i < 3; ++i) {
+ TestThread thread;
+ thread.start();
+ QVERIFY(thread.wait(15000));
+ QByteArray data = thread.data();
+ QVERIFY2(QtNetworkSettings::compareReplyFtp(data), data.constData());
+ }
+}
+
+//----------------------------------------------------------------------------------
+void tst_QTcpSocket::socketsInThreads()
+{
+ for (int i = 0; i < 3; ++i) {
+ TestThread thread1;
+ TestThread thread2;
+ TestThread thread3;
+
+ thread1.start();
+ thread2.start();
+ thread3.start();
+
+ QVERIFY(thread2.wait(15000));
+ QVERIFY(thread3.wait(15000));
+ QVERIFY(thread1.wait(15000));
+
+ QByteArray data1 = thread1.data();
+ QByteArray data2 = thread2.data();
+ QByteArray data3 = thread3.data();
+
+ QVERIFY2(QtNetworkSettings::compareReplyFtp(data1), data1.constData());
+ QVERIFY2(QtNetworkSettings::compareReplyFtp(data2), data2.constData());
+ QVERIFY2(QtNetworkSettings::compareReplyFtp(data3), data3.constData());
+ }
+}
+
+//----------------------------------------------------------------------------------
+void tst_QTcpSocket::waitForReadyReadInASlot()
+{
+ QTcpSocket *socket = newSocket();
+ tmpSocket = socket;
+ connect(socket, SIGNAL(connected()), this, SLOT(waitForReadyReadInASlotSlot()));
+
+ socket->connectToHost(QtNetworkSettings::serverName(), 80);
+ socket->write("GET / HTTP/1.0\r\n\r\n");
+
+ enterLoop(30);
+ QVERIFY(!timeout());
+
+ delete socket;
+}
+
+void tst_QTcpSocket::waitForReadyReadInASlotSlot()
+{
+ QVERIFY(tmpSocket->waitForReadyRead(10000));
+ exitLoop();
+}
+
+class RemoteCloseErrorServer : public QTcpServer
+{
+ Q_OBJECT
+public:
+ RemoteCloseErrorServer()
+ {
+ connect(this, SIGNAL(newConnection()),
+ this, SLOT(getConnection()));
+ }
+
+private slots:
+ void getConnection()
+ {
+ tst_QTcpSocket::exitLoop();
+ }
+};
+
+//----------------------------------------------------------------------------------
+void tst_QTcpSocket::remoteCloseError()
+{
+ QFETCH_GLOBAL(bool, setProxy);
+ if (setProxy)
+ return; //proxy not useful for localhost test case
+ RemoteCloseErrorServer server;
+ QVERIFY(server.listen(QHostAddress::LocalHost));
+
+ QCoreApplication::instance()->processEvents();
+
+ QTcpSocket *clientSocket = newSocket();
+ connect(clientSocket, SIGNAL(readyRead()), this, SLOT(exitLoopSlot()));
+
+ clientSocket->connectToHost(server.serverAddress(), server.serverPort());
+
+ enterLoop(30);
+ QVERIFY(!timeout());
+
+ QVERIFY(server.hasPendingConnections());
+ QTcpSocket *serverSocket = server.nextPendingConnection();
+ connect(clientSocket, SIGNAL(disconnected()), this, SLOT(exitLoopSlot()));
+
+ serverSocket->write("Hello");
+
+ enterLoop(30);
+ QVERIFY(!timeout());
+
+ QCOMPARE(clientSocket->bytesAvailable(), qint64(5));
+
+ qRegisterMetaType<QAbstractSocket::SocketError>("QAbstractSocket::SocketError");
+ QSignalSpy errorSpy(clientSocket, SIGNAL(error(QAbstractSocket::SocketError)));
+ QSignalSpy disconnectedSpy(clientSocket, SIGNAL(disconnected()));
+
+ clientSocket->write("World");
+ serverSocket->disconnectFromHost();
+
+ tmpSocket = clientSocket;
+ connect(clientSocket, SIGNAL(error(QAbstractSocket::SocketError)),
+ this, SLOT(remoteCloseErrorSlot()));
+
+ enterLoop(30);
+ QVERIFY(!timeout());
+
+ QCOMPARE(disconnectedSpy.count(), 1);
+ QCOMPARE(errorSpy.count(), 1);
+ QCOMPARE(clientSocket->error(), QAbstractSocket::RemoteHostClosedError);
+
+ delete serverSocket;
+
+ clientSocket->connectToHost(server.serverAddress(), server.serverPort());
+
+ enterLoop(30);
+ QVERIFY(!timeout());
+
+ QVERIFY(server.hasPendingConnections());
+ serverSocket = server.nextPendingConnection();
+ serverSocket->disconnectFromHost();
+
+ enterLoop(30);
+ QVERIFY(!timeout());
+
+ QCOMPARE(clientSocket->state(), QAbstractSocket::UnconnectedState);
+
+ delete clientSocket;
+}
+
+void tst_QTcpSocket::remoteCloseErrorSlot()
+{
+ QCOMPARE(tmpSocket->state(), QAbstractSocket::ConnectedState);
+ static_cast<QTcpSocket *>(sender())->close();
+}
+
+void tst_QTcpSocket::messageBoxSlot()
+{
+#if !defined(Q_OS_VXWORKS) // no gui
+ QTcpSocket *socket = qobject_cast<QTcpSocket *>(sender());
+ socket->deleteLater();
+ QMessageBox box;
+ QTimer::singleShot(100, &box, SLOT(close()));
+
+ // This should not delete the socket
+ box.exec();
+
+ // Fire a non-0 singleshot to leave time for the delete
+ QTimer::singleShot(250, this, SLOT(exitLoopSlot()));
+#endif
+}
+//----------------------------------------------------------------------------------
+void tst_QTcpSocket::openMessageBoxInErrorSlot()
+{
+#if defined(Q_OS_VXWORKS) // no gui
+ QSKIP("no default gui available on VxWorks", SkipAll);
+#else
+ QTcpSocket *socket = newSocket();
+ QPointer<QTcpSocket> p(socket);
+ connect(socket, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(messageBoxSlot()));
+
+ socket->connectToHost("hostnotfoundhostnotfound.troll.no", 9999); // Host not found, fyi
+ enterLoop(30);
+ QVERIFY(!p);
+#endif
+}
+
+//----------------------------------------------------------------------------------
+#ifndef Q_OS_WIN
+void tst_QTcpSocket::connectToLocalHostNoService()
+{
+ // This test was created after we received a report that claimed
+ // QTcpSocket would crash if trying to connect to "localhost" on a random
+ // port with no service listening.
+ QTcpSocket *socket = newSocket();
+ socket->connectToHost("localhost", 31415); // no service running here, one suspects
+
+ while(socket->state() == QTcpSocket::HostLookupState || socket->state() == QTcpSocket::ConnectingState) {
+ QTest::qWait(100);
+ }
+ QCOMPARE(socket->state(), QTcpSocket::UnconnectedState);
+ delete socket;
+}
+#endif
+
+//----------------------------------------------------------------------------------
+void tst_QTcpSocket::waitForConnectedInHostLookupSlot()
+{
+ // This test tries to reproduce the problem where waitForConnected() is
+ // called at a point where the host lookup is already done. QTcpSocket
+ // will try to abort the "pending lookup", but since it's already done and
+ // the queued signal is already underway, we will receive the signal after
+ // waitForConnected() has returned, and control goes back to the event
+ // loop. When the signal has been received, the connection is torn down,
+ // then reopened. Yikes. If we reproduce this by calling
+ // waitForConnected() inside hostLookupSlot(), it will even crash.
+ tmpSocket = newSocket();
+ QEventLoop loop;
+ connect(tmpSocket, SIGNAL(connected()), &loop, SLOT(quit()));
+ QTimer timer;
+ connect(&timer, SIGNAL(timeout()), &loop, SLOT(quit()));
+ QSignalSpy timerSpy(&timer, SIGNAL(timeout()));
+ timer.start(15000);
+
+ connect(tmpSocket, SIGNAL(hostFound()), this, SLOT(hostLookupSlot()));
+ tmpSocket->connectToHost(QtNetworkSettings::serverName(), 143);
+
+ // only execute the loop if not already connected
+ if (tmpSocket->state() != QAbstractSocket::ConnectedState)
+ loop.exec();
+
+ QCOMPARE(timerSpy.count(), 0);
+
+ delete tmpSocket;
+}
+
+void tst_QTcpSocket::hostLookupSlot()
+{
+ // This will fail to cancel the pending signal
+ QVERIFY(tmpSocket->waitForConnected(10000));
+}
+
+class Foo : public QObject
+{
+ Q_OBJECT
+ QTcpSocket *sock;
+public:
+ bool attemptedToConnect;
+ bool networkTimeout;
+ int count;
+
+ inline Foo(QObject *parent = 0) : QObject(parent)
+ {
+ attemptedToConnect = false;
+ networkTimeout = false;
+ count = 0;
+#ifndef QT_NO_OPENSSL
+ QFETCH_GLOBAL(bool, ssl);
+ if (ssl)
+ sock = new QSslSocket;
+ else
+#endif
+ sock = new QTcpSocket;
+ connect(sock, SIGNAL(connected()), this, SLOT(connectedToIt()));
+ connect(sock, SIGNAL(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)),
+ SLOT(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)));
+ }
+
+ inline ~Foo()
+ {
+ delete sock;
+ }
+
+public slots:
+ inline void connectedToIt()
+ { count++; }
+
+ inline void doIt()
+ {
+ attemptedToConnect = true;
+ sock->connectToHost(QtNetworkSettings::serverName(), 80);
+
+#ifdef Q_OS_MAC
+ pthread_yield_np();
+#elif defined Q_OS_LINUX
+ pthread_yield();
+#endif
+ if (!sock->waitForConnected()) {
+ networkTimeout = true;
+ }
+ tst_QTcpSocket::exitLoop();
+ }
+
+ inline void exitLoop()
+ {
+ tst_QTcpSocket::exitLoop();
+ }
+
+ inline void proxyAuthenticationRequired(const QNetworkProxy &, QAuthenticator *auth)
+ {
+ auth->setUser("qsockstest");
+ auth->setPassword("password");
+ }
+};
+
+//----------------------------------------------------------------------------------
+void tst_QTcpSocket::waitForConnectedInHostLookupSlot2()
+{
+#if defined(Q_OS_WIN) || defined(Q_OS_VXWORKS)
+ QSKIP("waitForConnectedInHostLookupSlot2 is not run on Windows and VxWorks", SkipAll);
+#else
+
+ Foo foo;
+ QPushButton top("Go", 0);
+ top.show();
+ connect(&top, SIGNAL(clicked()), &foo, SLOT(doIt()));
+
+ QTimer::singleShot(100, &top, SLOT(animateClick()));
+ QTimer::singleShot(5000, &foo, SLOT(exitLoop()));
+
+ enterLoop(30);
+ if (timeout() || foo.networkTimeout)
+ QFAIL("Network timeout");
+
+ QVERIFY(foo.attemptedToConnect);
+ QCOMPARE(foo.count, 1);
+#endif
+}
+
+//----------------------------------------------------------------------------------
+void tst_QTcpSocket::readyReadSignalsAfterWaitForReadyRead()
+{
+ QTcpSocket *socket = newSocket();
+
+ QSignalSpy readyReadSpy(socket, SIGNAL(readyRead()));
+
+ // Connect
+ socket->connectToHost(QtNetworkSettings::serverName(), 143);
+
+ // Wait for the read
+ QVERIFY(socket->waitForReadyRead(10000));
+
+ QCOMPARE(readyReadSpy.count(), 1);
+
+ QString s = socket->readLine();
+ QVERIFY2(QtNetworkSettings::compareReplyIMAP(s.toLatin1()), s.toLatin1().constData());
+ QCOMPARE(socket->bytesAvailable(), qint64(0));
+
+ QCoreApplication::instance()->processEvents();
+ QCOMPARE(socket->bytesAvailable(), qint64(0));
+ QCOMPARE(readyReadSpy.count(), 1);
+
+ delete socket;
+}
+
+class TestThread2 : public QThread
+{
+ Q_OBJECT
+public:
+ void run()
+ {
+ QFile fileWriter("fifo");
+ QVERIFY(fileWriter.open(QFile::WriteOnly));
+ QCOMPARE(fileWriter.write(QByteArray(32, '@')), qint64(32));
+ QCOMPARE(fileWriter.write(QByteArray(32, '@')), qint64(32));
+ QCOMPARE(fileWriter.write(QByteArray(32, '@')), qint64(32));
+ QCOMPARE(fileWriter.write(QByteArray(32, '@')), qint64(32));
+ }
+};
+
+//----------------------------------------------------------------------------------
+#ifdef Q_OS_LINUX
+void tst_QTcpSocket::linuxKernelBugLocalSocket()
+{
+ QFile::remove("fifo");
+ mkfifo("fifo", 0666);
+
+ TestThread2 test;
+ test.start();
+
+ QFile fileReader("fifo");
+ QVERIFY(fileReader.open(QFile::ReadOnly));
+
+ test.wait();
+
+ QTcpSocket *socket = newSocket();
+ socket->setSocketDescriptor(fileReader.handle());
+ QVERIFY(socket->waitForReadyRead(5000));
+ QCOMPARE(socket->bytesAvailable(), qint64(128));
+
+ QFile::remove("fifo");
+
+ delete socket;
+}
+#endif
+
+//----------------------------------------------------------------------------------
+void tst_QTcpSocket::abortiveClose()
+{
+ QFETCH_GLOBAL(bool, setProxy);
+ if (setProxy)
+ return; //proxy not useful for localhost test case
+ QTcpServer server;
+ QVERIFY(server.listen(QHostAddress::LocalHost));
+ connect(&server, SIGNAL(newConnection()), this, SLOT(exitLoopSlot()));
+
+ QTcpSocket *clientSocket = newSocket();
+ clientSocket->connectToHost(server.serverAddress(), server.serverPort());
+
+ enterLoop(10);
+ QVERIFY(server.hasPendingConnections());
+
+ QVERIFY(tmpSocket = server.nextPendingConnection());
+
+ qRegisterMetaType<QAbstractSocket::SocketError>("QAbstractSocket::SocketError");
+ QSignalSpy readyReadSpy(clientSocket, SIGNAL(readyRead()));
+ QSignalSpy errorSpy(clientSocket, SIGNAL(error(QAbstractSocket::SocketError)));
+
+ connect(clientSocket, SIGNAL(disconnected()), this, SLOT(exitLoopSlot()));
+ QTimer::singleShot(0, this, SLOT(abortiveClose_abortSlot()));
+
+ enterLoop(5);
+
+ QCOMPARE(readyReadSpy.count(), 0);
+ QCOMPARE(errorSpy.count(), 1);
+
+ QCOMPARE(*static_cast<const int *>(errorSpy.at(0).at(0).constData()),
+ int(QAbstractSocket::RemoteHostClosedError));
+
+ delete clientSocket;
+}
+
+void tst_QTcpSocket::abortiveClose_abortSlot()
+{
+ tmpSocket->abort();
+}
+
+//----------------------------------------------------------------------------------
+void tst_QTcpSocket::localAddressEmptyOnBSD()
+{
+ QFETCH_GLOBAL(bool, setProxy);
+ if (setProxy)
+ return; //proxy not useful for localhost test case
+ QTcpServer server;
+ QVERIFY(server.listen(QHostAddress::LocalHost));
+
+ QTcpSocket *tcpSocket = 0;
+ // we try 10 times, but note that this doesn't always provoke the bug
+ for (int i = 0; i < 10; ++i) {
+ delete tcpSocket;
+ tcpSocket = newSocket();
+ tcpSocket->connectToHost(QHostAddress::LocalHost, server.serverPort());
+ if (!tcpSocket->waitForConnected(0)) {
+ // to provoke the bug, we need a local socket that connects immediately
+ // --i;
+ tcpSocket->abort();
+ if (tcpSocket->state() != QTcpSocket::UnconnectedState)
+ QVERIFY(tcpSocket->waitForDisconnected(-1));
+ continue;
+ }
+ QCOMPARE(tcpSocket->localAddress(), QHostAddress(QHostAddress::LocalHost));
+ }
+ delete tcpSocket;
+}
+
+//----------------------------------------------------------------------------------
+void tst_QTcpSocket::zeroAndMinusOneReturns()
+{
+ QTcpSocket *socket = newSocket();
+ socket->connectToHost(QtNetworkSettings::serverName(), 80);
+ socket->write("GET / HTTP/1.0\r\nConnection: keep-alive\r\n\r\n");
+ QVERIFY(socket->waitForReadyRead(15000));
+
+ char c[16];
+ QVERIFY(socket->getChar(c));
+ QCOMPARE(socket->read(c, 16), qint64(16));
+ QVERIFY(socket->readLine(c, 16) > 0);
+ QVERIFY(!socket->readAll().isEmpty());
+
+ // the last operation emptied the read buffer
+ // all read operations from this point on should fail
+ // with return 0 because the socket is still open
+ QVERIFY(socket->readAll().isEmpty());
+ QCOMPARE(socket->read(c, 16), qint64(0));
+ QCOMPARE(socket->readLine(c, 16), qint64(0));
+ QVERIFY(!socket->getChar(c));
+
+ socket->write("GET / HTTP/1.0\r\n\r\n");
+ QVERIFY(socket->waitForDisconnected(15000));
+ QCOMPARE(socket->error(), QAbstractSocket::RemoteHostClosedError);
+
+ QCOMPARE(socket->write("BLUBBER"), qint64(-1));
+ QVERIFY(socket->getChar(c));
+ QCOMPARE(socket->read(c, 16), qint64(16));
+ QVERIFY(socket->readLine(c, 16) > 0);
+ QVERIFY(!socket->readAll().isEmpty());
+
+ // the last operation emptied the read buffer
+ // all read operations from this point on should fail
+ // with return -1 because the socket is not connected
+ QVERIFY(socket->readAll().isEmpty());
+ QCOMPARE(socket->read(c, 16), qint64(-1));
+ QCOMPARE(socket->readLine(c, 16), qint64(-1));
+ QVERIFY(!socket->getChar(c));
+ QVERIFY(!socket->putChar('a'));
+
+ socket->close();
+
+ // now the QIODevice is closed, which means getChar complains
+ QCOMPARE(socket->write("BLUBBER"), qint64(-1));
+ QCOMPARE(socket->read(c, 16), qint64(-1));
+ QCOMPARE(socket->readLine(c, 16), qint64(-1));
+ QVERIFY(!socket->getChar(c));
+ QVERIFY(!socket->putChar('a'));
+
+ delete socket;
+}
+
+//----------------------------------------------------------------------------------
+void tst_QTcpSocket::connectionRefused()
+{
+ qRegisterMetaType<QAbstractSocket::SocketError>("QAbstractSocket::SocketError");
+ qRegisterMetaType<QAbstractSocket::SocketState>("QAbstractSocket::SocketState");
+
+ QTcpSocket *socket = newSocket();
+ QSignalSpy stateSpy(socket, SIGNAL(stateChanged(QAbstractSocket::SocketState)));
+ QSignalSpy errorSpy(socket, SIGNAL(error(QAbstractSocket::SocketError)));
+ connect(socket, SIGNAL(error(QAbstractSocket::SocketError)),
+ &QTestEventLoop::instance(), SLOT(exitLoop()));
+
+ socket->connectToHost(QtNetworkSettings::serverName(), 144);
+
+ enterLoop(10);
+ disconnect(socket, SIGNAL(error(QAbstractSocket::SocketError)),
+ &QTestEventLoop::instance(), SLOT(exitLoop()));
+ QVERIFY2(!timeout(), "Network timeout");
+
+ QCOMPARE(socket->state(), QAbstractSocket::UnconnectedState);
+ QCOMPARE(socket->error(), QAbstractSocket::ConnectionRefusedError);
+
+ QCOMPARE(stateSpy.count(), 3);
+ QCOMPARE(qVariantValue<QAbstractSocket::SocketState>(stateSpy.at(0).at(0)), QAbstractSocket::HostLookupState);
+ QCOMPARE(qVariantValue<QAbstractSocket::SocketState>(stateSpy.at(1).at(0)), QAbstractSocket::ConnectingState);
+ QCOMPARE(qVariantValue<QAbstractSocket::SocketState>(stateSpy.at(2).at(0)), QAbstractSocket::UnconnectedState);
+ QCOMPARE(errorSpy.count(), 1);
+
+ delete socket;
+}
+
+//----------------------------------------------------------------------------------
+void tst_QTcpSocket::suddenRemoteDisconnect_data()
+{
+ QTest::addColumn<QString>("client");
+ QTest::addColumn<QString>("server");
+
+ QTest::newRow("Qt4 Client <-> Qt4 Server") << QString::fromLatin1("qt4client") << QString::fromLatin1("qt4server");
+}
+
+void tst_QTcpSocket::suddenRemoteDisconnect()
+{
+#if defined( Q_OS_SYMBIAN )
+ QSKIP("Symbian: QProcess IO is not yet supported, fix when supported", SkipAll);
+#else
+ QFETCH(QString, client);
+ QFETCH(QString, server);
+
+ QFETCH_GLOBAL(bool, setProxy);
+ if (setProxy)
+ return;
+ QFETCH_GLOBAL(bool, ssl);
+ if (ssl)
+ return;
+
+ // Start server
+ QProcess serverProcess;
+ serverProcess.setReadChannel(QProcess::StandardError);
+ serverProcess.start(QString::fromLatin1("stressTest/stressTest %1").arg(server),
+ QIODevice::ReadWrite | QIODevice::Text);
+ while (!serverProcess.canReadLine())
+ QVERIFY(serverProcess.waitForReadyRead(10000));
+ QCOMPARE(serverProcess.readLine().data(), (server.toLatin1() + "\n").data());
+
+ // Start client
+ QProcess clientProcess;
+ clientProcess.setReadChannel(QProcess::StandardError);
+ clientProcess.start(QString::fromLatin1("stressTest/stressTest %1").arg(client),
+ QIODevice::ReadWrite | QIODevice::Text);
+ while (!clientProcess.canReadLine())
+ QVERIFY(clientProcess.waitForReadyRead(10000));
+ QCOMPARE(clientProcess.readLine().data(), (client.toLatin1() + "\n").data());
+
+ // Let them play for a while
+ qDebug("Running stress test for 5 seconds");
+ QEventLoop loop;
+ connect(&serverProcess, SIGNAL(finished(int)), &loop, SLOT(quit()));
+ connect(&clientProcess, SIGNAL(finished(int)), &loop, SLOT(quit()));
+ QTime stopWatch;
+ stopWatch.start();
+ QTimer::singleShot(20000, &loop, SLOT(quit()));
+
+ while ((serverProcess.state() == QProcess::Running
+ || clientProcess.state() == QProcess::Running) && stopWatch.elapsed() < 20000)
+ loop.exec();
+
+ QVERIFY(stopWatch.elapsed() < 20000);
+
+ // Check that both exited normally.
+ QCOMPARE(clientProcess.readAll().constData(), "SUCCESS\n");
+ QCOMPARE(serverProcess.readAll().constData(), "SUCCESS\n");
+#endif
+}
+
+//----------------------------------------------------------------------------------
+void tst_QTcpSocket::connectToMultiIP()
+{
+ QSKIP("TODO: setup DNS in the new network", SkipAll);
+
+#if defined(Q_OS_VXWORKS)
+ QSKIP("VxSim in standard config doesn't even run a DNS resolver", SkipAll);
+#else
+ QFETCH_GLOBAL(bool, ssl);
+ if (ssl)
+ return;
+ QFETCH_GLOBAL(bool, setProxy);
+ if (setProxy)
+ QSKIP("This test takes too long if we also add the proxies.", SkipSingle);
+
+ qDebug("Please wait, this test can take a while...");
+
+ QTcpSocket *socket = newSocket();
+ // rationale: this domain resolves to 3 A-records, 2 of them are
+ // invalid. QTcpSocket should never spend more than 30 seconds per IP, and
+ // 30s*2 = 60s.
+ QTime stopWatch;
+ stopWatch.start();
+ socket->connectToHost("multi.dev.troll.no", 80);
+ QVERIFY(socket->waitForConnected(60500));
+ QVERIFY(stopWatch.elapsed() < 70000);
+ socket->abort();
+
+ stopWatch.restart();
+ socket->connectToHost("multi.dev.troll.no", 81);
+ QVERIFY(!socket->waitForConnected(2000));
+ QVERIFY(stopWatch.elapsed() < 2000);
+ QCOMPARE(socket->error(), QAbstractSocket::SocketTimeoutError);
+
+ delete socket;
+#endif
+}
+
+//----------------------------------------------------------------------------------
+void tst_QTcpSocket::moveToThread0()
+{
+ QFETCH_GLOBAL(int, proxyType);
+ if (proxyType & AuthMask)
+ return;
+
+ {
+ // Case 1: Moved after connecting, before waiting for connection.
+ QTcpSocket *socket = newSocket();;
+ socket->connectToHost(QtNetworkSettings::serverName(), 143);
+ socket->moveToThread(0);
+ QVERIFY(socket->waitForConnected(5000));
+ socket->write("XXX LOGOUT\r\n");
+ QVERIFY(socket->waitForBytesWritten(5000));
+ QVERIFY(socket->waitForDisconnected());
+ delete socket;
+ }
+ {
+ // Case 2: Moved before connecting
+ QTcpSocket *socket = newSocket();
+ socket->moveToThread(0);
+ socket->connectToHost(QtNetworkSettings::serverName(), 143);
+ QVERIFY(socket->waitForConnected(5000));
+ socket->write("XXX LOGOUT\r\n");
+ QVERIFY(socket->waitForBytesWritten(5000));
+ QVERIFY(socket->waitForDisconnected());
+ delete socket;
+ }
+ {
+ // Case 3: Moved after writing, while waiting for bytes to be written.
+ QTcpSocket *socket = newSocket();
+ socket->connectToHost(QtNetworkSettings::serverName(), 143);
+ QVERIFY(socket->waitForConnected(5000));
+ socket->write("XXX LOGOUT\r\n");
+ socket->moveToThread(0);
+ QVERIFY(socket->waitForBytesWritten(5000));
+ QVERIFY(socket->waitForDisconnected());
+ delete socket;
+ }
+ {
+ // Case 4: Moved after writing, while waiting for response.
+ QTcpSocket *socket = newSocket();
+ socket->connectToHost(QtNetworkSettings::serverName(), 143);
+ QVERIFY(socket->waitForConnected(5000));
+ socket->write("XXX LOGOUT\r\n");
+ QVERIFY(socket->waitForBytesWritten(5000));
+ socket->moveToThread(0);
+ QVERIFY(socket->waitForDisconnected());
+ delete socket;
+ }
+}
+
+void tst_QTcpSocket::increaseReadBufferSize()
+{
+ QFETCH_GLOBAL(bool, setProxy);
+ if (setProxy)
+ return; //proxy not useful for localhost test case
+ QTcpServer server;
+ QTcpSocket *active = newSocket();
+ connect(active, SIGNAL(readyRead()), SLOT(exitLoopSlot()));
+
+ // connect two sockets to each other:
+ QVERIFY(server.listen(QHostAddress::LocalHost));
+ active->connectToHost("127.0.0.1", server.serverPort());
+ QVERIFY(active->waitForConnected(5000));
+ QVERIFY(server.waitForNewConnection(5000));
+
+ QTcpSocket *passive = server.nextPendingConnection();
+ QVERIFY(passive);
+
+ // now write 512 bytes of data on one end
+ QByteArray data(512, 'a');
+ passive->write(data);
+ QVERIFY2(passive->waitForBytesWritten(5000), "Network timeout");
+
+ // set the read buffer size to less than what was written and iterate:
+ active->setReadBufferSize(256);
+ enterLoop(10);
+ QVERIFY2(!timeout(), "Network timeout");
+ QCOMPARE(active->bytesAvailable(), active->readBufferSize());
+
+ // increase the buffer size and iterate again:
+ active->setReadBufferSize(384);
+ enterLoop(10);
+ QVERIFY2(!timeout(), "Network timeout");
+ QCOMPARE(active->bytesAvailable(), active->readBufferSize());
+
+ // once more, but now it should read everything there was to read
+ active->setReadBufferSize(1024);
+ enterLoop(10);
+ QVERIFY2(!timeout(), "Network timeout");
+ QCOMPARE(active->bytesAvailable(), qint64(data.size()));
+
+ // drain it and compare
+ QCOMPARE(active->readAll(), data);
+
+ // now one more test by setting the buffer size to unlimited:
+ passive->write(data);
+ QVERIFY2(passive->waitForBytesWritten(5000), "Network timeout");
+ active->setReadBufferSize(256);
+ enterLoop(10);
+ QVERIFY2(!timeout(), "Network timeout");
+ QCOMPARE(active->bytesAvailable(), active->readBufferSize());
+ active->setReadBufferSize(0);
+ enterLoop(10);
+ QVERIFY2(!timeout(), "Network timeout");
+ QCOMPARE(active->bytesAvailable(), qint64(data.size()));
+ QCOMPARE(active->readAll(), data);
+
+ delete active;
+}
+
+void tst_QTcpSocket::taskQtBug5799ConnectionErrorWaitForConnected()
+{
+ QFETCH_GLOBAL(bool, setProxy);
+ if (setProxy)
+ return;
+
+ // check that we get a proper error connecting to port 12346
+ // use waitForConnected, e.g. this should use a synchronous select() on the OS level
+
+ QTcpSocket socket;
+ socket.connectToHost(QtNetworkSettings::serverName(), 12346);
+ QTime timer;
+ timer.start();
+ socket.waitForConnected(10000);
+ QVERIFY2(timer.elapsed() < 9900, "Connection to closed port timed out instead of refusing, something is wrong");
+ QVERIFY2(socket.state() == QAbstractSocket::UnconnectedState, "Socket connected unexpectedly!");
+ QVERIFY2(socket.error() == QAbstractSocket::ConnectionRefusedError,
+ QString("Could not reach server: %1").arg(socket.errorString()).toLocal8Bit());
+}
+
+void tst_QTcpSocket::taskQtBug5799ConnectionErrorEventLoop()
+{
+ QFETCH_GLOBAL(bool, setProxy);
+ if (setProxy)
+ return;
+
+ // check that we get a proper error connecting to port 12346
+ // This testcase uses an event loop
+ QTcpSocket socket;
+ connect(&socket, SIGNAL(error(QAbstractSocket::SocketError)), &QTestEventLoop::instance(), SLOT(exitLoop()));
+ socket.connectToHost(QtNetworkSettings::serverName(), 12346);
+
+ QTestEventLoop::instance().enterLoop(10);
+ QVERIFY2(!QTestEventLoop::instance().timeout(), "Connection to closed port timed out instead of refusing, something is wrong");
+ QVERIFY2(socket.state() == QAbstractSocket::UnconnectedState, "Socket connected unexpectedly!");
+ QVERIFY2(socket.error() == QAbstractSocket::ConnectionRefusedError,
+ QString("Could not reach server: %1").arg(socket.errorString()).toLocal8Bit());
+}
+
+void tst_QTcpSocket::taskQtBug7054TimeoutErrorResetting()
+{
+ QTcpSocket *socket = newSocket();
+
+ socket->connectToHost(QtNetworkSettings::serverName(), 443);
+ QVERIFY(socket->waitForConnected(5*1000));
+ QVERIFY(socket->error() == QAbstractSocket::UnknownSocketError);
+
+ // We connected to the HTTPS port. Wait two seconds to receive data. We will receive
+ // nothing because we would need to start the SSL handshake
+ QVERIFY(!socket->waitForReadyRead(2*1000));
+ QVERIFY(socket->error() == QAbstractSocket::SocketTimeoutError);
+
+ // Now write some crap to make the server disconnect us. 4 lines are enough.
+ socket->write("a\r\nb\r\nc\r\nd\r\n");
+ socket->waitForBytesWritten(2*1000);
+
+ // we try to waitForReadyRead another time, but this time instead of a timeout we
+ // should get a better error since the server disconnected us
+ QVERIFY(!socket->waitForReadyRead(2*1000));
+ // It must NOT be the SocketTimeoutError that had been set before
+ QVERIFY(socket->error() == QAbstractSocket::RemoteHostClosedError);
+}
+
+void tst_QTcpSocket::invalidProxy_data()
+{
+ QTest::addColumn<int>("type");
+ QTest::addColumn<QString>("host");
+ QTest::addColumn<int>("port");
+ QTest::addColumn<bool>("failsAtConnect");
+ QTest::addColumn<int>("expectedError");
+
+ QString fluke = QHostInfo::fromName(QtNetworkSettings::serverName()).addresses().first().toString();
+ QTest::newRow("ftp-proxy") << int(QNetworkProxy::FtpCachingProxy) << fluke << 21 << true
+ << int(QAbstractSocket::UnsupportedSocketOperationError);
+ QTest::newRow("http-caching-proxy") << int(QNetworkProxy::HttpCachingProxy) << fluke << 3128 << true
+ << int(QAbstractSocket::UnsupportedSocketOperationError);
+ QTest::newRow("no-such-host-socks5") << int(QNetworkProxy::Socks5Proxy)
+ << "this-host-will-never-exist.troll.no" << 1080 << false
+ << int(QAbstractSocket::ProxyNotFoundError);
+ QTest::newRow("no-such-host-http") << int(QNetworkProxy::HttpProxy)
+ << "this-host-will-never-exist.troll.no" << 3128 << false
+ << int(QAbstractSocket::ProxyNotFoundError);
+#if !defined(Q_OS_SYMBIAN)
+ QTest::newRow("http-on-socks5") << int(QNetworkProxy::HttpProxy) << fluke << 1080 << false
+ << int(QAbstractSocket::ProxyConnectionClosedError);
+ QTest::newRow("socks5-on-http") << int(QNetworkProxy::Socks5Proxy) << fluke << 3128 << false
+ << int(QAbstractSocket::SocketTimeoutError);
+#endif
+}
+
+void tst_QTcpSocket::invalidProxy()
+{
+ QFETCH_GLOBAL(bool, setProxy);
+ if (setProxy)
+ return;
+
+ QFETCH(int, type);
+ QFETCH(QString, host);
+ QFETCH(int, port);
+ QFETCH(bool, failsAtConnect);
+ QNetworkProxy::ProxyType proxyType = QNetworkProxy::ProxyType(type);
+ QNetworkProxy proxy(proxyType, host, port);
+
+ QTcpSocket *socket = newSocket();
+ socket->setProxy(proxy);
+ socket->connectToHost(QHostInfo::fromName(QtNetworkSettings::serverName()).addresses().first().toString(), 80);
+
+ if (failsAtConnect) {
+ QCOMPARE(socket->state(), QAbstractSocket::UnconnectedState);
+ } else {
+ QCOMPARE(socket->state(), QAbstractSocket::ConnectingState);
+ QVERIFY(!socket->waitForConnected(5000));
+ }
+ QVERIFY(!socket->errorString().isEmpty());
+
+ // note: the following test is not a hard failure.
+ // Sometimes, error codes change for the better
+ QTEST(int(socket->error()), "expectedError");
+
+ delete socket;
+}
+
+// copied from tst_qnetworkreply.cpp
+class MyProxyFactory: public QNetworkProxyFactory
+{
+public:
+ int callCount;
+ QList<QNetworkProxy> toReturn;
+ QNetworkProxyQuery lastQuery;
+ inline MyProxyFactory() { clear(); }
+
+ inline void clear()
+ {
+ callCount = 0;
+ toReturn = QList<QNetworkProxy>() << QNetworkProxy::DefaultProxy;
+ lastQuery = QNetworkProxyQuery();
+ }
+
+ virtual QList<QNetworkProxy> queryProxy(const QNetworkProxyQuery &query)
+ {
+ lastQuery = query;
+ ++callCount;
+ return toReturn;
+ }
+};
+
+void tst_QTcpSocket::proxyFactory_data()
+{
+ QTest::addColumn<QList<QNetworkProxy> >("proxyList");
+ QTest::addColumn<QNetworkProxy>("proxyUsed");
+ QTest::addColumn<bool>("failsAtConnect");
+ QTest::addColumn<int>("expectedError");
+
+ QList<QNetworkProxy> proxyList;
+
+ // tests that do connect
+
+ proxyList << QNetworkProxy(QNetworkProxy::HttpProxy, QtNetworkSettings::serverName(), 3129);
+ QTest::newRow("http")
+ << proxyList << proxyList.at(0)
+ << false << int(QAbstractSocket::UnknownSocketError);
+
+ proxyList.clear();
+ proxyList << QNetworkProxy(QNetworkProxy::Socks5Proxy, QtNetworkSettings::serverName(), 1081);
+ QTest::newRow("socks5")
+ << proxyList << proxyList.at(0)
+ << false << int(QAbstractSocket::UnknownSocketError);
+
+ proxyList.clear();
+ proxyList << QNetworkProxy(QNetworkProxy::HttpCachingProxy, QtNetworkSettings::serverName(), 3129)
+ << QNetworkProxy(QNetworkProxy::Socks5Proxy, QtNetworkSettings::serverName(), 1081);
+ QTest::newRow("cachinghttp+socks5")
+ << proxyList << proxyList.at(1)
+ << false << int(QAbstractSocket::UnknownSocketError);
+
+ proxyList.clear();
+ proxyList << QNetworkProxy(QNetworkProxy::FtpCachingProxy, QtNetworkSettings::serverName(), 2121)
+ << QNetworkProxy(QNetworkProxy::HttpCachingProxy, QtNetworkSettings::serverName(), 3129)
+ << QNetworkProxy(QNetworkProxy::Socks5Proxy, QtNetworkSettings::serverName(), 1081);
+ QTest::newRow("ftp+cachinghttp+socks5")
+ << proxyList << proxyList.at(2)
+ << false << int(QAbstractSocket::UnknownSocketError);
+
+ // tests that fail to connect
+ proxyList.clear();
+ proxyList << QNetworkProxy(QNetworkProxy::HttpCachingProxy, QtNetworkSettings::serverName(), 3129);
+ QTest::newRow("cachinghttp")
+ << proxyList << QNetworkProxy()
+ << true << int(QAbstractSocket::UnsupportedSocketOperationError);
+
+ proxyList.clear();
+ proxyList << QNetworkProxy(QNetworkProxy::FtpCachingProxy, QtNetworkSettings::serverName(), 2121);
+ QTest::newRow("ftp")
+ << proxyList << QNetworkProxy()
+ << true << int(QAbstractSocket::UnsupportedSocketOperationError);
+
+ proxyList.clear();
+ proxyList << QNetworkProxy(QNetworkProxy::FtpCachingProxy, QtNetworkSettings::serverName(), 2121)
+ << QNetworkProxy(QNetworkProxy::HttpCachingProxy, QtNetworkSettings::serverName(), 3129);
+ QTest::newRow("ftp+cachinghttp")
+ << proxyList << QNetworkProxy()
+ << true << int(QAbstractSocket::UnsupportedSocketOperationError);
+}
+
+void tst_QTcpSocket::proxyFactory()
+{
+ QFETCH_GLOBAL(bool, setProxy);
+ if (setProxy)
+ return;
+
+ QFETCH(QList<QNetworkProxy>, proxyList);
+ QFETCH(QNetworkProxy, proxyUsed);
+ QFETCH(bool, failsAtConnect);
+
+ MyProxyFactory *factory = new MyProxyFactory;
+ factory->toReturn = proxyList;
+ QNetworkProxyFactory::setApplicationProxyFactory(factory);
+
+ QTcpSocket *socket = newSocket();
+ QString host = QtNetworkSettings::serverName();
+ socket->connectToHost(host, 80);
+
+ // Verify that the factory was called properly
+ QCOMPARE(factory->callCount, 1);
+ QCOMPARE(factory->lastQuery, QNetworkProxyQuery(host, 80));
+
+ if (failsAtConnect) {
+ QCOMPARE(socket->state(), QAbstractSocket::UnconnectedState);
+ } else {
+ QCOMPARE(socket->state(), QAbstractSocket::ConnectingState);
+ QVERIFY(socket->waitForConnected(5000));
+ QCOMPARE(proxyAuthCalled, 1);
+ }
+ QVERIFY(!socket->errorString().isEmpty());
+
+ // note: the following test is not a hard failure.
+ // Sometimes, error codes change for the better
+ QTEST(int(socket->error()), "expectedError");
+
+ delete socket;
+}
+
+// there is a similar test inside tst_qtcpserver that uses the event loop instead
+void tst_QTcpSocket::qtbug14268_peek()
+{
+ QFETCH_GLOBAL(bool, setProxy);
+ if (setProxy)
+ return;
+
+ SocketPair socketPair;
+ QVERIFY(socketPair.create());
+ QTcpSocket *outgoing = socketPair.endPoints[0];
+ QTcpSocket *incoming = socketPair.endPoints[1];
+
+ QVERIFY(incoming->state() == QTcpSocket::ConnectedState);
+ QVERIFY(outgoing->state() == QTcpSocket::ConnectedState);
+
+ outgoing->write("abc\n");
+ QVERIFY(outgoing->waitForBytesWritten(2000));
+ QVERIFY(incoming->waitForReadyRead(2000));
+ QVERIFY(incoming->peek(128*1024) == QByteArray("abc\n"));
+
+ outgoing->write("def\n");
+ QVERIFY(outgoing->waitForBytesWritten(2000));
+ QVERIFY(incoming->waitForReadyRead(2000));
+ QVERIFY(incoming->peek(128*1024) == QByteArray("abc\ndef\n"));
+
+ outgoing->write("ghi\n");
+ QVERIFY(outgoing->waitForBytesWritten(2000));
+ QVERIFY(incoming->waitForReadyRead(2000));
+ QVERIFY(incoming->peek(128*1024) == QByteArray("abc\ndef\nghi\n"));
+
+ QVERIFY(incoming->read(128*1024) == QByteArray("abc\ndef\nghi\n"));
+}
+
+
+
+QTEST_MAIN(tst_QTcpSocket)
+#include "tst_qtcpsocket.moc"
diff --git a/tests/auto/network/socket/qudpsocket/.gitignore b/tests/auto/network/socket/qudpsocket/.gitignore
new file mode 100644
index 0000000000..c6134126a0
--- /dev/null
+++ b/tests/auto/network/socket/qudpsocket/.gitignore
@@ -0,0 +1,2 @@
+tst_qudpsocket
+clientserver/clientserver
diff --git a/tests/auto/network/socket/qudpsocket/clientserver/clientserver.pro b/tests/auto/network/socket/qudpsocket/clientserver/clientserver.pro
new file mode 100644
index 0000000000..6da148659c
--- /dev/null
+++ b/tests/auto/network/socket/qudpsocket/clientserver/clientserver.pro
@@ -0,0 +1,8 @@
+QT = core network
+SOURCES += main.cpp
+CONFIG += console
+CONFIG -= app_bundle
+TARGET = clientserver
+DESTDIR = ./
+
+symbian: TARGET.CAPABILITY += NetworkServices
diff --git a/tests/auto/network/socket/qudpsocket/clientserver/main.cpp b/tests/auto/network/socket/qudpsocket/clientserver/main.cpp
new file mode 100644
index 0000000000..9145a5199f
--- /dev/null
+++ b/tests/auto/network/socket/qudpsocket/clientserver/main.cpp
@@ -0,0 +1,170 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#include <QtNetwork>
+
+class ClientServer : public QUdpSocket
+{
+ Q_OBJECT
+public:
+ enum Type {
+ ConnectedClient,
+ UnconnectedClient,
+ Server
+ };
+
+ ClientServer(Type type, const QString &host, quint16 port)
+ : type(type)
+ {
+ switch (type) {
+ case Server:
+ if (bind(0, ShareAddress | ReuseAddressHint)) {
+ printf("%d\n", localPort());
+ } else {
+ printf("XXX\n");
+ }
+ break;
+ case ConnectedClient:
+ connectToHost(host, port);
+ startTimer(250);
+ printf("ok\n");
+ break;
+ case UnconnectedClient:
+ peerAddress = host;
+ peerPort = port;
+ if (bind(QHostAddress::Any, port + 1, ShareAddress | ReuseAddressHint)) {
+ startTimer(250);
+ printf("ok\n");
+ } else {
+ printf("XXX\n");
+ }
+ break;
+ }
+ fflush(stdout);
+
+ connect(this, SIGNAL(readyRead()), this, SLOT(readData()));
+ }
+
+protected:
+ void timerEvent(QTimerEvent *event)
+ {
+ static int n = 0;
+ switch (type) {
+ case ConnectedClient:
+ write(QByteArray::number(n++));
+ break;
+ case UnconnectedClient:
+ writeDatagram(QByteArray::number(n++), peerAddress, peerPort);
+ break;
+ default:
+ break;
+ }
+
+ QUdpSocket::timerEvent(event);
+ }
+
+private slots:
+ void readData()
+ {
+ printf("readData()\n");
+ switch (type) {
+ case ConnectedClient: {
+ while (bytesAvailable() || hasPendingDatagrams()) {
+ QByteArray data = readAll();
+ printf("got %d\n", data.toInt());
+ }
+ break;
+ }
+ case UnconnectedClient: {
+ while (hasPendingDatagrams()) {
+ QByteArray data;
+ data.resize(pendingDatagramSize());
+ readDatagram(data.data(), data.size());
+ printf("got %d\n", data.toInt());
+ }
+ break;
+ }
+ case Server: {
+ while (hasPendingDatagrams()) {
+ QHostAddress sender;
+ quint16 senderPort;
+ QByteArray data;
+ data.resize(pendingDatagramSize());
+ readDatagram(data.data(), data.size(), &sender, &senderPort);
+ printf("got %d\n", data.toInt());
+ printf("sending %d\n", data.toInt() * 2);
+ writeDatagram(QByteArray::number(data.toInt() * 2), sender, senderPort);
+ }
+ break;
+ }
+ }
+ fflush(stdout);
+ }
+
+private:
+ Type type;
+ QHostAddress peerAddress;
+ quint16 peerPort;
+};
+
+int main(int argc, char **argv)
+{
+ QCoreApplication app(argc, argv);
+ ClientServer::Type type;
+ if (app.arguments().size() < 4) {
+ qDebug("usage: ./%s [ConnectedClient <server> <port>|UnconnectedClient <server> <port>|Server]", argv[0]);
+ return 1;
+ }
+
+ QString arg = app.arguments().at(1).trimmed().toLower();
+ if (arg == "connectedclient")
+ type = ClientServer::ConnectedClient;
+ else if (arg == "unconnectedclient")
+ type = ClientServer::UnconnectedClient;
+ else if (arg == "server")
+ type = ClientServer::Server;
+
+ ClientServer clientServer(type, app.arguments().at(2),
+ app.arguments().at(3).toInt());
+
+ return app.exec();
+}
+
+#include "main.moc"
diff --git a/tests/auto/network/socket/qudpsocket/qudpsocket.pro b/tests/auto/network/socket/qudpsocket/qudpsocket.pro
new file mode 100644
index 0000000000..4ddb7178a4
--- /dev/null
+++ b/tests/auto/network/socket/qudpsocket/qudpsocket.pro
@@ -0,0 +1,4 @@
+TEMPLATE = subdirs
+SUBDIRS = test clientserver
+
+
diff --git a/tests/auto/network/socket/qudpsocket/test/test.pro b/tests/auto/network/socket/qudpsocket/test/test.pro
new file mode 100644
index 0000000000..508dc97053
--- /dev/null
+++ b/tests/auto/network/socket/qudpsocket/test/test.pro
@@ -0,0 +1,28 @@
+load(qttest_p4)
+SOURCES += ../tst_qudpsocket.cpp
+QT = core network
+
+MOC_DIR=tmp
+
+win32 {
+ CONFIG(debug, debug|release) {
+ DESTDIR = ../debug
+} else {
+ DESTDIR = ../release
+ }
+} else {
+ DESTDIR = ../
+}
+
+wince*|symbian: {
+ addApp.files = ../clientserver/clientserver.exe
+ addApp.path = clientserver
+ DEPLOYMENT += addApp
+}
+
+TARGET = tst_qudpsocket
+
+symbian: TARGET.CAPABILITY += NetworkServices
+
+
+CONFIG+=insignificant_test
diff --git a/tests/auto/network/socket/qudpsocket/tst_qudpsocket.cpp b/tests/auto/network/socket/qudpsocket/tst_qudpsocket.cpp
new file mode 100644
index 0000000000..83d30cc40a
--- /dev/null
+++ b/tests/auto/network/socket/qudpsocket/tst_qudpsocket.cpp
@@ -0,0 +1,1356 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+
+#include <QtTest/QtTest>
+
+#include <qcoreapplication.h>
+#include <qfileinfo.h>
+#include <qdatastream.h>
+#include <qudpsocket.h>
+#include <qhostaddress.h>
+#include <qhostinfo.h>
+#include <qmap.h>
+#include <QNetworkProxy>
+#include <QNetworkInterface>
+
+#include <qstringlist.h>
+#include "../../../network-settings.h"
+
+#ifndef QT_NO_BEARERMANAGEMENT
+#include <QtNetwork/qnetworkconfigmanager.h>
+#include <QtNetwork/qnetworkconfiguration.h>
+#include <QtNetwork/qnetworksession.h>
+#endif
+
+Q_DECLARE_METATYPE(QHostAddress)
+Q_DECLARE_METATYPE(QNetworkInterface)
+Q_DECLARE_METATYPE(QSharedPointer<QNetworkSession>)
+//TESTED_CLASS=
+//TESTED_FILES=
+
+QT_FORWARD_DECLARE_CLASS(QUdpSocket)
+
+class tst_QUdpSocket : public QObject
+{
+ Q_OBJECT
+
+public:
+ tst_QUdpSocket();
+ virtual ~tst_QUdpSocket();
+
+
+public slots:
+ void initTestCase_data();
+ void init();
+ void cleanup();
+private slots:
+ void constructing();
+ void unconnectedServerAndClientTest();
+ void broadcasting();
+ void loop_data();
+ void loop();
+ void ipv6Loop_data();
+ void ipv6Loop();
+ void dualStack();
+ void readLine();
+ void pendingDatagramSize();
+ void writeDatagram();
+ void performance();
+ void bindMode();
+ void writeDatagramToNonExistingPeer_data();
+ void writeDatagramToNonExistingPeer();
+ void writeToNonExistingPeer_data();
+ void writeToNonExistingPeer();
+ void outOfProcessConnectedClientServerTest();
+ void outOfProcessUnconnectedClientServerTest();
+ void zeroLengthDatagram();
+ void multicastTtlOption_data();
+ void multicastTtlOption();
+ void multicastLoopbackOption_data();
+ void multicastLoopbackOption();
+ void multicastJoinBeforeBind_data();
+ void multicastJoinBeforeBind();
+ void multicastLeaveAfterClose_data();
+ void multicastLeaveAfterClose();
+ void setMulticastInterface_data();
+ void setMulticastInterface();
+ void multicast_data();
+ void multicast();
+ void echo_data();
+ void echo();
+
+protected slots:
+ void empty_readyReadSlot();
+ void empty_connectedSlot();
+
+private:
+#ifndef QT_NO_BEARERMANAGEMENT
+ QNetworkConfigurationManager *netConfMan;
+ QNetworkConfiguration networkConfiguration;
+ QSharedPointer<QNetworkSession> networkSession;
+#endif
+};
+
+tst_QUdpSocket::tst_QUdpSocket()
+{
+ Q_SET_DEFAULT_IAP
+}
+
+tst_QUdpSocket::~tst_QUdpSocket()
+{
+}
+
+void tst_QUdpSocket::initTestCase_data()
+{
+ QTest::addColumn<bool>("setProxy");
+ QTest::addColumn<int>("proxyType");
+
+ QTest::newRow("WithoutProxy") << false << 0;
+ QTest::newRow("WithSocks5Proxy") << true << int(QNetworkProxy::Socks5Proxy);
+
+#ifndef QT_NO_BEARERMANAGEMENT
+ netConfMan = new QNetworkConfigurationManager(this);
+ networkConfiguration = netConfMan->defaultConfiguration();
+ networkSession = QSharedPointer<QNetworkSession>(new QNetworkSession(networkConfiguration));
+ if (!networkSession->isOpen()) {
+ networkSession->open();
+ QVERIFY(networkSession->waitForOpened(30000));
+ }
+#endif
+}
+
+void tst_QUdpSocket::init()
+{
+ QFETCH_GLOBAL(bool, setProxy);
+ if (setProxy) {
+ QFETCH_GLOBAL(int, proxyType);
+ if (proxyType == QNetworkProxy::Socks5Proxy) {
+ QNetworkProxy::setApplicationProxy(QNetworkProxy(QNetworkProxy::Socks5Proxy, QtNetworkSettings::serverName(), 1080));
+ }
+ }
+}
+
+void tst_QUdpSocket::cleanup()
+{
+ QNetworkProxy::setApplicationProxy(QNetworkProxy::DefaultProxy);
+}
+
+
+//----------------------------------------------------------------------------------
+
+void tst_QUdpSocket::constructing()
+{
+ QUdpSocket socket;
+#ifdef FORCE_SESSION
+ socket.setProperty("_q_networksession", QVariant::fromValue(networkSession));
+#endif
+
+ QVERIFY(socket.isSequential());
+ QVERIFY(!socket.isOpen());
+ QVERIFY(socket.socketType() == QUdpSocket::UdpSocket);
+ QCOMPARE((int) socket.bytesAvailable(), 0);
+ QCOMPARE(socket.canReadLine(), false);
+ QCOMPARE(socket.readLine(), QByteArray());
+ QCOMPARE(socket.socketDescriptor(), -1);
+ QCOMPARE(socket.error(), QUdpSocket::UnknownSocketError);
+ QCOMPARE(socket.errorString(), QString("Unknown error"));
+
+ // Check the state of the socket api
+}
+
+void tst_QUdpSocket::unconnectedServerAndClientTest()
+{
+ QUdpSocket serverSocket;
+#ifdef FORCE_SESSION
+ serverSocket.setProperty("_q_networksession", QVariant::fromValue(networkSession));
+#endif
+
+ qRegisterMetaType<QAbstractSocket::SocketState>("QAbstractSocket::SocketState");
+
+ QSignalSpy stateChangedSpy(&serverSocket, SIGNAL(stateChanged(QAbstractSocket::SocketState)));
+ QVERIFY2(serverSocket.bind(), serverSocket.errorString().toLatin1().constData());
+ QCOMPARE(stateChangedSpy.count(), 1);
+
+ const char *message[] = {"Yo mista", "Yo", "Wassap"};
+
+ QHostAddress serverAddress = QHostAddress::LocalHost;
+ if (!(serverSocket.localAddress() == QHostAddress::AnyIPv4 || serverSocket.localAddress() == QHostAddress::AnyIPv6))
+ serverAddress = serverSocket.localAddress();
+
+ for (int i = 0; i < 3; ++i) {
+ QUdpSocket clientSocket;
+#ifdef FORCE_SESSION
+ clientSocket.setProperty("_q_networksession", QVariant::fromValue(networkSession));
+#endif
+ QCOMPARE(int(clientSocket.writeDatagram(message[i], strlen(message[i]),
+ serverAddress, serverSocket.localPort())),
+ int(strlen(message[i])));
+ char buf[1024];
+ QHostAddress host;
+ quint16 port;
+ QVERIFY(serverSocket.waitForReadyRead(5000));
+ QCOMPARE(int(serverSocket.readDatagram(buf, sizeof(buf), &host, &port)),
+ int(strlen(message[i])));
+ buf[strlen(message[i])] = '\0';
+ QCOMPARE(QByteArray(buf), QByteArray(message[i]));
+ }
+}
+
+//----------------------------------------------------------------------------------
+
+void tst_QUdpSocket::broadcasting()
+{
+ QFETCH_GLOBAL(bool, setProxy);
+ if (setProxy) {
+ QFETCH_GLOBAL(int, proxyType);
+ if (proxyType == QNetworkProxy::Socks5Proxy) {
+ QSKIP("With socks5 Broadcast is not supported.", SkipSingle);
+ }
+ }
+#ifdef Q_OS_AIX
+ QSKIP("Broadcast does not work on darko", SkipAll);
+#endif
+ const char *message[] = {"Yo mista", "", "Yo", "Wassap"};
+
+ QList<QHostAddress> broadcastAddresses;
+ foreach (QNetworkInterface iface, QNetworkInterface::allInterfaces()) {
+ if ((iface.flags() & QNetworkInterface::CanBroadcast)
+ && iface.flags() & QNetworkInterface::IsUp) {
+ for (int i=0;i<iface.addressEntries().count();i++)
+ broadcastAddresses.append(iface.addressEntries().at(i).broadcast());
+ }
+ }
+ if (broadcastAddresses.isEmpty())
+ QSKIP("No interface can broadcast", SkipAll);
+ for (int i = 0; i < 4; ++i) {
+ QUdpSocket serverSocket;
+#ifdef FORCE_SESSION
+ serverSocket.setProperty("_q_networksession", QVariant::fromValue(networkSession));
+#endif
+ QVERIFY2(serverSocket.bind(QHostAddress::Any, 5000), serverSocket.errorString().toLatin1().constData());
+
+ QCOMPARE(serverSocket.state(), QUdpSocket::BoundState);
+
+ connect(&serverSocket, SIGNAL(readyRead()), SLOT(empty_readyReadSlot()));
+
+ QUdpSocket broadcastSocket;
+#ifdef FORCE_SESSION
+ broadcastSocket.setProperty("_q_networksession", QVariant::fromValue(networkSession));
+#endif
+ broadcastSocket.bind();
+
+ for (int j = 0; j < 100; ++j) {
+ for (int k = 0; k < 4; k++) {
+ broadcastSocket.writeDatagram(message[i], strlen(message[i]),
+ QHostAddress::Broadcast, 5000);
+ foreach (QHostAddress addr, broadcastAddresses)
+ broadcastSocket.writeDatagram(message[i], strlen(message[i]), addr, 5000);
+ }
+ QTestEventLoop::instance().enterLoop(15);
+ if (QTestEventLoop::instance().timeout()) {
+#if defined(Q_OS_FREEBSD)
+ QEXPECT_FAIL("",
+ "Broadcasting to 255.255.255.255 does not work on FreeBSD",
+ Abort);
+ QVERIFY(false); // seems that QFAIL() doesn't respect the QEXPECT_FAIL() :/
+#endif
+ QFAIL("Network operation timed out");
+ }
+ QVERIFY(serverSocket.hasPendingDatagrams());
+
+ do {
+ QByteArray arr; arr.resize(serverSocket.pendingDatagramSize() + 1);
+ QHostAddress host;
+ quint16 port;
+ QCOMPARE((int) serverSocket.readDatagram(arr.data(), arr.size() - 1, &host, &port),
+ (int) strlen(message[i]));
+ arr.resize(strlen(message[i]));
+ QCOMPARE(arr, QByteArray(message[i]));
+ } while (serverSocket.hasPendingDatagrams());
+ }
+ }
+}
+
+//----------------------------------------------------------------------------------
+
+void tst_QUdpSocket::loop_data()
+{
+ QTest::addColumn<QByteArray>("peterMessage");
+ QTest::addColumn<QByteArray>("paulMessage");
+ QTest::addColumn<bool>("success");
+
+ QTest::newRow("\"Almond!\" | \"Joy!\"") << QByteArray("Almond!") << QByteArray("Joy!") << true;
+ QTest::newRow("\"A\" | \"B\"") << QByteArray("A") << QByteArray("B") << true;
+ QTest::newRow("\"AB\" | \"B\"") << QByteArray("AB") << QByteArray("B") << true;
+ QTest::newRow("\"AB\" | \"BB\"") << QByteArray("AB") << QByteArray("BB") << true;
+ QTest::newRow("\"A\\0B\" | \"B\\0B\"") << QByteArray::fromRawData("A\0B", 3) << QByteArray::fromRawData("B\0B", 3) << true;
+ QTest::newRow("\"(nil)\" | \"(nil)\"") << QByteArray() << QByteArray() << true;
+ QTest::newRow("Bigmessage") << QByteArray(600, '@') << QByteArray(600, '@') << true;
+}
+
+void tst_QUdpSocket::loop()
+{
+ QFETCH(QByteArray, peterMessage);
+ QFETCH(QByteArray, paulMessage);
+ QFETCH(bool, success);
+
+ QUdpSocket peter;
+ QUdpSocket paul;
+#ifdef FORCE_SESSION
+ peter.setProperty("_q_networksession", QVariant::fromValue(networkSession));
+ paul.setProperty("_q_networksession", QVariant::fromValue(networkSession));
+#endif
+
+ QVERIFY2(peter.bind(), peter.errorString().toLatin1().constData());
+ QVERIFY2(paul.bind(), paul.errorString().toLatin1().constData());
+
+ QHostAddress peterAddress = QHostAddress::LocalHost;
+ if (!(peter.localAddress() == QHostAddress::AnyIPv4 || peter.localAddress() == QHostAddress::AnyIPv6))
+ peterAddress = peter.localAddress();
+ QHostAddress pualAddress = QHostAddress::LocalHost;
+ if (!(paul.localAddress() == QHostAddress::AnyIPv4 || paul.localAddress() == QHostAddress::AnyIPv6))
+ pualAddress = paul.localAddress();
+
+ QCOMPARE(peter.writeDatagram(peterMessage.data(), peterMessage.length(),
+ pualAddress, paul.localPort()), qint64(peterMessage.length()));
+ QCOMPARE(paul.writeDatagram(paulMessage.data(), paulMessage.length(),
+ peterAddress, peter.localPort()), qint64(paulMessage.length()));
+
+ QVERIFY(peter.waitForReadyRead(9000));
+ QVERIFY(paul.waitForReadyRead(9000));
+ char peterBuffer[16*1024];
+ char paulBuffer[16*1024];
+ if (success) {
+ QCOMPARE(peter.readDatagram(peterBuffer, sizeof(peterBuffer)), qint64(paulMessage.length()));
+ QCOMPARE(paul.readDatagram(paulBuffer, sizeof(peterBuffer)), qint64(peterMessage.length()));
+ } else {
+ QVERIFY(peter.readDatagram(peterBuffer, sizeof(peterBuffer)) != paulMessage.length());
+ QVERIFY(paul.readDatagram(paulBuffer, sizeof(peterBuffer)) != peterMessage.length());
+ }
+
+ QCOMPARE(QByteArray(peterBuffer, paulMessage.length()), paulMessage);
+ QCOMPARE(QByteArray(paulBuffer, peterMessage.length()), peterMessage);
+}
+
+//----------------------------------------------------------------------------------
+
+void tst_QUdpSocket::ipv6Loop_data()
+{
+ loop_data();
+}
+
+void tst_QUdpSocket::ipv6Loop()
+{
+ QFETCH(QByteArray, peterMessage);
+ QFETCH(QByteArray, paulMessage);
+ QFETCH(bool, success);
+
+ QUdpSocket peter;
+ QUdpSocket paul;
+#ifdef FORCE_SESSION
+ peter.setProperty("_q_networksession", QVariant::fromValue(networkSession));
+ paul.setProperty("_q_networksession", QVariant::fromValue(networkSession));
+#endif
+
+ quint16 peterPort = 28124;
+ quint16 paulPort = 28123;
+
+ if (!peter.bind(QHostAddress::LocalHostIPv6, peterPort)) {
+ QCOMPARE(peter.error(), QUdpSocket::UnsupportedSocketOperationError);
+ } else {
+ QVERIFY(paul.bind(QHostAddress::LocalHostIPv6, paulPort));
+
+ QCOMPARE(peter.writeDatagram(peterMessage.data(), peterMessage.length(), QHostAddress("::1"),
+ paulPort), qint64(peterMessage.length()));
+ QCOMPARE(paul.writeDatagram(paulMessage.data(), paulMessage.length(),
+ QHostAddress("::1"), peterPort), qint64(paulMessage.length()));
+
+ char peterBuffer[16*1024];
+ char paulBuffer[16*1024];
+#if !defined(Q_OS_WINCE)
+ QVERIFY(peter.waitForReadyRead(5000));
+ QVERIFY(paul.waitForReadyRead(5000));
+#else
+ QVERIFY(peter.waitForReadyRead(15000));
+ QVERIFY(paul.waitForReadyRead(15000));
+#endif
+ if (success) {
+ QCOMPARE(peter.readDatagram(peterBuffer, sizeof(peterBuffer)), qint64(paulMessage.length()));
+ QCOMPARE(paul.readDatagram(paulBuffer, sizeof(peterBuffer)), qint64(peterMessage.length()));
+ } else {
+ QVERIFY(peter.readDatagram(peterBuffer, sizeof(peterBuffer)) != paulMessage.length());
+ QVERIFY(paul.readDatagram(paulBuffer, sizeof(peterBuffer)) != peterMessage.length());
+ }
+
+ QCOMPARE(QByteArray(peterBuffer, paulMessage.length()), paulMessage);
+ QCOMPARE(QByteArray(paulBuffer, peterMessage.length()), peterMessage);
+ }
+}
+
+void tst_QUdpSocket::dualStack()
+{
+ QFETCH_GLOBAL(bool, setProxy);
+ if (setProxy)
+ QSKIP("test server SOCKS proxy doesn't support IPv6", SkipSingle);
+ QUdpSocket dualSock;
+ QByteArray dualData("dual");
+ QVERIFY(dualSock.bind(QHostAddress(QHostAddress::Any), 0));
+
+ QUdpSocket v4Sock;
+ QByteArray v4Data("v4");
+ QVERIFY(v4Sock.bind(QHostAddress(QHostAddress::AnyIPv4), 0));
+
+ QUdpSocket v6Sock;
+ QByteArray v6Data("v6");
+ QVERIFY(v6Sock.bind(QHostAddress(QHostAddress::AnyIPv6), 0));
+
+ QHostAddress from;
+ quint16 port;
+ QByteArray buffer;
+ //test v4 -> dual
+ QCOMPARE((int)v4Sock.writeDatagram(v4Data.constData(), v4Data.length(), QHostAddress(QHostAddress::LocalHost), dualSock.localPort()), v4Data.length());
+ QVERIFY(dualSock.waitForReadyRead(5000));
+ buffer.reserve(100);
+ qint64 size = dualSock.readDatagram(buffer.data(), 100, &from, &port);
+ QCOMPARE((int)size, v4Data.length());
+ buffer.resize(size);
+ QCOMPARE(buffer, v4Data);
+
+ //test v6 -> dual
+ QCOMPARE((int)v6Sock.writeDatagram(v6Data.constData(), v6Data.length(), QHostAddress(QHostAddress::LocalHostIPv6), dualSock.localPort()), v6Data.length());
+ QVERIFY(dualSock.waitForReadyRead(5000));
+ buffer.reserve(100);
+ size = dualSock.readDatagram(buffer.data(), 100, &from, &port);
+ QCOMPARE((int)size, v6Data.length());
+ buffer.resize(size);
+ QCOMPARE(buffer, v6Data);
+
+ //test dual -> v4
+ QCOMPARE((int)dualSock.writeDatagram(dualData.constData(), dualData.length(), QHostAddress(QHostAddress::LocalHost), v4Sock.localPort()), dualData.length());
+ QVERIFY(v4Sock.waitForReadyRead(5000));
+ buffer.reserve(100);
+ size = v4Sock.readDatagram(buffer.data(), 100, &from, &port);
+ QCOMPARE((int)size, dualData.length());
+ buffer.resize(size);
+ QCOMPARE(buffer, dualData);
+
+ //test dual -> v6
+ QCOMPARE((int)dualSock.writeDatagram(dualData.constData(), dualData.length(), QHostAddress(QHostAddress::LocalHostIPv6), v6Sock.localPort()), dualData.length());
+ QVERIFY(v6Sock.waitForReadyRead(5000));
+ buffer.reserve(100);
+ size = v6Sock.readDatagram(buffer.data(), 100, &from, &port);
+ QCOMPARE((int)size, dualData.length());
+ buffer.resize(size);
+ QCOMPARE(buffer, dualData);
+
+}
+
+void tst_QUdpSocket::empty_readyReadSlot()
+{
+ QTestEventLoop::instance().exitLoop();
+}
+
+void tst_QUdpSocket::empty_connectedSlot()
+{
+ QTestEventLoop::instance().exitLoop();
+}
+
+//----------------------------------------------------------------------------------
+
+void tst_QUdpSocket::readLine()
+{
+ QUdpSocket socket1;
+ QUdpSocket socket2;
+#ifdef FORCE_SESSION
+ socket1.setProperty("_q_networksession", QVariant::fromValue(networkSession));
+ socket2.setProperty("_q_networksession", QVariant::fromValue(networkSession));
+#endif
+ QVERIFY2(socket1.bind(), socket1.errorString().toLatin1().constData());
+
+ socket2.connectToHost("127.0.0.1", socket1.localPort());
+ QVERIFY(socket2.waitForConnected(5000));
+}
+
+//----------------------------------------------------------------------------------
+
+void tst_QUdpSocket::pendingDatagramSize()
+{
+ QUdpSocket server;
+#ifdef FORCE_SESSION
+ server.setProperty("_q_networksession", QVariant::fromValue(networkSession));
+#endif
+ QVERIFY2(server.bind(), server.errorString().toLatin1().constData());
+
+ QHostAddress serverAddress = QHostAddress::LocalHost;
+ if (!(server.localAddress() == QHostAddress::AnyIPv4 || server.localAddress() == QHostAddress::AnyIPv6))
+ serverAddress = server.localAddress();
+
+ QUdpSocket client;
+#ifdef FORCE_SESSION
+ client.setProperty("_q_networksession", QVariant::fromValue(networkSession));
+#endif
+ QVERIFY(client.writeDatagram("this is", 7, serverAddress, server.localPort()) == 7);
+ QVERIFY(client.writeDatagram(0, 0, serverAddress, server.localPort()) == 0);
+ QVERIFY(client.writeDatagram("3 messages", 10, serverAddress, server.localPort()) == 10);
+
+ char c = 0;
+ QVERIFY(server.waitForReadyRead());
+ if (server.hasPendingDatagrams()) {
+#if defined Q_OS_HPUX && defined __ia64
+ QEXPECT_FAIL("", "HP-UX 11i v2 can't determine the datagram size correctly.", Abort);
+#endif
+ QCOMPARE(server.pendingDatagramSize(), qint64(7));
+ c = '\0';
+ QCOMPARE(server.readDatagram(&c, 1), qint64(1));
+ QCOMPARE(c, 't');
+ c = '\0';
+ } else {
+ QSKIP("does not have the 1st datagram", SkipSingle);
+ }
+
+ if (server.hasPendingDatagrams()) {
+ QCOMPARE(server.pendingDatagramSize(), qint64(0));
+ QCOMPARE(server.readDatagram(&c, 1), qint64(0));
+ QCOMPARE(c, '\0'); // untouched
+ c = '\0';
+ } else {
+ QSKIP("does not have the 2nd datagram", SkipSingle);
+ }
+
+ if (server.hasPendingDatagrams()) {
+ QCOMPARE(server.pendingDatagramSize(), qint64(10));
+ QCOMPARE(server.readDatagram(&c, 1), qint64(1));
+ QCOMPARE(c, '3');
+ } else {
+ QSKIP("does not have the 3rd datagram", SkipSingle);
+ }
+}
+
+
+void tst_QUdpSocket::writeDatagram()
+{
+ QUdpSocket server;
+#ifdef FORCE_SESSION
+ server.setProperty("_q_networksession", QVariant::fromValue(networkSession));
+#endif
+ QVERIFY2(server.bind(), server.errorString().toLatin1().constData());
+
+ QHostAddress serverAddress = QHostAddress::LocalHost;
+ if (!(server.localAddress() == QHostAddress::AnyIPv4 || server.localAddress() == QHostAddress::AnyIPv6))
+ serverAddress = server.localAddress();
+
+ QUdpSocket client;
+#ifdef FORCE_SESSION
+ client.setProperty("_q_networksession", QVariant::fromValue(networkSession));
+#endif
+
+ qRegisterMetaType<qint64>("qint64");
+ qRegisterMetaType<QAbstractSocket::SocketError>("QAbstractSocket::SocketError");
+
+ for(int i=0;;i++) {
+ QSignalSpy errorspy(&client, SIGNAL(error(QAbstractSocket::SocketError)));
+ QSignalSpy bytesspy(&client, SIGNAL(bytesWritten(qint64)));
+
+ qint64 written = client.writeDatagram(QByteArray(i * 1024, 'w'), serverAddress,
+ server.localPort());
+
+ if (written != i * 1024) {
+#if defined (Q_OS_HPUX)
+ QSKIP("HP-UX 11.11 on hai (PA-RISC 64) truncates too long datagrams.", SkipSingle);
+#endif
+ QCOMPARE(bytesspy.count(), 0);
+ QCOMPARE(errorspy.count(), 1);
+ QCOMPARE(*static_cast<const int *>(errorspy.at(0).at(0).constData()),
+ int(QUdpSocket::DatagramTooLargeError));
+ QCOMPARE(client.error(), QUdpSocket::DatagramTooLargeError);
+ break;
+ }
+ QVERIFY(bytesspy.count() == 1);
+ QCOMPARE(*static_cast<const qint64 *>(bytesspy.at(0).at(0).constData()),
+ qint64(i * 1024));
+ QCOMPARE(errorspy.count(), 0);
+ if (!server.waitForReadyRead(5000)) {
+#ifdef Q_OS_SYMBIAN
+ //symbian receive buffer for datagrams is ~30k, but it can send datagrams up to the maximum 64k...
+ if (i > 28) {
+ i = 64;
+ continue;
+ }
+#endif
+ QSKIP(QString("UDP packet lost at size %1, unable to complete the test.").arg(i * 1024).toLatin1().data(), SkipSingle);
+ }
+ QCOMPARE(server.pendingDatagramSize(), qint64(i * 1024));
+ QCOMPARE(server.readDatagram(0, 0), qint64(0));
+ }
+}
+
+void tst_QUdpSocket::performance()
+{
+#if defined(Q_OS_SYMBIAN)
+ // Large packets seems not to go through on Symbian
+ // Reason might be also fragmentation due to VPN connection etc
+
+ QFETCH_GLOBAL(bool, setProxy);
+ QFETCH_GLOBAL(int, proxyType);
+
+ int arrSize = 8192;
+ if (setProxy && proxyType == QNetworkProxy::Socks5Proxy)
+ arrSize = 1024;
+
+ QByteArray arr(arrSize, '@');
+#else
+ QByteArray arr(8192, '@');
+#endif // Q_OS_SYMBIAN
+
+ QUdpSocket server;
+#ifdef FORCE_SESSION
+ server.setProperty("_q_networksession", QVariant::fromValue(networkSession));
+#endif
+ QVERIFY2(server.bind(), server.errorString().toLatin1().constData());
+
+ QHostAddress serverAddress = QHostAddress::LocalHost;
+ if (!(server.localAddress() == QHostAddress::AnyIPv4 || server.localAddress() == QHostAddress::AnyIPv6))
+ serverAddress = server.localAddress();
+
+ QUdpSocket client;
+#ifdef FORCE_SESSION
+ client.setProperty("_q_networksession", QVariant::fromValue(networkSession));
+#endif
+ client.connectToHost(serverAddress, server.localPort());
+ QVERIFY(client.waitForConnected(10000));
+
+ QTime stopWatch;
+ stopWatch.start();
+
+ qint64 nbytes = 0;
+ while (stopWatch.elapsed() < 5000) {
+ for (int i = 0; i < 100; ++i) {
+ if (client.write(arr.data(), arr.size()) > 0) {
+ do {
+ nbytes += server.readDatagram(arr.data(), arr.size());
+ } while (server.hasPendingDatagrams());
+ }
+ }
+ }
+
+ float secs = stopWatch.elapsed() / 1000.0;
+ qDebug("\t%.2fMB/%.2fs: %.2fMB/s", float(nbytes / (1024.0*1024.0)),
+ secs, float(nbytes / (1024.0*1024.0)) / secs);
+
+#if defined(Q_OS_SYMBIAN)
+ if(nbytes == 0) {
+ qDebug("No bytes passed through local UDP socket, since UDP socket write returns EWOULDBLOCK");
+ qDebug("Should try with blocking sockets, but it is not currently possible due to Open C defect");
+ }
+#endif
+
+}
+
+void tst_QUdpSocket::bindMode()
+{
+ QFETCH_GLOBAL(bool, setProxy);
+ if (setProxy) {
+ QFETCH_GLOBAL(int, proxyType);
+ if (proxyType == QNetworkProxy::Socks5Proxy) {
+ QSKIP("With socks5 explicit port binding is not supported.", SkipAll);
+ }
+ }
+
+ QUdpSocket socket;
+#ifdef FORCE_SESSION
+ socket.setProperty("_q_networksession", QVariant::fromValue(networkSession));
+#endif
+ QVERIFY2(socket.bind(), socket.errorString().toLatin1().constData());
+ QUdpSocket socket2;
+#ifdef FORCE_SESSION
+ socket2.setProperty("_q_networksession", QVariant::fromValue(networkSession));
+#endif
+ QVERIFY(!socket2.bind(socket.localPort()));
+#if defined(Q_OS_SYMBIAN)
+ if(RProcess().HasCapability(ECapabilityNetworkControl)) {
+ qDebug("Test executed *with* NetworkControl capability");
+ // In Symbian OS ReuseAddressHint together with NetworkControl capability
+ // gives application *always* right to bind to port. I.e. it does not matter
+ // if first socket was bound with any bind flag. Since autotests in Symbian
+ // are currently executed with ALL -TCB rights, this path is the one executed.
+ QVERIFY(socket2.bind(socket.localPort(), QUdpSocket::ReuseAddressHint));
+ socket.close();
+ socket2.close();
+
+ QVERIFY2(socket.bind(0, QUdpSocket::ShareAddress), socket.errorString().toLatin1().constData());
+ QVERIFY(!socket2.bind(socket.localPort()));
+ QVERIFY2(socket2.bind(socket.localPort(), QUdpSocket::ReuseAddressHint), socket2.errorString().toLatin1().constData());
+ socket.close();
+ socket2.close();
+
+ QVERIFY2(socket.bind(0, QUdpSocket::DontShareAddress), socket.errorString().toLatin1().constData());
+ QVERIFY(!socket2.bind(socket.localPort()));
+ QVERIFY(socket2.bind(socket.localPort(), QUdpSocket::ReuseAddressHint));
+ socket.close();
+ socket2.close();
+ } else {
+ qDebug("Test executed *without* NetworkControl capability");
+ // If we don't have NetworkControl capability, attempt to bind already bound
+ // address will *always* fail. I.e. it does not matter if first socket was
+ // bound with any bind flag.
+ QVERIFY(!socket2.bind(socket.localPort(), QUdpSocket::ReuseAddressHint));
+ socket.close();
+
+ QVERIFY2(socket.bind(0, QUdpSocket::ShareAddress), socket.errorString().toLatin1().constData());
+ QVERIFY(!socket2.bind(socket.localPort()));
+ QVERIFY2(!socket2.bind(socket.localPort(), QUdpSocket::ReuseAddressHint), socket2.errorString().toLatin1().constData());
+ socket.close();
+
+ QVERIFY2(socket.bind(0, QUdpSocket::DontShareAddress), socket.errorString().toLatin1().constData());
+ QVERIFY(!socket2.bind(socket.localPort()));
+ QVERIFY(!socket2.bind(socket.localPort(), QUdpSocket::ReuseAddressHint));
+ socket.close();
+ }
+#elif defined(Q_OS_UNIX)
+ QVERIFY(!socket2.bind(socket.localPort(), QUdpSocket::ReuseAddressHint));
+ socket.close();
+ QVERIFY2(socket.bind(0, QUdpSocket::ShareAddress), socket.errorString().toLatin1().constData());
+ QVERIFY2(socket2.bind(socket.localPort()), socket2.errorString().toLatin1().constData());
+ socket2.close();
+ QVERIFY2(socket2.bind(socket.localPort(), QUdpSocket::ReuseAddressHint), socket2.errorString().toLatin1().constData());
+#else
+
+ // Depending on the user's privileges, this or will succeed or
+ // fail. Admins are allowed to reuse the address, but nobody else.
+ if (!socket2.bind(socket.localPort(), QUdpSocket::ReuseAddressHint), socket2.errorString().toLatin1().constData())
+ qWarning("Failed to bind with QUdpSocket::ReuseAddressHint, user isn't an administrator?");
+ socket.close();
+ QVERIFY2(socket.bind(0, QUdpSocket::ShareAddress), socket.errorString().toLatin1().constData());
+ QVERIFY(!socket2.bind(socket.localPort()));
+ socket.close();
+ QVERIFY2(socket.bind(0, QUdpSocket::DontShareAddress), socket.errorString().toLatin1().constData());
+ QVERIFY(!socket2.bind(socket.localPort()));
+ QVERIFY(!socket2.bind(socket.localPort(), QUdpSocket::ReuseAddressHint));
+#endif
+}
+
+void tst_QUdpSocket::writeDatagramToNonExistingPeer_data()
+{
+ QTest::addColumn<bool>("bind");
+ QTest::addColumn<QHostAddress>("peerAddress");
+ QHostAddress localhost(QHostAddress::LocalHost);
+ QHostAddress remote = QHostInfo::fromName(QtNetworkSettings::serverName()).addresses().first();
+
+ QTest::newRow("localhost-unbound") << false << localhost;
+ QTest::newRow("localhost-bound") << true << localhost;
+ QTest::newRow("remote-unbound") << false << remote;
+ QTest::newRow("remote-bound") << true << remote;
+}
+
+void tst_QUdpSocket::writeDatagramToNonExistingPeer()
+{
+ QFETCH(bool, bind);
+ QFETCH(QHostAddress, peerAddress);
+
+ quint16 peerPort = 33533 + int(bind);
+
+ QUdpSocket sUdp;
+#ifdef FORCE_SESSION
+ sUdp.setProperty("_q_networksession", QVariant::fromValue(networkSession));
+#endif
+ QSignalSpy sReadyReadSpy(&sUdp, SIGNAL(readyRead()));
+ if (bind)
+ QVERIFY(sUdp.bind());
+ QCOMPARE(sUdp.writeDatagram("", 1, peerAddress, peerPort), qint64(1));
+ QTestEventLoop::instance().enterLoop(1);
+ QCOMPARE(sReadyReadSpy.count(), 0);
+}
+
+void tst_QUdpSocket::writeToNonExistingPeer_data()
+{
+ QTest::addColumn<QHostAddress>("peerAddress");
+ QHostAddress localhost(QHostAddress::LocalHost);
+ QHostAddress remote = QHostInfo::fromName(QtNetworkSettings::serverName()).addresses().first();
+ // write (required to be connected)
+ QTest::newRow("localhost") << localhost;
+ QTest::newRow("remote") << remote;
+}
+
+void tst_QUdpSocket::writeToNonExistingPeer()
+{
+ QSKIP("Connected-mode UDP sockets and their behaviour are erratic", SkipAll);
+ QFETCH(QHostAddress, peerAddress);
+ quint16 peerPort = 34534;
+ qRegisterMetaType<QAbstractSocket::SocketError>("QAbstractSocket::SocketError");
+
+ QUdpSocket sConnected;
+#ifdef FORCE_SESSION
+ sConnected.setProperty("_q_networksession", QVariant::fromValue(networkSession));
+#endif
+ QSignalSpy sConnectedReadyReadSpy(&sConnected, SIGNAL(readyRead()));
+ QSignalSpy sConnectedErrorSpy(&sConnected, SIGNAL(error(QAbstractSocket::SocketError)));
+ sConnected.connectToHost(peerAddress, peerPort, QIODevice::ReadWrite);
+ QVERIFY(sConnected.waitForConnected(10000));
+
+ // the first write succeeds...
+ QCOMPARE(sConnected.write("", 1), qint64(1));
+
+ // the second one should fail!
+ QTest::qSleep(1000); // do not process events
+ QCOMPARE(sConnected.write("", 1), qint64(-1));
+ QCOMPARE(int(sConnected.error()), int(QUdpSocket::ConnectionRefusedError));
+
+ // the third one will succeed...
+ QCOMPARE(sConnected.write("", 1), qint64(1));
+ QTestEventLoop::instance().enterLoop(1);
+ QCOMPARE(sConnectedReadyReadSpy.count(), 0);
+ QCOMPARE(sConnectedErrorSpy.count(), 1);
+ QCOMPARE(int(sConnected.error()), int(QUdpSocket::ConnectionRefusedError));
+
+ // we should now get a read error
+ QCOMPARE(sConnected.write("", 1), qint64(1));
+ QTest::qSleep(1000); // do not process events
+ char buf[2];
+ QVERIFY(!sConnected.hasPendingDatagrams());
+ QCOMPARE(sConnected.bytesAvailable(), Q_INT64_C(0));
+ QCOMPARE(sConnected.pendingDatagramSize(), Q_INT64_C(-1));
+ QCOMPARE(sConnected.readDatagram(buf, 2), Q_INT64_C(-1));
+ QCOMPARE(int(sConnected.error()), int(QUdpSocket::ConnectionRefusedError));
+
+ QCOMPARE(sConnected.write("", 1), qint64(1));
+ QTest::qSleep(1000); // do not process events
+ QCOMPARE(sConnected.read(buf, 2), Q_INT64_C(0));
+ QCOMPARE(int(sConnected.error()), int(QUdpSocket::ConnectionRefusedError));
+
+ // we should still be connected
+ QCOMPARE(int(sConnected.state()), int(QUdpSocket::ConnectedState));
+}
+
+void tst_QUdpSocket::outOfProcessConnectedClientServerTest()
+{
+#if defined(Q_OS_WINCE) || defined (Q_OS_SYMBIAN)
+ QSKIP("This test depends on reading data from QProcess (not supported on Qt/WinCE and Symbian).", SkipAll);
+#endif
+#if defined(QT_NO_PROCESS)
+ QSKIP("Qt was compiled with QT_NO_PROCESS", SkipAll);
+#else
+
+ QProcess serverProcess;
+ serverProcess.start(QLatin1String("clientserver/clientserver server 1 1"),
+ QIODevice::ReadWrite | QIODevice::Text);
+ QVERIFY2(serverProcess.waitForStarted(3000),
+ qPrintable("Failed to start subprocess: " + serverProcess.errorString()));
+
+ // Wait until the server has started and reports success.
+ while (!serverProcess.canReadLine())
+ QVERIFY(serverProcess.waitForReadyRead(3000));
+ QByteArray serverGreeting = serverProcess.readLine();
+ QVERIFY(serverGreeting != QByteArray("XXX\n"));
+ int serverPort = serverGreeting.trimmed().toInt();
+ QVERIFY(serverPort > 0 && serverPort < 65536);
+
+ QProcess clientProcess;
+ clientProcess.start(QString::fromLatin1("clientserver/clientserver connectedclient %1 %2")
+ .arg(QLatin1String("127.0.0.1")).arg(serverPort),
+ QIODevice::ReadWrite | QIODevice::Text);
+ QVERIFY2(clientProcess.waitForStarted(3000),
+ qPrintable("Failed to start subprocess: " + clientProcess.errorString()));
+
+ // Wait until the server has started and reports success.
+ while (!clientProcess.canReadLine())
+ QVERIFY(clientProcess.waitForReadyRead(3000));
+ QByteArray clientGreeting = clientProcess.readLine();
+ QCOMPARE(clientGreeting, QByteArray("ok\n"));
+
+ // Let the client and server talk for 3 seconds
+ QTest::qWait(3000);
+
+ QStringList serverData = QString::fromLocal8Bit(serverProcess.readAll()).split("\n");
+ QStringList clientData = QString::fromLocal8Bit(clientProcess.readAll()).split("\n");
+ QVERIFY(serverData.size() > 5);
+ QVERIFY(clientData.size() > 5);
+
+ for (int i = 0; i < clientData.size() / 2; ++i) {
+ QCOMPARE(clientData.at(i * 2), QString("readData()"));
+ QCOMPARE(serverData.at(i * 3), QString("readData()"));
+
+ QString cdata = clientData.at(i * 2 + 1);
+ QString sdata = serverData.at(i * 3 + 1);
+ QVERIFY(cdata.startsWith(QLatin1String("got ")));
+
+ QCOMPARE(cdata.mid(4).trimmed().toInt(), sdata.mid(4).trimmed().toInt() * 2);
+ QVERIFY(serverData.at(i * 3 + 2).startsWith(QLatin1String("sending ")));
+ QCOMPARE(serverData.at(i * 3 + 2).trimmed().mid(8).toInt(),
+ sdata.mid(4).trimmed().toInt() * 2);
+ }
+
+ clientProcess.kill();
+ QVERIFY(clientProcess.waitForFinished());
+ serverProcess.kill();
+ QVERIFY(serverProcess.waitForFinished());
+#endif
+}
+
+void tst_QUdpSocket::outOfProcessUnconnectedClientServerTest()
+{
+#if defined(Q_OS_WINCE) || defined (Q_OS_SYMBIAN)
+ QSKIP("This test depends on reading data from QProcess (not supported on Qt/WinCE and Symbian).", SkipAll);
+#endif
+#if defined(QT_NO_PROCESS)
+ QSKIP("Qt was compiled with QT_NO_PROCESS", SkipAll);
+#else
+
+ QProcess serverProcess;
+ serverProcess.start(QLatin1String("clientserver/clientserver server 1 1"),
+ QIODevice::ReadWrite | QIODevice::Text);
+ QVERIFY2(serverProcess.waitForStarted(3000),
+ qPrintable("Failed to start subprocess: " + serverProcess.errorString()));
+
+ // Wait until the server has started and reports success.
+ while (!serverProcess.canReadLine())
+ QVERIFY(serverProcess.waitForReadyRead(3000));
+ QByteArray serverGreeting = serverProcess.readLine();
+ QVERIFY(serverGreeting != QByteArray("XXX\n"));
+ int serverPort = serverGreeting.trimmed().toInt();
+ QVERIFY(serverPort > 0 && serverPort < 65536);
+
+ QProcess clientProcess;
+ clientProcess.start(QString::fromLatin1("clientserver/clientserver unconnectedclient %1 %2")
+ .arg(QLatin1String("127.0.0.1")).arg(serverPort),
+ QIODevice::ReadWrite | QIODevice::Text);
+ QVERIFY2(clientProcess.waitForStarted(3000),
+ qPrintable("Failed to start subprocess: " + clientProcess.errorString()));
+
+ // Wait until the server has started and reports success.
+ while (!clientProcess.canReadLine())
+ QVERIFY(clientProcess.waitForReadyRead(3000));
+ QByteArray clientGreeting = clientProcess.readLine();
+ QCOMPARE(clientGreeting, QByteArray("ok\n"));
+
+ // Let the client and server talk for 3 seconds
+ QTest::qWait(3000);
+
+ QStringList serverData = QString::fromLocal8Bit(serverProcess.readAll()).split("\n");
+ QStringList clientData = QString::fromLocal8Bit(clientProcess.readAll()).split("\n");
+
+ QVERIFY(serverData.size() > 5);
+ QVERIFY(clientData.size() > 5);
+
+ for (int i = 0; i < clientData.size() / 2; ++i) {
+ QCOMPARE(clientData.at(i * 2), QString("readData()"));
+ QCOMPARE(serverData.at(i * 3), QString("readData()"));
+
+ QString cdata = clientData.at(i * 2 + 1);
+ QString sdata = serverData.at(i * 3 + 1);
+ QVERIFY(cdata.startsWith(QLatin1String("got ")));
+
+ QCOMPARE(cdata.mid(4).trimmed().toInt(), sdata.mid(4).trimmed().toInt() * 2);
+ QVERIFY(serverData.at(i * 3 + 2).startsWith(QLatin1String("sending ")));
+ QCOMPARE(serverData.at(i * 3 + 2).trimmed().mid(8).toInt(),
+ sdata.mid(4).trimmed().toInt() * 2);
+ }
+
+ clientProcess.kill();
+ QVERIFY(clientProcess.waitForFinished());
+ serverProcess.kill();
+ QVERIFY(serverProcess.waitForFinished());
+#endif
+}
+
+void tst_QUdpSocket::zeroLengthDatagram()
+{
+ QFETCH_GLOBAL(bool, setProxy);
+ if (setProxy)
+ return;
+
+ QUdpSocket receiver;
+#ifdef FORCE_SESSION
+ receiver.setProperty("_q_networksession", QVariant::fromValue(networkSession));
+#endif
+ QVERIFY(receiver.bind());
+
+ QVERIFY(!receiver.waitForReadyRead(100));
+ QVERIFY(!receiver.hasPendingDatagrams());
+
+ QUdpSocket sender;
+#ifdef FORCE_SESSION
+ sender.setProperty("_q_networksession", QVariant::fromValue(networkSession));
+#endif
+ QCOMPARE(sender.writeDatagram(QByteArray(), QHostAddress::LocalHost, receiver.localPort()), qint64(0));
+
+ QVERIFY(receiver.waitForReadyRead(1000));
+ QVERIFY(receiver.hasPendingDatagrams());
+
+ char buf;
+ QCOMPARE(receiver.readDatagram(&buf, 1), qint64(0));
+}
+
+void tst_QUdpSocket::multicastTtlOption_data()
+{
+ QTest::addColumn<QHostAddress>("bindAddress");
+ QTest::addColumn<int>("ttl");
+ QTest::addColumn<int>("expected");
+
+ QList<QHostAddress> addresses;
+ addresses += QHostAddress(QHostAddress::Any);
+ addresses += QHostAddress(QHostAddress::AnyIPv6);
+
+ foreach (const QHostAddress &address, addresses) {
+ QTest::newRow(QString("%1 0").arg(address.toString()).toAscii()) << address << 0 << 0;
+ QTest::newRow(QString("%1 1").arg(address.toString()).toAscii()) << address << 1 << 1;
+ QTest::newRow(QString("%1 2").arg(address.toString()).toAscii()) << address << 2 << 2;
+ QTest::newRow(QString("%1 128").arg(address.toString()).toAscii()) << address << 128 << 128;
+ QTest::newRow(QString("%1 255").arg(address.toString()).toAscii()) << address << 255 << 255;
+ QTest::newRow(QString("%1 1024").arg(address.toString()).toAscii()) << address << 1024 << 1;
+ }
+}
+
+void tst_QUdpSocket::multicastTtlOption()
+{
+ QFETCH_GLOBAL(bool, setProxy);
+ QFETCH(QHostAddress, bindAddress);
+ QFETCH(int, ttl);
+ QFETCH(int, expected);
+ if (setProxy) {
+ // UDP multicast does not work with proxies
+ expected = 0;
+ }
+
+ QUdpSocket udpSocket;
+#ifdef FORCE_SESSION
+ udpSocket.setProperty("_q_networksession", QVariant::fromValue(networkSession));
+#endif
+ // bind, but ignore the result, we are only interested in initializing the socket
+ (void) udpSocket.bind(bindAddress, 0);
+ udpSocket.setSocketOption(QUdpSocket::MulticastTtlOption, ttl);
+ QCOMPARE(udpSocket.socketOption(QUdpSocket::MulticastTtlOption).toInt(), expected);
+}
+
+void tst_QUdpSocket::multicastLoopbackOption_data()
+{
+ QTest::addColumn<QHostAddress>("bindAddress");
+ QTest::addColumn<int>("loopback");
+ QTest::addColumn<int>("expected");
+
+ QList<QHostAddress> addresses;
+ addresses += QHostAddress(QHostAddress::Any);
+ addresses += QHostAddress(QHostAddress::AnyIPv6);
+
+ foreach (const QHostAddress &address, addresses) {
+ QTest::newRow(QString("%1 0").arg(address.toString()).toAscii()) << address << 0 << 0;
+ QTest::newRow(QString("%1 1").arg(address.toString()).toAscii()) << address << 1 << 1;
+ QTest::newRow(QString("%1 2").arg(address.toString()).toAscii()) << address << 2 << 1;
+ QTest::newRow(QString("%1 0 again").arg(address.toString()).toAscii()) << address << 0 << 0;
+ QTest::newRow(QString("%1 2 again").arg(address.toString()).toAscii()) << address << 2 << 1;
+ QTest::newRow(QString("%1 0 last time").arg(address.toString()).toAscii()) << address << 0 << 0;
+ QTest::newRow(QString("%1 1 again").arg(address.toString()).toAscii()) << address << 1 << 1;
+ }
+}
+
+void tst_QUdpSocket::multicastLoopbackOption()
+{
+ QFETCH_GLOBAL(bool, setProxy);
+ QFETCH(QHostAddress, bindAddress);
+ QFETCH(int, loopback);
+ QFETCH(int, expected);
+ if (setProxy) {
+ // UDP multicast does not work with proxies
+ expected = 0;
+ }
+
+ QUdpSocket udpSocket;
+#ifdef FORCE_SESSION
+ udpSocket.setProperty("_q_networksession", QVariant::fromValue(networkSession));
+#endif
+ // bind, but ignore the result, we are only interested in initializing the socket
+ (void) udpSocket.bind(bindAddress, 0);
+ udpSocket.setSocketOption(QUdpSocket::MulticastLoopbackOption, loopback);
+ QCOMPARE(udpSocket.socketOption(QUdpSocket::MulticastLoopbackOption).toInt(), expected);
+}
+
+void tst_QUdpSocket::multicastJoinBeforeBind_data()
+{
+ QTest::addColumn<QHostAddress>("groupAddress");
+ QTest::newRow("valid ipv4 group address") << QHostAddress("239.255.118.62");
+ QTest::newRow("invalid ipv4 group address") << QHostAddress(QHostAddress::Broadcast);
+ QTest::newRow("valid ipv6 group address") << QHostAddress("FF01::114");
+ QTest::newRow("invalid ipv6 group address") << QHostAddress(QHostAddress::AnyIPv6);
+}
+
+void tst_QUdpSocket::multicastJoinBeforeBind()
+{
+ QFETCH(QHostAddress, groupAddress);
+
+ QUdpSocket udpSocket;
+#ifdef FORCE_SESSION
+ udpSocket.setProperty("_q_networksession", QVariant::fromValue(networkSession));
+#endif
+ // cannot join group before binding
+ QTest::ignoreMessage(QtWarningMsg, "QUdpSocket::joinMulticastGroup() called on a QUdpSocket when not in QUdpSocket::BoundState");
+ QVERIFY(!udpSocket.joinMulticastGroup(groupAddress));
+}
+
+void tst_QUdpSocket::multicastLeaveAfterClose_data()
+{
+ QTest::addColumn<QHostAddress>("groupAddress");
+ QTest::newRow("valid ipv4 group address") << QHostAddress("239.255.118.62");
+ QTest::newRow("valid ipv6 group address") << QHostAddress("FF01::114");
+}
+
+void tst_QUdpSocket::multicastLeaveAfterClose()
+{
+ QFETCH_GLOBAL(bool, setProxy);
+ QFETCH(QHostAddress, groupAddress);
+ if (setProxy) {
+ QSKIP("UDP Multicast does not work with proxies", SkipAll);
+ }
+
+ QUdpSocket udpSocket;
+#ifdef FORCE_SESSION
+ udpSocket.setProperty("_q_networksession", QVariant::fromValue(networkSession));
+#endif
+#ifdef Q_OS_SYMBIAN
+ QVERIFY2(udpSocket.bind(),
+ qPrintable(udpSocket.errorString()));
+#else
+ QVERIFY2(udpSocket.bind(groupAddress, 0),
+ qPrintable(udpSocket.errorString()));
+#endif
+ QVERIFY2(udpSocket.joinMulticastGroup(groupAddress),
+ qPrintable(udpSocket.errorString()));
+ udpSocket.close();
+ QTest::ignoreMessage(QtWarningMsg, "QUdpSocket::leaveMulticastGroup() called on a QUdpSocket when not in QUdpSocket::BoundState");
+ QVERIFY(!udpSocket.leaveMulticastGroup(groupAddress));
+}
+
+void tst_QUdpSocket::setMulticastInterface_data()
+{
+ QTest::addColumn<QNetworkInterface>("iface");
+ QTest::addColumn<QHostAddress>("address");
+ QList<QNetworkInterface> interfaces = QNetworkInterface::allInterfaces();
+ foreach (const QNetworkInterface &iface, interfaces) {
+ foreach (const QNetworkAddressEntry &entry, iface.addressEntries()) {
+ QTest::newRow(QString("%1:%2").arg(iface.name()).arg(entry.ip().toString()).toAscii())
+ << iface
+ << entry.ip();
+ }
+ }
+}
+
+void tst_QUdpSocket::setMulticastInterface()
+{
+#ifdef Q_OS_SYMBIAN
+ QSKIP("Symbian has no IPV6_MULTICAST_IF equivalent", SkipAll);
+#else
+ QFETCH_GLOBAL(bool, setProxy);
+ QFETCH(QNetworkInterface, iface);
+ QFETCH(QHostAddress, address);
+
+ QUdpSocket udpSocket;
+ // bind initializes the socket
+ bool bound = udpSocket.bind((address.protocol() == QAbstractSocket::IPv6Protocol
+ ? QHostAddress(QHostAddress::AnyIPv6)
+ : QHostAddress(QHostAddress::Any)),
+ 0);
+ if (!bound)
+ QTest::ignoreMessage(QtWarningMsg, "QUdpSocket::setMulticastInterface() called on a QUdpSocket when not in QUdpSocket::BoundState");
+ udpSocket.setMulticastInterface(iface);
+ if (!bound)
+ QTest::ignoreMessage(QtWarningMsg, "QUdpSocket::multicastInterface() called on a QUdpSocket when not in QUdpSocket::BoundState");
+ QNetworkInterface iface2 = udpSocket.multicastInterface();
+ if (!setProxy) {
+ QVERIFY(iface2.isValid());
+ QCOMPARE(iface.name(), iface2.name());
+ } else {
+ QVERIFY(!iface2.isValid());
+ }
+#endif
+}
+
+void tst_QUdpSocket::multicast_data()
+{
+ QHostAddress anyAddress = QHostAddress(QHostAddress::AnyIPv4);
+ QHostAddress groupAddress = QHostAddress("239.255.118.62");
+ QHostAddress any6Address = QHostAddress(QHostAddress::AnyIPv6);
+ QHostAddress group6Address = QHostAddress("FF01::114");
+
+ QTest::addColumn<QHostAddress>("bindAddress");
+ QTest::addColumn<bool>("bindResult");
+ QTest::addColumn<QHostAddress>("groupAddress");
+ QTest::addColumn<bool>("joinResult");
+ QTest::newRow("valid bind, group ipv4 address") << anyAddress << true << groupAddress << true;
+ QTest::newRow("valid bind, invalid group ipv4 address") << anyAddress << true << anyAddress << false;
+ QTest::newRow("same bind, group ipv4 address") << groupAddress << true << groupAddress << true;
+ QTest::newRow("valid bind, group ipv6 address") << any6Address << true << group6Address << true;
+ QTest::newRow("valid bind, invalid group ipv6 address") << any6Address << true << any6Address << false;
+ QTest::newRow("same bind, group ipv6 address") << group6Address << true << group6Address << true;
+}
+
+void tst_QUdpSocket::multicast()
+{
+ QFETCH_GLOBAL(bool, setProxy);
+ QFETCH(QHostAddress, bindAddress);
+ QFETCH(bool, bindResult);
+ QFETCH(QHostAddress, groupAddress);
+ QFETCH(bool, joinResult);
+ if (setProxy) {
+ // UDP multicast does not work with proxies
+ if (
+#ifndef Q_OS_WIN
+ //windows native socket engine binds 0.0.0.0 instead of the requested multicast address
+ (bindAddress.protocol() == QAbstractSocket::IPv4Protocol && (bindAddress.toIPv4Address() & 0xffff0000) == 0xefff0000) ||
+#endif
+ bindAddress.protocol() == QAbstractSocket::IPv6Protocol) {
+ // proxy cannot bind to IPv6 or multicast addresses
+ bindResult = false;
+ }
+ joinResult = false;
+ }
+
+ QUdpSocket receiver;
+#ifdef FORCE_SESSION
+ receiver.setProperty("_q_networksession", QVariant::fromValue(networkSession));
+#endif
+
+ // bind first, then verify that we can join the multicast group
+#ifdef Q_OS_SYMBIAN
+ if (!setProxy) {
+ QEXPECT_FAIL("same bind, group ipv4 address", "bind to group address not supported on symbian", Abort);
+ QEXPECT_FAIL("same bind, group ipv6 address", "bind to group address not supported on symbian", Abort);
+ }
+#endif
+ QVERIFY2(receiver.bind(bindAddress, 0) == bindResult,
+ qPrintable(receiver.errorString()));
+ if (!bindResult)
+ return;
+
+ QVERIFY2(receiver.joinMulticastGroup(groupAddress) == joinResult,
+ qPrintable(receiver.errorString()));
+ if (!joinResult)
+ return;
+
+ QList<QByteArray> datagrams = QList<QByteArray>()
+ << QByteArray("0123")
+ << QByteArray("4567")
+ << QByteArray("89ab")
+ << QByteArray("cdef");
+
+ QUdpSocket sender;
+#ifdef FORCE_SESSION
+ sender.setProperty("_q_networksession", QVariant::fromValue(networkSession));
+#endif
+ sender.bind();
+ foreach (const QByteArray &datagram, datagrams) {
+ QCOMPARE(int(sender.writeDatagram(datagram, groupAddress, receiver.localPort())),
+ int(datagram.size()));
+ }
+
+ QVERIFY2(receiver.waitForReadyRead(),
+ qPrintable(receiver.errorString()));
+ QVERIFY(receiver.hasPendingDatagrams());
+ QList<QByteArray> receivedDatagrams;
+ while (receiver.hasPendingDatagrams()) {
+ QByteArray datagram;
+ datagram.resize(receiver.pendingDatagramSize());
+ receiver.readDatagram(datagram.data(), datagram.size(), 0, 0);
+ receivedDatagrams << datagram;
+ }
+#ifdef Q_OS_SYMBIAN
+ QEXPECT_FAIL("valid bind, group ipv4 address", "IPv4 multicast not supported on symbian", Abort);
+#endif
+ QCOMPARE(receivedDatagrams, datagrams);
+
+ QVERIFY2(receiver.leaveMulticastGroup(groupAddress), qPrintable(receiver.errorString()));
+}
+
+void tst_QUdpSocket::echo_data()
+{
+ QTest::addColumn<bool>("connect");
+ QTest::newRow("writeDatagram") << false;
+ QTest::newRow("write") << true;
+}
+
+void tst_QUdpSocket::echo()
+{
+ QFETCH(bool, connect);
+ QHostInfo info = QHostInfo::fromName(QtNetworkSettings::serverName());
+ QVERIFY(info.addresses().count());
+ QHostAddress remote = info.addresses().first();
+
+ QUdpSocket sock;
+#ifdef FORCE_SESSION
+ sock.setProperty("_q_networksession", QVariant::fromValue(networkSession));
+#endif
+ if (connect) {
+ sock.connectToHost(remote, 7);
+ QVERIFY(sock.waitForConnected(10000));
+ } else {
+ sock.bind();
+ }
+ QByteArray out(30, 'x');
+ QByteArray in;
+ int successes = 0;
+ for (int i=0;i<10;i++) {
+ if (connect) {
+ sock.write(out);
+ } else {
+ sock.writeDatagram(out, remote, 7);
+ }
+ if (sock.waitForReadyRead(1000)) {
+ while (sock.hasPendingDatagrams()) {
+ QHostAddress from;
+ quint16 port;
+ if (connect) {
+ in = sock.read(sock.pendingDatagramSize());
+ } else {
+ in.resize(sock.pendingDatagramSize());
+ sock.readDatagram(in.data(), in.length(), &from, &port);
+ }
+ if (in==out)
+ successes++;
+ }
+ }
+ if (!sock.isValid())
+ QFAIL(sock.errorString().toLatin1().constData());
+ qDebug() << "packets in" << successes << "out" << i;
+ QTest::qWait(50); //choke to avoid triggering flood/DDoS protections on echo service
+ }
+ QVERIFY(successes >= 9);
+}
+
+QTEST_MAIN(tst_QUdpSocket)
+#include "tst_qudpsocket.moc"
diff --git a/tests/auto/network/socket/qudpsocket/udpServer/main.cpp b/tests/auto/network/socket/qudpsocket/udpServer/main.cpp
new file mode 100644
index 0000000000..ff3ca111d0
--- /dev/null
+++ b/tests/auto/network/socket/qudpsocket/udpServer/main.cpp
@@ -0,0 +1,90 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#include <QtNetwork>
+
+class Server : public QObject
+{
+ Q_OBJECT
+public:
+ Server(int port)
+ {
+ connect(&serverSocket, SIGNAL(readyRead()),
+ this, SLOT(sendEcho()));
+ if (serverSocket.bind(QHostAddress::Any, port,
+ QUdpSocket::ReuseAddressHint
+ | QUdpSocket::ShareAddress)) {
+ printf("OK\n");
+ } else {
+ printf("FAILED\n");
+ }
+ fflush(stdout);
+ }
+
+private slots:
+ void sendEcho()
+ {
+ QHostAddress senderAddress;
+ quint16 senderPort;
+
+ char data[1024];
+ qint64 bytes = serverSocket.readDatagram(data, sizeof(data), &senderAddress, &senderPort);
+ if (bytes == 1 && data[0] == '\0')
+ QCoreApplication::instance()->quit();
+
+ for (int i = 0; i < bytes; ++i)
+ data[i] += 1;
+ serverSocket.writeDatagram(data, bytes, senderAddress, senderPort);
+ }
+
+private:
+ QUdpSocket serverSocket;
+};
+
+int main(int argc, char **argv)
+{
+ QCoreApplication app(argc, argv);
+
+ Server server(app.arguments().at(1).toInt());
+
+ return app.exec();
+}
+
+#include "main.moc"
diff --git a/tests/auto/network/socket/qudpsocket/udpServer/udpServer.pro b/tests/auto/network/socket/qudpsocket/udpServer/udpServer.pro
new file mode 100644
index 0000000000..7438d40fb0
--- /dev/null
+++ b/tests/auto/network/socket/qudpsocket/udpServer/udpServer.pro
@@ -0,0 +1,7 @@
+SOURCES += main.cpp
+QT = core network
+CONFIG -= app_bundle
+CONFIG += console
+
+symbian:TARGET.CAPABILITY="ALL -TCB"
+
diff --git a/tests/auto/network/socket/socket.pro b/tests/auto/network/socket/socket.pro
new file mode 100644
index 0000000000..49fb52d1a5
--- /dev/null
+++ b/tests/auto/network/socket/socket.pro
@@ -0,0 +1,17 @@
+TEMPLATE=subdirs
+SUBDIRS=\
+ qhttpsocketengine \
+ qudpsocket \
+ qtcpsocket \
+ #qlocalsocket \ # FIXME: uses qtscript (QTBUG-19242)
+ qtcpserver \
+ qsocks5socketengine \
+ qabstractsocket \
+ platformsocketengine \
+
+!contains(QT_CONFIG, private_tests): SUBDIRS -= \
+ platformsocketengine \
+ qhttpsocketengine \
+ qsocks5socketengine \
+
+