summaryrefslogtreecommitdiffstats
path: root/tests/auto/network/socket/qudpsocket/tst_qudpsocket.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'tests/auto/network/socket/qudpsocket/tst_qudpsocket.cpp')
-rw-r--r--tests/auto/network/socket/qudpsocket/tst_qudpsocket.cpp343
1 files changed, 196 insertions, 147 deletions
diff --git a/tests/auto/network/socket/qudpsocket/tst_qudpsocket.cpp b/tests/auto/network/socket/qudpsocket/tst_qudpsocket.cpp
index 31fd1a3b30..689ff452f9 100644
--- a/tests/auto/network/socket/qudpsocket/tst_qudpsocket.cpp
+++ b/tests/auto/network/socket/qudpsocket/tst_qudpsocket.cpp
@@ -1,32 +1,6 @@
-/****************************************************************************
-**
-** Copyright (C) 2021 The Qt Company Ltd.
-** Copyright (C) 2017 Intel Corporation.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
+// Copyright (C) 2021 The Qt Company Ltd.
+// Copyright (C) 2017 Intel Corporation.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include <QTest>
#include <QSignalSpy>
@@ -36,6 +10,7 @@
#endif
#include <QScopeGuard>
#include <QVersionNumber>
+#include <QSemaphore>
#include <qcoreapplication.h>
#include <qfileinfo.h>
@@ -53,6 +28,7 @@
#include <QNetworkInterface>
#include <qstringlist.h>
+#include <QSet>
#include "../../../network-settings.h"
#include <QtTest/private/qemulationdetector_p.h>
@@ -70,6 +46,8 @@
# define RELIABLE_BYTES_AVAILABLE
#endif
+using namespace Qt::StringLiterals;
+
Q_DECLARE_METATYPE(QHostAddress)
QT_FORWARD_DECLARE_CLASS(QUdpSocket)
@@ -127,6 +105,8 @@ private slots:
void asyncReadDatagram();
void writeInHostLookupState();
+ void readyReadConnectionThrottling();
+
protected slots:
void empty_readyReadSlot();
void empty_connectedSlot();
@@ -145,6 +125,7 @@ private:
QList<QHostAddress> allAddresses;
QHostAddress multicastGroup4, multicastGroup6;
QList<QHostAddress> linklocalMulticastGroups;
+ QNetworkInterface ifaceWithIPv6;
QUdpSocket *m_asyncSender;
QUdpSocket *m_asyncReceiver;
};
@@ -195,26 +176,7 @@ QNetworkInterface tst_QUdpSocket::interfaceForGroup(const QHostAddress &multicas
if (!scope.isEmpty())
return QNetworkInterface::interfaceFromName(scope);
- static QNetworkInterface ipv6if = [&]() {
- // find any link local address in the allAddress list
- for (const QHostAddress &addr: qAsConst(allAddresses)) {
- if (addr.isLoopback())
- continue;
-
- QString scope = addr.scopeId();
- if (!scope.isEmpty()) {
- QNetworkInterface iface = QNetworkInterface::interfaceFromName(scope);
- qDebug() << "Will bind IPv6 sockets to" << iface;
- return iface;
- }
- }
-
- qWarning("interfaceForGroup(%s) could not find any link-local IPv6 address! "
- "Make sure this test is behind a check of QtNetworkSettings::hasIPv6().",
- qUtf8Printable(multicastGroup.toString()));
- return QNetworkInterface();
- }();
- return ipv6if;
+ return ifaceWithIPv6;
}
bool tst_QUdpSocket::shouldWorkaroundLinuxKernelBug()
@@ -293,15 +255,22 @@ void tst_QUdpSocket::initTestCase()
// ff12:: is temporary, not prefix-based, link-local
r[0] = qToBigEndian(Q_UINT64_C(0xff12) << 48);
QHostAddress llbase(*reinterpret_cast<Q_IPV6ADDR *>(&r));
- for (const QHostAddress &a : qAsConst(allAddresses)) {
+ for (const QHostAddress &a : std::as_const(allAddresses)) {
QString scope = a.scopeId();
if (scope.isEmpty())
continue;
llbase.setScopeId(scope);
linklocalMulticastGroups << llbase;
+ if (!ifaceWithIPv6.isValid()) {
+ // Remember the first interface we've found that has IPv6 so we can
+ // bind non-link-local sockets to it (the first is least likely to
+ // be some weird virtual interface).
+ ifaceWithIPv6 = QNetworkInterface::interfaceFromName(scope);
+ }
}
qDebug() << "Will use multicast groups" << multicastGroup4 << multicastGroup6 << linklocalMulticastGroups;
+ qDebug() << "Will bind IPv6 sockets to" << ifaceWithIPv6;
m_workaroundLinuxKernelBug = shouldWorkaroundLinuxKernelBug();
if (QTestPrivate::isRunningArmOnX86())
@@ -358,7 +327,7 @@ void tst_QUdpSocket::unconnectedServerAndClientTest()
QSignalSpy stateChangedSpy(&serverSocket, SIGNAL(stateChanged(QAbstractSocket::SocketState)));
QVERIFY2(serverSocket.bind(), serverSocket.errorString().toLatin1().constData());
- QCOMPARE(stateChangedSpy.count(), 1);
+ QCOMPARE(stateChangedSpy.size(), 1);
const char *message[] = {"Yo mista", "Yo", "Wassap"};
@@ -407,10 +376,11 @@ void tst_QUdpSocket::broadcasting()
const char *message[] = {"Yo mista", "", "Yo", "Wassap"};
QList<QHostAddress> broadcastAddresses;
- foreach (QNetworkInterface iface, QNetworkInterface::allInterfaces()) {
+ const auto ifaces = QNetworkInterface::allInterfaces();
+ for (const QNetworkInterface &iface : ifaces) {
if ((iface.flags() & QNetworkInterface::CanBroadcast)
&& iface.flags() & QNetworkInterface::IsUp) {
- for (int i=0;i<iface.addressEntries().count();i++) {
+ for (int i=0;i<iface.addressEntries().size();i++) {
QHostAddress broadcast = iface.addressEntries().at(i).broadcast();
if (broadcast.protocol() == QAbstractSocket::IPv4Protocol)
broadcastAddresses.append(broadcast);
@@ -435,7 +405,7 @@ void tst_QUdpSocket::broadcasting()
for (int k = 0; k < 4; k++) {
broadcastSocket.writeDatagram(message[i], strlen(message[i]),
QHostAddress::Broadcast, serverPort);
- foreach (QHostAddress addr, broadcastAddresses)
+ for (const QHostAddress &addr : std::as_const(broadcastAddresses))
broadcastSocket.writeDatagram(message[i], strlen(message[i]), addr, serverPort);
}
QTestEventLoop::instance().enterLoop(15);
@@ -455,7 +425,7 @@ void tst_QUdpSocket::broadcasting()
QVERIFY(dgram.isValid());
QByteArray arr = dgram.data();
- QCOMPARE(arr.length(), messageLength);
+ QCOMPARE(arr.size(), messageLength);
arr.resize(messageLength);
QCOMPARE(arr, QByteArray(message[i]));
@@ -515,27 +485,27 @@ void tst_QUdpSocket::loop()
QHostAddress peterAddress = makeNonAny(peter.localAddress());
QHostAddress paulAddress = makeNonAny(paul.localAddress());
- QCOMPARE(peter.writeDatagram(peterMessage.data(), peterMessage.length(),
- paulAddress, paul.localPort()), qint64(peterMessage.length()));
- QCOMPARE(paul.writeDatagram(paulMessage.data(), paulMessage.length(),
- peterAddress, peter.localPort()), qint64(paulMessage.length()));
+ QCOMPARE(peter.writeDatagram(peterMessage.data(), peterMessage.size(),
+ paulAddress, paul.localPort()), qint64(peterMessage.size()));
+ QCOMPARE(paul.writeDatagram(paulMessage.data(), paulMessage.size(),
+ peterAddress, peter.localPort()), qint64(paulMessage.size()));
QVERIFY2(peter.waitForReadyRead(9000), QtNetworkSettings::msgSocketError(peter).constData());
QVERIFY2(paul.waitForReadyRead(9000), QtNetworkSettings::msgSocketError(paul).constData());
- QNetworkDatagram peterDatagram = peter.receiveDatagram(paulMessage.length() * 2);
- QNetworkDatagram paulDatagram = paul.receiveDatagram(peterMessage.length() * 2);
+ QNetworkDatagram peterDatagram = peter.receiveDatagram(paulMessage.size() * 2);
+ QNetworkDatagram paulDatagram = paul.receiveDatagram(peterMessage.size() * 2);
if (success) {
- QCOMPARE(peterDatagram.data().length(), qint64(paulMessage.length()));
- QCOMPARE(paulDatagram.data().length(), qint64(peterMessage.length()));
+ QCOMPARE(peterDatagram.data().size(), qint64(paulMessage.size()));
+ QCOMPARE(paulDatagram.data().size(), qint64(peterMessage.size()));
} else {
// this code path seems to never be executed
- QVERIFY(peterDatagram.data().length() != paulMessage.length());
- QVERIFY(paulDatagram.data().length() != peterMessage.length());
+ QVERIFY(peterDatagram.data().size() != paulMessage.size());
+ QVERIFY(paulDatagram.data().size() != peterMessage.size());
}
- QCOMPARE(peterDatagram.data().left(paulMessage.length()), paulMessage);
- QCOMPARE(paulDatagram.data().left(peterMessage.length()), peterMessage);
+ QCOMPARE(peterDatagram.data().left(paulMessage.size()), paulMessage);
+ QCOMPARE(paulDatagram.data().left(peterMessage.size()), peterMessage);
QCOMPARE(peterDatagram.senderAddress(), paulAddress);
QCOMPARE(paulDatagram.senderAddress(), peterAddress);
@@ -592,27 +562,27 @@ void tst_QUdpSocket::ipv6Loop()
peterPort = peter.localPort();
paulPort = paul.localPort();
- 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()));
+ QCOMPARE(peter.writeDatagram(peterMessage.data(), peterMessage.size(), QHostAddress("::1"),
+ paulPort), qint64(peterMessage.size()));
+ QCOMPARE(paul.writeDatagram(paulMessage.data(), paulMessage.size(),
+ QHostAddress("::1"), peterPort), qint64(paulMessage.size()));
QVERIFY(peter.waitForReadyRead(5000));
QVERIFY(paul.waitForReadyRead(5000));
- QNetworkDatagram peterDatagram = peter.receiveDatagram(paulMessage.length() * 2);
- QNetworkDatagram paulDatagram = paul.receiveDatagram(peterMessage.length() * 2);
+ QNetworkDatagram peterDatagram = peter.receiveDatagram(paulMessage.size() * 2);
+ QNetworkDatagram paulDatagram = paul.receiveDatagram(peterMessage.size() * 2);
if (success) {
- QCOMPARE(peterDatagram.data().length(), qint64(paulMessage.length()));
- QCOMPARE(paulDatagram.data().length(), qint64(peterMessage.length()));
+ QCOMPARE(peterDatagram.data().size(), qint64(paulMessage.size()));
+ QCOMPARE(paulDatagram.data().size(), qint64(peterMessage.size()));
} else {
// this code path seems to never be executed
- QVERIFY(peterDatagram.data().length() != paulMessage.length());
- QVERIFY(paulDatagram.data().length() != peterMessage.length());
+ QVERIFY(peterDatagram.data().size() != paulMessage.size());
+ QVERIFY(paulDatagram.data().size() != peterMessage.size());
}
- QCOMPARE(peterDatagram.data().left(paulMessage.length()), paulMessage);
- QCOMPARE(paulDatagram.data().left(peterMessage.length()), peterMessage);
+ QCOMPARE(peterDatagram.data().left(paulMessage.size()), paulMessage);
+ QCOMPARE(paulDatagram.data().left(peterMessage.size()), peterMessage);
QCOMPARE(peterDatagram.senderAddress(), paulAddress);
QCOMPARE(paulDatagram.senderAddress(), peterAddress);
@@ -640,7 +610,7 @@ void tst_QUdpSocket::dualStack()
QVERIFY(v4Sock.bind(QHostAddress(QHostAddress::AnyIPv4), 0));
//test v4 -> dual
- QCOMPARE((int)v4Sock.writeDatagram(v4Data.constData(), v4Data.length(), QHostAddress(QHostAddress::LocalHost), dualSock.localPort()), v4Data.length());
+ QCOMPARE((int)v4Sock.writeDatagram(v4Data.constData(), v4Data.size(), QHostAddress(QHostAddress::LocalHost), dualSock.localPort()), v4Data.size());
QVERIFY2(dualSock.waitForReadyRead(5000), QtNetworkSettings::msgSocketError(dualSock).constData());
QNetworkDatagram dgram = dualSock.receiveDatagram(100);
QVERIFY(dgram.isValid());
@@ -652,7 +622,7 @@ void tst_QUdpSocket::dualStack()
QCOMPARE(dgram.senderAddress(), makeNonAny(v4Sock.localAddress(), QHostAddress::Null));
if (dgram.destinationPort() != -1) {
QCOMPARE(dgram.destinationPort(), int(dualSock.localPort()));
- QVERIFY(dgram.destinationAddress().isEqual(dualSock.localAddress()));
+ QVERIFY(dgram.destinationAddress().isEqual(makeNonAny(dualSock.localAddress(), QHostAddress::LocalHost)));
} else {
qInfo("Getting IPv4 destination address failed.");
}
@@ -663,7 +633,7 @@ void tst_QUdpSocket::dualStack()
QVERIFY(v6Sock.bind(QHostAddress(QHostAddress::AnyIPv6), 0));
//test v6 -> dual
- QCOMPARE((int)v6Sock.writeDatagram(v6Data.constData(), v6Data.length(), QHostAddress(QHostAddress::LocalHostIPv6), dualSock.localPort()), v6Data.length());
+ QCOMPARE((int)v6Sock.writeDatagram(v6Data.constData(), v6Data.size(), QHostAddress(QHostAddress::LocalHostIPv6), dualSock.localPort()), v6Data.size());
QVERIFY2(dualSock.waitForReadyRead(5000), QtNetworkSettings::msgSocketError(dualSock).constData());
dgram = dualSock.receiveDatagram(100);
QVERIFY(dgram.isValid());
@@ -674,7 +644,7 @@ void tst_QUdpSocket::dualStack()
QCOMPARE(dgram.destinationAddress(), makeNonAny(dualSock.localAddress(), QHostAddress::LocalHostIPv6));
//test dual -> v6
- QCOMPARE((int)dualSock.writeDatagram(dualData.constData(), dualData.length(), QHostAddress(QHostAddress::LocalHostIPv6), v6Sock.localPort()), dualData.length());
+ QCOMPARE((int)dualSock.writeDatagram(dualData.constData(), dualData.size(), QHostAddress(QHostAddress::LocalHostIPv6), v6Sock.localPort()), dualData.size());
QVERIFY2(v6Sock.waitForReadyRead(5000), QtNetworkSettings::msgSocketError(v6Sock).constData());
dgram = v6Sock.receiveDatagram(100);
QVERIFY(dgram.isValid());
@@ -686,7 +656,7 @@ void tst_QUdpSocket::dualStack()
}
//test dual -> v4
- QCOMPARE((int)dualSock.writeDatagram(dualData.constData(), dualData.length(), QHostAddress(QHostAddress::LocalHost), v4Sock.localPort()), dualData.length());
+ QCOMPARE((int)dualSock.writeDatagram(dualData.constData(), dualData.size(), QHostAddress(QHostAddress::LocalHost), v4Sock.localPort()), dualData.size());
QVERIFY2(v4Sock.waitForReadyRead(5000), QtNetworkSettings::msgSocketError(v4Sock).constData());
dgram = v4Sock.receiveDatagram(100);
QVERIFY(dgram.isValid());
@@ -725,19 +695,19 @@ void tst_QUdpSocket::dualStackAutoBinding()
//test an autobound socket can send to both v4 and v6 addresses (v4 first)
QUdpSocket dualSock;
- QCOMPARE((int)dualSock.writeDatagram(dualData.constData(), dualData.length(), QHostAddress(QHostAddress::LocalHost), v4Sock.localPort()), dualData.length());
+ QCOMPARE((int)dualSock.writeDatagram(dualData.constData(), dualData.size(), QHostAddress(QHostAddress::LocalHost), v4Sock.localPort()), dualData.size());
QVERIFY2(v4Sock.waitForReadyRead(5000), QtNetworkSettings::msgSocketError(v4Sock).constData());
buffer.reserve(100);
size = v4Sock.readDatagram(buffer.data(), 100, &from, &port);
- QCOMPARE((int)size, dualData.length());
+ QCOMPARE((int)size, dualData.size());
buffer.resize(size);
QCOMPARE(buffer, dualData);
- QCOMPARE((int)dualSock.writeDatagram(dualData.constData(), dualData.length(), QHostAddress(QHostAddress::LocalHostIPv6), v6Sock.localPort()), dualData.length());
+ QCOMPARE((int)dualSock.writeDatagram(dualData.constData(), dualData.size(), QHostAddress(QHostAddress::LocalHostIPv6), v6Sock.localPort()), dualData.size());
QVERIFY2(v6Sock.waitForReadyRead(5000), QtNetworkSettings::msgSocketError(v6Sock).constData());
buffer.reserve(100);
size = v6Sock.readDatagram(buffer.data(), 100, &from, &port);
- QCOMPARE((int)size, dualData.length());
+ QCOMPARE((int)size, dualData.size());
buffer.resize(size);
QCOMPARE(buffer, dualData);
}
@@ -746,19 +716,19 @@ void tst_QUdpSocket::dualStackAutoBinding()
//test an autobound socket can send to both v4 and v6 addresses (v6 first)
QUdpSocket dualSock;
- QCOMPARE((int)dualSock.writeDatagram(dualData.constData(), dualData.length(), QHostAddress(QHostAddress::LocalHostIPv6), v6Sock.localPort()), dualData.length());
+ QCOMPARE((int)dualSock.writeDatagram(dualData.constData(), dualData.size(), QHostAddress(QHostAddress::LocalHostIPv6), v6Sock.localPort()), dualData.size());
QVERIFY2(v6Sock.waitForReadyRead(5000), QtNetworkSettings::msgSocketError(v6Sock).constData());
buffer.reserve(100);
size = v6Sock.readDatagram(buffer.data(), 100, &from, &port);
- QCOMPARE((int)size, dualData.length());
+ QCOMPARE((int)size, dualData.size());
buffer.resize(size);
QCOMPARE(buffer, dualData);
- QCOMPARE((int)dualSock.writeDatagram(dualData.constData(), dualData.length(), QHostAddress(QHostAddress::LocalHost), v4Sock.localPort()), dualData.length());
+ QCOMPARE((int)dualSock.writeDatagram(dualData.constData(), dualData.size(), QHostAddress(QHostAddress::LocalHost), v4Sock.localPort()), dualData.size());
QVERIFY2(v4Sock.waitForReadyRead(5000), QtNetworkSettings::msgSocketError(v4Sock).constData());
buffer.reserve(100);
size = v4Sock.readDatagram(buffer.data(), 100, &from, &port);
- QCOMPARE((int)size, dualData.length());
+ QCOMPARE((int)size, dualData.size());
buffer.resize(size);
QCOMPARE(buffer, dualData);
}
@@ -779,7 +749,7 @@ void tst_QUdpSocket::dualStackNoIPv4onV6only()
QVERIFY(v6Sock.bind(QHostAddress(QHostAddress::AnyIPv6), 0));
//test v4 -> v6 (should not be received as this is a v6 only socket)
- QCOMPARE((int)v4Sock.writeDatagram(v4Data.constData(), v4Data.length(), QHostAddress(QHostAddress::LocalHost), v6Sock.localPort()), v4Data.length());
+ QCOMPARE((int)v4Sock.writeDatagram(v4Data.constData(), v4Data.size(), QHostAddress(QHostAddress::LocalHost), v6Sock.localPort()), v4Data.size());
QVERIFY(!v6Sock.waitForReadyRead(1000));
}
@@ -899,17 +869,17 @@ void tst_QUdpSocket::writeDatagram()
#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(bytesspy.size(), 0);
+ QCOMPARE(errorspy.size(), 1);
QCOMPARE(*static_cast<const int *>(errorspy.at(0).at(0).constData()),
int(QUdpSocket::DatagramTooLargeError));
QCOMPARE(client.error(), QUdpSocket::DatagramTooLargeError);
break;
}
- QCOMPARE(bytesspy.count(), 1);
+ QCOMPARE(bytesspy.size(), 1);
QCOMPARE(*static_cast<const qint64 *>(bytesspy.at(0).at(0).constData()),
qint64(i * 1024));
- QCOMPARE(errorspy.count(), 0);
+ QCOMPARE(errorspy.size(), 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));
@@ -1022,7 +992,7 @@ void tst_QUdpSocket::writeDatagramToNonExistingPeer()
QVERIFY(sUdp.bind());
QCOMPARE(sUdp.writeDatagram("", 1, peerAddress, peerPort), qint64(1));
QTestEventLoop::instance().enterLoop(1);
- QCOMPARE(sReadyReadSpy.count(), 0);
+ QCOMPARE(sReadyReadSpy.size(), 0);
}
void tst_QUdpSocket::writeToNonExistingPeer_data()
@@ -1065,8 +1035,8 @@ void tst_QUdpSocket::writeToNonExistingPeer()
// the third one will succeed...
QCOMPARE(sConnected.write("", 1), qint64(1));
QTestEventLoop::instance().enterLoop(1);
- QCOMPARE(sConnectedReadyReadSpy.count(), 0);
- QCOMPARE(sConnectedErrorSpy.count(), 1);
+ QCOMPARE(sConnectedReadyReadSpy.size(), 0);
+ QCOMPARE(sConnectedErrorSpy.size(), 1);
QCOMPARE(int(sConnected.error()), int(QUdpSocket::ConnectionRefusedError));
// we should now get a read error
@@ -1265,11 +1235,12 @@ void tst_QUdpSocket::multicastTtlOption_data()
QTest::addColumn<int>("ttl");
QTest::addColumn<int>("expected");
- QList<QHostAddress> addresses;
- addresses += QHostAddress(QHostAddress::AnyIPv4);
- addresses += QHostAddress(QHostAddress::AnyIPv6);
+ const QHostAddress addresses[] = {
+ QHostAddress(QHostAddress::AnyIPv4),
+ QHostAddress(QHostAddress::AnyIPv6),
+ };
- foreach (const QHostAddress &address, addresses) {
+ for (const QHostAddress &address : addresses) {
const QByteArray addressB = address.toString().toLatin1();
QTest::newRow((addressB + " 0").constData()) << address << 0 << 0;
QTest::newRow((addressB + " 1").constData()) << address << 1 << 1;
@@ -1311,11 +1282,12 @@ void tst_QUdpSocket::multicastLoopbackOption_data()
QTest::addColumn<int>("loopback");
QTest::addColumn<int>("expected");
- QList<QHostAddress> addresses;
- addresses += QHostAddress(QHostAddress::AnyIPv4);
- addresses += QHostAddress(QHostAddress::AnyIPv6);
+ const QHostAddress addresses[] = {
+ QHostAddress(QHostAddress::AnyIPv4),
+ QHostAddress(QHostAddress::AnyIPv6),
+ };
- foreach (const QHostAddress &address, addresses) {
+ for (const QHostAddress &address : addresses) {
const QByteArray addressB = address.toString().toLatin1();
QTest::newRow((addressB + " 0").constData()) << address << 0 << 0;
QTest::newRow((addressB + " 1").constData()) << address << 1 << 1;
@@ -1358,7 +1330,7 @@ void tst_QUdpSocket::multicastJoinBeforeBind_data()
QTest::newRow("valid ipv4 group address") << multicastGroup4;
QTest::newRow("invalid ipv4 group address") << QHostAddress(QHostAddress::Broadcast);
QTest::newRow("valid ipv6 group address") << multicastGroup6;
- for (const QHostAddress &a : qAsConst(linklocalMulticastGroups))
+ for (const QHostAddress &a : std::as_const(linklocalMulticastGroups))
QTest::addRow("valid ipv6 %s-link group address", a.scopeId().toLatin1().constData()) << a;
QTest::newRow("invalid ipv6 group address") << QHostAddress(QHostAddress::AnyIPv6);
}
@@ -1378,7 +1350,7 @@ void tst_QUdpSocket::multicastLeaveAfterClose_data()
QTest::addColumn<QHostAddress>("groupAddress");
QTest::newRow("ipv4") << multicastGroup4;
QTest::newRow("ipv6") << multicastGroup6;
- for (const QHostAddress &a : qAsConst(linklocalMulticastGroups))
+ for (const QHostAddress &a : std::as_const(linklocalMulticastGroups))
QTest::addRow("ipv6-link-%s", a.scopeId().toLatin1().constData()) << a;
}
@@ -1415,11 +1387,12 @@ void tst_QUdpSocket::setMulticastInterface_data()
{
QTest::addColumn<QNetworkInterface>("iface");
QTest::addColumn<QHostAddress>("address");
- QList<QNetworkInterface> interfaces = QNetworkInterface::allInterfaces();
- foreach (const QNetworkInterface &iface, interfaces) {
+ const QList<QNetworkInterface> interfaces = QNetworkInterface::allInterfaces();
+ for (const QNetworkInterface &iface : interfaces) {
if ((iface.flags() & QNetworkInterface::IsUp) == 0)
continue;
- foreach (const QNetworkAddressEntry &entry, iface.addressEntries()) {
+ const auto entries = iface.addressEntries();
+ for (const QNetworkAddressEntry &entry : entries) {
const QByteArray testName = iface.name().toLatin1() + ':' + entry.ip().toString().toLatin1();
QTest::newRow(testName.constData()) << iface << entry.ip();
}
@@ -1472,13 +1445,13 @@ void tst_QUdpSocket::multicast_data()
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("valid bind, group ipv6 address") << any6Address << true << group6Address << true;
- for (const QHostAddress &a : qAsConst(linklocalMulticastGroups))
+ for (const QHostAddress &a : std::as_const(linklocalMulticastGroups))
QTest::addRow("valid bind, %s-link group ipv6 address", a.scopeId().toLatin1().constData())
<< any6Address << true << a << true;
QTest::newRow("valid bind, invalid group ipv6 address") << any6Address << true << any6Address << false;
QTest::newRow("dual bind, group ipv4 address") << dualAddress << true << groupAddress << false;
QTest::newRow("dual bind, group ipv6 address") << dualAddress << true << group6Address << true;
- for (const QHostAddress &a : qAsConst(linklocalMulticastGroups))
+ for (const QHostAddress &a : std::as_const(linklocalMulticastGroups))
QTest::addRow("dual bind, %s-link group ipv6 address", a.scopeId().toLatin1().constData())
<< dualAddress << true << a << true;
}
@@ -1523,15 +1496,16 @@ void tst_QUdpSocket::multicast()
if (!joinResult)
return;
- QList<QByteArray> datagrams = QList<QByteArray>()
- << QByteArray("0123")
- << QByteArray("4567")
- << QByteArray("89ab")
- << QByteArray("cdef");
+ const QByteArray datagrams[] = {
+ "0123"_ba,
+ "4567"_ba,
+ "89ab"_ba,
+ "cdef"_ba,
+ };
QUdpSocket sender;
sender.bind();
- foreach (const QByteArray &datagram, datagrams) {
+ for (const QByteArray &datagram : datagrams) {
QNetworkDatagram dgram(datagram, groupAddress, receiver.localPort());
dgram.setInterfaceIndex(interfaceForGroup(groupAddress).index());
QCOMPARE(int(sender.writeDatagram(dgram)),
@@ -1574,7 +1548,7 @@ void tst_QUdpSocket::echo()
{
QFETCH(bool, connect);
QHostInfo info = QHostInfo::fromName(QtNetworkSettings::echoServerName());
- QVERIFY(info.addresses().count());
+ QVERIFY(info.addresses().size());
QHostAddress remote = info.addresses().first();
QUdpSocket sock;
@@ -1601,7 +1575,7 @@ void tst_QUdpSocket::echo()
in = sock.read(sock.pendingDatagramSize());
} else {
in.resize(sock.pendingDatagramSize());
- sock.readDatagram(in.data(), in.length(), &from, &port);
+ sock.readDatagram(in.data(), in.size(), &from, &port);
}
if (in==out)
successes++;
@@ -1624,7 +1598,8 @@ void tst_QUdpSocket::linkLocalIPv6()
QList <QHostAddress> addresses;
QSet <QString> scopes;
QHostAddress localMask("fe80::");
- foreach (const QNetworkInterface& iface, QNetworkInterface::allInterfaces()) {
+ const auto ifaces = QNetworkInterface::allInterfaces();
+ for (const QNetworkInterface &iface : ifaces) {
//Windows preallocates link local addresses to interfaces that are down.
//These may or may not work depending on network driver
if (iface.flags() & QNetworkInterface::IsUp) {
@@ -1639,7 +1614,8 @@ void tst_QUdpSocket::linkLocalIPv6()
continue;
#endif
- foreach (QNetworkAddressEntry addressEntry, iface.addressEntries()) {
+ const auto entries = iface.addressEntries();
+ for (const QNetworkAddressEntry &addressEntry : entries) {
QHostAddress addr(addressEntry.ip());
if (!addr.scopeId().isEmpty() && addr.isInSubnet(localMask, 64)) {
scopes << addr.scopeId();
@@ -1654,7 +1630,7 @@ void tst_QUdpSocket::linkLocalIPv6()
QList <QUdpSocket*> sockets;
quint16 port = 0;
- foreach (const QHostAddress& addr, addresses) {
+ for (const QHostAddress &addr : std::as_const(addresses)) {
QUdpSocket *s = new QUdpSocket;
QVERIFY2(s->bind(addr, port), addr.toString().toLatin1()
+ '/' + QByteArray::number(port) + ": " + qPrintable(s->errorString()));
@@ -1663,7 +1639,7 @@ void tst_QUdpSocket::linkLocalIPv6()
}
QByteArray testData("hello");
- foreach (QUdpSocket *s, sockets) {
+ for (QUdpSocket *s : std::as_const(sockets)) {
QUdpSocket neutral;
QVERIFY(neutral.bind(QHostAddress(QHostAddress::AnyIPv6)));
QSignalSpy neutralReadSpy(&neutral, SIGNAL(readyRead()));
@@ -1671,27 +1647,26 @@ void tst_QUdpSocket::linkLocalIPv6()
QSignalSpy spy(s, SIGNAL(readyRead()));
QVERIFY(s->writeDatagram(testData, s->localAddress(), neutral.localPort()));
- QTRY_VERIFY(neutralReadSpy.count() > 0); //note may need to accept a firewall prompt
+ QTRY_VERIFY(neutralReadSpy.size() > 0); //note may need to accept a firewall prompt
- QNetworkDatagram dgram = neutral.receiveDatagram(testData.length() * 2);
+ QNetworkDatagram dgram = neutral.receiveDatagram(testData.size() * 2);
QVERIFY(dgram.isValid());
QCOMPARE(dgram.senderAddress(), s->localAddress());
QCOMPARE(dgram.senderPort(), int(s->localPort()));
QCOMPARE(dgram.destinationAddress(), s->localAddress());
QCOMPARE(dgram.destinationPort(), int(neutral.localPort()));
- QCOMPARE(dgram.data().length(), testData.length());
+ QCOMPARE(dgram.data().size(), testData.size());
QCOMPARE(dgram.data(), testData);
QVERIFY(neutral.writeDatagram(dgram.makeReply(testData)));
- QTRY_VERIFY(spy.count() > 0); //note may need to accept a firewall prompt
+ QTRY_VERIFY(spy.size() > 0); //note may need to accept a firewall prompt
- dgram = s->receiveDatagram(testData.length() * 2);
+ dgram = s->receiveDatagram(testData.size() * 2);
QCOMPARE(dgram.data(), testData);
//sockets bound to other interfaces shouldn't have received anything
- foreach (QUdpSocket *s2, sockets) {
+ for (QUdpSocket *s2 : std::as_const(sockets))
QCOMPARE((int)s2->bytesAvailable(), 0);
- }
//Sending to the same address with different scope should normally fail
//However it will pass if there is a route between two interfaces,
@@ -1710,7 +1685,8 @@ void tst_QUdpSocket::linkLocalIPv4()
QList <QHostAddress> addresses;
QHostAddress localMask("169.254.0.0");
- foreach (const QNetworkInterface& iface, QNetworkInterface::allInterfaces()) {
+ const auto ifaces = QNetworkInterface::allInterfaces();
+ for (const QNetworkInterface &iface : ifaces) {
//Windows preallocates link local addresses to interfaces that are down.
//These may or may not work depending on network driver (they do not work for the Bluetooth PAN driver)
if (iface.flags() & QNetworkInterface::IsUp) {
@@ -1724,7 +1700,8 @@ void tst_QUdpSocket::linkLocalIPv4()
if (iface.name().startsWith("utun"))
continue;
#endif
- foreach (QNetworkAddressEntry addr, iface.addressEntries()) {
+ const auto entries = iface.addressEntries();
+ for (const QNetworkAddressEntry &addr : entries) {
if (addr.ip().isInSubnet(localMask, 16)) {
addresses << addr.ip();
qDebug() << "Found IPv4 link local address" << addr.ip();
@@ -1737,7 +1714,7 @@ void tst_QUdpSocket::linkLocalIPv4()
QList <QUdpSocket*> sockets;
quint16 port = 0;
- foreach (const QHostAddress& addr, addresses) {
+ for (const QHostAddress &addr : std::as_const(addresses)) {
QUdpSocket *s = new QUdpSocket;
QVERIFY2(s->bind(addr, port), qPrintable(s->errorString()));
port = s->localPort(); //bind same port, different networks
@@ -1748,15 +1725,15 @@ void tst_QUdpSocket::linkLocalIPv4()
QVERIFY(neutral.bind(QHostAddress(QHostAddress::AnyIPv4)));
QByteArray testData("hello");
- foreach (QUdpSocket *s, sockets) {
+ for (QUdpSocket *s : std::as_const(sockets)) {
QVERIFY(s->writeDatagram(testData, s->localAddress(), neutral.localPort()));
QVERIFY2(neutral.waitForReadyRead(10000), QtNetworkSettings::msgSocketError(neutral).constData());
- QNetworkDatagram dgram = neutral.receiveDatagram(testData.length() * 2);
+ QNetworkDatagram dgram = neutral.receiveDatagram(testData.size() * 2);
QVERIFY(dgram.isValid());
QCOMPARE(dgram.senderAddress(), s->localAddress());
QCOMPARE(dgram.senderPort(), int(s->localPort()));
- QCOMPARE(dgram.data().length(), testData.length());
+ QCOMPARE(dgram.data().size(), testData.size());
QCOMPARE(dgram.data(), testData);
// Unlike for IPv6 with IPV6_PKTINFO, IPv4 has no standardized way of
@@ -1775,14 +1752,13 @@ void tst_QUdpSocket::linkLocalIPv4()
QVERIFY(neutral.writeDatagram(dgram.makeReply(testData)));
QVERIFY2(s->waitForReadyRead(10000), QtNetworkSettings::msgSocketError(*s).constData());
- dgram = s->receiveDatagram(testData.length() * 2);
+ dgram = s->receiveDatagram(testData.size() * 2);
QVERIFY(dgram.isValid());
QCOMPARE(dgram.data(), testData);
//sockets bound to other interfaces shouldn't have received anything
- foreach (QUdpSocket *s2, sockets) {
+ for (QUdpSocket *s2 : std::as_const(sockets))
QCOMPARE((int)s2->bytesAvailable(), 0);
- }
}
qDeleteAll(sockets);
}
@@ -1810,7 +1786,7 @@ void tst_QUdpSocket::readyRead()
QTest::qWait(100);
// make sure only one signal was emitted
- QCOMPARE(spy.count(), 1);
+ QCOMPARE(spy.size(), 1);
QVERIFY(receiver.hasPendingDatagrams());
#ifdef RELIABLE_BYTES_AVAILABLE
QCOMPARE(receiver.bytesAvailable(), qint64(2));
@@ -1822,7 +1798,7 @@ void tst_QUdpSocket::readyRead()
// no new signal should be emitted because we haven't read the first datagram yet
QTest::qWait(100);
- QCOMPARE(spy.count(), 1);
+ QCOMPARE(spy.size(), 1);
QVERIFY(receiver.hasPendingDatagrams());
QVERIFY(receiver.bytesAvailable() >= 1); // most likely is 1, but it could be 1 + 2 in the future
QCOMPARE(receiver.pendingDatagramSize(), qint64(2));
@@ -1834,7 +1810,7 @@ void tst_QUdpSocket::readyRead()
// write a new datagram and ensure the signal is emitted now
sender.writeDatagram("abc", makeNonAny(receiver.localAddress()), port);
QTest::qWait(100);
- QCOMPARE(spy.count(), 2);
+ QCOMPARE(spy.size(), 2);
QVERIFY(receiver.hasPendingDatagrams());
#ifdef RELIABLE_BYTES_AVAILABLE
QCOMPARE(receiver.bytesAvailable(), qint64(3));
@@ -1914,7 +1890,7 @@ void tst_QUdpSocket::asyncReadDatagram()
QTestEventLoop::instance().enterLoop(1);
QVERIFY(!QTestEventLoop::instance().timeout());
- QCOMPARE(spy.count(), 2);
+ QCOMPARE(spy.size(), 2);
delete m_asyncSender;
delete m_asyncReceiver;
@@ -1932,5 +1908,78 @@ void tst_QUdpSocket::writeInHostLookupState()
QVERIFY(!socket.putChar('0'));
}
+void tst_QUdpSocket::readyReadConnectionThrottling()
+{
+ QFETCH_GLOBAL(bool, setProxy);
+ if (setProxy)
+ return;
+ using namespace std::chrono_literals;
+
+ // QTBUG-105871:
+ // We have some signal/slot connection throttling in QAbstractSocket, but it
+ // was caring about the bytes, not about the datagrams.
+ // Test that we don't disable read notifications until we have at least one
+ // datagram available. Otherwise our good users who use the datagram APIs
+ // can get into scenarios where they no longer get the readyRead signal
+ // unless they call a read function once in a while.
+
+ QUdpSocket receiver;
+ QVERIFY(receiver.bind(QHostAddress(QHostAddress::LocalHost), 0));
+
+ QSemaphore semaphore;
+
+ // Repro-ing deterministically eludes me, so we are bruteforcing it:
+ // The thread acts as a remote sender, flooding the receiver with datagrams,
+ // and at some point the receiver would get into the broken state mentioned
+ // earlier.
+ std::unique_ptr<QThread> thread(QThread::create([&semaphore, port = receiver.localPort()]() {
+ QUdpSocket sender;
+ sender.connectToHost(QHostAddress(QHostAddress::LocalHost), port);
+ QCOMPARE(sender.state(), QUdpSocket::ConnectedState);
+
+ constexpr qsizetype PayloadSize = 242;
+ const QByteArray payload(PayloadSize, 'a');
+
+ semaphore.acquire(); // Wait for main thread to be ready
+ while (true) {
+ // We send 100 datagrams at a time, then sleep.
+ // This is mostly to let the main thread catch up between bursts so
+ // it doesn't get stuck in the loop.
+ for (int i = 0; i < 100; ++i) {
+ [[maybe_unused]]
+ qsizetype sent = sender.write(payload);
+ Q_ASSERT(sent > 0);
+ }
+ if (QThread::currentThread()->isInterruptionRequested())
+ break;
+ QThread::sleep(20ms);
+ }
+ }));
+ thread->start();
+ auto threadStopAndWaitGuard = qScopeGuard([&thread] {
+ thread->requestInterruption();
+ thread->quit();
+ thread->wait();
+ });
+
+ qsizetype count = 0;
+ QObject::connect(&receiver, &QUdpSocket::readyRead, &receiver,
+ [&] {
+ while (receiver.hasPendingDatagrams()) {
+ receiver.readDatagram(nullptr, 0);
+ ++count;
+ }
+ // If this prints `false, xxxx` we were pretty much guaranteed
+ // that we would not get called again:
+ // qDebug() << receiver.hasPendingDatagrams() << receiver.bytesAvailable();
+ },
+ Qt::QueuedConnection);
+
+ semaphore.release();
+ constexpr qsizetype MaxCount = 500;
+ QVERIFY2(QTest::qWaitFor([&] { return count >= MaxCount; }, 10s),
+ QByteArray::number(count).constData());
+}
+
QTEST_MAIN(tst_QUdpSocket)
#include "tst_qudpsocket.moc"