1/****************************************************************************
2**
3** Copyright (C) 2016 The Qt Company Ltd.
4** Copyright (C) 2017 Intel Corporation.
5** Contact: https://www.qt.io/licensing/
6**
7** This file is part of the test suite of the Qt Toolkit.
8**
9** $QT_BEGIN_LICENSE:GPL-EXCEPT$
10** Commercial License Usage
11** Licensees holding valid commercial Qt licenses may use this file in
12** accordance with the commercial license agreement provided with the
13** Software or, alternatively, in accordance with the terms contained in
14** a written agreement between you and The Qt Company. For licensing terms
15** and conditions see https://www.qt.io/terms-conditions. For further
16** information use the contact form at https://www.qt.io/contact-us.
17**
18** GNU General Public License Usage
19** Alternatively, this file may be used under the terms of the GNU
20** General Public License version 3 as published by the Free Software
21** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
22** included in the packaging of this file. Please review the following
23** information to ensure the GNU General Public License requirements will
24** be met: https://www.gnu.org/licenses/gpl-3.0.html.
25**
26** $QT_END_LICENSE$
27**
28****************************************************************************/
29
30
31#include <QtTest/QtTest>
32
33#include <qcoreapplication.h>
34#include <qfileinfo.h>
35#include <qdatastream.h>
36#include <qdebug.h>
37#include <qrandom.h>
38#include <qudpsocket.h>
39#include <qhostaddress.h>
40#include <qhostinfo.h>
41#include <qtcpsocket.h>
42#include <qmap.h>
43#include <qelapsedtimer.h>
44#include <qnetworkdatagram.h>
45#include <QNetworkProxy>
46#include <QNetworkInterface>
47
48#include <qstringlist.h>
49#include "../../../network-settings.h"
50#include "emulationdetector.h"
51
52#if defined(Q_OS_LINUX)
53#define SHOULD_CHECK_SYSCALL_SUPPORT
54#include <netinet/in.h>
55#include <sys/socket.h>
56#include <errno.h>
57#endif
58
59#ifdef Q_OS_UNIX
60# include <sys/socket.h>
61#endif
62#if defined(Q_OS_LINUX) || defined(Q_OS_WIN) || defined(SO_NREAD)
63# define RELIABLE_BYTES_AVAILABLE
64#endif
65
66Q_DECLARE_METATYPE(QHostAddress)
67
68QT_FORWARD_DECLARE_CLASS(QUdpSocket)
69
70class tst_QUdpSocket : public QObject
71{
72 Q_OBJECT
73
74private slots:
75 void initTestCase_data();
76 void initTestCase();
77 void init();
78 void cleanup();
79 void constructing();
80 void unconnectedServerAndClientTest();
81 void broadcasting();
82 void loop_data();
83 void loop();
84 void ipv6Loop_data();
85 void ipv6Loop();
86 void dualStack();
87 void dualStackAutoBinding();
88 void dualStackNoIPv4onV6only();
89 void connectToHost();
90 void bindAndConnectToHost();
91 void pendingDatagramSize();
92 void writeDatagram();
93 void performance();
94 void bindMode();
95 void writeDatagramToNonExistingPeer_data();
96 void writeDatagramToNonExistingPeer();
97 void writeToNonExistingPeer_data();
98 void writeToNonExistingPeer();
99 void outOfProcessConnectedClientServerTest();
100 void outOfProcessUnconnectedClientServerTest();
101 void zeroLengthDatagram();
102 void multicastTtlOption_data();
103 void multicastTtlOption();
104 void multicastLoopbackOption_data();
105 void multicastLoopbackOption();
106 void multicastJoinBeforeBind_data();
107 void multicastJoinBeforeBind();
108 void multicastLeaveAfterClose_data();
109 void multicastLeaveAfterClose();
110 void setMulticastInterface_data();
111 void setMulticastInterface();
112 void multicast_data();
113 void multicast();
114 void echo_data();
115 void echo();
116 void linkLocalIPv6();
117 void linkLocalIPv4();
118 void readyRead();
119 void readyReadForEmptyDatagram();
120 void asyncReadDatagram();
121 void writeInHostLookupState();
122
123protected slots:
124 void empty_readyReadSlot();
125 void empty_connectedSlot();
126 void async_readDatagramSlot();
127
128private:
129 bool shouldSkipIpv6TestsForBrokenSetsockopt();
130 bool shouldWorkaroundLinuxKernelBug();
131#ifdef SHOULD_CHECK_SYSCALL_SUPPORT
132 bool ipv6SetsockoptionMissing(int level, int optname);
133#endif
134 QNetworkInterface interfaceForGroup(const QHostAddress &multicastGroup);
135
136 bool m_skipUnsupportedIPv6Tests;
137 bool m_workaroundLinuxKernelBug;
138 QList<QHostAddress> allAddresses;
139 QHostAddress multicastGroup4, multicastGroup6;
140 QVector<QHostAddress> linklocalMulticastGroups;
141 QUdpSocket *m_asyncSender;
142 QUdpSocket *m_asyncReceiver;
143};
144
145#ifdef SHOULD_CHECK_SYSCALL_SUPPORT
146bool tst_QUdpSocket::ipv6SetsockoptionMissing(int level, int optname)
147{
148 int testSocket;
149
150 testSocket = socket(PF_INET6, SOCK_DGRAM, protocol: 0);
151
152 // If we can't test here, assume it's not missing
153 if (testSocket == -1)
154 return false;
155
156 bool result = false;
157 if (setsockopt(fd: testSocket, level: level, optname: optname, optval: nullptr, optlen: 0) == -1)
158 if (errno == ENOPROTOOPT)
159 result = true;
160
161 close(fd: testSocket);
162 return result;
163}
164#endif //SHOULD_CHECK_SYSCALL_SUPPORT
165
166bool tst_QUdpSocket::shouldSkipIpv6TestsForBrokenSetsockopt()
167{
168#ifdef SHOULD_CHECK_SYSCALL_SUPPORT
169 // Following parameters for setsockopt are not supported by all QEMU versions:
170 if (ipv6SetsockoptionMissing(SOL_IPV6, IPV6_JOIN_GROUP)
171 || ipv6SetsockoptionMissing(SOL_IPV6, IPV6_MULTICAST_HOPS)
172 || ipv6SetsockoptionMissing(SOL_IPV6, IPV6_MULTICAST_IF)
173 || ipv6SetsockoptionMissing(SOL_IPV6, IPV6_MULTICAST_LOOP)
174 || ipv6SetsockoptionMissing(SOL_IPV6, IPV6_RECVHOPLIMIT)) {
175 return true;
176 }
177#endif //SHOULD_CHECK_SYSCALL_SUPPORT
178
179 return false;
180}
181
182QNetworkInterface tst_QUdpSocket::interfaceForGroup(const QHostAddress &multicastGroup)
183{
184 if (multicastGroup.protocol() == QAbstractSocket::IPv4Protocol)
185 return QNetworkInterface();
186
187 QString scope = multicastGroup.scopeId();
188 if (!scope.isEmpty())
189 return QNetworkInterface::interfaceFromName(name: scope);
190
191 static QNetworkInterface ipv6if = [=]() {
192 // find any link local address in the allAddress list
193 for (const QHostAddress &addr: qAsConst(t&: allAddresses)) {
194 if (addr.isLoopback())
195 continue;
196
197 QString scope = addr.scopeId();
198 if (!scope.isEmpty()) {
199 QNetworkInterface iface = QNetworkInterface::interfaceFromName(name: scope);
200 qDebug() << "Will bind IPv6 sockets to" << iface;
201 return iface;
202 }
203 }
204
205 qWarning(msg: "interfaceForGroup(%s) could not find any link-local IPv6 address! "
206 "Make sure this test is behind a check of QtNetworkSettings::hasIPv6().",
207 qUtf8Printable(multicastGroup.toString()));
208 return QNetworkInterface();
209 }();
210 return ipv6if;
211}
212
213bool tst_QUdpSocket::shouldWorkaroundLinuxKernelBug()
214{
215#ifdef Q_OS_LINUX
216 const QVersionNumber version = QVersionNumber::fromString(string: QSysInfo::kernelVersion());
217 return version.majorVersion() == 4 && version.minorVersion() >= 6 && version.minorVersion() < 13;
218#else
219 return false;
220#endif
221}
222
223static QHostAddress makeNonAny(const QHostAddress &address, QHostAddress::SpecialAddress preferForAny = QHostAddress::LocalHost)
224{
225 if (address == QHostAddress::Any)
226 return preferForAny;
227 if (address == QHostAddress::AnyIPv4)
228 return QHostAddress::LocalHost;
229 if (address == QHostAddress::AnyIPv6)
230 return QHostAddress::LocalHostIPv6;
231 return address;
232}
233
234void tst_QUdpSocket::initTestCase_data()
235{
236 // hack: we only enable the Socks5 over UDP tests on the old
237 // test server, because they fail on the new one. See QTBUG-35490
238 bool newTestServer = true;
239#ifndef QT_TEST_SERVER
240 QTcpSocket socket;
241 socket.connectToHost(hostName: QtNetworkSettings::serverName(), port: 22);
242 if (socket.waitForConnected(msecs: 10000)) {
243 socket.waitForReadyRead(msecs: 5000);
244 QByteArray ba = socket.readAll();
245 if (ba.startsWith(c: "SSH-2.0-OpenSSH_5.8p1"))
246 newTestServer = false;
247 socket.disconnectFromHost();
248 }
249#endif
250
251 QTest::addColumn<bool>(name: "setProxy");
252 QTest::addColumn<int>(name: "proxyType");
253
254 QTest::newRow(dataTag: "WithoutProxy") << false << 0;
255#if QT_CONFIG(socks5)
256 if (!newTestServer)
257 QTest::newRow(dataTag: "WithSocks5Proxy") << true << int(QNetworkProxy::Socks5Proxy);
258#endif
259}
260
261void tst_QUdpSocket::initTestCase()
262{
263#ifdef QT_TEST_SERVER
264 QVERIFY(QtNetworkSettings::verifyConnection(QtNetworkSettings::socksProxyServerName(), 1080));
265 QVERIFY(QtNetworkSettings::verifyConnection(QtNetworkSettings::echoServerName(), 7));
266#else
267 if (!QtNetworkSettings::verifyTestNetworkSettings())
268 QSKIP("No network test server available");
269#endif
270 allAddresses = QNetworkInterface::allAddresses();
271 m_skipUnsupportedIPv6Tests = shouldSkipIpv6TestsForBrokenSetsockopt();
272
273 // Create a pair of random multicast groups so we avoid clashing with any
274 // other tst_qudpsocket running on the same network at the same time.
275 quint64 r[2] = {
276 // ff14:: is temporary, not prefix-based, admin-local
277 qToBigEndian(Q_UINT64_C(0xff14) << 48),
278 QRandomGenerator64::global()->generate64()
279 };
280 multicastGroup6.setAddress(*reinterpret_cast<Q_IPV6ADDR *>(&r));
281
282 // 239.0.0.0/8 is "Organization-Local Scope"
283 multicastGroup4.setAddress((239U << 24) | (r[1] & 0xffffff));
284
285 // figure out some link-local IPv6 multicast groups
286 // ff12:: is temporary, not prefix-based, link-local
287 r[0] = qToBigEndian(Q_UINT64_C(0xff12) << 48);
288 QHostAddress llbase(*reinterpret_cast<Q_IPV6ADDR *>(&r));
289 for (const QHostAddress &a : qAsConst(t&: allAddresses)) {
290 QString scope = a.scopeId();
291 if (scope.isEmpty())
292 continue;
293 llbase.setScopeId(scope);
294 linklocalMulticastGroups << llbase;
295 }
296
297 qDebug() << "Will use multicast groups" << multicastGroup4 << multicastGroup6 << linklocalMulticastGroups;
298
299 m_workaroundLinuxKernelBug = shouldWorkaroundLinuxKernelBug();
300 if (EmulationDetector::isRunningArmOnX86())
301 QSKIP("This test is unreliable due to QEMU emulation shortcomings.");
302}
303
304void tst_QUdpSocket::init()
305{
306 QFETCH_GLOBAL(bool, setProxy);
307 if (setProxy) {
308#if QT_CONFIG(socks5)
309 QFETCH_GLOBAL(int, proxyType);
310 if (proxyType == QNetworkProxy::Socks5Proxy) {
311 QNetworkProxy::setApplicationProxy(QNetworkProxy(QNetworkProxy::Socks5Proxy, QtNetworkSettings::socksProxyServerName(), 1080));
312 }
313#else
314 QSKIP("No proxy support");
315#endif // QT_CONFIG(socks5)
316 }
317}
318
319void tst_QUdpSocket::cleanup()
320{
321#ifndef QT_NO_NETWORKPROXY
322 QNetworkProxy::setApplicationProxy(QNetworkProxy::DefaultProxy);
323#endif // !QT_NO_NETWORKPROXY
324}
325
326
327//----------------------------------------------------------------------------------
328
329void tst_QUdpSocket::constructing()
330{
331 QUdpSocket socket;
332
333 QVERIFY(socket.isSequential());
334 QVERIFY(!socket.isOpen());
335 QCOMPARE(socket.socketType(), QUdpSocket::UdpSocket);
336 QCOMPARE((int) socket.bytesAvailable(), 0);
337 QCOMPARE(socket.canReadLine(), false);
338 QCOMPARE(socket.readLine(), QByteArray());
339 QCOMPARE(socket.socketDescriptor(), (qintptr)-1);
340 QCOMPARE(socket.error(), QUdpSocket::UnknownSocketError);
341 QCOMPARE(socket.errorString(), QString("Unknown error"));
342
343 // Check the state of the socket api
344}
345
346void tst_QUdpSocket::unconnectedServerAndClientTest()
347{
348 QUdpSocket serverSocket;
349
350 qRegisterMetaType<QAbstractSocket::SocketState>(typeName: "QAbstractSocket::SocketState");
351
352 QSignalSpy stateChangedSpy(&serverSocket, SIGNAL(stateChanged(QAbstractSocket::SocketState)));
353 QVERIFY2(serverSocket.bind(), serverSocket.errorString().toLatin1().constData());
354 QCOMPARE(stateChangedSpy.count(), 1);
355
356 const char *message[] = {"Yo mista", "Yo", "Wassap"};
357
358 QHostAddress serverAddress = makeNonAny(address: serverSocket.localAddress());
359 for (int i = 0; i < 3; ++i) {
360 QUdpSocket clientSocket;
361 QCOMPARE(int(clientSocket.writeDatagram(message[i], strlen(message[i]),
362 serverAddress, serverSocket.localPort())),
363 int(strlen(message[i])));
364 char buf[1024];
365 QHostAddress host;
366 quint16 port;
367 QVERIFY2(serverSocket.waitForReadyRead(5000), QtNetworkSettings::msgSocketError(serverSocket).constData());
368 QCOMPARE(int(serverSocket.readDatagram(buf, sizeof(buf), &host, &port)),
369 int(strlen(message[i])));
370 buf[strlen(s: message[i])] = '\0';
371 QCOMPARE(QByteArray(buf), QByteArray(message[i]));
372 QCOMPARE(port, clientSocket.localPort());
373 if (host.toIPv4Address()) // in case the sender is IPv4 mapped in IPv6
374 QCOMPARE(host.toIPv4Address(), makeNonAny(clientSocket.localAddress()).toIPv4Address());
375 else
376 QCOMPARE(host, makeNonAny(clientSocket.localAddress()));
377 }
378}
379
380//----------------------------------------------------------------------------------
381
382void tst_QUdpSocket::broadcasting()
383{
384 if (m_workaroundLinuxKernelBug)
385 QSKIP("This test can fail due to linux kernel bug");
386
387 QFETCH_GLOBAL(bool, setProxy);
388 if (setProxy) {
389#ifndef QT_NO_NETWORKPROXY
390 QFETCH_GLOBAL(int, proxyType);
391 if (proxyType == QNetworkProxy::Socks5Proxy)
392 QSKIP("With socks5 Broadcast is not supported.");
393#else // !QT_NO_NETWORKPROXY
394 QSKIP("No proxy support");
395#endif // QT_NO_NETWORKPROXY
396 }
397#ifdef Q_OS_AIX
398 QSKIP("Broadcast does not work on darko");
399#endif
400 const char *message[] = {"Yo mista", "", "Yo", "Wassap"};
401
402 QList<QHostAddress> broadcastAddresses;
403 foreach (QNetworkInterface iface, QNetworkInterface::allInterfaces()) {
404 if ((iface.flags() & QNetworkInterface::CanBroadcast)
405 && iface.flags() & QNetworkInterface::IsUp) {
406 for (int i=0;i<iface.addressEntries().count();i++) {
407 QHostAddress broadcast = iface.addressEntries().at(i).broadcast();
408 if (broadcast.protocol() == QAbstractSocket::IPv4Protocol)
409 broadcastAddresses.append(t: broadcast);
410 }
411 }
412 }
413 if (broadcastAddresses.isEmpty())
414 QSKIP("No interface can broadcast");
415 for (int i = 0; i < 4; ++i) {
416 QUdpSocket serverSocket;
417 QVERIFY2(serverSocket.bind(QHostAddress(QHostAddress::AnyIPv4), 0), serverSocket.errorString().toLatin1().constData());
418 quint16 serverPort = serverSocket.localPort();
419
420 QCOMPARE(serverSocket.state(), QUdpSocket::BoundState);
421
422 connect(asender: &serverSocket, SIGNAL(readyRead()), SLOT(empty_readyReadSlot()));
423
424 QUdpSocket broadcastSocket;
425 broadcastSocket.bind(address: QHostAddress(QHostAddress::AnyIPv4), port: 0);
426
427 for (int j = 0; j < 10; ++j) {
428 for (int k = 0; k < 4; k++) {
429 broadcastSocket.writeDatagram(data: message[i], len: strlen(s: message[i]),
430 host: QHostAddress::Broadcast, port: serverPort);
431 foreach (QHostAddress addr, broadcastAddresses)
432 broadcastSocket.writeDatagram(data: message[i], len: strlen(s: message[i]), host: addr, port: serverPort);
433 }
434 QTestEventLoop::instance().enterLoop(secs: 15);
435 if (QTestEventLoop::instance().timeout()) {
436#if defined(Q_OS_FREEBSD)
437 QEXPECT_FAIL("",
438 "Broadcasting to 255.255.255.255 does not work on FreeBSD",
439 Abort);
440 QVERIFY(false); // seems that QFAIL() doesn't respect the QEXPECT_FAIL() :/
441#endif
442 QFAIL("Network operation timed out");
443 }
444 QVERIFY(serverSocket.hasPendingDatagrams());
445
446 do {
447 const int messageLength = int(strlen(s: message[i]));
448 QNetworkDatagram dgram = serverSocket.receiveDatagram();
449 QVERIFY(dgram.isValid());
450 QByteArray arr = dgram.data();
451
452 QCOMPARE(arr.length(), messageLength);
453 arr.resize(size: messageLength);
454 QCOMPARE(arr, QByteArray(message[i]));
455
456 if (dgram.senderAddress().toIPv4Address()) // in case it's a v6-mapped address
457 QVERIFY2(allAddresses.contains(QHostAddress(dgram.senderAddress().toIPv4Address())),
458 dgram.senderAddress().toString().toLatin1());
459 else if (!dgram.senderAddress().isNull())
460 QVERIFY2(allAddresses.contains(dgram.senderAddress()),
461 dgram.senderAddress().toString().toLatin1());
462 QCOMPARE(dgram.senderPort(), int(broadcastSocket.localPort()));
463 if (!dgram.destinationAddress().isNull()) {
464 QVERIFY2(dgram.destinationAddress() == QHostAddress::Broadcast
465 || broadcastAddresses.contains(dgram.destinationAddress()),
466 dgram.destinationAddress().toString().toLatin1());
467 QCOMPARE(dgram.destinationPort(), int(serverSocket.localPort()));
468 }
469
470 int ttl = dgram.hopLimit();
471 if (ttl != -1)
472 QVERIFY(ttl != 0);
473 } while (serverSocket.hasPendingDatagrams());
474 }
475 }
476}
477
478//----------------------------------------------------------------------------------
479
480void tst_QUdpSocket::loop_data()
481{
482 QTest::addColumn<QByteArray>(name: "peterMessage");
483 QTest::addColumn<QByteArray>(name: "paulMessage");
484 QTest::addColumn<bool>(name: "success");
485
486 QTest::newRow(dataTag: "\"Almond!\" | \"Joy!\"") << QByteArray("Almond!") << QByteArray("Joy!") << true;
487 QTest::newRow(dataTag: "\"A\" | \"B\"") << QByteArray("A") << QByteArray("B") << true;
488 QTest::newRow(dataTag: "\"AB\" | \"B\"") << QByteArray("AB") << QByteArray("B") << true;
489 QTest::newRow(dataTag: "\"AB\" | \"BB\"") << QByteArray("AB") << QByteArray("BB") << true;
490 QTest::newRow(dataTag: "\"A\\0B\" | \"B\\0B\"") << QByteArray::fromRawData("A\0B", size: 3) << QByteArray::fromRawData("B\0B", size: 3) << true;
491 QTest::newRow(dataTag: "\"(nil)\" | \"(nil)\"") << QByteArray() << QByteArray() << true;
492 QTest::newRow(dataTag: "Bigmessage") << QByteArray(600, '@') << QByteArray(600, '@') << true;
493}
494
495void tst_QUdpSocket::loop()
496{
497 QFETCH(QByteArray, peterMessage);
498 QFETCH(QByteArray, paulMessage);
499 QFETCH(bool, success);
500
501 QUdpSocket peter;
502 QUdpSocket paul;
503
504 // make sure we bind to IPv4
505 QHostAddress localhost = QHostAddress::LocalHost;
506 QVERIFY2(peter.bind(localhost), peter.errorString().toLatin1().constData());
507 QVERIFY2(paul.bind(localhost), paul.errorString().toLatin1().constData());
508
509 QHostAddress peterAddress = makeNonAny(address: peter.localAddress());
510 QHostAddress paulAddress = makeNonAny(address: paul.localAddress());
511
512 QCOMPARE(peter.writeDatagram(peterMessage.data(), peterMessage.length(),
513 paulAddress, paul.localPort()), qint64(peterMessage.length()));
514 QCOMPARE(paul.writeDatagram(paulMessage.data(), paulMessage.length(),
515 peterAddress, peter.localPort()), qint64(paulMessage.length()));
516
517 QVERIFY2(peter.waitForReadyRead(9000), QtNetworkSettings::msgSocketError(peter).constData());
518 QVERIFY2(paul.waitForReadyRead(9000), QtNetworkSettings::msgSocketError(paul).constData());
519
520 QNetworkDatagram peterDatagram = peter.receiveDatagram(maxSize: paulMessage.length() * 2);
521 QNetworkDatagram paulDatagram = paul.receiveDatagram(maxSize: peterMessage.length() * 2);
522 if (success) {
523 QCOMPARE(peterDatagram.data().length(), qint64(paulMessage.length()));
524 QCOMPARE(paulDatagram.data().length(), qint64(peterMessage.length()));
525 } else {
526 // this code path seems to never be executed
527 QVERIFY(peterDatagram.data().length() != paulMessage.length());
528 QVERIFY(paulDatagram.data().length() != peterMessage.length());
529 }
530
531 QCOMPARE(peterDatagram.data().left(paulMessage.length()), paulMessage);
532 QCOMPARE(paulDatagram.data().left(peterMessage.length()), peterMessage);
533
534 QCOMPARE(peterDatagram.senderAddress(), paulAddress);
535 QCOMPARE(paulDatagram.senderAddress(), peterAddress);
536 QCOMPARE(paulDatagram.senderPort(), int(peter.localPort()));
537 QCOMPARE(peterDatagram.senderPort(), int(paul.localPort()));
538
539 // Unlike for IPv6 with IPV6_PKTINFO, IPv4 has no standardized way of
540 // obtaining the packet's destination addresses. The destinationAddress and
541 // destinationPort calls could fail, so whitelist the OSes for which we
542 // know we have an implementation.
543#if defined(Q_OS_LINUX) || defined(Q_OS_BSD4) || defined(Q_OS_WIN)
544 QVERIFY(peterDatagram.destinationPort() != -1);
545 QVERIFY(paulDatagram.destinationPort() != -1);
546#endif
547 if (peterDatagram.destinationPort() == -1) {
548 QCOMPARE(peterDatagram.destinationAddress().protocol(), QAbstractSocket::UnknownNetworkLayerProtocol);
549 QCOMPARE(paulDatagram.destinationAddress().protocol(), QAbstractSocket::UnknownNetworkLayerProtocol);
550 } else {
551 QCOMPARE(peterDatagram.destinationAddress(), makeNonAny(peter.localAddress()));
552 QCOMPARE(paulDatagram.destinationAddress(), makeNonAny(paul.localAddress()));
553 QVERIFY(peterDatagram.destinationAddress().isEqual(makeNonAny(peter.localAddress())));
554 QVERIFY(paulDatagram.destinationAddress().isEqual(makeNonAny(paul.localAddress())));
555 }
556}
557
558//----------------------------------------------------------------------------------
559
560void tst_QUdpSocket::ipv6Loop_data()
561{
562 loop_data();
563}
564
565void tst_QUdpSocket::ipv6Loop()
566{
567 QFETCH(QByteArray, peterMessage);
568 QFETCH(QByteArray, paulMessage);
569 QFETCH(bool, success);
570
571 QUdpSocket peter;
572 QUdpSocket paul;
573
574 int peterPort;
575 int paulPort;
576
577 if (!peter.bind(address: QHostAddress(QHostAddress::LocalHostIPv6), port: 0)) {
578 QCOMPARE(peter.error(), QUdpSocket::UnsupportedSocketOperationError);
579 return;
580 }
581
582 QVERIFY(paul.bind(QHostAddress(QHostAddress::LocalHostIPv6), 0));
583
584 QHostAddress peterAddress = makeNonAny(address: peter.localAddress());
585 QHostAddress paulAddress = makeNonAny(address: paul.localAddress());
586 peterPort = peter.localPort();
587 paulPort = paul.localPort();
588
589 QCOMPARE(peter.writeDatagram(peterMessage.data(), peterMessage.length(), QHostAddress("::1"),
590 paulPort), qint64(peterMessage.length()));
591 QCOMPARE(paul.writeDatagram(paulMessage.data(), paulMessage.length(),
592 QHostAddress("::1"), peterPort), qint64(paulMessage.length()));
593
594 QVERIFY(peter.waitForReadyRead(5000));
595 QVERIFY(paul.waitForReadyRead(5000));
596 QNetworkDatagram peterDatagram = peter.receiveDatagram(maxSize: paulMessage.length() * 2);
597 QNetworkDatagram paulDatagram = paul.receiveDatagram(maxSize: peterMessage.length() * 2);
598
599 if (success) {
600 QCOMPARE(peterDatagram.data().length(), qint64(paulMessage.length()));
601 QCOMPARE(paulDatagram.data().length(), qint64(peterMessage.length()));
602 } else {
603 // this code path seems to never be executed
604 QVERIFY(peterDatagram.data().length() != paulMessage.length());
605 QVERIFY(paulDatagram.data().length() != peterMessage.length());
606 }
607
608 QCOMPARE(peterDatagram.data().left(paulMessage.length()), paulMessage);
609 QCOMPARE(paulDatagram.data().left(peterMessage.length()), peterMessage);
610
611 QCOMPARE(peterDatagram.senderAddress(), paulAddress);
612 QCOMPARE(paulDatagram.senderAddress(), peterAddress);
613 QCOMPARE(paulDatagram.senderPort(), peterPort);
614 QCOMPARE(peterDatagram.senderPort(), paulPort);
615
616 // For IPv6, IPV6_PKTINFO is a mandatory feature (RFC 3542).
617 QCOMPARE(peterDatagram.destinationAddress(), makeNonAny(peter.localAddress()));
618 QCOMPARE(paulDatagram.destinationAddress(), makeNonAny(paul.localAddress()));
619 QCOMPARE(peterDatagram.destinationPort(), peterPort);
620 QCOMPARE(paulDatagram.destinationPort(), paulPort);
621}
622
623void tst_QUdpSocket::dualStack()
624{
625 QFETCH_GLOBAL(bool, setProxy);
626 if (setProxy)
627 QSKIP("test server SOCKS proxy doesn't support IPv6");
628 QUdpSocket dualSock;
629 QByteArray dualData("dual");
630 QVERIFY(dualSock.bind(QHostAddress(QHostAddress::Any), 0));
631
632 QUdpSocket v4Sock;
633 QByteArray v4Data("v4");
634 QVERIFY(v4Sock.bind(QHostAddress(QHostAddress::AnyIPv4), 0));
635
636 //test v4 -> dual
637 QCOMPARE((int)v4Sock.writeDatagram(v4Data.constData(), v4Data.length(), QHostAddress(QHostAddress::LocalHost), dualSock.localPort()), v4Data.length());
638 QVERIFY2(dualSock.waitForReadyRead(5000), QtNetworkSettings::msgSocketError(dualSock).constData());
639 QNetworkDatagram dgram = dualSock.receiveDatagram(maxSize: 100);
640 QVERIFY(dgram.isValid());
641 QCOMPARE(dgram.data(), v4Data);
642 QCOMPARE(dgram.senderPort(), int(v4Sock.localPort()));
643 // receiving v4 on dual stack will receive as IPv6, so use isEqual()
644 QVERIFY(dgram.senderAddress().isEqual(makeNonAny(v4Sock.localAddress(), QHostAddress::Null)));
645 if (dualSock.localAddress().protocol() == QAbstractSocket::IPv4Protocol)
646 QCOMPARE(dgram.senderAddress(), makeNonAny(v4Sock.localAddress(), QHostAddress::Null));
647 if (dgram.destinationPort() != -1) {
648 QCOMPARE(dgram.destinationPort(), int(dualSock.localPort()));
649 QVERIFY(dgram.destinationAddress().isEqual(dualSock.localAddress()));
650 } else {
651 qInfo(msg: "Getting IPv4 destination address failed.");
652 }
653
654 if (QtNetworkSettings::hasIPv6()) {
655 QUdpSocket v6Sock;
656 QByteArray v6Data("v6");
657 QVERIFY(v6Sock.bind(QHostAddress(QHostAddress::AnyIPv6), 0));
658
659 //test v6 -> dual
660 QCOMPARE((int)v6Sock.writeDatagram(v6Data.constData(), v6Data.length(), QHostAddress(QHostAddress::LocalHostIPv6), dualSock.localPort()), v6Data.length());
661 QVERIFY2(dualSock.waitForReadyRead(5000), QtNetworkSettings::msgSocketError(dualSock).constData());
662 dgram = dualSock.receiveDatagram(maxSize: 100);
663 QVERIFY(dgram.isValid());
664 QCOMPARE(dgram.data(), v6Data);
665 QCOMPARE(dgram.senderPort(), int(v6Sock.localPort()));
666 QCOMPARE(dgram.senderAddress(), makeNonAny(v6Sock.localAddress(), QHostAddress::LocalHostIPv6));
667 QCOMPARE(dgram.destinationPort(), int(dualSock.localPort()));
668 QCOMPARE(dgram.destinationAddress(), makeNonAny(dualSock.localAddress(), QHostAddress::LocalHostIPv6));
669
670 //test dual -> v6
671 QCOMPARE((int)dualSock.writeDatagram(dualData.constData(), dualData.length(), QHostAddress(QHostAddress::LocalHostIPv6), v6Sock.localPort()), dualData.length());
672 QVERIFY2(v6Sock.waitForReadyRead(5000), QtNetworkSettings::msgSocketError(v6Sock).constData());
673 dgram = v6Sock.receiveDatagram(maxSize: 100);
674 QVERIFY(dgram.isValid());
675 QCOMPARE(dgram.data(), dualData);
676 QCOMPARE(dgram.senderPort(), int(dualSock.localPort()));
677 QCOMPARE(dgram.senderAddress(), makeNonAny(dualSock.localAddress(), QHostAddress::LocalHostIPv6));
678 QCOMPARE(dgram.destinationPort(), int(v6Sock.localPort()));
679 QCOMPARE(dgram.destinationAddress(), makeNonAny(v6Sock.localAddress(), QHostAddress::LocalHostIPv6));
680 }
681
682 //test dual -> v4
683 QCOMPARE((int)dualSock.writeDatagram(dualData.constData(), dualData.length(), QHostAddress(QHostAddress::LocalHost), v4Sock.localPort()), dualData.length());
684 QVERIFY2(v4Sock.waitForReadyRead(5000), QtNetworkSettings::msgSocketError(v4Sock).constData());
685 dgram = v4Sock.receiveDatagram(maxSize: 100);
686 QVERIFY(dgram.isValid());
687 QCOMPARE(dgram.data(), dualData);
688 QCOMPARE(dgram.senderPort(), int(dualSock.localPort()));
689 QCOMPARE(dgram.senderAddress(), makeNonAny(dualSock.localAddress(), QHostAddress::LocalHost));
690#if defined(Q_OS_LINUX) || defined(Q_OS_BSD4) || defined(Q_OS_WIN)
691 QVERIFY(dgram.destinationPort() != -1);
692#endif
693 if (dgram.destinationPort() != -1) {
694 QCOMPARE(dgram.destinationPort(), int(v4Sock.localPort()));
695 QCOMPARE(dgram.destinationAddress(), makeNonAny(v4Sock.localAddress(), QHostAddress::LocalHost));
696 }
697}
698
699void tst_QUdpSocket::dualStackAutoBinding()
700{
701 QFETCH_GLOBAL(bool, setProxy);
702 if (setProxy)
703 QSKIP("test server SOCKS proxy doesn't support IPv6");
704 if (!QtNetworkSettings::hasIPv6())
705 QSKIP("system doesn't support ipv6!");
706 QUdpSocket v4Sock;
707 QVERIFY(v4Sock.bind(QHostAddress(QHostAddress::AnyIPv4), 0));
708
709 QUdpSocket v6Sock;
710 QVERIFY(v6Sock.bind(QHostAddress(QHostAddress::AnyIPv6), 0));
711
712 QByteArray dualData("dual");
713 QHostAddress from;
714 quint16 port;
715 QByteArray buffer;
716 int size;
717
718 {
719 //test an autobound socket can send to both v4 and v6 addresses (v4 first)
720 QUdpSocket dualSock;
721
722 QCOMPARE((int)dualSock.writeDatagram(dualData.constData(), dualData.length(), QHostAddress(QHostAddress::LocalHost), v4Sock.localPort()), dualData.length());
723 QVERIFY2(v4Sock.waitForReadyRead(5000), QtNetworkSettings::msgSocketError(v4Sock).constData());
724 buffer.reserve(asize: 100);
725 size = v4Sock.readDatagram(data: buffer.data(), maxlen: 100, host: &from, port: &port);
726 QCOMPARE((int)size, dualData.length());
727 buffer.resize(size);
728 QCOMPARE(buffer, dualData);
729
730 QCOMPARE((int)dualSock.writeDatagram(dualData.constData(), dualData.length(), QHostAddress(QHostAddress::LocalHostIPv6), v6Sock.localPort()), dualData.length());
731 QVERIFY2(v6Sock.waitForReadyRead(5000), QtNetworkSettings::msgSocketError(v6Sock).constData());
732 buffer.reserve(asize: 100);
733 size = v6Sock.readDatagram(data: buffer.data(), maxlen: 100, host: &from, port: &port);
734 QCOMPARE((int)size, dualData.length());
735 buffer.resize(size);
736 QCOMPARE(buffer, dualData);
737 }
738
739 {
740 //test an autobound socket can send to both v4 and v6 addresses (v6 first)
741 QUdpSocket dualSock;
742
743 QCOMPARE((int)dualSock.writeDatagram(dualData.constData(), dualData.length(), QHostAddress(QHostAddress::LocalHostIPv6), v6Sock.localPort()), dualData.length());
744 QVERIFY2(v6Sock.waitForReadyRead(5000), QtNetworkSettings::msgSocketError(v6Sock).constData());
745 buffer.reserve(asize: 100);
746 size = v6Sock.readDatagram(data: buffer.data(), maxlen: 100, host: &from, port: &port);
747 QCOMPARE((int)size, dualData.length());
748 buffer.resize(size);
749 QCOMPARE(buffer, dualData);
750
751 QCOMPARE((int)dualSock.writeDatagram(dualData.constData(), dualData.length(), QHostAddress(QHostAddress::LocalHost), v4Sock.localPort()), dualData.length());
752 QVERIFY2(v4Sock.waitForReadyRead(5000), QtNetworkSettings::msgSocketError(v4Sock).constData());
753 buffer.reserve(asize: 100);
754 size = v4Sock.readDatagram(data: buffer.data(), maxlen: 100, host: &from, port: &port);
755 QCOMPARE((int)size, dualData.length());
756 buffer.resize(size);
757 QCOMPARE(buffer, dualData);
758 }
759}
760
761void tst_QUdpSocket::dualStackNoIPv4onV6only()
762{
763 QFETCH_GLOBAL(bool, setProxy);
764 if (setProxy)
765 QSKIP("test server SOCKS proxy doesn't support IPv6");
766 if (!QtNetworkSettings::hasIPv6())
767 QSKIP("system doesn't support ipv6!");
768 QUdpSocket v4Sock;
769 QVERIFY(v4Sock.bind(QHostAddress(QHostAddress::AnyIPv4), 0));
770 QByteArray v4Data("v4");
771
772 QUdpSocket v6Sock;
773 QVERIFY(v6Sock.bind(QHostAddress(QHostAddress::AnyIPv6), 0));
774
775 //test v4 -> v6 (should not be received as this is a v6 only socket)
776 QCOMPARE((int)v4Sock.writeDatagram(v4Data.constData(), v4Data.length(), QHostAddress(QHostAddress::LocalHost), v6Sock.localPort()), v4Data.length());
777 QVERIFY(!v6Sock.waitForReadyRead(1000));
778}
779
780void tst_QUdpSocket::empty_readyReadSlot()
781{
782 QTestEventLoop::instance().exitLoop();
783}
784
785void tst_QUdpSocket::empty_connectedSlot()
786{
787 QTestEventLoop::instance().exitLoop();
788}
789
790//----------------------------------------------------------------------------------
791
792void tst_QUdpSocket::connectToHost()
793{
794 QUdpSocket socket1;
795 QUdpSocket socket2;
796
797 QVERIFY2(socket1.bind(), socket1.errorString().toLatin1().constData());
798
799 socket2.connectToHost(address: makeNonAny(address: socket1.localAddress()), port: socket1.localPort());
800 QVERIFY(socket2.waitForConnected(5000));
801}
802
803//----------------------------------------------------------------------------------
804
805void tst_QUdpSocket::bindAndConnectToHost()
806{
807 QUdpSocket socket1;
808 QUdpSocket socket2;
809 QUdpSocket dummysocket;
810
811 // we use the dummy socket to use up a file descriptor
812 dummysocket.bind();
813
814 QVERIFY2(socket2.bind(), socket2.errorString().toLatin1());
815 quint16 boundPort = socket2.localPort();
816 qintptr fd = socket2.socketDescriptor();
817
818 QVERIFY2(socket1.bind(), socket1.errorString().toLatin1().constData());
819
820 dummysocket.close();
821 socket2.connectToHost(address: makeNonAny(address: socket1.localAddress()), port: socket1.localPort());
822 QVERIFY(socket2.waitForConnected(5000));
823
824 QCOMPARE(socket2.localPort(), boundPort);
825 QCOMPARE(socket2.socketDescriptor(), fd);
826}
827
828//----------------------------------------------------------------------------------
829
830void tst_QUdpSocket::pendingDatagramSize()
831{
832 if (m_workaroundLinuxKernelBug)
833 QSKIP("This test can fail due to linux kernel bug");
834
835 QUdpSocket server;
836 QVERIFY2(server.bind(), server.errorString().toLatin1().constData());
837
838 QHostAddress serverAddress = makeNonAny(address: server.localAddress());
839 QUdpSocket client;
840 QVERIFY(client.writeDatagram("this is", 7, serverAddress, server.localPort()) == 7);
841 QVERIFY(client.writeDatagram(0, 0, serverAddress, server.localPort()) == 0);
842 QVERIFY(client.writeDatagram("3 messages", 10, serverAddress, server.localPort()) == 10);
843
844 char c = 0;
845 QVERIFY2(server.waitForReadyRead(), QtNetworkSettings::msgSocketError(server).constData());
846 if (server.hasPendingDatagrams()) {
847#if defined Q_OS_HPUX && defined __ia64
848 QEXPECT_FAIL("", "HP-UX 11i v2 can't determine the datagram size correctly.", Abort);
849#endif
850 QCOMPARE(server.pendingDatagramSize(), qint64(7));
851 c = '\0';
852 QCOMPARE(server.readDatagram(&c, 1), qint64(1));
853 QCOMPARE(c, 't');
854 c = '\0';
855 } else
856 QSKIP("does not have the 1st datagram");
857
858 if (server.hasPendingDatagrams()) {
859 QCOMPARE(server.pendingDatagramSize(), qint64(0));
860 QCOMPARE(server.readDatagram(&c, 1), qint64(0));
861 QCOMPARE(c, '\0'); // untouched
862 c = '\0';
863 } else
864 QSKIP("does not have the 2nd datagram");
865
866 if (server.hasPendingDatagrams()) {
867 QCOMPARE(server.pendingDatagramSize(), qint64(10));
868 QCOMPARE(server.readDatagram(&c, 1), qint64(1));
869 QCOMPARE(c, '3');
870 } else
871 QSKIP("does not have the 3rd datagram");
872}
873
874
875void tst_QUdpSocket::writeDatagram()
876{
877 QUdpSocket server;
878 QVERIFY2(server.bind(), server.errorString().toLatin1().constData());
879
880 QHostAddress serverAddress = makeNonAny(address: server.localAddress());
881 QUdpSocket client;
882
883 qRegisterMetaType<QAbstractSocket::SocketError>(typeName: "QAbstractSocket::SocketError");
884
885 for(int i=0;;i++) {
886 QSignalSpy errorspy(&client, SIGNAL(errorOccurred(QAbstractSocket::SocketError)));
887 QSignalSpy bytesspy(&client, SIGNAL(bytesWritten(qint64)));
888
889 qint64 written = client.writeDatagram(datagram: QByteArray(i * 1024, 'w'), host: serverAddress,
890 port: server.localPort());
891
892 if (written != i * 1024) {
893#if defined (Q_OS_HPUX)
894 QSKIP("HP-UX 11.11 on hai (PA-RISC 64) truncates too long datagrams.");
895#endif
896 QCOMPARE(bytesspy.count(), 0);
897 QCOMPARE(errorspy.count(), 1);
898 QCOMPARE(*static_cast<const int *>(errorspy.at(0).at(0).constData()),
899 int(QUdpSocket::DatagramTooLargeError));
900 QCOMPARE(client.error(), QUdpSocket::DatagramTooLargeError);
901 break;
902 }
903 QCOMPARE(bytesspy.count(), 1);
904 QCOMPARE(*static_cast<const qint64 *>(bytesspy.at(0).at(0).constData()),
905 qint64(i * 1024));
906 QCOMPARE(errorspy.count(), 0);
907 if (!server.waitForReadyRead(msecs: 5000))
908 QSKIP(QString("UDP packet lost at size %1, unable to complete the test.").arg(i * 1024).toLatin1().data());
909 QCOMPARE(server.pendingDatagramSize(), qint64(i * 1024));
910 QCOMPARE(server.readDatagram(0, 0), qint64(0));
911 }
912}
913
914void tst_QUdpSocket::performance()
915{
916 QByteArray arr(8192, '@');
917
918 QUdpSocket server;
919 QVERIFY2(server.bind(), server.errorString().toLatin1().constData());
920
921 QHostAddress serverAddress = makeNonAny(address: server.localAddress());
922 QUdpSocket client;
923 client.connectToHost(address: serverAddress, port: server.localPort());
924 QVERIFY(client.waitForConnected(10000));
925
926 QElapsedTimer stopWatch;
927 stopWatch.start();
928
929 qint64 nbytes = 0;
930 while (stopWatch.elapsed() < 5000) {
931 for (int i = 0; i < 100; ++i) {
932 if (client.write(data: arr.data(), len: arr.size()) > 0) {
933 do {
934 nbytes += server.readDatagram(data: arr.data(), maxlen: arr.size());
935 } while (server.hasPendingDatagrams());
936 }
937 }
938 }
939
940 float secs = stopWatch.elapsed() / 1000.0;
941 qDebug(msg: "\t%.2fMB/%.2fs: %.2fMB/s", float(nbytes / (1024.0*1024.0)),
942 secs, float(nbytes / (1024.0*1024.0)) / secs);
943}
944
945void tst_QUdpSocket::bindMode()
946{
947 QFETCH_GLOBAL(bool, setProxy);
948 if (setProxy) {
949#ifndef QT_NO_NETWORKPROXY
950 QFETCH_GLOBAL(int, proxyType);
951 if (proxyType == QNetworkProxy::Socks5Proxy)
952 QSKIP("With socks5 explicit port binding is not supported.");
953#else // !QT_NO_NETWORKPROXY
954 QSKIP("No proxy support");
955#endif // QT_NO_NETWORKPROXY
956 }
957
958 QUdpSocket socket;
959 QVERIFY2(socket.bind(), socket.errorString().toLatin1().constData());
960 QUdpSocket socket2;
961 QVERIFY(!socket2.bind(socket.localPort()));
962#if defined(Q_OS_UNIX)
963 QVERIFY(!socket2.bind(socket.localPort(), QUdpSocket::ReuseAddressHint));
964 socket.close();
965 QVERIFY2(socket.bind(0, QUdpSocket::ShareAddress), socket.errorString().toLatin1().constData());
966 QVERIFY2(socket2.bind(socket.localPort()), socket2.errorString().toLatin1().constData());
967 socket2.close();
968 QVERIFY2(socket2.bind(socket.localPort(), QUdpSocket::ReuseAddressHint), socket2.errorString().toLatin1().constData());
969#else
970
971 // Depending on the user's privileges, this or will succeed or
972 // fail. Admins are allowed to reuse the address, but nobody else.
973 if (!socket2.bind(socket.localPort(), QUdpSocket::ReuseAddressHint)) {
974 qWarning("Failed to bind with QUdpSocket::ReuseAddressHint(%s), user isn't an administrator?",
975 qPrintable(socket2.errorString()));
976 }
977 socket.close();
978 QVERIFY2(socket.bind(0, QUdpSocket::ShareAddress), socket.errorString().toLatin1().constData());
979 QVERIFY(!socket2.bind(socket.localPort()));
980 socket.close();
981 QVERIFY2(socket.bind(0, QUdpSocket::DontShareAddress), socket.errorString().toLatin1().constData());
982 QVERIFY(!socket2.bind(socket.localPort()));
983 QVERIFY(!socket2.bind(socket.localPort(), QUdpSocket::ReuseAddressHint));
984#endif
985}
986
987void tst_QUdpSocket::writeDatagramToNonExistingPeer_data()
988{
989 QTest::addColumn<bool>(name: "bind");
990 QTest::addColumn<QHostAddress>(name: "peerAddress");
991 QHostAddress localhost(QHostAddress::LocalHost);
992 QList<QHostAddress> serverAddresses(QHostInfo::fromName(name: QtNetworkSettings::socksProxyServerName()).addresses());
993 if (serverAddresses.isEmpty())
994 return;
995
996 QHostAddress remote = serverAddresses.first();
997
998 QTest::newRow(dataTag: "localhost-unbound") << false << localhost;
999 QTest::newRow(dataTag: "localhost-bound") << true << localhost;
1000 QTest::newRow(dataTag: "remote-unbound") << false << remote;
1001 QTest::newRow(dataTag: "remote-bound") << true << remote;
1002}
1003
1004void tst_QUdpSocket::writeDatagramToNonExistingPeer()
1005{
1006 if (QHostInfo::fromName(name: QtNetworkSettings::socksProxyServerName()).addresses().isEmpty())
1007 QFAIL("Could not find test server address");
1008 QFETCH(bool, bind);
1009 QFETCH(QHostAddress, peerAddress);
1010
1011 quint16 peerPort = 33533 + int(bind);
1012
1013 QUdpSocket sUdp;
1014 QSignalSpy sReadyReadSpy(&sUdp, SIGNAL(readyRead()));
1015 if (bind)
1016 QVERIFY(sUdp.bind());
1017 QCOMPARE(sUdp.writeDatagram("", 1, peerAddress, peerPort), qint64(1));
1018 QTestEventLoop::instance().enterLoop(secs: 1);
1019 QCOMPARE(sReadyReadSpy.count(), 0);
1020}
1021
1022void tst_QUdpSocket::writeToNonExistingPeer_data()
1023{
1024 QTest::addColumn<QHostAddress>(name: "peerAddress");
1025 QHostAddress localhost(QHostAddress::LocalHost);
1026 QList<QHostAddress> serverAddresses(QHostInfo::fromName(name: QtNetworkSettings::socksProxyServerName()).addresses());
1027 if (serverAddresses.isEmpty())
1028 return;
1029
1030 QHostAddress remote = serverAddresses.first();
1031 // write (required to be connected)
1032 QTest::newRow(dataTag: "localhost") << localhost;
1033 QTest::newRow(dataTag: "remote") << remote;
1034}
1035
1036void tst_QUdpSocket::writeToNonExistingPeer()
1037{
1038 QSKIP("Connected-mode UDP sockets and their behaviour are erratic");
1039 if (QHostInfo::fromName(name: QtNetworkSettings::socksProxyServerName()).addresses().isEmpty())
1040 QFAIL("Could not find test server address");
1041 QFETCH(QHostAddress, peerAddress);
1042 quint16 peerPort = 34534;
1043 qRegisterMetaType<QAbstractSocket::SocketError>(typeName: "QAbstractSocket::SocketError");
1044
1045 QUdpSocket sConnected;
1046 QSignalSpy sConnectedReadyReadSpy(&sConnected, SIGNAL(readyRead()));
1047 QSignalSpy sConnectedErrorSpy(&sConnected, SIGNAL(errorOccurred(QAbstractSocket::SocketError)));
1048 sConnected.connectToHost(address: peerAddress, port: peerPort, mode: QIODevice::ReadWrite);
1049 QVERIFY(sConnected.waitForConnected(10000));
1050
1051 // the first write succeeds...
1052 QCOMPARE(sConnected.write("", 1), qint64(1));
1053
1054 // the second one should fail!
1055 QTest::qSleep(ms: 1000); // do not process events
1056 QCOMPARE(sConnected.write("", 1), qint64(-1));
1057 QCOMPARE(int(sConnected.error()), int(QUdpSocket::ConnectionRefusedError));
1058
1059 // the third one will succeed...
1060 QCOMPARE(sConnected.write("", 1), qint64(1));
1061 QTestEventLoop::instance().enterLoop(secs: 1);
1062 QCOMPARE(sConnectedReadyReadSpy.count(), 0);
1063 QCOMPARE(sConnectedErrorSpy.count(), 1);
1064 QCOMPARE(int(sConnected.error()), int(QUdpSocket::ConnectionRefusedError));
1065
1066 // we should now get a read error
1067 QCOMPARE(sConnected.write("", 1), qint64(1));
1068 QTest::qSleep(ms: 1000); // do not process events
1069 char buf[2];
1070 QVERIFY(!sConnected.hasPendingDatagrams());
1071 QCOMPARE(sConnected.bytesAvailable(), Q_INT64_C(0));
1072 QCOMPARE(sConnected.pendingDatagramSize(), Q_INT64_C(-1));
1073 QCOMPARE(sConnected.readDatagram(buf, 2), Q_INT64_C(-1));
1074 QCOMPARE(int(sConnected.error()), int(QUdpSocket::ConnectionRefusedError));
1075
1076 QCOMPARE(sConnected.write("", 1), qint64(1));
1077 QTest::qSleep(ms: 1000); // do not process events
1078 QCOMPARE(sConnected.read(buf, 2), Q_INT64_C(0));
1079 QCOMPARE(int(sConnected.error()), int(QUdpSocket::ConnectionRefusedError));
1080
1081 // we should still be connected
1082 QCOMPARE(int(sConnected.state()), int(QUdpSocket::ConnectedState));
1083}
1084
1085void tst_QUdpSocket::outOfProcessConnectedClientServerTest()
1086{
1087#if !QT_CONFIG(process)
1088 QSKIP("No qprocess support", SkipAll);
1089#else
1090 QProcess serverProcess;
1091 serverProcess.start(command: QLatin1String("clientserver/clientserver server 1 1"),
1092 mode: QIODevice::ReadWrite | QIODevice::Text);
1093
1094 const auto serverProcessCleaner = qScopeGuard(f: [&serverProcess] {
1095 serverProcess.kill();
1096 serverProcess.waitForFinished();
1097 });
1098
1099 if (!serverProcess.waitForStarted(msecs: 3000))
1100 QSKIP("Failed to start server as a subprocess");
1101
1102 // Wait until the server has started and reports success.
1103 while (!serverProcess.canReadLine()) {
1104 if (!serverProcess.waitForReadyRead(msecs: 3000))
1105 QSKIP("No output from the server process, bailing out");
1106 }
1107
1108 QByteArray serverGreeting = serverProcess.readLine();
1109 QVERIFY(serverGreeting != QByteArray("XXX\n"));
1110 int serverPort = serverGreeting.trimmed().toInt();
1111 QVERIFY(serverPort > 0 && serverPort < 65536);
1112
1113 QProcess clientProcess;
1114 clientProcess.start(command: QString::fromLatin1(str: "clientserver/clientserver connectedclient %1 %2")
1115 .arg(a: QLatin1String("127.0.0.1")).arg(a: serverPort),
1116 mode: QIODevice::ReadWrite | QIODevice::Text);
1117
1118 const auto clientProcessCleaner = qScopeGuard(f: [&clientProcess] {
1119 clientProcess.kill();
1120 clientProcess.waitForFinished();
1121 });
1122
1123 if (!clientProcess.waitForStarted(msecs: 3000))
1124 QSKIP("Client process did not start");
1125
1126 // Wait until the client has started and reports success.
1127 while (!clientProcess.canReadLine()) {
1128 if (!clientProcess.waitForReadyRead(msecs: 3000))
1129 QSKIP("No output from the client process, bailing out");
1130 }
1131
1132 QByteArray clientGreeting = clientProcess.readLine();
1133 QCOMPARE(clientGreeting, QByteArray("ok\n"));
1134
1135 // Let the client and server talk for 3 seconds
1136 QTest::qWait(ms: 3000);
1137
1138 QStringList serverData = QString::fromLocal8Bit(str: serverProcess.readAll()).split(sep: "\n");
1139 QStringList clientData = QString::fromLocal8Bit(str: clientProcess.readAll()).split(sep: "\n");
1140 QVERIFY(serverData.size() > 5);
1141 QVERIFY(clientData.size() > 5);
1142
1143 for (int i = 0; i < clientData.size() / 2; ++i) {
1144 QCOMPARE(clientData.at(i * 2), QString("readData()"));
1145 QCOMPARE(serverData.at(i * 3), QString("readData()"));
1146
1147 QString cdata = clientData.at(i: i * 2 + 1);
1148 QString sdata = serverData.at(i: i * 3 + 1);
1149 QVERIFY(cdata.startsWith(QLatin1String("got ")));
1150
1151 QCOMPARE(cdata.mid(4).trimmed().toInt(), sdata.mid(4).trimmed().toInt() * 2);
1152 QVERIFY(serverData.at(i * 3 + 2).startsWith(QLatin1String("sending ")));
1153 QCOMPARE(serverData.at(i * 3 + 2).trimmed().mid(8).toInt(),
1154 sdata.mid(4).trimmed().toInt() * 2);
1155 }
1156#endif
1157}
1158
1159void tst_QUdpSocket::outOfProcessUnconnectedClientServerTest()
1160{
1161#if !QT_CONFIG(process)
1162 QSKIP("No qprocess support", SkipAll);
1163#else
1164 QProcess serverProcess;
1165 serverProcess.start(command: QLatin1String("clientserver/clientserver server 1 1"),
1166 mode: QIODevice::ReadWrite | QIODevice::Text);
1167
1168 const auto serverProcessCleaner = qScopeGuard(f: [&serverProcess] {
1169 serverProcess.kill();
1170 serverProcess.waitForFinished();
1171 });
1172
1173 if (!serverProcess.waitForStarted(msecs: 3000))
1174 QSKIP("Failed to start the server subprocess");
1175
1176 // Wait until the server has started and reports success.
1177 while (!serverProcess.canReadLine()) {
1178 if (!serverProcess.waitForReadyRead(msecs: 3000))
1179 QSKIP("No output from the server, probably, it is not running");
1180 }
1181
1182 QByteArray serverGreeting = serverProcess.readLine();
1183 QVERIFY(serverGreeting != QByteArray("XXX\n"));
1184 int serverPort = serverGreeting.trimmed().toInt();
1185 QVERIFY(serverPort > 0 && serverPort < 65536);
1186
1187 QProcess clientProcess;
1188 clientProcess.start(command: QString::fromLatin1(str: "clientserver/clientserver unconnectedclient %1 %2")
1189 .arg(a: QLatin1String("127.0.0.1")).arg(a: serverPort),
1190 mode: QIODevice::ReadWrite | QIODevice::Text);
1191
1192 const auto clientProcessCleaner = qScopeGuard(f: [&clientProcess] {
1193 clientProcess.kill();
1194 clientProcess.waitForFinished();
1195 });
1196
1197 if (!clientProcess.waitForStarted(msecs: 3000))
1198 QSKIP("Failed to start the client's subprocess");
1199
1200 // Wait until the client has started and reports success.
1201 while (!clientProcess.canReadLine()) {
1202 if (!clientProcess.waitForReadyRead(msecs: 3000))
1203 QSKIP("The client subprocess produced not output, exiting.");
1204 }
1205
1206 QByteArray clientGreeting = clientProcess.readLine();
1207 QCOMPARE(clientGreeting, QByteArray("ok\n"));
1208
1209 // Let the client and server talk for 3 seconds
1210 QTest::qWait(ms: 3000);
1211
1212 QStringList serverData = QString::fromLocal8Bit(str: serverProcess.readAll()).split(sep: "\n");
1213 QStringList clientData = QString::fromLocal8Bit(str: clientProcess.readAll()).split(sep: "\n");
1214
1215 QVERIFY(serverData.size() > 5);
1216 QVERIFY(clientData.size() > 5);
1217
1218 for (int i = 0; i < clientData.size() / 2; ++i) {
1219 QCOMPARE(clientData.at(i * 2), QString("readData()"));
1220 QCOMPARE(serverData.at(i * 3), QString("readData()"));
1221
1222 QString cdata = clientData.at(i: i * 2 + 1);
1223 QString sdata = serverData.at(i: i * 3 + 1);
1224 QVERIFY(cdata.startsWith(QLatin1String("got ")));
1225
1226 QCOMPARE(cdata.mid(4).trimmed().toInt(), sdata.mid(4).trimmed().toInt() * 2);
1227 QVERIFY(serverData.at(i * 3 + 2).startsWith(QLatin1String("sending ")));
1228 QCOMPARE(serverData.at(i * 3 + 2).trimmed().mid(8).toInt(),
1229 sdata.mid(4).trimmed().toInt() * 2);
1230 }
1231#endif
1232}
1233
1234void tst_QUdpSocket::zeroLengthDatagram()
1235{
1236 QFETCH_GLOBAL(bool, setProxy);
1237 if (setProxy)
1238 return;
1239
1240 QUdpSocket receiver;
1241 QVERIFY(receiver.bind());
1242
1243 QVERIFY(!receiver.waitForReadyRead(100));
1244 QVERIFY(!receiver.hasPendingDatagrams());
1245
1246 QUdpSocket sender;
1247 QCOMPARE(sender.writeDatagram(QNetworkDatagram(QByteArray(), QHostAddress::LocalHost, receiver.localPort())), qint64(0));
1248
1249 QVERIFY2(receiver.waitForReadyRead(1000), QtNetworkSettings::msgSocketError(receiver).constData());
1250 QVERIFY(receiver.hasPendingDatagrams());
1251
1252 char buf;
1253 QCOMPARE(receiver.readDatagram(&buf, 1), qint64(0));
1254}
1255
1256void tst_QUdpSocket::multicastTtlOption_data()
1257{
1258 QTest::addColumn<QHostAddress>(name: "bindAddress");
1259 QTest::addColumn<int>(name: "ttl");
1260 QTest::addColumn<int>(name: "expected");
1261
1262 QList<QHostAddress> addresses;
1263 addresses += QHostAddress(QHostAddress::AnyIPv4);
1264 addresses += QHostAddress(QHostAddress::AnyIPv6);
1265
1266 foreach (const QHostAddress &address, addresses) {
1267 const QByteArray addressB = address.toString().toLatin1();
1268 QTest::newRow(dataTag: (addressB + " 0").constData()) << address << 0 << 0;
1269 QTest::newRow(dataTag: (addressB + " 1").constData()) << address << 1 << 1;
1270 QTest::newRow(dataTag: (addressB + " 2").constData()) << address << 2 << 2;
1271 QTest::newRow(dataTag: (addressB + " 128").constData()) << address << 128 << 128;
1272 QTest::newRow(dataTag: (addressB + " 255").constData()) << address << 255 << 255;
1273 QTest::newRow(dataTag: (addressB + " 1024").constData()) << address << 1024 << 1;
1274 }
1275}
1276
1277void tst_QUdpSocket::multicastTtlOption()
1278{
1279#ifdef Q_OS_WINRT
1280 QSKIP("WinRT does not support multicast.");
1281#endif
1282 QFETCH_GLOBAL(bool, setProxy);
1283 QFETCH(QHostAddress, bindAddress);
1284 QFETCH(int, ttl);
1285 QFETCH(int, expected);
1286 if (setProxy) {
1287 // UDP multicast does not work with proxies
1288 expected = 0;
1289 }
1290
1291 // Some syscalls needed for ipv6 udp multicasting are not functional
1292 if (m_skipUnsupportedIPv6Tests) {
1293 if (bindAddress.protocol() == QAbstractSocket::IPv6Protocol) {
1294 QSKIP("Syscalls needed for ipv6 udp multicasting missing functionality");
1295 }
1296 }
1297
1298 QUdpSocket udpSocket;
1299 // bind, but ignore the result, we are only interested in initializing the socket
1300 (void) udpSocket.bind(address: bindAddress, port: 0);
1301 udpSocket.setSocketOption(option: QUdpSocket::MulticastTtlOption, value: ttl);
1302 QCOMPARE(udpSocket.socketOption(QUdpSocket::MulticastTtlOption).toInt(), expected);
1303}
1304
1305void tst_QUdpSocket::multicastLoopbackOption_data()
1306{
1307 QTest::addColumn<QHostAddress>(name: "bindAddress");
1308 QTest::addColumn<int>(name: "loopback");
1309 QTest::addColumn<int>(name: "expected");
1310
1311 QList<QHostAddress> addresses;
1312 addresses += QHostAddress(QHostAddress::AnyIPv4);
1313 addresses += QHostAddress(QHostAddress::AnyIPv6);
1314
1315 foreach (const QHostAddress &address, addresses) {
1316 const QByteArray addressB = address.toString().toLatin1();
1317 QTest::newRow(dataTag: (addressB + " 0").constData()) << address << 0 << 0;
1318 QTest::newRow(dataTag: (addressB + " 1").constData()) << address << 1 << 1;
1319 QTest::newRow(dataTag: (addressB + " 2").constData()) << address << 2 << 1;
1320 QTest::newRow(dataTag: (addressB + " 0 again").constData()) << address << 0 << 0;
1321 QTest::newRow(dataTag: (addressB + " 2 again").constData()) << address << 2 << 1;
1322 QTest::newRow(dataTag: (addressB + " 0 last time").constData()) << address << 0 << 0;
1323 QTest::newRow(dataTag: (addressB + " 1 again").constData()) << address << 1 << 1;
1324 }
1325}
1326
1327void tst_QUdpSocket::multicastLoopbackOption()
1328{
1329#ifdef Q_OS_WINRT
1330 QSKIP("WinRT does not support multicast.");
1331#endif
1332 QFETCH_GLOBAL(bool, setProxy);
1333 QFETCH(QHostAddress, bindAddress);
1334 QFETCH(int, loopback);
1335 QFETCH(int, expected);
1336 if (setProxy) {
1337 // UDP multicast does not work with proxies
1338 expected = 0;
1339 }
1340
1341 // Some syscalls needed for ipv6 udp multicasting are not functional
1342 if (m_skipUnsupportedIPv6Tests) {
1343 if (bindAddress.protocol() == QAbstractSocket::IPv6Protocol) {
1344 QSKIP("Syscalls needed for ipv6 udp multicasting missing functionality");
1345 }
1346 }
1347
1348 QUdpSocket udpSocket;
1349 // bind, but ignore the result, we are only interested in initializing the socket
1350 (void) udpSocket.bind(address: bindAddress, port: 0);
1351 udpSocket.setSocketOption(option: QUdpSocket::MulticastLoopbackOption, value: loopback);
1352 QCOMPARE(udpSocket.socketOption(QUdpSocket::MulticastLoopbackOption).toInt(), expected);
1353}
1354
1355void tst_QUdpSocket::multicastJoinBeforeBind_data()
1356{
1357 QTest::addColumn<QHostAddress>(name: "groupAddress");
1358 QTest::newRow(dataTag: "valid ipv4 group address") << multicastGroup4;
1359 QTest::newRow(dataTag: "invalid ipv4 group address") << QHostAddress(QHostAddress::Broadcast);
1360 QTest::newRow(dataTag: "valid ipv6 group address") << multicastGroup6;
1361 for (const QHostAddress &a : qAsConst(t&: linklocalMulticastGroups))
1362 QTest::addRow(format: "valid ipv6 %s-link group address", a.scopeId().toLatin1().constData()) << a;
1363 QTest::newRow(dataTag: "invalid ipv6 group address") << QHostAddress(QHostAddress::AnyIPv6);
1364}
1365
1366void tst_QUdpSocket::multicastJoinBeforeBind()
1367{
1368#ifdef Q_OS_WINRT
1369 QSKIP("WinRT does not support multicast.");
1370#endif
1371 QFETCH(QHostAddress, groupAddress);
1372
1373 QUdpSocket udpSocket;
1374 // cannot join group before binding
1375 QTest::ignoreMessage(type: QtWarningMsg, message: "QUdpSocket::joinMulticastGroup() called on a QUdpSocket when not in QUdpSocket::BoundState");
1376 QVERIFY(!udpSocket.joinMulticastGroup(groupAddress));
1377}
1378
1379void tst_QUdpSocket::multicastLeaveAfterClose_data()
1380{
1381 QTest::addColumn<QHostAddress>(name: "groupAddress");
1382 QTest::newRow(dataTag: "ipv4") << multicastGroup4;
1383 QTest::newRow(dataTag: "ipv6") << multicastGroup6;
1384 for (const QHostAddress &a : qAsConst(t&: linklocalMulticastGroups))
1385 QTest::addRow(format: "ipv6-link-%s", a.scopeId().toLatin1().constData()) << a;
1386}
1387
1388void tst_QUdpSocket::multicastLeaveAfterClose()
1389{
1390#ifdef Q_OS_WINRT
1391 QSKIP("WinRT does not support multicast.");
1392#endif
1393 QFETCH_GLOBAL(bool, setProxy);
1394 QFETCH(QHostAddress, groupAddress);
1395 if (setProxy)
1396 QSKIP("UDP Multicast does not work with proxies");
1397 if (!QtNetworkSettings::hasIPv6() && groupAddress.protocol() == QAbstractSocket::IPv6Protocol)
1398 QSKIP("system doesn't support ipv6!");
1399
1400 // Some syscalls needed for ipv6 udp multicasting are not functional
1401 if (m_skipUnsupportedIPv6Tests) {
1402 if (groupAddress.protocol() == QAbstractSocket::IPv6Protocol) {
1403 QSKIP("Syscalls needed for ipv6 udp multicasting missing functionality");
1404 }
1405 }
1406
1407 QUdpSocket udpSocket;
1408 QHostAddress bindAddress = QHostAddress::AnyIPv4;
1409 if (groupAddress.protocol() == QAbstractSocket::IPv6Protocol)
1410 bindAddress = QHostAddress::AnyIPv6;
1411 QVERIFY2(udpSocket.bind(bindAddress, 0),
1412 qPrintable(udpSocket.errorString()));
1413 QVERIFY2(udpSocket.joinMulticastGroup(groupAddress, interfaceForGroup(groupAddress)),
1414 qPrintable(udpSocket.errorString()));
1415 udpSocket.close();
1416 QTest::ignoreMessage(type: QtWarningMsg, message: "QUdpSocket::leaveMulticastGroup() called on a QUdpSocket when not in QUdpSocket::BoundState");
1417 QVERIFY(!udpSocket.leaveMulticastGroup(groupAddress));
1418}
1419
1420void tst_QUdpSocket::setMulticastInterface_data()
1421{
1422 QTest::addColumn<QNetworkInterface>(name: "iface");
1423 QTest::addColumn<QHostAddress>(name: "address");
1424 QList<QNetworkInterface> interfaces = QNetworkInterface::allInterfaces();
1425 foreach (const QNetworkInterface &iface, interfaces) {
1426 if ((iface.flags() & QNetworkInterface::IsUp) == 0)
1427 continue;
1428 foreach (const QNetworkAddressEntry &entry, iface.addressEntries()) {
1429 const QByteArray testName = iface.name().toLatin1() + ':' + entry.ip().toString().toLatin1();
1430 QTest::newRow(dataTag: testName.constData()) << iface << entry.ip();
1431 }
1432 }
1433}
1434
1435void tst_QUdpSocket::setMulticastInterface()
1436{
1437#ifdef Q_OS_WINRT
1438 QSKIP("WinRT does not support multicast.");
1439#endif
1440 QFETCH_GLOBAL(bool, setProxy);
1441 QFETCH(QNetworkInterface, iface);
1442 QFETCH(QHostAddress, address);
1443
1444 // Some syscalls needed for udp multicasting are not functional
1445 if (m_skipUnsupportedIPv6Tests) {
1446 QSKIP("Syscalls needed for udp multicasting missing functionality");
1447 }
1448
1449 QUdpSocket udpSocket;
1450 // bind initializes the socket
1451 bool bound = udpSocket.bind(address: (address.protocol() == QAbstractSocket::IPv6Protocol
1452 ? QHostAddress(QHostAddress::AnyIPv6)
1453 : QHostAddress(QHostAddress::AnyIPv4)),
1454 port: 0);
1455 if (!bound)
1456 QTest::ignoreMessage(type: QtWarningMsg, message: "QUdpSocket::setMulticastInterface() called on a QUdpSocket when not in QUdpSocket::BoundState");
1457 udpSocket.setMulticastInterface(iface);
1458 if (!bound)
1459 QTest::ignoreMessage(type: QtWarningMsg, message: "QUdpSocket::multicastInterface() called on a QUdpSocket when not in QUdpSocket::BoundState");
1460 QNetworkInterface iface2 = udpSocket.multicastInterface();
1461 if (!setProxy) {
1462 QVERIFY(iface2.isValid());
1463 QCOMPARE(iface.name(), iface2.name());
1464 } else {
1465 QVERIFY(!iface2.isValid());
1466 }
1467}
1468
1469void tst_QUdpSocket::multicast_data()
1470{
1471 QHostAddress anyAddress = QHostAddress(QHostAddress::AnyIPv4);
1472 QHostAddress groupAddress = multicastGroup4;
1473 QHostAddress any6Address = QHostAddress(QHostAddress::AnyIPv6);
1474 QHostAddress group6Address = multicastGroup6;
1475 QHostAddress dualAddress = QHostAddress(QHostAddress::Any);
1476
1477 QTest::addColumn<QHostAddress>(name: "bindAddress");
1478 QTest::addColumn<bool>(name: "bindResult");
1479 QTest::addColumn<QHostAddress>(name: "groupAddress");
1480 QTest::addColumn<bool>(name: "joinResult");
1481 QTest::newRow(dataTag: "valid bind, group ipv4 address") << anyAddress << true << groupAddress << true;
1482 QTest::newRow(dataTag: "valid bind, invalid group ipv4 address") << anyAddress << true << anyAddress << false;
1483 QTest::newRow(dataTag: "valid bind, group ipv6 address") << any6Address << true << group6Address << true;
1484 for (const QHostAddress &a : qAsConst(t&: linklocalMulticastGroups))
1485 QTest::addRow(format: "valid bind, %s-link group ipv6 address", a.scopeId().toLatin1().constData())
1486 << any6Address << true << a << true;
1487 QTest::newRow(dataTag: "valid bind, invalid group ipv6 address") << any6Address << true << any6Address << false;
1488 QTest::newRow(dataTag: "dual bind, group ipv4 address") << dualAddress << true << groupAddress << false;
1489 QTest::newRow(dataTag: "dual bind, group ipv6 address") << dualAddress << true << group6Address << true;
1490 for (const QHostAddress &a : qAsConst(t&: linklocalMulticastGroups))
1491 QTest::addRow(format: "dual bind, %s-link group ipv6 address", a.scopeId().toLatin1().constData())
1492 << dualAddress << true << a << true;
1493}
1494
1495void tst_QUdpSocket::multicast()
1496{
1497#ifdef Q_OS_WINRT
1498 QSKIP("WinRT does not support multicast.");
1499#endif
1500 QFETCH_GLOBAL(bool, setProxy);
1501 QFETCH(QHostAddress, bindAddress);
1502 QFETCH(bool, bindResult);
1503 QFETCH(QHostAddress, groupAddress);
1504 QFETCH(bool, joinResult);
1505 if (groupAddress.protocol() == QAbstractSocket::IPv6Protocol && !QtNetworkSettings::hasIPv6())
1506 QSKIP("system doesn't support ipv6!");
1507 if (setProxy) {
1508 // UDP multicast does not work with proxies
1509 return;
1510 }
1511
1512 // Some syscalls needed for ipv6 udp multicasting are not functional
1513 if (m_skipUnsupportedIPv6Tests) {
1514 if (groupAddress.protocol() == QAbstractSocket::IPv6Protocol) {
1515 QSKIP("Syscalls needed for ipv6 udp multicasting missing functionality");
1516 }
1517 }
1518
1519 QUdpSocket receiver;
1520
1521 // bind first, then verify that we can join the multicast group
1522 QVERIFY2(receiver.bind(bindAddress, 0) == bindResult,
1523 qPrintable(receiver.errorString()));
1524 if (!bindResult)
1525 return;
1526
1527 if (bindAddress == QHostAddress::Any && groupAddress.protocol() == QAbstractSocket::IPv4Protocol) {
1528 QCOMPARE(joinResult, false);
1529 QTest::ignoreMessage(type: QtWarningMsg,
1530 message: "QAbstractSocket: cannot bind to QHostAddress::Any (or an IPv6 address) and join an IPv4 multicast group;"
1531 " bind to QHostAddress::AnyIPv4 instead if you want to do this");
1532 }
1533 QVERIFY2(receiver.joinMulticastGroup(groupAddress, interfaceForGroup(groupAddress)) == joinResult,
1534 qPrintable(receiver.errorString()));
1535 if (!joinResult)
1536 return;
1537
1538 QList<QByteArray> datagrams = QList<QByteArray>()
1539 << QByteArray("0123")
1540 << QByteArray("4567")
1541 << QByteArray("89ab")
1542 << QByteArray("cdef");
1543
1544 QUdpSocket sender;
1545 sender.bind();
1546 foreach (const QByteArray &datagram, datagrams) {
1547 QNetworkDatagram dgram(datagram, groupAddress, receiver.localPort());
1548 dgram.setInterfaceIndex(interfaceForGroup(multicastGroup: groupAddress).index());
1549 QCOMPARE(int(sender.writeDatagram(dgram)),
1550 int(datagram.size()));
1551 }
1552
1553 QVERIFY2(receiver.waitForReadyRead(), QtNetworkSettings::msgSocketError(receiver).constData());
1554 QVERIFY(receiver.hasPendingDatagrams());
1555 QList<QByteArray> receivedDatagrams;
1556 while (receiver.hasPendingDatagrams()) {
1557 QNetworkDatagram dgram = receiver.receiveDatagram();
1558 receivedDatagrams << dgram.data();
1559
1560 QVERIFY2(allAddresses.contains(dgram.senderAddress()),
1561 dgram.senderAddress().toString().toLatin1());
1562 QCOMPARE(dgram.senderPort(), int(sender.localPort()));
1563 if (!dgram.destinationAddress().isNull()) {
1564 QCOMPARE(dgram.destinationAddress(), groupAddress);
1565 QCOMPARE(dgram.destinationPort(), int(receiver.localPort()));
1566 }
1567
1568 int ttl = dgram.hopLimit();
1569 if (ttl != -1)
1570 QVERIFY(ttl != 0);
1571 }
1572 QCOMPARE(receivedDatagrams, datagrams);
1573
1574 QVERIFY2(receiver.leaveMulticastGroup(groupAddress, interfaceForGroup(groupAddress)),
1575 qPrintable(receiver.errorString()));
1576}
1577
1578void tst_QUdpSocket::echo_data()
1579{
1580 QTest::addColumn<bool>(name: "connect");
1581 QTest::newRow(dataTag: "writeDatagram") << false;
1582 QTest::newRow(dataTag: "write") << true;
1583}
1584
1585void tst_QUdpSocket::echo()
1586{
1587 QFETCH(bool, connect);
1588 QHostInfo info = QHostInfo::fromName(name: QtNetworkSettings::echoServerName());
1589 QVERIFY(info.addresses().count());
1590 QHostAddress remote = info.addresses().first();
1591
1592 QUdpSocket sock;
1593 if (connect) {
1594 sock.connectToHost(address: remote, port: 7);
1595 QVERIFY(sock.waitForConnected(10000));
1596 } else {
1597 sock.bind();
1598 }
1599 QByteArray out(30, 'x');
1600 QByteArray in;
1601 int successes = 0;
1602 for (int i=0;i<10;i++) {
1603 if (connect) {
1604 sock.write(data: out);
1605 } else {
1606 sock.writeDatagram(datagram: out, host: remote, port: 7);
1607 }
1608 if (sock.waitForReadyRead(msecs: 1000)) {
1609 while (sock.hasPendingDatagrams()) {
1610 QHostAddress from;
1611 quint16 port;
1612 if (connect) {
1613 in = sock.read(maxlen: sock.pendingDatagramSize());
1614 } else {
1615 in.resize(size: sock.pendingDatagramSize());
1616 sock.readDatagram(data: in.data(), maxlen: in.length(), host: &from, port: &port);
1617 }
1618 if (in==out)
1619 successes++;
1620 }
1621 }
1622 if (!sock.isValid())
1623 QFAIL(sock.errorString().toLatin1().constData());
1624 qDebug() << "packets in" << successes << "out" << i;
1625 QTest::qWait(ms: 50); //choke to avoid triggering flood/DDoS protections on echo service
1626 }
1627 QVERIFY2(successes >= 9, QByteArray::number(successes).constData());
1628}
1629
1630void tst_QUdpSocket::linkLocalIPv6()
1631{
1632 QFETCH_GLOBAL(bool, setProxy);
1633 if (setProxy)
1634 return;
1635
1636 QList <QHostAddress> addresses;
1637 QSet <QString> scopes;
1638 QHostAddress localMask("fe80::");
1639 foreach (const QNetworkInterface& iface, QNetworkInterface::allInterfaces()) {
1640 //Windows preallocates link local addresses to interfaces that are down.
1641 //These may or may not work depending on network driver
1642 if (iface.flags() & QNetworkInterface::IsUp) {
1643#if defined(Q_OS_WIN)
1644 // Do not add the Teredo Tunneling Pseudo Interface on Windows.
1645 if (iface.humanReadableName().contains("Teredo"))
1646 continue;
1647#elif defined(Q_OS_DARWIN)
1648 // Do not add "utun" interfaces on macOS: nothing ever gets received
1649 // (we don't know why)
1650 if (iface.name().startsWith("utun"))
1651 continue;
1652#endif
1653
1654 foreach (QNetworkAddressEntry addressEntry, iface.addressEntries()) {
1655 QHostAddress addr(addressEntry.ip());
1656 if (!addr.scopeId().isEmpty() && addr.isInSubnet(subnet: localMask, netmask: 64)) {
1657 scopes << addr.scopeId();
1658 addresses << addr;
1659 qDebug() << addr;
1660 }
1661 }
1662 }
1663 }
1664 if (addresses.isEmpty())
1665 QSKIP("No IPv6 link local addresses");
1666
1667 QList <QUdpSocket*> sockets;
1668 quint16 port = 0;
1669 foreach (const QHostAddress& addr, addresses) {
1670 QUdpSocket *s = new QUdpSocket;
1671 QVERIFY2(s->bind(addr, port), addr.toString().toLatin1()
1672 + '/' + QByteArray::number(port) + ": " + qPrintable(s->errorString()));
1673 port = s->localPort(); //bind same port, different networks
1674 sockets << s;
1675 }
1676
1677 QByteArray testData("hello");
1678 foreach (QUdpSocket *s, sockets) {
1679 QUdpSocket neutral;
1680 QVERIFY(neutral.bind(QHostAddress(QHostAddress::AnyIPv6)));
1681 QSignalSpy neutralReadSpy(&neutral, SIGNAL(readyRead()));
1682
1683 QSignalSpy spy(s, SIGNAL(readyRead()));
1684
1685 QVERIFY(s->writeDatagram(testData, s->localAddress(), neutral.localPort()));
1686 QTRY_VERIFY(neutralReadSpy.count() > 0); //note may need to accept a firewall prompt
1687
1688 QNetworkDatagram dgram = neutral.receiveDatagram(maxSize: testData.length() * 2);
1689 QVERIFY(dgram.isValid());
1690 QCOMPARE(dgram.senderAddress(), s->localAddress());
1691 QCOMPARE(dgram.senderPort(), int(s->localPort()));
1692 QCOMPARE(dgram.destinationAddress(), s->localAddress());
1693 QCOMPARE(dgram.destinationPort(), int(neutral.localPort()));
1694 QCOMPARE(dgram.data().length(), testData.length());
1695 QCOMPARE(dgram.data(), testData);
1696
1697 QVERIFY(neutral.writeDatagram(dgram.makeReply(testData)));
1698 QTRY_VERIFY(spy.count() > 0); //note may need to accept a firewall prompt
1699
1700 dgram = s->receiveDatagram(maxSize: testData.length() * 2);
1701 QCOMPARE(dgram.data(), testData);
1702
1703 //sockets bound to other interfaces shouldn't have received anything
1704 foreach (QUdpSocket *s2, sockets) {
1705 QCOMPARE((int)s2->bytesAvailable(), 0);
1706 }
1707
1708 //Sending to the same address with different scope should normally fail
1709 //However it will pass if there is a route between two interfaces,
1710 //e.g. connected to a home/office network via wired and wireless interfaces
1711 //which is a reasonably common case.
1712 //So this is not auto tested.
1713 }
1714 qDeleteAll(c: sockets);
1715}
1716
1717void tst_QUdpSocket::linkLocalIPv4()
1718{
1719 QFETCH_GLOBAL(bool, setProxy);
1720 if (setProxy)
1721 return;
1722
1723 QList <QHostAddress> addresses;
1724 QHostAddress localMask("169.254.0.0");
1725 foreach (const QNetworkInterface& iface, QNetworkInterface::allInterfaces()) {
1726 //Windows preallocates link local addresses to interfaces that are down.
1727 //These may or may not work depending on network driver (they do not work for the Bluetooth PAN driver)
1728 if (iface.flags() & QNetworkInterface::IsUp) {
1729#if defined(Q_OS_WIN)
1730 // Do not add the Teredo Tunneling Pseudo Interface on Windows.
1731 if (iface.humanReadableName().contains("Teredo"))
1732 continue;
1733#elif defined(Q_OS_DARWIN)
1734 // Do not add "utun" interfaces on macOS: nothing ever gets received
1735 // (we don't know why)
1736 if (iface.name().startsWith("utun"))
1737 continue;
1738#endif
1739 foreach (QNetworkAddressEntry addr, iface.addressEntries()) {
1740 if (addr.ip().isInSubnet(subnet: localMask, netmask: 16)) {
1741 addresses << addr.ip();
1742 qDebug() << "Found IPv4 link local address" << addr.ip();
1743 }
1744 }
1745 }
1746 }
1747 if (addresses.isEmpty())
1748 QSKIP("No IPv4 link local addresses");
1749
1750 QList <QUdpSocket*> sockets;
1751 quint16 port = 0;
1752 foreach (const QHostAddress& addr, addresses) {
1753 QUdpSocket *s = new QUdpSocket;
1754 QVERIFY2(s->bind(addr, port), qPrintable(s->errorString()));
1755 port = s->localPort(); //bind same port, different networks
1756 sockets << s;
1757 }
1758
1759 QUdpSocket neutral;
1760 QVERIFY(neutral.bind(QHostAddress(QHostAddress::AnyIPv4)));
1761
1762 QByteArray testData("hello");
1763 foreach (QUdpSocket *s, sockets) {
1764 QVERIFY(s->writeDatagram(testData, s->localAddress(), neutral.localPort()));
1765 QVERIFY2(neutral.waitForReadyRead(10000), QtNetworkSettings::msgSocketError(neutral).constData());
1766
1767 QNetworkDatagram dgram = neutral.receiveDatagram(maxSize: testData.length() * 2);
1768 QVERIFY(dgram.isValid());
1769 QCOMPARE(dgram.senderAddress(), s->localAddress());
1770 QCOMPARE(dgram.senderPort(), int(s->localPort()));
1771 QCOMPARE(dgram.data().length(), testData.length());
1772 QCOMPARE(dgram.data(), testData);
1773
1774 // Unlike for IPv6 with IPV6_PKTINFO, IPv4 has no standardized way of
1775 // obtaining the packet's destination addresses. The destinationAddress
1776 // and destinationPort calls could fail, so whitelist the OSes we know
1777 // we have an implementation.
1778#if defined(Q_OS_LINUX) || defined(Q_OS_BSD4) || defined(Q_OS_WIN)
1779 QVERIFY(dgram.destinationPort() != -1);
1780#endif
1781 if (dgram.destinationPort() == -1) {
1782 QCOMPARE(dgram.destinationAddress().protocol(), QAbstractSocket::UnknownNetworkLayerProtocol);
1783 } else {
1784 QCOMPARE(dgram.destinationAddress(), s->localAddress());
1785 QCOMPARE(dgram.destinationPort(), int(neutral.localPort()));
1786 }
1787
1788 QVERIFY(neutral.writeDatagram(dgram.makeReply(testData)));
1789 QVERIFY2(s->waitForReadyRead(10000), QtNetworkSettings::msgSocketError(*s).constData());
1790 dgram = s->receiveDatagram(maxSize: testData.length() * 2);
1791 QVERIFY(dgram.isValid());
1792 QCOMPARE(dgram.data(), testData);
1793
1794 //sockets bound to other interfaces shouldn't have received anything
1795 foreach (QUdpSocket *s2, sockets) {
1796 QCOMPARE((int)s2->bytesAvailable(), 0);
1797 }
1798 }
1799 qDeleteAll(c: sockets);
1800}
1801
1802void tst_QUdpSocket::readyRead()
1803{
1804 QFETCH_GLOBAL(bool, setProxy);
1805 if (setProxy)
1806 return;
1807
1808 char buf[1];
1809 QUdpSocket sender, receiver;
1810
1811 QVERIFY(receiver.bind(QHostAddress(QHostAddress::AnyIPv4), 0));
1812 quint16 port = receiver.localPort();
1813 QVERIFY(port != 0);
1814
1815 QSignalSpy spy(&receiver, SIGNAL(readyRead()));
1816
1817 // send a datagram to that port
1818 sender.writeDatagram(datagram: "aa", host: makeNonAny(address: receiver.localAddress()), port);
1819
1820 // wait a little
1821 // if QTBUG-43857 is still going, we'll live-lock on socket notifications from receiver's socket
1822 QTest::qWait(ms: 100);
1823
1824 // make sure only one signal was emitted
1825 QCOMPARE(spy.count(), 1);
1826 QVERIFY(receiver.hasPendingDatagrams());
1827#ifdef RELIABLE_BYTES_AVAILABLE
1828 QCOMPARE(receiver.bytesAvailable(), qint64(2));
1829#endif
1830 QCOMPARE(receiver.pendingDatagramSize(), qint64(2));
1831
1832 // write another datagram
1833 sender.writeDatagram(datagram: "ab", host: makeNonAny(address: receiver.localAddress()), port);
1834
1835 // no new signal should be emitted because we haven't read the first datagram yet
1836 QTest::qWait(ms: 100);
1837 QCOMPARE(spy.count(), 1);
1838 QVERIFY(receiver.hasPendingDatagrams());
1839 QVERIFY(receiver.bytesAvailable() >= 1); // most likely is 1, but it could be 1 + 2 in the future
1840 QCOMPARE(receiver.pendingDatagramSize(), qint64(2));
1841
1842 // read all the datagrams (we could read one only, but we can't be sure the OS is queueing)
1843 while (receiver.hasPendingDatagrams())
1844 receiver.readDatagram(data: buf, maxlen: sizeof buf);
1845
1846 // write a new datagram and ensure the signal is emitted now
1847 sender.writeDatagram(datagram: "abc", host: makeNonAny(address: receiver.localAddress()), port);
1848 QTest::qWait(ms: 100);
1849 QCOMPARE(spy.count(), 2);
1850 QVERIFY(receiver.hasPendingDatagrams());
1851#ifdef RELIABLE_BYTES_AVAILABLE
1852 QCOMPARE(receiver.bytesAvailable(), qint64(3));
1853#endif
1854 QCOMPARE(receiver.pendingDatagramSize(), qint64(3));
1855}
1856
1857void tst_QUdpSocket::readyReadForEmptyDatagram()
1858{
1859 QFETCH_GLOBAL(bool, setProxy);
1860 if (setProxy)
1861 return;
1862
1863 QUdpSocket sender, receiver;
1864
1865 QVERIFY(receiver.bind(QHostAddress(QHostAddress::AnyIPv4), 0));
1866 quint16 port = receiver.localPort();
1867 QVERIFY(port != 0);
1868
1869 connect(asender: &receiver, SIGNAL(readyRead()), SLOT(empty_readyReadSlot()));
1870
1871 // send an empty datagram to that port
1872 sender.writeDatagram(datagram: "", host: makeNonAny(address: receiver.localAddress()), port);
1873
1874 // ensure that we got a readyRead, despite bytesAvailable() == 0
1875 QTestEventLoop::instance().enterLoop(secs: 1);
1876 QVERIFY(!QTestEventLoop::instance().timeout());
1877
1878 char buf[1];
1879 QVERIFY(receiver.hasPendingDatagrams());
1880 QCOMPARE(receiver.pendingDatagramSize(), qint64(0));
1881#ifdef RELIABLE_BYTES_AVAILABLE
1882 QCOMPARE(receiver.bytesAvailable(), qint64(0));
1883#endif
1884 QCOMPARE(receiver.readDatagram(buf, sizeof buf), qint64(0));
1885}
1886
1887void tst_QUdpSocket::async_readDatagramSlot()
1888{
1889 char buf[1];
1890 QVERIFY(m_asyncReceiver->hasPendingDatagrams());
1891 QCOMPARE(m_asyncReceiver->pendingDatagramSize(), qint64(1));
1892#ifdef RELIABLE_BYTES_AVAILABLE
1893 QCOMPARE(m_asyncReceiver->bytesAvailable(), qint64(1));
1894#endif
1895 QCOMPARE(m_asyncReceiver->readDatagram(buf, sizeof(buf)), qint64(1));
1896
1897 if (buf[0] == '2') {
1898 QTestEventLoop::instance().exitLoop();
1899 return;
1900 }
1901
1902 m_asyncSender->writeDatagram(datagram: "2", host: makeNonAny(address: m_asyncReceiver->localAddress()), port: m_asyncReceiver->localPort());
1903 // wait a little to ensure that the datagram we've just sent
1904 // will be delivered on receiver side.
1905 QTest::qSleep(ms: 100);
1906}
1907
1908void tst_QUdpSocket::asyncReadDatagram()
1909{
1910 QFETCH_GLOBAL(bool, setProxy);
1911 if (setProxy)
1912 return;
1913
1914 m_asyncSender = new QUdpSocket;
1915 m_asyncReceiver = new QUdpSocket;
1916
1917 QVERIFY(m_asyncReceiver->bind(QHostAddress(QHostAddress::AnyIPv4), 0));
1918 quint16 port = m_asyncReceiver->localPort();
1919 QVERIFY(port != 0);
1920
1921 QSignalSpy spy(m_asyncReceiver, SIGNAL(readyRead()));
1922 connect(asender: m_asyncReceiver, SIGNAL(readyRead()), SLOT(async_readDatagramSlot()));
1923
1924 m_asyncSender->writeDatagram(datagram: "1", host: makeNonAny(address: m_asyncReceiver->localAddress()), port);
1925
1926 QTestEventLoop::instance().enterLoop(secs: 1);
1927
1928 QVERIFY(!QTestEventLoop::instance().timeout());
1929 QCOMPARE(spy.count(), 2);
1930
1931 delete m_asyncSender;
1932 delete m_asyncReceiver;
1933}
1934
1935void tst_QUdpSocket::writeInHostLookupState()
1936{
1937 QFETCH_GLOBAL(bool, setProxy);
1938 if (setProxy)
1939 return;
1940
1941 QUdpSocket socket;
1942 socket.connectToHost(hostName: "nosuchserver.qt-project.org", port: 80);
1943 QCOMPARE(socket.state(), QUdpSocket::HostLookupState);
1944 QVERIFY(!socket.putChar('0'));
1945}
1946
1947QTEST_MAIN(tst_QUdpSocket)
1948#include "tst_qudpsocket.moc"
1949

source code of qtbase/tests/auto/network/socket/qudpsocket/tst_qudpsocket.cpp