qt5base-lts/tests/auto/network/socket/qudpsocket/tst_qudpsocket.cpp
Jonas M. Gastal bf7f170607 Make socket descriptors qintptr.
Windows x64 uses 64 bits integer for sockets, to ensure compatibility we
should use ptr sized integers for our socket descriptors.

Task-number: QTBUG-19004
Change-Id: I4b56023874a4f1bad107c66c054fecfedde33d88
Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
Reviewed-by: Oswald Buddenhagen <oswald.buddenhagen@nokia.com>
2012-01-05 15:07:51 +01:00

1262 lines
47 KiB
C++

/****************************************************************************
**
** Copyright (C) 2012 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>)
QT_FORWARD_DECLARE_CLASS(QUdpSocket)
class tst_QUdpSocket : public QObject
{
Q_OBJECT
public:
tst_QUdpSocket();
virtual ~tst_QUdpSocket();
public slots:
void initTestCase_data();
void initTestCase();
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();
#ifndef QT_NO_PROCESS
void outOfProcessConnectedClientServerTest();
void outOfProcessUnconnectedClientServerTest();
#endif
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()
{
}
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::initTestCase()
{
QVERIFY(QtNetworkSettings::verifyTestNetworkSettings());
}
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(), (qintptr)-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.");
}
#ifdef Q_OS_AIX
QSKIP("Broadcast does not work on darko");
#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");
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");
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");
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");
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");
}
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.");
#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());
QCOMPARE(server.pendingDatagramSize(), qint64(i * 1024));
QCOMPARE(server.readDatagram(0, 0), qint64(0));
}
}
void tst_QUdpSocket::performance()
{
QByteArray arr(8192, '@');
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);
}
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.");
}
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_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");
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));
}
#ifndef QT_NO_PROCESS
void tst_QUdpSocket::outOfProcessConnectedClientServerTest()
{
#if defined(Q_OS_WINCE)
QSKIP("This test depends on reading data from QProcess (not supported on Qt/WinCE).");
#endif
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
#ifndef QT_NO_PROCESS
void tst_QUdpSocket::outOfProcessUnconnectedClientServerTest()
{
#if defined(Q_OS_WINCE)
QSKIP("This test depends on reading data from QProcess (not supported on Qt/WinCE).");
#endif
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");
QUdpSocket udpSocket;
#ifdef FORCE_SESSION
udpSocket.setProperty("_q_networksession", QVariant::fromValue(networkSession));
#endif
QVERIFY2(udpSocket.bind(groupAddress, 0),
qPrintable(udpSocket.errorString()));
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()
{
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());
}
}
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
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;
}
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"