diff options
Diffstat (limited to 'tests/auto/network/kernel/qhostinfo/tst_qhostinfo.cpp')
-rw-r--r-- | tests/auto/network/kernel/qhostinfo/tst_qhostinfo.cpp | 362 |
1 files changed, 147 insertions, 215 deletions
diff --git a/tests/auto/network/kernel/qhostinfo/tst_qhostinfo.cpp b/tests/auto/network/kernel/qhostinfo/tst_qhostinfo.cpp index 273bf3a035..bd4bb7ef81 100644 --- a/tests/auto/network/kernel/qhostinfo/tst_qhostinfo.cpp +++ b/tests/auto/network/kernel/qhostinfo/tst_qhostinfo.cpp @@ -1,51 +1,52 @@ // Copyright (C) 2016 The Qt Company Ltd. // Copyright (C) 2016 Intel Corporation. -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only // When using WinSock2 on Windows, it's the first thing that can be included // (except qglobal.h), or else you'll get tons of compile errors #include <qglobal.h> -// To prevent windows system header files from re-defining min/max -#define NOMINMAX 1 - #if defined(Q_OS_WIN) # include <winsock2.h> # include <ws2tcpip.h> #endif -#include <QTest> -#include <QTestEventLoop> -#include <QProcess> +#include <qhostinfo.h> +#include "private/qhostinfo_p.h" +#include "private/qnativesocketengine_p.h" + #include <QCoreApplication> #include <QDebug> -#include <QTcpSocket> #include <QTcpServer> +#include <QTcpSocket> +#include <QTest> +#include <QTestEventLoop> #include <private/qthread_p.h> -#include <time.h> +#include <sys/types.h> + #if defined(Q_OS_WIN) -#include <qt_windows.h> +# include <qt_windows.h> +# ifdef gai_strerror +# undef gai_strerror +# define gai_strerror gai_strerrorA +# endif #else -#include <unistd.h> -#include <signal.h> -#endif - -#include <qhostinfo.h> -#include "private/qhostinfo_p.h" - -#include <sys/types.h> -#if defined(Q_OS_UNIX) -# include <sys/socket.h> # include <netdb.h> +# include <sys/socket.h> +# include <unistd.h> +#endif +#ifndef NI_MAXHOST +# define NI_MAXHOST 1025 #endif #include "../../../network-settings.h" #define TEST_DOMAIN ".test.qt-project.org" +using namespace std::chrono_literals; class tst_QHostInfo : public QObject { @@ -84,15 +85,55 @@ private slots: void cache(); void abortHostLookup(); -protected slots: - void resultsReady(const QHostInfo &); private: bool ipv6LookupsAvailable; bool ipv6Available; - bool lookupDone; - int lookupsDoneCounter; +}; + +class tst_QHostInfo_Helper : public QObject +{ + Q_OBJECT +protected slots: + void resultsReady(const QHostInfo &); +public: + tst_QHostInfo_Helper(const QString &hostname) + : hostname(hostname) + {} + + QString hostname; + bool lookupDone = false; + int lookupsDoneCounter = 0; QHostInfo lookupResults; + + void blockingLookup() + { + lookupResults = QHostInfo::fromName(hostname); + lookupDone = true; + ++lookupsDoneCounter; + } + void lookupHostOldStyle() + { + QHostInfo::lookupHost(hostname, this, SLOT(resultsReady(QHostInfo))); + } + void lookupHostNewStyle() + { + QHostInfo::lookupHost(hostname, this, &tst_QHostInfo_Helper::resultsReady); + } + void lookupHostLambda() + { + QHostInfo::lookupHost(hostname, this, [this](const QHostInfo &hostInfo) { + resultsReady(hostInfo); + }); + } + + bool waitForResults(std::chrono::milliseconds timeout = 15s) + { + QTestEventLoop::instance().enterLoop(timeout); + return !QTestEventLoop::instance().timeout() && lookupDone; + } + + void checkResults(QHostInfo::HostInfoError err, const QString &addresses); }; void tst_QHostInfo::swapFunction() @@ -208,23 +249,12 @@ void tst_QHostInfo::lookupIPv4_data() QTest::newRow("idn-unicode") << QString::fromLatin1("a-single.alqualond\353" TEST_DOMAIN) << "192.0.2.1" << int(QHostInfo::NoError); } -void tst_QHostInfo::lookupIPv4() +void tst_QHostInfo_Helper::checkResults(QHostInfo::HostInfoError err, const QString &addresses) { - QFETCH(QString, hostname); - QFETCH(int, err); - QFETCH(QString, addresses); - - lookupDone = false; - QHostInfo::lookupHost(hostname, this, SLOT(resultsReady(QHostInfo))); - - QTestEventLoop::instance().enterLoop(10); - QVERIFY(!QTestEventLoop::instance().timeout()); - QVERIFY(lookupDone); - if ((int)lookupResults.error() != (int)err) { qWarning() << hostname << "=>" << lookupResults.errorString(); } - QCOMPARE((int)lookupResults.error(), (int)err); + QCOMPARE(lookupResults.error(), err); QStringList tmp; for (int i = 0; i < lookupResults.addresses().size(); ++i) @@ -237,6 +267,18 @@ void tst_QHostInfo::lookupIPv4() QCOMPARE(tmp.join(' '), expected.join(' ')); } +void tst_QHostInfo::lookupIPv4() +{ + QFETCH(QString, hostname); + QFETCH(int, err); + QFETCH(QString, addresses); + + tst_QHostInfo_Helper helper(hostname); + helper.lookupHostOldStyle(); + QVERIFY(helper.waitForResults()); + helper.checkResults(QHostInfo::HostInfoError(err), addresses); +} + void tst_QHostInfo::lookupIPv6_data() { QTest::addColumn<QString>("hostname"); @@ -262,24 +304,10 @@ void tst_QHostInfo::lookupIPv6() if (!ipv6LookupsAvailable) QSKIP("This platform does not support IPv6 lookups"); - lookupDone = false; - QHostInfo::lookupHost(hostname, this, SLOT(resultsReady(QHostInfo))); - - QTestEventLoop::instance().enterLoop(10); - QVERIFY(!QTestEventLoop::instance().timeout()); - QVERIFY(lookupDone); - - QCOMPARE((int)lookupResults.error(), (int)err); - - QStringList tmp; - for (int i = 0; i < lookupResults.addresses().size(); ++i) - tmp.append(lookupResults.addresses().at(i).toString()); - tmp.sort(); - - QStringList expected = addresses.split(' '); - expected.sort(); - - QCOMPARE(tmp.join(' ').toLower(), expected.join(' ').toLower()); + tst_QHostInfo_Helper helper(hostname); + helper.lookupHostOldStyle(); + QVERIFY(helper.waitForResults()); + helper.checkResults(QHostInfo::HostInfoError(err), addresses); } void tst_QHostInfo::lookupConnectToFunctionPointer_data() @@ -293,26 +321,10 @@ void tst_QHostInfo::lookupConnectToFunctionPointer() QFETCH(int, err); QFETCH(QString, addresses); - lookupDone = false; - QHostInfo::lookupHost(hostname, this, &tst_QHostInfo::resultsReady); - - QTestEventLoop::instance().enterLoop(10); - QVERIFY(!QTestEventLoop::instance().timeout()); - QVERIFY(lookupDone); - - if (int(lookupResults.error()) != int(err)) - qWarning() << hostname << "=>" << lookupResults.errorString(); - QCOMPARE(int(lookupResults.error()), int(err)); - - QStringList tmp; - for (const auto &result : lookupResults.addresses()) - tmp.append(result.toString()); - tmp.sort(); - - QStringList expected = addresses.split(' '); - expected.sort(); - - QCOMPARE(tmp.join(' '), expected.join(' ')); + tst_QHostInfo_Helper helper(hostname); + helper.lookupHostNewStyle(); + QVERIFY(helper.waitForResults()); + helper.checkResults(QHostInfo::HostInfoError(err), addresses); } void tst_QHostInfo::lookupConnectToFunctionPointerDeleted() @@ -337,89 +349,38 @@ void tst_QHostInfo::lookupConnectToLambda() QFETCH(int, err); QFETCH(QString, addresses); - lookupDone = false; - QHostInfo::lookupHost(hostname, [this](const QHostInfo &hostInfo) { - resultsReady(hostInfo); - }); - - QTestEventLoop::instance().enterLoop(10); - QVERIFY(!QTestEventLoop::instance().timeout()); - QVERIFY(lookupDone); - - if (int(lookupResults.error()) != int(err)) - qWarning() << hostname << "=>" << lookupResults.errorString(); - QCOMPARE(int(lookupResults.error()), int(err)); - - QStringList tmp; - for (int i = 0; i < lookupResults.addresses().size(); ++i) - tmp.append(lookupResults.addresses().at(i).toString()); - tmp.sort(); - - QStringList expected = addresses.split(' '); - expected.sort(); - - QCOMPARE(tmp.join(' '), expected.join(' ')); + tst_QHostInfo_Helper helper(hostname); + helper.lookupHostLambda(); + QVERIFY(helper.waitForResults()); + helper.checkResults(QHostInfo::HostInfoError(err), addresses); } static QStringList reverseLookupHelper(const QString &ip) { QStringList results; - - const QString pythonCode = - "import socket;" - "import sys;" - "print (socket.getnameinfo((sys.argv[1], 0), 0)[0]);"; - - QList<QByteArray> lines; - QProcess python; - python.setProcessChannelMode(QProcess::ForwardedErrorChannel); - python.start("python3", QStringList() << QString("-c") << pythonCode << ip); - if (python.waitForFinished()) { - if (python.exitStatus() == QProcess::NormalExit && python.exitCode() == 0) - lines = python.readAllStandardOutput().split('\n'); - for (QByteArray line : lines) { - if (!line.isEmpty()) - results << line.trimmed(); - } - if (!results.isEmpty()) - return results; - } - - qDebug() << "Python failed, falling back to nslookup"; - QProcess lookup; - lookup.setProcessChannelMode(QProcess::ForwardedErrorChannel); - lookup.start("nslookup", QStringList(ip)); - if (!lookup.waitForFinished()) { - results << "nslookup failure"; - qDebug() << "nslookup failure"; + union qt_sockaddr { + sockaddr a; + sockaddr_in a4; + sockaddr_in6 a6; + } sa = {}; + + QHostAddress addr(ip); + if (addr.isNull()) { + qWarning("Could not parse IP address: %ls", qUtf16Printable(ip)); return results; } - lines = lookup.readAllStandardOutput().split('\n'); - - QByteArray name; - - const QByteArray nameMarkerNix("name ="); - const QByteArray nameMarkerWin("Name:"); - const QByteArray addressMarkerWin("Address:"); - - for (QByteArray line : lines) { - int index = -1; - if ((index = line.indexOf(nameMarkerNix)) != -1) { // Linux and macOS - name = line.mid(index + nameMarkerNix.size()).chopped(1).trimmed(); - results << name; - } else if (line.startsWith(nameMarkerWin)) { // Windows formatting - name = line.mid(line.lastIndexOf(" ")).trimmed(); - } else if (line.startsWith(addressMarkerWin)) { - QByteArray address = line.mid(addressMarkerWin.size()).trimmed(); - if (address == ip.toUtf8()) { - results << name; - } - } - } - if (results.isEmpty()) { - qDebug() << "Failure to parse nslookup output: " << lines; + // from qnativesocketengine_p.h: + QT_SOCKLEN_T len = setSockaddr(&sa.a, addr, /*port = */ 0); + + QByteArray name(NI_MAXHOST, Qt::Uninitialized); + int ni_flags = NI_NAMEREQD | NI_NUMERICSERV; + if (int r = getnameinfo(&sa.a, len, name.data(), name.size(), nullptr, 0, ni_flags)) { + qWarning("Failed to reverse look up '%ls': %s", qUtf16Printable(ip), gai_strerror(r)); + } else { + results << QString::fromLatin1(name, qstrnlen(name, name.size())); } + return results; } @@ -432,8 +393,10 @@ void tst_QHostInfo::reverseLookup_data() QTest::newRow("dns.google") << QString("8.8.8.8") << reverseLookupHelper("8.8.8.8") << 0 << false; QTest::newRow("one.one.one.one") << QString("1.1.1.1") << reverseLookupHelper("1.1.1.1") << 0 << false; - QTest::newRow("dns.google IPv6") << QString("2001:4860:4860::8888") << reverseLookupHelper("2001:4860:4860::8888") << 0 << true; - QTest::newRow("cloudflare IPv6") << QString("2606:4700:4700::1111") << reverseLookupHelper("2606:4700:4700::1111") << 0 << true; + if (QStringList hostNames = reverseLookupHelper("2001:4860:4860::8888"); !hostNames.isEmpty()) + QTest::newRow("dns.google IPv6") << QString("2001:4860:4860::8888") << std::move(hostNames) << 0 << true; + if (QStringList hostNames = reverseLookupHelper("2606:4700:4700::1111"); !hostNames.isEmpty()) + QTest::newRow("cloudflare IPv6") << QString("2606:4700:4700::1111") << std::move(hostNames) << 0 << true; QTest::newRow("bogus-name IPv6") << QString("1::2::3::4") << QStringList() << 1 << true; } @@ -442,11 +405,6 @@ void tst_QHostInfo::reverseLookup() QFETCH(QString, address); QFETCH(QStringList, hostNames); QFETCH(int, err); - QFETCH(bool, ipv6); - - if (ipv6 && !ipv6LookupsAvailable) { - QSKIP("IPv6 reverse lookups are not supported on this platform"); - } QHostInfo info = QHostInfo::fromName(address); @@ -454,7 +412,7 @@ void tst_QHostInfo::reverseLookup() if (!hostNames.contains(info.hostName())) qDebug() << "Failure: expecting" << hostNames << ",got " << info.hostName(); QVERIFY(hostNames.contains(info.hostName())); - QCOMPARE(info.addresses().first(), QHostAddress(address)); + QCOMPARE(info.addresses().constFirst(), QHostAddress(address)); } else { QCOMPARE(info.hostName(), address); QCOMPARE(info.error(), QHostInfo::HostNotFound); @@ -475,21 +433,9 @@ void tst_QHostInfo::blockingLookup() QFETCH(int, err); QFETCH(QString, addresses); - QHostInfo hostInfo = QHostInfo::fromName(hostname); - QStringList tmp; - for (int i = 0; i < hostInfo.addresses().size(); ++i) - tmp.append(hostInfo.addresses().at(i).toString()); - tmp.sort(); - - if ((int)hostInfo.error() != (int)err) { - qWarning() << hostname << "=>" << lookupResults.errorString(); - } - QCOMPARE((int)hostInfo.error(), (int)err); - - QStringList expected = addresses.split(' '); - expected.sort(); - - QCOMPARE(tmp.join(' ').toUpper(), expected.join(' ').toUpper()); + tst_QHostInfo_Helper helper(hostname); + helper.blockingLookup(); + helper.checkResults(QHostInfo::HostInfoError(err), addresses); } void tst_QHostInfo::raceCondition() @@ -555,24 +501,22 @@ void tst_QHostInfo::threadSafetyAsynchronousAPI() { const int nattempts = 10; const int lookupsperthread = 10; - QList<QThread*> threads; - QList<LookupReceiver*> receivers; + QThread threads[nattempts]; + LookupReceiver receivers[nattempts]; for (int i = 0; i < nattempts; ++i) { - QThread* thread = new QThread; - LookupReceiver* receiver = new LookupReceiver; + QThread *thread = &threads[i]; + LookupReceiver *receiver = &receivers[i]; receiver->numrequests = lookupsperthread; - receivers.append(receiver); receiver->moveToThread(thread); connect(thread, SIGNAL(started()), receiver, SLOT(start())); thread->start(); - threads.append(thread); } - for (int k = threads.size() - 1; k >= 0; --k) - QVERIFY(threads.at(k)->wait(60000)); - foreach (LookupReceiver* receiver, receivers) { - QCOMPARE(receiver->result.error(), QHostInfo::NoError); - QCOMPARE(receiver->result.addresses().at(0).toString(), QString("192.0.2.1")); - QCOMPARE(receiver->numrequests, 0); + for (int k = nattempts - 1; k >= 0; --k) + QVERIFY(threads[k].wait(60000)); + for (LookupReceiver &receiver : receivers) { + QCOMPARE(receiver.result.error(), QHostInfo::NoError); + QCOMPARE(receiver.result.addresses().at(0).toString(), QString("192.0.2.1")); + QCOMPARE(receiver.numrequests, 0); } } @@ -581,17 +525,11 @@ void tst_QHostInfo::threadSafetyAsynchronousAPI() void tst_QHostInfo::multipleSameLookups() { const int COUNT = 10; - lookupsDoneCounter = 0; - + tst_QHostInfo_Helper helper("localhost"); for (int i = 0; i < COUNT; i++) - QHostInfo::lookupHost("localhost", this, SLOT(resultsReady(QHostInfo))); + helper.lookupHostOldStyle(); - QElapsedTimer timer; - timer.start(); - while (timer.elapsed() < 10000 && lookupsDoneCounter < COUNT) { - QTestEventLoop::instance().enterLoop(2); - } - QCOMPARE(lookupsDoneCounter, COUNT); + QTRY_COMPARE_WITH_TIMEOUT(helper.lookupsDoneCounter, COUNT, 10s); } // this test is for the multi-threaded QHostInfo rewrite. It is about getting results at all, @@ -620,19 +558,15 @@ void tst_QHostInfo::multipleDifferentLookups() QFETCH(int, repeats); const int COUNT = hostnameList.size(); - lookupsDoneCounter = 0; + tst_QHostInfo_Helper helper(QString{}); for (int i = 0; i < hostnameList.size(); i++) - for (int j = 0; j < repeats; ++j) - QHostInfo::lookupHost(hostnameList.at(i), this, SLOT(resultsReady(QHostInfo))); - - QElapsedTimer timer; - timer.start(); - while (timer.elapsed() < 60000 && lookupsDoneCounter < repeats*COUNT) { - QTestEventLoop::instance().enterLoop(2); - //qDebug() << "t:" << timer.elapsed(); - } - QCOMPARE(lookupsDoneCounter, repeats*COUNT); + for (int j = 0; j < repeats; ++j) { + helper.hostname = hostnameList.at(i); + helper.lookupHostOldStyle(); + } + + QTRY_COMPARE_WITH_TIMEOUT(helper.lookupsDoneCounter, repeats*COUNT, 60s); } void tst_QHostInfo::cache() @@ -641,13 +575,12 @@ void tst_QHostInfo::cache() if (!cache) return; // test makes only sense when cache enabled - // reset slot counter - lookupsDoneCounter = 0; + tst_QHostInfo_Helper helper("localhost"); // lookup once, wait in event loop, result should not come directly. bool valid = true; int id = -1; - QHostInfo result = qt_qhostinfo_lookup("localhost", this, SLOT(resultsReady(QHostInfo)), &valid, &id); + QHostInfo result = qt_qhostinfo_lookup(helper.hostname, &helper, SLOT(resultsReady(QHostInfo)), &valid, &id); QTestEventLoop::instance().enterLoop(5); QVERIFY(!QTestEventLoop::instance().timeout()); QVERIFY(!valid); @@ -655,7 +588,7 @@ void tst_QHostInfo::cache() // loopkup second time, result should come directly valid = false; - result = qt_qhostinfo_lookup("localhost", this, SLOT(resultsReady(QHostInfo)), &valid, &id); + result = qt_qhostinfo_lookup(helper.hostname, &helper, SLOT(resultsReady(QHostInfo)), &valid, &id); QVERIFY(valid); QVERIFY(!result.addresses().isEmpty()); @@ -664,17 +597,17 @@ void tst_QHostInfo::cache() // lookup third time, result should not come directly. valid = true; - result = qt_qhostinfo_lookup("localhost", this, SLOT(resultsReady(QHostInfo)), &valid, &id); + result = qt_qhostinfo_lookup(helper.hostname, &helper, SLOT(resultsReady(QHostInfo)), &valid, &id); QTestEventLoop::instance().enterLoop(5); QVERIFY(!QTestEventLoop::instance().timeout()); QVERIFY(!valid); QVERIFY(result.addresses().isEmpty()); // the slot should have been called 2 times. - QCOMPARE(lookupsDoneCounter, 2); + QCOMPARE(helper.lookupsDoneCounter, 2); } -void tst_QHostInfo::resultsReady(const QHostInfo &hi) +void tst_QHostInfo_Helper::resultsReady(const QHostInfo &hi) { QVERIFY(QThread::currentThread() == thread()); lookupDone = true; @@ -685,16 +618,15 @@ void tst_QHostInfo::resultsReady(const QHostInfo &hi) void tst_QHostInfo::abortHostLookup() { - //reset counter - lookupsDoneCounter = 0; + tst_QHostInfo_Helper helper("a-single" TEST_DOMAIN); bool valid = false; int id = -1; - QHostInfo result = qt_qhostinfo_lookup("a-single" TEST_DOMAIN, this, SLOT(resultsReady(QHostInfo)), &valid, &id); + QHostInfo result = qt_qhostinfo_lookup(helper.hostname, &helper, SLOT(resultsReady(QHostInfo)), &valid, &id); QVERIFY(!valid); //it is assumed that the DNS request/response in the backend is slower than it takes to call abort QHostInfo::abortHostLookup(id); QTestEventLoop::instance().enterLoop(5); - QCOMPARE(lookupsDoneCounter, 0); + QCOMPARE(helper.lookupsDoneCounter, 0); } class LookupAborter : public QObject |