diff options
Diffstat (limited to 'tests/auto/network/socket/qtcpsocket')
5 files changed, 209 insertions, 42 deletions
diff --git a/tests/auto/network/socket/qtcpsocket/qtcpsocket.pro b/tests/auto/network/socket/qtcpsocket/qtcpsocket.pro index cdab37bd07..347359f508 100644 --- a/tests/auto/network/socket/qtcpsocket/qtcpsocket.pro +++ b/tests/auto/network/socket/qtcpsocket/qtcpsocket.pro @@ -4,6 +4,4 @@ TEMPLATE = subdirs !wince*: SUBDIRS = test stressTest wince*|vxworks* : SUBDIRS = test -linux-*:system(". /etc/lsb-release && [ "$DISTRIB_CODENAME" = oneiric ]"):DEFINES+=UBUNTU_ONEIRIC - requires(contains(QT_CONFIG,private_tests)) diff --git a/tests/auto/network/socket/qtcpsocket/stressTest/Test.cpp b/tests/auto/network/socket/qtcpsocket/stressTest/Test.cpp index 768f122377..ba3ea68d46 100644 --- a/tests/auto/network/socket/qtcpsocket/stressTest/Test.cpp +++ b/tests/auto/network/socket/qtcpsocket/stressTest/Test.cpp @@ -1,7 +1,7 @@ /**************************************************************************** ** -** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). -** Contact: http://www.qt-project.org/legal +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ ** ** This file is part of the test suite of the Qt Toolkit. ** @@ -10,9 +10,9 @@ ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and Digia. For licensing terms and -** conditions see http://qt.digia.com/licensing. For further information -** use the contact form at http://qt.digia.com/contact-us. +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser @@ -23,8 +23,8 @@ ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** -** In addition, as a special exception, Digia gives you certain additional -** rights. These rights are described in the Digia Qt LGPL Exception +** As a special exception, The Qt Company gives you certain additional +** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ** $QT_END_LICENSE$ diff --git a/tests/auto/network/socket/qtcpsocket/stressTest/Test.h b/tests/auto/network/socket/qtcpsocket/stressTest/Test.h index 6c075db5fd..b7b1f9775f 100644 --- a/tests/auto/network/socket/qtcpsocket/stressTest/Test.h +++ b/tests/auto/network/socket/qtcpsocket/stressTest/Test.h @@ -1,7 +1,7 @@ /**************************************************************************** ** -** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). -** Contact: http://www.qt-project.org/legal +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ ** ** This file is part of the test suite of the Qt Toolkit. ** @@ -10,9 +10,9 @@ ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and Digia. For licensing terms and -** conditions see http://qt.digia.com/licensing. For further information -** use the contact form at http://qt.digia.com/contact-us. +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser @@ -23,8 +23,8 @@ ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** -** In addition, as a special exception, Digia gives you certain additional -** rights. These rights are described in the Digia Qt LGPL Exception +** As a special exception, The Qt Company gives you certain additional +** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ** $QT_END_LICENSE$ diff --git a/tests/auto/network/socket/qtcpsocket/stressTest/main.cpp b/tests/auto/network/socket/qtcpsocket/stressTest/main.cpp index e32080ce1d..146161015a 100644 --- a/tests/auto/network/socket/qtcpsocket/stressTest/main.cpp +++ b/tests/auto/network/socket/qtcpsocket/stressTest/main.cpp @@ -1,7 +1,7 @@ /**************************************************************************** ** -** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). -** Contact: http://www.qt-project.org/legal +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ ** ** This file is part of the test suite of the Qt Toolkit. ** @@ -10,9 +10,9 @@ ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and Digia. For licensing terms and -** conditions see http://qt.digia.com/licensing. For further information -** use the contact form at http://qt.digia.com/contact-us. +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser @@ -23,8 +23,8 @@ ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** -** In addition, as a special exception, Digia gives you certain additional -** rights. These rights are described in the Digia Qt LGPL Exception +** As a special exception, The Qt Company gives you certain additional +** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ** $QT_END_LICENSE$ diff --git a/tests/auto/network/socket/qtcpsocket/tst_qtcpsocket.cpp b/tests/auto/network/socket/qtcpsocket/tst_qtcpsocket.cpp index 684bd0db68..0ba9b6a58c 100644 --- a/tests/auto/network/socket/qtcpsocket/tst_qtcpsocket.cpp +++ b/tests/auto/network/socket/qtcpsocket/tst_qtcpsocket.cpp @@ -1,7 +1,7 @@ /**************************************************************************** ** -** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). -** Contact: http://www.qt-project.org/legal +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ ** ** This file is part of the test suite of the Qt Toolkit. ** @@ -10,9 +10,9 @@ ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and Digia. For licensing terms and -** conditions see http://qt.digia.com/licensing. For further information -** use the contact form at http://qt.digia.com/contact-us. +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser @@ -23,8 +23,8 @@ ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** -** In addition, as a special exception, Digia gives you certain additional -** rights. These rights are described in the Digia Qt LGPL Exception +** As a special exception, The Qt Company gives you certain additional +** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ** $QT_END_LICENSE$ @@ -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(); @@ -196,7 +199,7 @@ private slots: void qtbug14268_peek(); void setSocketOption(); - + void clientSendDataOnDelayedDisconnect(); protected slots: void nonBlockingIMAP_hostFound(); @@ -245,6 +248,9 @@ private: int earlyBytesWrittenCount; int earlyReadyReadCount; QString stressTestDir; + + QString firstFailName; + QHostInfo firstFailInfo; }; enum ProxyTests { @@ -297,7 +303,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 @@ -308,6 +317,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() @@ -389,6 +400,7 @@ void tst_QTcpSocket::init() } qt_qhostinfo_clear_cache(); + qt_qhostinfo_cache_inject(firstFailName, firstFailInfo); } QTcpSocket *tst_QTcpSocket::newSocket() const @@ -486,9 +498,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) { @@ -501,10 +516,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 @@ -513,8 +544,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() @@ -523,23 +562,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; } @@ -592,13 +732,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 @@ -615,8 +752,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); @@ -2815,5 +2952,37 @@ void tst_QTcpSocket::setSocketOption() QVERIFY(v.isValid() && v.toInt() == 32); } +// Test buffered socket properly send data on delayed disconnect +void tst_QTcpSocket::clientSendDataOnDelayedDisconnect() +{ + QFETCH_GLOBAL(bool, setProxy); + if (setProxy) + return; + + QTcpServer server; + QTcpSocket *socket = newSocket(); + + QVERIFY(server.listen(QHostAddress::LocalHost)); + + // Connect to server, write data and close socket + const QByteArray sendData("GET /\r\n"); + socket->connectToHost(server.serverAddress(), server.serverPort()); + QVERIFY(socket->waitForConnected(5000)); // ready for write + QCOMPARE(socket->write(sendData), sendData.size()); + socket->close(); + QVERIFY(socket->waitForDisconnected(5000)); // flush buffer + + // Check data on server side + QByteArray recData; + QVERIFY(server.waitForNewConnection(5000)); + QTcpSocket *newConnection = server.nextPendingConnection(); + QVERIFY(newConnection != NULL); + while (newConnection->waitForReadyRead(5000)) // have data to read + recData += newConnection->readAll(); + QCOMPARE(sendData, recData); + + delete socket; +} + QTEST_MAIN(tst_QTcpSocket) #include "tst_qtcpsocket.moc" |