summaryrefslogtreecommitdiffstats
path: root/tests/auto/qudpsocket
diff options
context:
space:
mode:
Diffstat (limited to 'tests/auto/qudpsocket')
-rw-r--r--tests/auto/qudpsocket/.gitignore2
-rw-r--r--tests/auto/qudpsocket/clientserver/clientserver.pro8
-rw-r--r--tests/auto/qudpsocket/clientserver/main.cpp170
-rw-r--r--tests/auto/qudpsocket/qudpsocket.pro5
-rw-r--r--tests/auto/qudpsocket/test/test.pro26
-rw-r--r--tests/auto/qudpsocket/tst_qudpsocket.cpp787
-rw-r--r--tests/auto/qudpsocket/udpServer/main.cpp90
-rw-r--r--tests/auto/qudpsocket/udpServer/udpServer.pro6
8 files changed, 1094 insertions, 0 deletions
diff --git a/tests/auto/qudpsocket/.gitignore b/tests/auto/qudpsocket/.gitignore
new file mode 100644
index 0000000..c613412
--- /dev/null
+++ b/tests/auto/qudpsocket/.gitignore
@@ -0,0 +1,2 @@
+tst_qudpsocket
+clientserver/clientserver
diff --git a/tests/auto/qudpsocket/clientserver/clientserver.pro b/tests/auto/qudpsocket/clientserver/clientserver.pro
new file mode 100644
index 0000000..5fe65b3
--- /dev/null
+++ b/tests/auto/qudpsocket/clientserver/clientserver.pro
@@ -0,0 +1,8 @@
+QT = core network
+SOURCES += main.cpp
+CONFIG += console
+CONFIG -= app_bundle
+TARGET = clientserver
+DESTDIR = ./
+
+
diff --git a/tests/auto/qudpsocket/clientserver/main.cpp b/tests/auto/qudpsocket/clientserver/main.cpp
new file mode 100644
index 0000000..7bdf337
--- /dev/null
+++ b/tests/auto/qudpsocket/clientserver/main.cpp
@@ -0,0 +1,170 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, 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.0, 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.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $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/qudpsocket/qudpsocket.pro b/tests/auto/qudpsocket/qudpsocket.pro
new file mode 100644
index 0000000..4ef8a40
--- /dev/null
+++ b/tests/auto/qudpsocket/qudpsocket.pro
@@ -0,0 +1,5 @@
+TEMPLATE = subdirs
+SUBDIRS = test clientserver
+
+
+
diff --git a/tests/auto/qudpsocket/test/test.pro b/tests/auto/qudpsocket/test/test.pro
new file mode 100644
index 0000000..2444dac
--- /dev/null
+++ b/tests/auto/qudpsocket/test/test.pro
@@ -0,0 +1,26 @@
+load(qttest_p4)
+SOURCES += ../tst_qudpsocket.cpp
+QT = core network
+
+MOC_DIR=tmp
+DEFINES += TEST_QNETWORK_PROXY
+
+win32 {
+ CONFIG(debug, debug|release) {
+ DESTDIR = ../debug
+} else {
+ DESTDIR = ../release
+ }
+} else {
+ DESTDIR = ../
+}
+
+wince*: {
+ addApp.sources = ../clientserver/clientserver.exe
+ addApp.path = clientserver
+ DEPLOYMENT += addApp
+}
+
+TARGET = tst_qudpsocket
+
+
diff --git a/tests/auto/qudpsocket/tst_qudpsocket.cpp b/tests/auto/qudpsocket/tst_qudpsocket.cpp
new file mode 100644
index 0000000..57e779c
--- /dev/null
+++ b/tests/auto/qudpsocket/tst_qudpsocket.cpp
@@ -0,0 +1,787 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, 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.0, 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.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $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>
+#ifdef TEST_QNETWORK_PROXY
+# include <QNetworkProxy>
+#endif
+
+
+#include <qstringlist.h>
+#include "../network-settings.h"
+
+Q_DECLARE_METATYPE(QHostAddress)
+
+//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 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();
+
+protected slots:
+ void empty_readyReadSlot();
+ void empty_connectedSlot();
+};
+
+tst_QUdpSocket::tst_QUdpSocket()
+{
+}
+
+tst_QUdpSocket::~tst_QUdpSocket()
+{
+
+}
+
+void tst_QUdpSocket::initTestCase_data()
+{
+ QTest::addColumn<bool>("setProxy");
+ QTest::addColumn<int>("proxyType");
+
+ QTest::newRow("WithoutProxy") << false << 0;
+#ifdef TEST_QNETWORK_PROXY
+ QTest::newRow("WithSocks5Proxy") << true << int(QNetworkProxy::Socks5Proxy);
+#endif
+}
+
+void tst_QUdpSocket::init()
+{
+ QFETCH_GLOBAL(bool, setProxy);
+ if (setProxy) {
+#ifdef TEST_QNETWORK_PROXY
+ QFETCH_GLOBAL(int, proxyType);
+ if (proxyType == QNetworkProxy::Socks5Proxy) {
+ QNetworkProxy::setApplicationProxy(QNetworkProxy(QNetworkProxy::Socks5Proxy, QtNetworkSettings::serverName(), 1080));
+ }
+#endif
+ }
+}
+
+void tst_QUdpSocket::cleanup()
+{
+ QFETCH_GLOBAL(bool, setProxy);
+ if (setProxy) {
+#ifdef TEST_QNETWORK_PROXY
+ QNetworkProxy::setApplicationProxy(QNetworkProxy::DefaultProxy);
+#endif
+ }
+}
+
+
+//----------------------------------------------------------------------------------
+
+void tst_QUdpSocket::constructing()
+{
+ QUdpSocket socket;
+
+ 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;
+
+ 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::Any))
+ serverAddress = serverSocket.localAddress();
+
+ for (int i = 0; i < 3; ++i) {
+ QUdpSocket clientSocket;
+ 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) {
+#ifdef TEST_QNETWORK_PROXY
+ QFETCH_GLOBAL(int, proxyType);
+ if (proxyType == QNetworkProxy::Socks5Proxy) {
+ QSKIP("With socks5 Broadcast is not supported.", SkipAll);
+ }
+#endif
+ }
+#ifdef Q_OS_AIX
+ QSKIP("Broadcast does not work on darko", SkipAll);
+#endif
+ const char *message[] = {"Yo mista", "", "Yo", "Wassap"};
+
+ for (int i = 0; i < 4; ++i) {
+ QUdpSocket serverSocket;
+ QVERIFY2(serverSocket.bind(QHostAddress::Any, 5000), serverSocket.errorString().toLatin1().constData());
+
+ QCOMPARE(serverSocket.state(), QUdpSocket::BoundState);
+
+ connect(&serverSocket, SIGNAL(readyRead()), SLOT(empty_readyReadSlot()));
+
+ QUdpSocket broadcastSocket;
+
+ for (int j = 0; j < 100; ++j) {
+ broadcastSocket.writeDatagram(message[i], strlen(message[i]),
+ QHostAddress::Broadcast, 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;
+
+ QVERIFY2(peter.bind(), peter.errorString().toLatin1().constData());
+ QVERIFY2(paul.bind(), paul.errorString().toLatin1().constData());
+
+ QHostAddress peterAddress = QHostAddress::LocalHost;
+ if (!(peter.localAddress() == QHostAddress::Any))
+ peterAddress = peter.localAddress();
+ QHostAddress pualAddress = QHostAddress::LocalHost;
+ if (!(paul.localAddress() == QHostAddress::Any))
+ 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(5000));
+ QVERIFY(paul.waitForReadyRead(5000));
+ 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;
+
+ 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::empty_readyReadSlot()
+{
+ QTestEventLoop::instance().exitLoop();
+}
+
+void tst_QUdpSocket::empty_connectedSlot()
+{
+ QTestEventLoop::instance().exitLoop();
+}
+
+//----------------------------------------------------------------------------------
+
+void tst_QUdpSocket::readLine()
+{
+ QUdpSocket socket1;
+ QVERIFY2(socket1.bind(), socket1.errorString().toLatin1().constData());
+
+ QUdpSocket socket2;
+ socket2.connectToHost("127.0.0.1", socket1.localPort());
+ QVERIFY(socket2.waitForConnected(5000));
+}
+
+//----------------------------------------------------------------------------------
+
+void tst_QUdpSocket::pendingDatagramSize()
+{
+ QUdpSocket server;
+ QVERIFY2(server.bind(), server.errorString().toLatin1().constData());
+
+ QHostAddress serverAddress = QHostAddress::LocalHost;
+ if (!(server.localAddress() == QHostAddress::Any))
+ serverAddress = server.localAddress();
+
+ QUdpSocket client;
+ 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;
+ QVERIFY2(server.bind(), server.errorString().toLatin1().constData());
+
+ QHostAddress serverAddress = QHostAddress::LocalHost;
+ if (!(server.localAddress() == QHostAddress::Any))
+ serverAddress = server.localAddress();
+
+ QUdpSocket client;
+
+ 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))
+ 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()
+{
+ QUdpSocket server;
+ QVERIFY2(server.bind(), server.errorString().toLatin1().constData());
+
+ QHostAddress serverAddress = QHostAddress::LocalHost;
+ if (!(server.localAddress() == QHostAddress::Any))
+ serverAddress = server.localAddress();
+
+ QUdpSocket client;
+ client.connectToHost(serverAddress, server.localPort());
+
+ QByteArray arr(8192, '@');
+
+ 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);
+}
+
+void tst_QUdpSocket::bindMode()
+{
+ QFETCH_GLOBAL(bool, setProxy);
+ if (setProxy) {
+#ifdef TEST_QNETWORK_PROXY
+ QFETCH_GLOBAL(int, proxyType);
+ if (proxyType == QNetworkProxy::Socks5Proxy) {
+ QSKIP("With socks5 explicit port binding is not supported.", SkipAll);
+ }
+#endif
+ }
+
+#if QT_VERSION < 0x040100
+ QSKIP("QUdpSocket::BindMode was added in Qt 4.1.", SkipAll);
+#else
+ QUdpSocket socket;
+ QVERIFY2(socket.bind(), socket.errorString().toLatin1().constData());
+ QUdpSocket socket2;
+ QVERIFY(!socket2.bind(socket.localPort()));
+
+#ifdef 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 adminstrator?");
+ 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
+#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;
+ 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;
+ QSignalSpy sConnectedReadyReadSpy(&sConnected, SIGNAL(readyRead()));
+ QSignalSpy sConnectedErrorSpy(&sConnected, SIGNAL(error(QAbstractSocket::SocketError)));
+ sConnected.connectToHost(peerAddress, peerPort, QIODevice::ReadWrite);
+
+ // 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)
+ QSKIP("This test depends on reading data from QProcess (not supported on Qt/WinCE.", 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);
+
+ // 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);
+ // 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)
+ QSKIP("This test depends on reading data from QProcess (not supported on Qt/WinCE.", 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);
+
+ // 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);
+ // 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;
+ QVERIFY(receiver.bind());
+
+ QVERIFY(!receiver.waitForReadyRead(100));
+ QVERIFY(!receiver.hasPendingDatagrams());
+
+ QUdpSocket sender;
+ 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));
+}
+
+QTEST_MAIN(tst_QUdpSocket)
+#include "tst_qudpsocket.moc"
diff --git a/tests/auto/qudpsocket/udpServer/main.cpp b/tests/auto/qudpsocket/udpServer/main.cpp
new file mode 100644
index 0000000..68bfe85
--- /dev/null
+++ b/tests/auto/qudpsocket/udpServer/main.cpp
@@ -0,0 +1,90 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, 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.0, 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.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $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/qudpsocket/udpServer/udpServer.pro b/tests/auto/qudpsocket/udpServer/udpServer.pro
new file mode 100644
index 0000000..f04833c
--- /dev/null
+++ b/tests/auto/qudpsocket/udpServer/udpServer.pro
@@ -0,0 +1,6 @@
+SOURCES += main.cpp
+QT = core network
+CONFIG -= app_bundle
+CONFIG += console
+
+