diff options
Diffstat (limited to 'tests/auto/network/socket')
-rw-r--r-- | tests/auto/network/socket/qtcpsocket/tst_qtcpsocket.cpp | 159 | ||||
-rw-r--r-- | tests/auto/network/socket/qudpsocket/tst_qudpsocket.cpp | 36 |
2 files changed, 182 insertions, 13 deletions
diff --git a/tests/auto/network/socket/qtcpsocket/tst_qtcpsocket.cpp b/tests/auto/network/socket/qtcpsocket/tst_qtcpsocket.cpp index 13d8a21794..109e48ed74 100644 --- a/tests/auto/network/socket/qtcpsocket/tst_qtcpsocket.cpp +++ b/tests/auto/network/socket/qtcpsocket/tst_qtcpsocket.cpp @@ -73,6 +73,7 @@ // RVCT compiles also unused inline methods # include <QNetworkProxy> +#include <time.h> #ifdef Q_OS_LINUX #include <stdio.h> #include <stdlib.h> @@ -123,6 +124,8 @@ private slots: void constructing(); void bind_data(); void bind(); + void bindThenResolveHost_data(); + void bindThenResolveHost(); void setInvalidSocketDescriptor(); #ifndef Q_OS_WINRT void setSocketDescriptor(); @@ -246,6 +249,9 @@ private: int earlyBytesWrittenCount; int earlyReadyReadCount; QString stressTestDir; + + QString firstFailName; + QHostInfo firstFailInfo; }; enum ProxyTests { @@ -298,7 +304,10 @@ public: }; tst_QTcpSocket::tst_QTcpSocket() + : firstFailName("qt-test-server-first-fail") { + qsrand(time(NULL)); + tmpSocket = 0; //This code relates to the socketsConstructedBeforeEventLoop test case @@ -309,6 +318,8 @@ tst_QTcpSocket::tst_QTcpSocket() connect(earlyConstructedSockets->endPoints[0], SIGNAL(readyRead()), this, SLOT(earlySocketReadyRead())); connect(earlyConstructedSockets->endPoints[1], SIGNAL(bytesWritten(qint64)), this, SLOT(earlySocketBytesSent(qint64))); earlyConstructedSockets->endPoints[1]->write("hello work"); + + firstFailInfo.setAddresses(QList<QHostAddress>() << QHostAddress("224.0.0.0") << QtNetworkSettings::serverIP()); } tst_QTcpSocket::~tst_QTcpSocket() @@ -390,6 +401,7 @@ void tst_QTcpSocket::init() } qt_qhostinfo_clear_cache(); + qt_qhostinfo_cache_inject(firstFailName, firstFailInfo); } QTcpSocket *tst_QTcpSocket::newSocket() const @@ -487,9 +499,12 @@ void tst_QTcpSocket::constructing() void tst_QTcpSocket::bind_data() { QTest::addColumn<QString>("stringAddr"); + QTest::addColumn<int>("port"); QTest::addColumn<bool>("successExpected"); QTest::addColumn<QString>("stringExpectedLocalAddress"); + bool testIpv6 = false; + // iterate all interfaces, add all addresses on them as test data QList<QNetworkInterface> interfaces = QNetworkInterface::allInterfaces(); foreach (const QNetworkInterface &netinterface, interfaces) { @@ -502,10 +517,26 @@ void tst_QTcpSocket::bind_data() continue; // link-local bind will fail, at least on Linux, so skip it. QString ip(entry.ip().toString()); - QTest::newRow(ip.toLatin1().constData()) << ip << true << ip; + QTest::newRow(ip.toLatin1().constData()) << ip << 0 << true << ip; + + if (!testIpv6 && entry.ip().protocol() == QAbstractSocket::IPv6Protocol) + testIpv6 = true; } } + // test binding to localhost + QTest::newRow("0.0.0.0") << "0.0.0.0" << 0 << true << "0.0.0.0"; + if (testIpv6) + QTest::newRow("[::]") << "::" << 0 << true << "::"; + + // and binding with a port number... + // Since we want to test that we got the port number we asked for, we need a random port number. + // We use random in case a previous run of the test left the port lingering open. + // -1 indicates "random port" + QTest::newRow("0.0.0.0:randomport") << "0.0.0.0" << -1 << true << "0.0.0.0"; + if (testIpv6) + QTest::newRow("[::]:randomport") << "::" << -1 << true << "::"; + // additionally, try bind to known-bad addresses, and make sure this doesn't work // these ranges are guaranteed to be reserved for 'documentation purposes', // and thus, should be unused in the real world. Not that I'm assuming the @@ -514,8 +545,16 @@ void tst_QTcpSocket::bind_data() knownBad << "198.51.100.1"; knownBad << "2001:0DB8::1"; foreach (const QString &badAddress, knownBad) { - QTest::newRow(badAddress.toLatin1().constData()) << badAddress << false << QString(); + QTest::newRow(badAddress.toLatin1().constData()) << badAddress << 0 << false << QString(); } + +#ifdef Q_OS_UNIX + // try to bind to a privileged ports + // we should fail if we're not root (unless the ports are in use!) + QTest::newRow("127.0.0.1:1") << "127.0.0.1" << 1 << !geteuid() << (geteuid() ? QString() : "127.0.0.1"); + if (testIpv6) + QTest::newRow("[::]:1") << "::" << 1 << !geteuid() << (geteuid() ? QString() : "::"); +#endif } void tst_QTcpSocket::bind() @@ -524,23 +563,124 @@ void tst_QTcpSocket::bind() if (setProxy) return; // QTBUG-22964 for proxies, QTBUG-29972 for QSKIP QFETCH(QString, stringAddr); + QFETCH(int, port); QFETCH(bool, successExpected); QFETCH(QString, stringExpectedLocalAddress); QHostAddress addr(stringAddr); QHostAddress expectedLocalAddress(stringExpectedLocalAddress); + QTcpSocket dummySocket; // used only to "use up" a file descriptor + dummySocket.bind(); + QTcpSocket *socket = newSocket(); - qDebug() << "Binding " << addr; + quint16 boundPort; + qintptr fd; if (successExpected) { - QVERIFY2(socket->bind(addr), qPrintable(socket->errorString())); + bool randomPort = port == -1; + int attemptsLeft = 5; // only used with randomPort + do { + if (randomPort) { + // try to get a random port number + // we do this to ensure we're not trying to bind to the same port as we've just used in + // a previous run - race condition with the OS actually freeing the port + Q_STATIC_ASSERT(RAND_MAX > 1024); + port = qrand() & USHRT_MAX; + if (port < 1024) + continue; + } + + bool bindSuccess = socket->bind(addr, port); + if (!bindSuccess && randomPort && socket->error() == QTcpSocket::AddressInUseError) { + // we may have been unlucky and hit an already open port, so try another + --attemptsLeft; + continue; + } + + QVERIFY2(bindSuccess, qPrintable(socket->errorString() + ", tried port " + QString::number(port))); + break; + } while (randomPort && attemptsLeft); + + QCOMPARE(socket->state(), QAbstractSocket::BoundState); + boundPort = socket->localPort(); + if (port) + QCOMPARE(int(boundPort), port); + fd = socket->socketDescriptor(); + QVERIFY(fd != INVALID_SOCKET); } else { - QVERIFY(!socket->bind(addr)); + QVERIFY(!socket->bind(addr, port)); + QCOMPARE(socket->localPort(), quint16(0)); } QCOMPARE(socket->localAddress(), expectedLocalAddress); + if (successExpected) { + // try to use the socket and expect it to remain working + QTcpServer server; + QVERIFY(server.listen(addr)); + + // free up the file descriptor + dummySocket.close(); + + QHostAddress remoteAddr = addr; + if (addr == QHostAddress::AnyIPv4) + remoteAddr = QHostAddress::LocalHost; + else if (addr == QHostAddress::AnyIPv6) + remoteAddr = QHostAddress::LocalHostIPv6; + + socket->connectToHost(remoteAddr, server.serverPort()); + QVERIFY2(socket->waitForConnected(2000), socket->errorString().toLocal8Bit()); + QVERIFY(server.waitForNewConnection(2000)); + + QTcpSocket *acceptedSocket = server.nextPendingConnection(); + QCOMPARE(socket->localPort(), boundPort); + QCOMPARE(acceptedSocket->peerPort(), boundPort); + QCOMPARE(socket->localAddress(), remoteAddr); + QCOMPARE(socket->socketDescriptor(), fd); + } + + delete socket; +} + +//---------------------------------------------------------------------------------- + +void tst_QTcpSocket::bindThenResolveHost_data() +{ + QTest::addColumn<QString>("hostName"); + QTest::newRow("ip-literal") << QtNetworkSettings::serverIP().toString(); + QTest::newRow("name") << QtNetworkSettings::serverName(); + QTest::newRow("first-fail") << firstFailName; +} + +// similar to the previous test, but we'll connect to a host name that needs resolving +void tst_QTcpSocket::bindThenResolveHost() +{ + QFETCH_GLOBAL(bool, setProxy); + if (setProxy) + return; // doesn't make sense to test binding locally with proxies + + QFETCH(QString, hostName); + + QTcpSocket dummySocket; // used only to "use up" a file descriptor + dummySocket.bind(); + + QTcpSocket *socket = newSocket(); + + QVERIFY2(socket->bind(QHostAddress(QHostAddress::AnyIPv4), 0), socket->errorString().toLocal8Bit()); + QCOMPARE(socket->state(), QAbstractSocket::BoundState); + quint16 boundPort = socket->localPort(); + qintptr fd = socket->socketDescriptor(); + QVERIFY(fd != INVALID_SOCKET); + + dummySocket.close(); + + socket->connectToHost(hostName, 80); + QVERIFY2(socket->waitForConnected(), "Network timeout"); + + QCOMPARE(socket->localPort(), boundPort); + QCOMPARE(socket->socketDescriptor(), fd); + delete socket; } @@ -593,13 +733,10 @@ void tst_QTcpSocket::setSocketDescriptor() QCOMPARE(socket->socketDescriptor(), (qintptr)sock); qt_qhostinfo_clear_cache(); //avoid the HostLookupState being skipped due to address being in cache from previous test. - socket->connectToHost(QtNetworkSettings::serverName(), 143); + socket->connectToHost(QtNetworkSettings::serverName(), 80); QCOMPARE(socket->state(), QTcpSocket::HostLookupState); QCOMPARE(socket->socketDescriptor(), (qintptr)sock); QVERIFY(socket->waitForConnected(10000)); - // skip this, it has been broken for years, see task 260735 - // if somebody complains, consider fixing it, but it might break existing applications. - QEXPECT_FAIL("", "bug has been around for years, will not fix without need", Continue); QCOMPARE(socket->socketDescriptor(), (qintptr)sock); delete socket; #ifdef Q_OS_WIN @@ -616,8 +753,8 @@ void tst_QTcpSocket::socketDescriptor() QCOMPARE(socket->socketDescriptor(), (qintptr)-1); socket->connectToHost(QtNetworkSettings::serverName(), 143); - QVERIFY((socket->state() == QAbstractSocket::HostLookupState && socket->socketDescriptor() == -1) || - (socket->state() == QAbstractSocket::ConnectingState && socket->socketDescriptor() != -1)); + QVERIFY(socket->state() == QAbstractSocket::HostLookupState || + socket->state() == QAbstractSocket::ConnectingState); QVERIFY(socket->waitForConnected(10000)); QVERIFY(socket->state() == QAbstractSocket::ConnectedState); QVERIFY(socket->socketDescriptor() != -1); diff --git a/tests/auto/network/socket/qudpsocket/tst_qudpsocket.cpp b/tests/auto/network/socket/qudpsocket/tst_qudpsocket.cpp index 76d4543da9..4bd330b04f 100644 --- a/tests/auto/network/socket/qudpsocket/tst_qudpsocket.cpp +++ b/tests/auto/network/socket/qudpsocket/tst_qudpsocket.cpp @@ -85,7 +85,8 @@ private slots: void dualStack(); void dualStackAutoBinding(); void dualStackNoIPv4onV6only(); - void readLine(); + void connectToHost(); + void bindAndConnectToHost(); void pendingDatagramSize(); void writeDatagram(); void performance(); @@ -621,7 +622,7 @@ void tst_QUdpSocket::empty_connectedSlot() //---------------------------------------------------------------------------------- -void tst_QUdpSocket::readLine() +void tst_QUdpSocket::connectToHost() { QUdpSocket socket1; QUdpSocket socket2; @@ -629,10 +630,41 @@ void tst_QUdpSocket::readLine() socket1.setProperty("_q_networksession", QVariant::fromValue(networkSession)); socket2.setProperty("_q_networksession", QVariant::fromValue(networkSession)); #endif + + QVERIFY2(socket1.bind(), socket1.errorString().toLatin1().constData()); + + socket2.connectToHost(makeNonAny(socket1.localAddress()), socket1.localPort()); + QVERIFY(socket2.waitForConnected(5000)); +} + +//---------------------------------------------------------------------------------- + +void tst_QUdpSocket::bindAndConnectToHost() +{ + QUdpSocket socket1; + QUdpSocket socket2; + QUdpSocket dummysocket; +#ifdef FORCE_SESSION + socket1.setProperty("_q_networksession", QVariant::fromValue(networkSession)); + socket2.setProperty("_q_networksession", QVariant::fromValue(networkSession)); + dummysocket.setProperty("_q_networksession", QVariant::fromValue(networkSession)); +#endif + + // we use the dummy socket to use up a file descriptor + dummysocket.bind(); + + QVERIFY2(socket2.bind(), socket2.errorString().toLatin1()); + quint16 boundPort = socket2.localPort(); + qintptr fd = socket2.socketDescriptor(); + QVERIFY2(socket1.bind(), socket1.errorString().toLatin1().constData()); + dummysocket.close(); socket2.connectToHost(makeNonAny(socket1.localAddress()), socket1.localPort()); QVERIFY(socket2.waitForConnected(5000)); + + QCOMPARE(socket2.localPort(), boundPort); + QCOMPARE(socket2.socketDescriptor(), fd); } //---------------------------------------------------------------------------------- |