diff options
Diffstat (limited to 'tests/auto/qudpsocket')
-rw-r--r-- | tests/auto/qudpsocket/.gitignore | 2 | ||||
-rw-r--r-- | tests/auto/qudpsocket/clientserver/clientserver.pro | 8 | ||||
-rw-r--r-- | tests/auto/qudpsocket/clientserver/main.cpp | 170 | ||||
-rw-r--r-- | tests/auto/qudpsocket/qudpsocket.pro | 5 | ||||
-rw-r--r-- | tests/auto/qudpsocket/test/test.pro | 26 | ||||
-rw-r--r-- | tests/auto/qudpsocket/tst_qudpsocket.cpp | 787 | ||||
-rw-r--r-- | tests/auto/qudpsocket/udpServer/main.cpp | 90 | ||||
-rw-r--r-- | tests/auto/qudpsocket/udpServer/udpServer.pro | 6 |
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 + + |