qt5base-lts/tests/auto/qudpsocket/tst_qudpsocket.cpp
Qt by Nokia 38be0d1383 Initial import from the monolithic Qt.
This is the beginning of revision history for this module. If you
want to look at revision history older than this, please refer to the
Qt Git wiki for how to use Git history grafting. At the time of
writing, this wiki is located here:

http://qt.gitorious.org/qt/pages/GitIntroductionWithQt

If you have already performed the grafting and you don't see any
history beyond this commit, try running "git log" with the "--follow"
argument.

Branched from the monolithic repo, Qt master branch, at commit
896db169ea224deb96c59ce8af800d019de63f12
2011-04-27 12:05:43 +02:00

1297 lines
48 KiB
C++

/****************************************************************************
**
** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the test suite of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** 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 Technology Preview License Agreement accompanying
** this package.
**
** 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.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** If you have questions regarding the use of this file, please contact
** Nokia at qt-info@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>
#include <QNetworkProxy>
#include <QNetworkInterface>
#include <qstringlist.h>
#include "../network-settings.h"
#ifndef QT_NO_BEARERMANAGEMENT
#include <QtNetwork/qnetworkconfigmanager.h>
#include <QtNetwork/qnetworkconfiguration.h>
#include <QtNetwork/qnetworksession.h>
#endif
Q_DECLARE_METATYPE(QHostAddress)
Q_DECLARE_METATYPE(QNetworkInterface)
Q_DECLARE_METATYPE(QSharedPointer<QNetworkSession>)
//TESTED_CLASS=
//TESTED_FILES=
QT_FORWARD_DECLARE_CLASS(QUdpSocket)
class tst_QUdpSocket : public QObject
{
Q_OBJECT
public:
tst_QUdpSocket();
virtual ~tst_QUdpSocket();
public slots:
void initTestCase_data();
void init();
void cleanup();
private slots:
void constructing();
void unconnectedServerAndClientTest();
void broadcasting();
void loop_data();
void loop();
void ipv6Loop_data();
void ipv6Loop();
void readLine();
void pendingDatagramSize();
void writeDatagram();
void performance();
void bindMode();
void writeDatagramToNonExistingPeer_data();
void writeDatagramToNonExistingPeer();
void writeToNonExistingPeer_data();
void writeToNonExistingPeer();
void outOfProcessConnectedClientServerTest();
void outOfProcessUnconnectedClientServerTest();
void zeroLengthDatagram();
void multicastTtlOption_data();
void multicastTtlOption();
void multicastLoopbackOption_data();
void multicastLoopbackOption();
void multicastJoinBeforeBind_data();
void multicastJoinBeforeBind();
void multicastLeaveAfterClose_data();
void multicastLeaveAfterClose();
void setMulticastInterface_data();
void setMulticastInterface();
void multicast_data();
void multicast();
void echo_data();
void echo();
protected slots:
void empty_readyReadSlot();
void empty_connectedSlot();
private:
#ifndef QT_NO_BEARERMANAGEMENT
QNetworkConfigurationManager *netConfMan;
QNetworkConfiguration networkConfiguration;
QSharedPointer<QNetworkSession> networkSession;
#endif
};
tst_QUdpSocket::tst_QUdpSocket()
{
Q_SET_DEFAULT_IAP
}
tst_QUdpSocket::~tst_QUdpSocket()
{
}
void tst_QUdpSocket::initTestCase_data()
{
QTest::addColumn<bool>("setProxy");
QTest::addColumn<int>("proxyType");
QTest::newRow("WithoutProxy") << false << 0;
QTest::newRow("WithSocks5Proxy") << true << int(QNetworkProxy::Socks5Proxy);
#ifndef QT_NO_BEARERMANAGEMENT
netConfMan = new QNetworkConfigurationManager(this);
networkConfiguration = netConfMan->defaultConfiguration();
networkSession = QSharedPointer<QNetworkSession>(new QNetworkSession(networkConfiguration));
if (!networkSession->isOpen()) {
networkSession->open();
QVERIFY(networkSession->waitForOpened(30000));
}
#endif
}
void tst_QUdpSocket::init()
{
QFETCH_GLOBAL(bool, setProxy);
if (setProxy) {
QFETCH_GLOBAL(int, proxyType);
if (proxyType == QNetworkProxy::Socks5Proxy) {
QNetworkProxy::setApplicationProxy(QNetworkProxy(QNetworkProxy::Socks5Proxy, QtNetworkSettings::serverName(), 1080));
}
}
}
void tst_QUdpSocket::cleanup()
{
QNetworkProxy::setApplicationProxy(QNetworkProxy::DefaultProxy);
}
//----------------------------------------------------------------------------------
void tst_QUdpSocket::constructing()
{
QUdpSocket socket;
#ifdef FORCE_SESSION
socket.setProperty("_q_networksession", QVariant::fromValue(networkSession));
#endif
QVERIFY(socket.isSequential());
QVERIFY(!socket.isOpen());
QVERIFY(socket.socketType() == QUdpSocket::UdpSocket);
QCOMPARE((int) socket.bytesAvailable(), 0);
QCOMPARE(socket.canReadLine(), false);
QCOMPARE(socket.readLine(), QByteArray());
QCOMPARE(socket.socketDescriptor(), -1);
QCOMPARE(socket.error(), QUdpSocket::UnknownSocketError);
QCOMPARE(socket.errorString(), QString("Unknown error"));
// Check the state of the socket api
}
void tst_QUdpSocket::unconnectedServerAndClientTest()
{
QUdpSocket serverSocket;
#ifdef FORCE_SESSION
serverSocket.setProperty("_q_networksession", QVariant::fromValue(networkSession));
#endif
qRegisterMetaType<QAbstractSocket::SocketState>("QAbstractSocket::SocketState");
QSignalSpy stateChangedSpy(&serverSocket, SIGNAL(stateChanged(QAbstractSocket::SocketState)));
QVERIFY2(serverSocket.bind(), serverSocket.errorString().toLatin1().constData());
QCOMPARE(stateChangedSpy.count(), 1);
const char *message[] = {"Yo mista", "Yo", "Wassap"};
QHostAddress serverAddress = QHostAddress::LocalHost;
if (!(serverSocket.localAddress() == QHostAddress::Any || serverSocket.localAddress() == QHostAddress::AnyIPv6))
serverAddress = serverSocket.localAddress();
for (int i = 0; i < 3; ++i) {
QUdpSocket clientSocket;
#ifdef FORCE_SESSION
clientSocket.setProperty("_q_networksession", QVariant::fromValue(networkSession));
#endif
QCOMPARE(int(clientSocket.writeDatagram(message[i], strlen(message[i]),
serverAddress, serverSocket.localPort())),
int(strlen(message[i])));
char buf[1024];
QHostAddress host;
quint16 port;
QVERIFY(serverSocket.waitForReadyRead(5000));
QCOMPARE(int(serverSocket.readDatagram(buf, sizeof(buf), &host, &port)),
int(strlen(message[i])));
buf[strlen(message[i])] = '\0';
QCOMPARE(QByteArray(buf), QByteArray(message[i]));
}
}
//----------------------------------------------------------------------------------
void tst_QUdpSocket::broadcasting()
{
QFETCH_GLOBAL(bool, setProxy);
if (setProxy) {
QFETCH_GLOBAL(int, proxyType);
if (proxyType == QNetworkProxy::Socks5Proxy) {
QSKIP("With socks5 Broadcast is not supported.", SkipSingle);
}
}
#ifdef Q_OS_AIX
QSKIP("Broadcast does not work on darko", SkipAll);
#endif
const char *message[] = {"Yo mista", "", "Yo", "Wassap"};
QList<QHostAddress> broadcastAddresses;
foreach (QNetworkInterface iface, QNetworkInterface::allInterfaces()) {
if ((iface.flags() & QNetworkInterface::CanBroadcast)
&& iface.flags() & QNetworkInterface::IsUp) {
for (int i=0;i<iface.addressEntries().count();i++)
broadcastAddresses.append(iface.addressEntries().at(i).broadcast());
}
}
if (broadcastAddresses.isEmpty())
QSKIP("No interface can broadcast", SkipAll);
for (int i = 0; i < 4; ++i) {
QUdpSocket serverSocket;
#ifdef FORCE_SESSION
serverSocket.setProperty("_q_networksession", QVariant::fromValue(networkSession));
#endif
QVERIFY2(serverSocket.bind(QHostAddress::Any, 5000), serverSocket.errorString().toLatin1().constData());
QCOMPARE(serverSocket.state(), QUdpSocket::BoundState);
connect(&serverSocket, SIGNAL(readyRead()), SLOT(empty_readyReadSlot()));
QUdpSocket broadcastSocket;
#ifdef FORCE_SESSION
broadcastSocket.setProperty("_q_networksession", QVariant::fromValue(networkSession));
#endif
broadcastSocket.bind();
for (int j = 0; j < 100; ++j) {
for (int k = 0; k < 4; k++) {
broadcastSocket.writeDatagram(message[i], strlen(message[i]),
QHostAddress::Broadcast, 5000);
foreach (QHostAddress addr, broadcastAddresses)
broadcastSocket.writeDatagram(message[i], strlen(message[i]), addr, 5000);
}
QTestEventLoop::instance().enterLoop(15);
if (QTestEventLoop::instance().timeout()) {
#if defined(Q_OS_FREEBSD)
QEXPECT_FAIL("",
"Broadcasting to 255.255.255.255 does not work on FreeBSD",
Abort);
QVERIFY(false); // seems that QFAIL() doesn't respect the QEXPECT_FAIL() :/
#endif
QFAIL("Network operation timed out");
}
QVERIFY(serverSocket.hasPendingDatagrams());
do {
QByteArray arr; arr.resize(serverSocket.pendingDatagramSize() + 1);
QHostAddress host;
quint16 port;
QCOMPARE((int) serverSocket.readDatagram(arr.data(), arr.size() - 1, &host, &port),
(int) strlen(message[i]));
arr.resize(strlen(message[i]));
QCOMPARE(arr, QByteArray(message[i]));
} while (serverSocket.hasPendingDatagrams());
}
}
}
//----------------------------------------------------------------------------------
void tst_QUdpSocket::loop_data()
{
QTest::addColumn<QByteArray>("peterMessage");
QTest::addColumn<QByteArray>("paulMessage");
QTest::addColumn<bool>("success");
QTest::newRow("\"Almond!\" | \"Joy!\"") << QByteArray("Almond!") << QByteArray("Joy!") << true;
QTest::newRow("\"A\" | \"B\"") << QByteArray("A") << QByteArray("B") << true;
QTest::newRow("\"AB\" | \"B\"") << QByteArray("AB") << QByteArray("B") << true;
QTest::newRow("\"AB\" | \"BB\"") << QByteArray("AB") << QByteArray("BB") << true;
QTest::newRow("\"A\\0B\" | \"B\\0B\"") << QByteArray::fromRawData("A\0B", 3) << QByteArray::fromRawData("B\0B", 3) << true;
QTest::newRow("\"(nil)\" | \"(nil)\"") << QByteArray() << QByteArray() << true;
QTest::newRow("Bigmessage") << QByteArray(600, '@') << QByteArray(600, '@') << true;
}
void tst_QUdpSocket::loop()
{
QFETCH(QByteArray, peterMessage);
QFETCH(QByteArray, paulMessage);
QFETCH(bool, success);
QUdpSocket peter;
QUdpSocket paul;
#ifdef FORCE_SESSION
peter.setProperty("_q_networksession", QVariant::fromValue(networkSession));
paul.setProperty("_q_networksession", QVariant::fromValue(networkSession));
#endif
QVERIFY2(peter.bind(), peter.errorString().toLatin1().constData());
QVERIFY2(paul.bind(), paul.errorString().toLatin1().constData());
QHostAddress peterAddress = QHostAddress::LocalHost;
if (!(peter.localAddress() == QHostAddress::Any || peter.localAddress() == QHostAddress::AnyIPv6))
peterAddress = peter.localAddress();
QHostAddress pualAddress = QHostAddress::LocalHost;
if (!(paul.localAddress() == QHostAddress::Any || 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()
{
#if defined(QT_NO_IPV6)
QSKIP("IPv6 is not yet supported", SkipAll);
#endif
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::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::Any || server.localAddress() == QHostAddress::AnyIPv6))
serverAddress = server.localAddress();
QUdpSocket client;
#ifdef FORCE_SESSION
client.setProperty("_q_networksession", QVariant::fromValue(networkSession));
#endif
QVERIFY(client.writeDatagram("this is", 7, serverAddress, server.localPort()) == 7);
QVERIFY(client.writeDatagram(0, 0, serverAddress, server.localPort()) == 0);
QVERIFY(client.writeDatagram("3 messages", 10, serverAddress, server.localPort()) == 10);
char c = 0;
QVERIFY(server.waitForReadyRead());
if (server.hasPendingDatagrams()) {
#if defined Q_OS_HPUX && defined __ia64
QEXPECT_FAIL("", "HP-UX 11i v2 can't determine the datagram size correctly.", Abort);
#endif
QCOMPARE(server.pendingDatagramSize(), qint64(7));
c = '\0';
QCOMPARE(server.readDatagram(&c, 1), qint64(1));
QCOMPARE(c, 't');
c = '\0';
} else {
QSKIP("does not have the 1st datagram", SkipSingle);
}
if (server.hasPendingDatagrams()) {
QCOMPARE(server.pendingDatagramSize(), qint64(0));
QCOMPARE(server.readDatagram(&c, 1), qint64(0));
QCOMPARE(c, '\0'); // untouched
c = '\0';
} else {
QSKIP("does not have the 2nd datagram", SkipSingle);
}
if (server.hasPendingDatagrams()) {
QCOMPARE(server.pendingDatagramSize(), qint64(10));
QCOMPARE(server.readDatagram(&c, 1), qint64(1));
QCOMPARE(c, '3');
} else {
QSKIP("does not have the 3rd datagram", SkipSingle);
}
}
void tst_QUdpSocket::writeDatagram()
{
QUdpSocket server;
#ifdef FORCE_SESSION
server.setProperty("_q_networksession", QVariant::fromValue(networkSession));
#endif
QVERIFY2(server.bind(), server.errorString().toLatin1().constData());
QHostAddress serverAddress = QHostAddress::LocalHost;
if (!(server.localAddress() == QHostAddress::Any || server.localAddress() == QHostAddress::AnyIPv6))
serverAddress = server.localAddress();
QUdpSocket client;
#ifdef FORCE_SESSION
client.setProperty("_q_networksession", QVariant::fromValue(networkSession));
#endif
qRegisterMetaType<qint64>("qint64");
qRegisterMetaType<QAbstractSocket::SocketError>("QAbstractSocket::SocketError");
for(int i=0;;i++) {
QSignalSpy errorspy(&client, SIGNAL(error(QAbstractSocket::SocketError)));
QSignalSpy bytesspy(&client, SIGNAL(bytesWritten(qint64)));
qint64 written = client.writeDatagram(QByteArray(i * 1024, 'w'), serverAddress,
server.localPort());
if (written != i * 1024) {
#if defined (Q_OS_HPUX)
QSKIP("HP-UX 11.11 on hai (PA-RISC 64) truncates too long datagrams.", SkipSingle);
#endif
QCOMPARE(bytesspy.count(), 0);
QCOMPARE(errorspy.count(), 1);
QCOMPARE(*static_cast<const int *>(errorspy.at(0).at(0).constData()),
int(QUdpSocket::DatagramTooLargeError));
QCOMPARE(client.error(), QUdpSocket::DatagramTooLargeError);
break;
}
QVERIFY(bytesspy.count() == 1);
QCOMPARE(*static_cast<const qint64 *>(bytesspy.at(0).at(0).constData()),
qint64(i * 1024));
QCOMPARE(errorspy.count(), 0);
if (!server.waitForReadyRead(5000)) {
#ifdef Q_OS_SYMBIAN
//symbian receive buffer for datagrams is ~30k, but it can send datagrams up to the maximum 64k...
if (i > 28) {
i = 64;
continue;
}
#endif
QSKIP(QString("UDP packet lost at size %1, unable to complete the test.").arg(i * 1024).toLatin1().data(), SkipSingle);
}
QCOMPARE(server.pendingDatagramSize(), qint64(i * 1024));
QCOMPARE(server.readDatagram(0, 0), qint64(0));
}
}
void tst_QUdpSocket::performance()
{
#if defined(Q_OS_SYMBIAN)
// Large packets seems not to go through on Symbian
// Reason might be also fragmentation due to VPN connection etc
QFETCH_GLOBAL(bool, setProxy);
QFETCH_GLOBAL(int, proxyType);
int arrSize = 8192;
if (setProxy && proxyType == QNetworkProxy::Socks5Proxy)
arrSize = 1024;
QByteArray arr(arrSize, '@');
#else
QByteArray arr(8192, '@');
#endif // Q_OS_SYMBIAN
QUdpSocket server;
#ifdef FORCE_SESSION
server.setProperty("_q_networksession", QVariant::fromValue(networkSession));
#endif
QVERIFY2(server.bind(), server.errorString().toLatin1().constData());
QHostAddress serverAddress = QHostAddress::LocalHost;
if (!(server.localAddress() == QHostAddress::Any || server.localAddress() == QHostAddress::AnyIPv6))
serverAddress = server.localAddress();
QUdpSocket client;
#ifdef FORCE_SESSION
client.setProperty("_q_networksession", QVariant::fromValue(networkSession));
#endif
client.connectToHost(serverAddress, server.localPort());
QVERIFY(client.waitForConnected(10000));
QTime stopWatch;
stopWatch.start();
qint64 nbytes = 0;
while (stopWatch.elapsed() < 5000) {
for (int i = 0; i < 100; ++i) {
if (client.write(arr.data(), arr.size()) > 0) {
do {
nbytes += server.readDatagram(arr.data(), arr.size());
} while (server.hasPendingDatagrams());
}
}
}
float secs = stopWatch.elapsed() / 1000.0;
qDebug("\t%.2fMB/%.2fs: %.2fMB/s", float(nbytes / (1024.0*1024.0)),
secs, float(nbytes / (1024.0*1024.0)) / secs);
#if defined(Q_OS_SYMBIAN)
if(nbytes == 0) {
qDebug("No bytes passed through local UDP socket, since UDP socket write returns EWOULDBLOCK");
qDebug("Should try with blocking sockets, but it is not currently possible due to Open C defect");
}
#endif
}
void tst_QUdpSocket::bindMode()
{
QFETCH_GLOBAL(bool, setProxy);
if (setProxy) {
QFETCH_GLOBAL(int, proxyType);
if (proxyType == QNetworkProxy::Socks5Proxy) {
QSKIP("With socks5 explicit port binding is not supported.", SkipAll);
}
}
QUdpSocket socket;
#ifdef FORCE_SESSION
socket.setProperty("_q_networksession", QVariant::fromValue(networkSession));
#endif
QVERIFY2(socket.bind(), socket.errorString().toLatin1().constData());
QUdpSocket socket2;
#ifdef FORCE_SESSION
socket2.setProperty("_q_networksession", QVariant::fromValue(networkSession));
#endif
QVERIFY(!socket2.bind(socket.localPort()));
#if defined(Q_OS_SYMBIAN)
if(RProcess().HasCapability(ECapabilityNetworkControl)) {
qDebug("Test executed *with* NetworkControl capability");
// In Symbian OS ReuseAddressHint together with NetworkControl capability
// gives application *always* right to bind to port. I.e. it does not matter
// if first socket was bound with any bind flag. Since autotests in Symbian
// are currently executed with ALL -TCB rights, this path is the one executed.
QVERIFY(socket2.bind(socket.localPort(), QUdpSocket::ReuseAddressHint));
socket.close();
socket2.close();
QVERIFY2(socket.bind(0, QUdpSocket::ShareAddress), socket.errorString().toLatin1().constData());
QVERIFY(!socket2.bind(socket.localPort()));
QVERIFY2(socket2.bind(socket.localPort(), QUdpSocket::ReuseAddressHint), socket2.errorString().toLatin1().constData());
socket.close();
socket2.close();
QVERIFY2(socket.bind(0, QUdpSocket::DontShareAddress), socket.errorString().toLatin1().constData());
QVERIFY(!socket2.bind(socket.localPort()));
QVERIFY(socket2.bind(socket.localPort(), QUdpSocket::ReuseAddressHint));
socket.close();
socket2.close();
} else {
qDebug("Test executed *without* NetworkControl capability");
// If we don't have NetworkControl capability, attempt to bind already bound
// address will *always* fail. I.e. it does not matter if first socket was
// bound with any bind flag.
QVERIFY(!socket2.bind(socket.localPort(), QUdpSocket::ReuseAddressHint));
socket.close();
QVERIFY2(socket.bind(0, QUdpSocket::ShareAddress), socket.errorString().toLatin1().constData());
QVERIFY(!socket2.bind(socket.localPort()));
QVERIFY2(!socket2.bind(socket.localPort(), QUdpSocket::ReuseAddressHint), socket2.errorString().toLatin1().constData());
socket.close();
QVERIFY2(socket.bind(0, QUdpSocket::DontShareAddress), socket.errorString().toLatin1().constData());
QVERIFY(!socket2.bind(socket.localPort()));
QVERIFY(!socket2.bind(socket.localPort(), QUdpSocket::ReuseAddressHint));
socket.close();
}
#elif defined(Q_OS_UNIX)
QVERIFY(!socket2.bind(socket.localPort(), QUdpSocket::ReuseAddressHint));
socket.close();
QVERIFY2(socket.bind(0, QUdpSocket::ShareAddress), socket.errorString().toLatin1().constData());
QVERIFY2(socket2.bind(socket.localPort()), socket2.errorString().toLatin1().constData());
socket2.close();
QVERIFY2(socket2.bind(socket.localPort(), QUdpSocket::ReuseAddressHint), socket2.errorString().toLatin1().constData());
#else
// Depending on the user's privileges, this or will succeed or
// fail. Admins are allowed to reuse the address, but nobody else.
if (!socket2.bind(socket.localPort(), QUdpSocket::ReuseAddressHint), socket2.errorString().toLatin1().constData())
qWarning("Failed to bind with QUdpSocket::ReuseAddressHint, user isn't an 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
}
void tst_QUdpSocket::writeDatagramToNonExistingPeer_data()
{
QTest::addColumn<bool>("bind");
QTest::addColumn<QHostAddress>("peerAddress");
QHostAddress localhost(QHostAddress::LocalHost);
QHostAddress remote = QHostInfo::fromName(QtNetworkSettings::serverName()).addresses().first();
QTest::newRow("localhost-unbound") << false << localhost;
QTest::newRow("localhost-bound") << true << localhost;
QTest::newRow("remote-unbound") << false << remote;
QTest::newRow("remote-bound") << true << remote;
}
void tst_QUdpSocket::writeDatagramToNonExistingPeer()
{
QFETCH(bool, bind);
QFETCH(QHostAddress, peerAddress);
quint16 peerPort = 33533 + int(bind);
QUdpSocket sUdp;
#ifdef FORCE_SESSION
sUdp.setProperty("_q_networksession", QVariant::fromValue(networkSession));
#endif
QSignalSpy sReadyReadSpy(&sUdp, SIGNAL(readyRead()));
if (bind)
QVERIFY(sUdp.bind());
QCOMPARE(sUdp.writeDatagram("", 1, peerAddress, peerPort), qint64(1));
QTestEventLoop::instance().enterLoop(1);
QCOMPARE(sReadyReadSpy.count(), 0);
}
void tst_QUdpSocket::writeToNonExistingPeer_data()
{
QTest::addColumn<QHostAddress>("peerAddress");
QHostAddress localhost(QHostAddress::LocalHost);
QHostAddress remote = QHostInfo::fromName(QtNetworkSettings::serverName()).addresses().first();
// write (required to be connected)
QTest::newRow("localhost") << localhost;
QTest::newRow("remote") << remote;
}
void tst_QUdpSocket::writeToNonExistingPeer()
{
QSKIP("Connected-mode UDP sockets and their behaviour are erratic", SkipAll);
QFETCH(QHostAddress, peerAddress);
quint16 peerPort = 34534;
qRegisterMetaType<QAbstractSocket::SocketError>("QAbstractSocket::SocketError");
QUdpSocket sConnected;
#ifdef FORCE_SESSION
sConnected.setProperty("_q_networksession", QVariant::fromValue(networkSession));
#endif
QSignalSpy sConnectedReadyReadSpy(&sConnected, SIGNAL(readyRead()));
QSignalSpy sConnectedErrorSpy(&sConnected, SIGNAL(error(QAbstractSocket::SocketError)));
sConnected.connectToHost(peerAddress, peerPort, QIODevice::ReadWrite);
QVERIFY(sConnected.waitForConnected(10000));
// the first write succeeds...
QCOMPARE(sConnected.write("", 1), qint64(1));
// the second one should fail!
QTest::qSleep(1000); // do not process events
QCOMPARE(sConnected.write("", 1), qint64(-1));
QCOMPARE(int(sConnected.error()), int(QUdpSocket::ConnectionRefusedError));
// the third one will succeed...
QCOMPARE(sConnected.write("", 1), qint64(1));
QTestEventLoop::instance().enterLoop(1);
QCOMPARE(sConnectedReadyReadSpy.count(), 0);
QCOMPARE(sConnectedErrorSpy.count(), 1);
QCOMPARE(int(sConnected.error()), int(QUdpSocket::ConnectionRefusedError));
// we should now get a read error
QCOMPARE(sConnected.write("", 1), qint64(1));
QTest::qSleep(1000); // do not process events
char buf[2];
QVERIFY(!sConnected.hasPendingDatagrams());
QCOMPARE(sConnected.bytesAvailable(), Q_INT64_C(0));
QCOMPARE(sConnected.pendingDatagramSize(), Q_INT64_C(-1));
QCOMPARE(sConnected.readDatagram(buf, 2), Q_INT64_C(-1));
QCOMPARE(int(sConnected.error()), int(QUdpSocket::ConnectionRefusedError));
QCOMPARE(sConnected.write("", 1), qint64(1));
QTest::qSleep(1000); // do not process events
QCOMPARE(sConnected.read(buf, 2), Q_INT64_C(0));
QCOMPARE(int(sConnected.error()), int(QUdpSocket::ConnectionRefusedError));
// we should still be connected
QCOMPARE(int(sConnected.state()), int(QUdpSocket::ConnectedState));
}
void tst_QUdpSocket::outOfProcessConnectedClientServerTest()
{
#if defined(Q_OS_WINCE) || defined (Q_OS_SYMBIAN)
QSKIP("This test depends on reading data from QProcess (not supported on Qt/WinCE and Symbian).", SkipAll);
#endif
#if defined(QT_NO_PROCESS)
QSKIP("Qt was compiled with QT_NO_PROCESS", SkipAll);
#else
QProcess serverProcess;
serverProcess.start(QLatin1String("clientserver/clientserver server 1 1"),
QIODevice::ReadWrite | QIODevice::Text);
QVERIFY2(serverProcess.waitForStarted(3000),
qPrintable("Failed to start subprocess: " + serverProcess.errorString()));
// Wait until the server has started and reports success.
while (!serverProcess.canReadLine())
QVERIFY(serverProcess.waitForReadyRead(3000));
QByteArray serverGreeting = serverProcess.readLine();
QVERIFY(serverGreeting != QByteArray("XXX\n"));
int serverPort = serverGreeting.trimmed().toInt();
QVERIFY(serverPort > 0 && serverPort < 65536);
QProcess clientProcess;
clientProcess.start(QString::fromLatin1("clientserver/clientserver connectedclient %1 %2")
.arg(QLatin1String("127.0.0.1")).arg(serverPort),
QIODevice::ReadWrite | QIODevice::Text);
QVERIFY2(clientProcess.waitForStarted(3000),
qPrintable("Failed to start subprocess: " + clientProcess.errorString()));
// Wait until the server has started and reports success.
while (!clientProcess.canReadLine())
QVERIFY(clientProcess.waitForReadyRead(3000));
QByteArray clientGreeting = clientProcess.readLine();
QCOMPARE(clientGreeting, QByteArray("ok\n"));
// Let the client and server talk for 3 seconds
QTest::qWait(3000);
QStringList serverData = QString::fromLocal8Bit(serverProcess.readAll()).split("\n");
QStringList clientData = QString::fromLocal8Bit(clientProcess.readAll()).split("\n");
QVERIFY(serverData.size() > 5);
QVERIFY(clientData.size() > 5);
for (int i = 0; i < clientData.size() / 2; ++i) {
QCOMPARE(clientData.at(i * 2), QString("readData()"));
QCOMPARE(serverData.at(i * 3), QString("readData()"));
QString cdata = clientData.at(i * 2 + 1);
QString sdata = serverData.at(i * 3 + 1);
QVERIFY(cdata.startsWith(QLatin1String("got ")));
QCOMPARE(cdata.mid(4).trimmed().toInt(), sdata.mid(4).trimmed().toInt() * 2);
QVERIFY(serverData.at(i * 3 + 2).startsWith(QLatin1String("sending ")));
QCOMPARE(serverData.at(i * 3 + 2).trimmed().mid(8).toInt(),
sdata.mid(4).trimmed().toInt() * 2);
}
clientProcess.kill();
QVERIFY(clientProcess.waitForFinished());
serverProcess.kill();
QVERIFY(serverProcess.waitForFinished());
#endif
}
void tst_QUdpSocket::outOfProcessUnconnectedClientServerTest()
{
#if defined(Q_OS_WINCE) || defined (Q_OS_SYMBIAN)
QSKIP("This test depends on reading data from QProcess (not supported on Qt/WinCE and Symbian).", SkipAll);
#endif
#if defined(QT_NO_PROCESS)
QSKIP("Qt was compiled with QT_NO_PROCESS", SkipAll);
#else
QProcess serverProcess;
serverProcess.start(QLatin1String("clientserver/clientserver server 1 1"),
QIODevice::ReadWrite | QIODevice::Text);
QVERIFY2(serverProcess.waitForStarted(3000),
qPrintable("Failed to start subprocess: " + serverProcess.errorString()));
// Wait until the server has started and reports success.
while (!serverProcess.canReadLine())
QVERIFY(serverProcess.waitForReadyRead(3000));
QByteArray serverGreeting = serverProcess.readLine();
QVERIFY(serverGreeting != QByteArray("XXX\n"));
int serverPort = serverGreeting.trimmed().toInt();
QVERIFY(serverPort > 0 && serverPort < 65536);
QProcess clientProcess;
clientProcess.start(QString::fromLatin1("clientserver/clientserver unconnectedclient %1 %2")
.arg(QLatin1String("127.0.0.1")).arg(serverPort),
QIODevice::ReadWrite | QIODevice::Text);
QVERIFY2(clientProcess.waitForStarted(3000),
qPrintable("Failed to start subprocess: " + clientProcess.errorString()));
// Wait until the server has started and reports success.
while (!clientProcess.canReadLine())
QVERIFY(clientProcess.waitForReadyRead(3000));
QByteArray clientGreeting = clientProcess.readLine();
QCOMPARE(clientGreeting, QByteArray("ok\n"));
// Let the client and server talk for 3 seconds
QTest::qWait(3000);
QStringList serverData = QString::fromLocal8Bit(serverProcess.readAll()).split("\n");
QStringList clientData = QString::fromLocal8Bit(clientProcess.readAll()).split("\n");
QVERIFY(serverData.size() > 5);
QVERIFY(clientData.size() > 5);
for (int i = 0; i < clientData.size() / 2; ++i) {
QCOMPARE(clientData.at(i * 2), QString("readData()"));
QCOMPARE(serverData.at(i * 3), QString("readData()"));
QString cdata = clientData.at(i * 2 + 1);
QString sdata = serverData.at(i * 3 + 1);
QVERIFY(cdata.startsWith(QLatin1String("got ")));
QCOMPARE(cdata.mid(4).trimmed().toInt(), sdata.mid(4).trimmed().toInt() * 2);
QVERIFY(serverData.at(i * 3 + 2).startsWith(QLatin1String("sending ")));
QCOMPARE(serverData.at(i * 3 + 2).trimmed().mid(8).toInt(),
sdata.mid(4).trimmed().toInt() * 2);
}
clientProcess.kill();
QVERIFY(clientProcess.waitForFinished());
serverProcess.kill();
QVERIFY(serverProcess.waitForFinished());
#endif
}
void tst_QUdpSocket::zeroLengthDatagram()
{
QFETCH_GLOBAL(bool, setProxy);
if (setProxy)
return;
QUdpSocket receiver;
#ifdef FORCE_SESSION
receiver.setProperty("_q_networksession", QVariant::fromValue(networkSession));
#endif
QVERIFY(receiver.bind());
QVERIFY(!receiver.waitForReadyRead(100));
QVERIFY(!receiver.hasPendingDatagrams());
QUdpSocket sender;
#ifdef FORCE_SESSION
sender.setProperty("_q_networksession", QVariant::fromValue(networkSession));
#endif
QCOMPARE(sender.writeDatagram(QByteArray(), QHostAddress::LocalHost, receiver.localPort()), qint64(0));
QVERIFY(receiver.waitForReadyRead(1000));
QVERIFY(receiver.hasPendingDatagrams());
char buf;
QCOMPARE(receiver.readDatagram(&buf, 1), qint64(0));
}
void tst_QUdpSocket::multicastTtlOption_data()
{
QTest::addColumn<QHostAddress>("bindAddress");
QTest::addColumn<int>("ttl");
QTest::addColumn<int>("expected");
QList<QHostAddress> addresses;
addresses += QHostAddress(QHostAddress::Any);
addresses += QHostAddress(QHostAddress::AnyIPv6);
foreach (const QHostAddress &address, addresses) {
QTest::newRow(QString("%1 0").arg(address.toString()).toAscii()) << address << 0 << 0;
QTest::newRow(QString("%1 1").arg(address.toString()).toAscii()) << address << 1 << 1;
QTest::newRow(QString("%1 2").arg(address.toString()).toAscii()) << address << 2 << 2;
QTest::newRow(QString("%1 128").arg(address.toString()).toAscii()) << address << 128 << 128;
QTest::newRow(QString("%1 255").arg(address.toString()).toAscii()) << address << 255 << 255;
QTest::newRow(QString("%1 1024").arg(address.toString()).toAscii()) << address << 1024 << 1;
}
}
void tst_QUdpSocket::multicastTtlOption()
{
QFETCH_GLOBAL(bool, setProxy);
QFETCH(QHostAddress, bindAddress);
QFETCH(int, ttl);
QFETCH(int, expected);
if (setProxy) {
// UDP multicast does not work with proxies
expected = 0;
}
QUdpSocket udpSocket;
#ifdef FORCE_SESSION
udpSocket.setProperty("_q_networksession", QVariant::fromValue(networkSession));
#endif
// bind, but ignore the result, we are only interested in initializing the socket
(void) udpSocket.bind(bindAddress, 0);
udpSocket.setSocketOption(QUdpSocket::MulticastTtlOption, ttl);
QCOMPARE(udpSocket.socketOption(QUdpSocket::MulticastTtlOption).toInt(), expected);
}
void tst_QUdpSocket::multicastLoopbackOption_data()
{
QTest::addColumn<QHostAddress>("bindAddress");
QTest::addColumn<int>("loopback");
QTest::addColumn<int>("expected");
QList<QHostAddress> addresses;
addresses += QHostAddress(QHostAddress::Any);
addresses += QHostAddress(QHostAddress::AnyIPv6);
foreach (const QHostAddress &address, addresses) {
QTest::newRow(QString("%1 0").arg(address.toString()).toAscii()) << address << 0 << 0;
QTest::newRow(QString("%1 1").arg(address.toString()).toAscii()) << address << 1 << 1;
QTest::newRow(QString("%1 2").arg(address.toString()).toAscii()) << address << 2 << 1;
QTest::newRow(QString("%1 0 again").arg(address.toString()).toAscii()) << address << 0 << 0;
QTest::newRow(QString("%1 2 again").arg(address.toString()).toAscii()) << address << 2 << 1;
QTest::newRow(QString("%1 0 last time").arg(address.toString()).toAscii()) << address << 0 << 0;
QTest::newRow(QString("%1 1 again").arg(address.toString()).toAscii()) << address << 1 << 1;
}
}
void tst_QUdpSocket::multicastLoopbackOption()
{
QFETCH_GLOBAL(bool, setProxy);
QFETCH(QHostAddress, bindAddress);
QFETCH(int, loopback);
QFETCH(int, expected);
if (setProxy) {
// UDP multicast does not work with proxies
expected = 0;
}
QUdpSocket udpSocket;
#ifdef FORCE_SESSION
udpSocket.setProperty("_q_networksession", QVariant::fromValue(networkSession));
#endif
// bind, but ignore the result, we are only interested in initializing the socket
(void) udpSocket.bind(bindAddress, 0);
udpSocket.setSocketOption(QUdpSocket::MulticastLoopbackOption, loopback);
QCOMPARE(udpSocket.socketOption(QUdpSocket::MulticastLoopbackOption).toInt(), expected);
}
void tst_QUdpSocket::multicastJoinBeforeBind_data()
{
QTest::addColumn<QHostAddress>("groupAddress");
QTest::newRow("valid ipv4 group address") << QHostAddress("239.255.118.62");
QTest::newRow("invalid ipv4 group address") << QHostAddress(QHostAddress::Broadcast);
QTest::newRow("valid ipv6 group address") << QHostAddress("FF01::114");
QTest::newRow("invalid ipv6 group address") << QHostAddress(QHostAddress::AnyIPv6);
}
void tst_QUdpSocket::multicastJoinBeforeBind()
{
QFETCH(QHostAddress, groupAddress);
QUdpSocket udpSocket;
#ifdef FORCE_SESSION
udpSocket.setProperty("_q_networksession", QVariant::fromValue(networkSession));
#endif
// cannot join group before binding
QTest::ignoreMessage(QtWarningMsg, "QUdpSocket::joinMulticastGroup() called on a QUdpSocket when not in QUdpSocket::BoundState");
QVERIFY(!udpSocket.joinMulticastGroup(groupAddress));
}
void tst_QUdpSocket::multicastLeaveAfterClose_data()
{
QTest::addColumn<QHostAddress>("groupAddress");
QTest::newRow("valid ipv4 group address") << QHostAddress("239.255.118.62");
QTest::newRow("valid ipv6 group address") << QHostAddress("FF01::114");
}
void tst_QUdpSocket::multicastLeaveAfterClose()
{
QFETCH_GLOBAL(bool, setProxy);
QFETCH(QHostAddress, groupAddress);
if (setProxy) {
QSKIP("UDP Multicast does not work with proxies", SkipAll);
}
QUdpSocket udpSocket;
#ifdef FORCE_SESSION
udpSocket.setProperty("_q_networksession", QVariant::fromValue(networkSession));
#endif
#ifdef Q_OS_SYMBIAN
QVERIFY2(udpSocket.bind(),
qPrintable(udpSocket.errorString()));
#else
QVERIFY2(udpSocket.bind(groupAddress, 0),
qPrintable(udpSocket.errorString()));
#endif
QVERIFY2(udpSocket.joinMulticastGroup(groupAddress),
qPrintable(udpSocket.errorString()));
udpSocket.close();
QTest::ignoreMessage(QtWarningMsg, "QUdpSocket::leaveMulticastGroup() called on a QUdpSocket when not in QUdpSocket::BoundState");
QVERIFY(!udpSocket.leaveMulticastGroup(groupAddress));
}
void tst_QUdpSocket::setMulticastInterface_data()
{
QTest::addColumn<QNetworkInterface>("iface");
QTest::addColumn<QHostAddress>("address");
QList<QNetworkInterface> interfaces = QNetworkInterface::allInterfaces();
foreach (const QNetworkInterface &iface, interfaces) {
foreach (const QNetworkAddressEntry &entry, iface.addressEntries()) {
QTest::newRow(QString("%1:%2").arg(iface.name()).arg(entry.ip().toString()).toAscii())
<< iface
<< entry.ip();
}
}
}
void tst_QUdpSocket::setMulticastInterface()
{
#ifdef Q_OS_SYMBIAN
QSKIP("Symbian has no IPV6_MULTICAST_IF equivalent", SkipAll);
#else
QFETCH_GLOBAL(bool, setProxy);
QFETCH(QNetworkInterface, iface);
QFETCH(QHostAddress, address);
QUdpSocket udpSocket;
// bind initializes the socket
bool bound = udpSocket.bind((address.protocol() == QAbstractSocket::IPv6Protocol
? QHostAddress(QHostAddress::AnyIPv6)
: QHostAddress(QHostAddress::Any)),
0);
if (!bound)
QTest::ignoreMessage(QtWarningMsg, "QUdpSocket::setMulticastInterface() called on a QUdpSocket when not in QUdpSocket::BoundState");
udpSocket.setMulticastInterface(iface);
if (!bound)
QTest::ignoreMessage(QtWarningMsg, "QUdpSocket::multicastInterface() called on a QUdpSocket when not in QUdpSocket::BoundState");
QNetworkInterface iface2 = udpSocket.multicastInterface();
if (!setProxy) {
QVERIFY(iface2.isValid());
QCOMPARE(iface.name(), iface2.name());
} else {
QVERIFY(!iface2.isValid());
}
#endif
}
void tst_QUdpSocket::multicast_data()
{
QHostAddress anyAddress = QHostAddress(QHostAddress::Any);
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 ((bindAddress.protocol() == QAbstractSocket::IPv4Protocol && (bindAddress.toIPv4Address() & 0xffff0000) == 0xefff0000)
|| bindAddress.protocol() == QAbstractSocket::IPv6Protocol) {
// proxy cannot bind to IPv6 or multicast addresses
bindResult = false;
}
joinResult = false;
}
QUdpSocket receiver;
#ifdef FORCE_SESSION
receiver.setProperty("_q_networksession", QVariant::fromValue(networkSession));
#endif
// bind first, then verify that we can join the multicast group
#ifdef Q_OS_SYMBIAN
if (!setProxy) {
QEXPECT_FAIL("same bind, group ipv4 address", "bind to group address not supported on symbian", Abort);
QEXPECT_FAIL("same bind, group ipv6 address", "bind to group address not supported on symbian", Abort);
}
#endif
QVERIFY2(receiver.bind(bindAddress, 0) == bindResult,
qPrintable(receiver.errorString()));
if (!bindResult)
return;
QVERIFY2(receiver.joinMulticastGroup(groupAddress) == joinResult,
qPrintable(receiver.errorString()));
if (!joinResult)
return;
QList<QByteArray> datagrams = QList<QByteArray>()
<< QByteArray("0123")
<< QByteArray("4567")
<< QByteArray("89ab")
<< QByteArray("cdef");
QUdpSocket sender;
#ifdef FORCE_SESSION
sender.setProperty("_q_networksession", QVariant::fromValue(networkSession));
#endif
sender.bind();
foreach (const QByteArray &datagram, datagrams) {
QCOMPARE(int(sender.writeDatagram(datagram, groupAddress, receiver.localPort())),
int(datagram.size()));
}
QVERIFY2(receiver.waitForReadyRead(),
qPrintable(receiver.errorString()));
QVERIFY(receiver.hasPendingDatagrams());
QList<QByteArray> receivedDatagrams;
while (receiver.hasPendingDatagrams()) {
QByteArray datagram;
datagram.resize(receiver.pendingDatagramSize());
receiver.readDatagram(datagram.data(), datagram.size(), 0, 0);
receivedDatagrams << datagram;
}
#ifdef Q_OS_SYMBIAN
QEXPECT_FAIL("valid bind, group ipv4 address", "IPv4 multicast not supported on symbian", Abort);
#endif
QCOMPARE(receivedDatagrams, datagrams);
QVERIFY2(receiver.leaveMulticastGroup(groupAddress), qPrintable(receiver.errorString()));
}
void tst_QUdpSocket::echo_data()
{
QTest::addColumn<bool>("connect");
QTest::newRow("writeDatagram") << false;
QTest::newRow("write") << true;
}
void tst_QUdpSocket::echo()
{
QFETCH(bool, connect);
QHostInfo info = QHostInfo::fromName(QtNetworkSettings::serverName());
QVERIFY(info.addresses().count());
QHostAddress remote = info.addresses().first();
QUdpSocket sock;
#ifdef FORCE_SESSION
sock.setProperty("_q_networksession", QVariant::fromValue(networkSession));
#endif
if (connect) {
sock.connectToHost(remote, 7);
QVERIFY(sock.waitForConnected(10000));
} else {
sock.bind();
}
QByteArray out(30, 'x');
QByteArray in;
int successes = 0;
for (int i=0;i<10;i++) {
if (connect) {
sock.write(out);
} else {
sock.writeDatagram(out, remote, 7);
}
if (sock.waitForReadyRead(1000)) {
while (sock.hasPendingDatagrams()) {
QHostAddress from;
quint16 port;
if (connect) {
in = sock.read(sock.pendingDatagramSize());
} else {
in.resize(sock.pendingDatagramSize());
sock.readDatagram(in.data(), in.length(), &from, &port);
}
if (in==out)
successes++;
}
}
if (!sock.isValid())
QFAIL(sock.errorString().toLatin1().constData());
qDebug() << "packets in" << successes << "out" << i;
QTest::qWait(50); //choke to avoid triggering flood/DDoS protections on echo service
}
QVERIFY(successes >= 9);
}
QTEST_MAIN(tst_QUdpSocket)
#include "tst_qudpsocket.moc"