5635823e17
As in the past, to avoid rewriting various autotests that contain line-number information, an extra blank line has been inserted at the end of the license text to ensure that this commit does not change the total number of lines in the license header. Change-Id: I311e001373776812699d6efc045b5f742890c689 Reviewed-by: Rohan McGovern <rohan.mcgovern@nokia.com>
827 lines
26 KiB
C++
827 lines
26 KiB
C++
/****************************************************************************
|
|
**
|
|
** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
|
|
** Contact: http://www.qt-project.org/
|
|
**
|
|
** This file is part of the test suite of the Qt Toolkit.
|
|
**
|
|
** $QT_BEGIN_LICENSE:LGPL$
|
|
** GNU Lesser General Public License Usage
|
|
** This file may be used under the terms of the GNU Lesser General Public
|
|
** License version 2.1 as published by the Free Software Foundation and
|
|
** appearing in the file LICENSE.LGPL included in the packaging of this
|
|
** file. Please review the following information to ensure the GNU Lesser
|
|
** General Public License version 2.1 requirements will be met:
|
|
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
|
**
|
|
** In addition, as a special exception, Nokia gives you certain additional
|
|
** rights. These rights are described in the Nokia Qt LGPL Exception
|
|
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
|
**
|
|
** GNU General Public License Usage
|
|
** Alternatively, this file may be used under the terms of the GNU General
|
|
** Public License version 3.0 as published by the Free Software Foundation
|
|
** and appearing in the file LICENSE.GPL included in the packaging of this
|
|
** file. Please review the following information to ensure the GNU General
|
|
** Public License version 3.0 requirements will be met:
|
|
** http://www.gnu.org/copyleft/gpl.html.
|
|
**
|
|
** Other Usage
|
|
** Alternatively, this file may be used in accordance with the terms and
|
|
** conditions contained in a signed written agreement between you and Nokia.
|
|
**
|
|
**
|
|
**
|
|
**
|
|
**
|
|
**
|
|
** $QT_END_LICENSE$
|
|
**
|
|
****************************************************************************/
|
|
|
|
#include <qglobal.h>
|
|
#if defined(_WIN32)
|
|
#include <winsock2.h>
|
|
#else
|
|
#include <sys/types.h>
|
|
#include <sys/socket.h>
|
|
#define SOCKET int
|
|
#define INVALID_SOCKET -1
|
|
#endif
|
|
|
|
#include <QtTest/QtTest>
|
|
|
|
#ifndef Q_OS_WIN
|
|
#include <unistd.h>
|
|
#include <sys/ioctl.h>
|
|
#endif
|
|
|
|
#include <qcoreapplication.h>
|
|
#include <qtcpsocket.h>
|
|
#include <qtcpserver.h>
|
|
#include <qhostaddress.h>
|
|
#include <qprocess.h>
|
|
#include <qstringlist.h>
|
|
#include <qplatformdefs.h>
|
|
#include <qhostinfo.h>
|
|
|
|
#include <QNetworkProxy>
|
|
Q_DECLARE_METATYPE(QNetworkProxy)
|
|
Q_DECLARE_METATYPE(QList<QNetworkProxy>)
|
|
|
|
#include <QNetworkSession>
|
|
#include <QNetworkConfiguration>
|
|
#include <QNetworkConfigurationManager>
|
|
#include "../../../network-settings.h"
|
|
|
|
class tst_QTcpServer : public QObject
|
|
{
|
|
Q_OBJECT
|
|
|
|
public:
|
|
tst_QTcpServer();
|
|
virtual ~tst_QTcpServer();
|
|
|
|
|
|
public slots:
|
|
void initTestCase_data();
|
|
void initTestCase();
|
|
void init();
|
|
void cleanup();
|
|
private slots:
|
|
void getSetCheck();
|
|
void constructing();
|
|
void clientServerLoop();
|
|
void ipv6Server();
|
|
void dualStack_data();
|
|
void dualStack();
|
|
void ipv6ServerMapped();
|
|
void crashTests();
|
|
void maxPendingConnections();
|
|
void listenError();
|
|
void waitForConnectionTest();
|
|
void setSocketDescriptor();
|
|
void listenWhileListening();
|
|
#ifndef QT_NO_PROCESS
|
|
void addressReusable();
|
|
#endif
|
|
void setNewSocketDescriptorBlocking();
|
|
void invalidProxy_data();
|
|
void invalidProxy();
|
|
void proxyFactory_data();
|
|
void proxyFactory();
|
|
|
|
void qtbug14268_peek();
|
|
|
|
void serverAddress_data();
|
|
void serverAddress();
|
|
private:
|
|
#ifndef QT_NO_BEARERMANAGEMENT
|
|
QNetworkSession *networkSession;
|
|
#endif
|
|
};
|
|
|
|
// Testing get/set functions
|
|
void tst_QTcpServer::getSetCheck()
|
|
{
|
|
QTcpServer obj1;
|
|
// int QTcpServer::maxPendingConnections()
|
|
// void QTcpServer::setMaxPendingConnections(int)
|
|
obj1.setMaxPendingConnections(0);
|
|
QCOMPARE(0, obj1.maxPendingConnections());
|
|
obj1.setMaxPendingConnections(INT_MIN);
|
|
QCOMPARE(INT_MIN, obj1.maxPendingConnections());
|
|
obj1.setMaxPendingConnections(INT_MAX);
|
|
QCOMPARE(INT_MAX, obj1.maxPendingConnections());
|
|
}
|
|
|
|
tst_QTcpServer::tst_QTcpServer()
|
|
{
|
|
}
|
|
|
|
tst_QTcpServer::~tst_QTcpServer()
|
|
{
|
|
}
|
|
|
|
void tst_QTcpServer::initTestCase_data()
|
|
{
|
|
QTest::addColumn<bool>("setProxy");
|
|
QTest::addColumn<int>("proxyType");
|
|
|
|
QTest::newRow("WithoutProxy") << false << 0;
|
|
QTest::newRow("WithSocks5Proxy") << true << int(QNetworkProxy::Socks5Proxy);
|
|
}
|
|
|
|
void tst_QTcpServer::initTestCase()
|
|
{
|
|
QVERIFY(QtNetworkSettings::verifyTestNetworkSettings());
|
|
#ifndef QT_NO_BEARERMANAGEMENT
|
|
QNetworkConfigurationManager man;
|
|
networkSession = new QNetworkSession(man.defaultConfiguration(), this);
|
|
networkSession->open();
|
|
QVERIFY(networkSession->waitForOpened());
|
|
#endif
|
|
}
|
|
|
|
void tst_QTcpServer::init()
|
|
{
|
|
QFETCH_GLOBAL(bool, setProxy);
|
|
if (setProxy) {
|
|
QFETCH_GLOBAL(int, proxyType);
|
|
if (proxyType == QNetworkProxy::Socks5Proxy) {
|
|
QNetworkProxy::setApplicationProxy(QNetworkProxy(QNetworkProxy::Socks5Proxy, QtNetworkSettings::serverName(), 1080));
|
|
}
|
|
}
|
|
}
|
|
|
|
void tst_QTcpServer::cleanup()
|
|
{
|
|
QNetworkProxy::setApplicationProxy(QNetworkProxy::DefaultProxy);
|
|
}
|
|
|
|
//----------------------------------------------------------------------------------
|
|
|
|
void tst_QTcpServer::constructing()
|
|
{
|
|
QTcpServer socket;
|
|
|
|
// Check the initial state of the QTcpSocket.
|
|
QCOMPARE(socket.isListening(), false);
|
|
QCOMPARE((int)socket.serverPort(), 0);
|
|
QCOMPARE(socket.serverAddress(), QHostAddress());
|
|
QCOMPARE(socket.maxPendingConnections(), 30);
|
|
QCOMPARE(socket.hasPendingConnections(), false);
|
|
QCOMPARE(socket.socketDescriptor(), (qintptr)-1);
|
|
QCOMPARE(socket.serverError(), QAbstractSocket::UnknownSocketError);
|
|
|
|
// Check the state of the socket layer?
|
|
}
|
|
|
|
//----------------------------------------------------------------------------------
|
|
void tst_QTcpServer::clientServerLoop()
|
|
{
|
|
QTcpServer server;
|
|
|
|
QSignalSpy spy(&server, SIGNAL(newConnection()));
|
|
|
|
QVERIFY(!server.isListening());
|
|
QVERIFY(!server.hasPendingConnections());
|
|
QVERIFY(server.listen(QHostAddress::Any, 11423));
|
|
QVERIFY(server.isListening());
|
|
|
|
QTcpSocket client;
|
|
|
|
QHostAddress serverAddress = QHostAddress::LocalHost;
|
|
if (!(server.serverAddress() == QHostAddress::Any) && !(server.serverAddress() == QHostAddress::AnyIPv6))
|
|
serverAddress = server.serverAddress();
|
|
|
|
client.connectToHost(serverAddress, server.serverPort());
|
|
QVERIFY(client.waitForConnected(5000));
|
|
|
|
QVERIFY(server.waitForNewConnection(5000));
|
|
QVERIFY(server.hasPendingConnections());
|
|
|
|
QCOMPARE(spy.count(), 1);
|
|
|
|
QTcpSocket *serverSocket = server.nextPendingConnection();
|
|
QVERIFY(serverSocket != 0);
|
|
|
|
QVERIFY(serverSocket->write("Greetings, client!\n", 19) == 19);
|
|
serverSocket->flush();
|
|
|
|
QVERIFY(client.waitForReadyRead(5000));
|
|
QByteArray arr = client.readAll();
|
|
QCOMPARE(arr.constData(), "Greetings, client!\n");
|
|
|
|
QVERIFY(client.write("Well, hello to you!\n", 20) == 20);
|
|
client.flush();
|
|
|
|
QVERIFY(serverSocket->waitForReadyRead(5000));
|
|
arr = serverSocket->readAll();
|
|
QCOMPARE(arr.constData(), "Well, hello to you!\n");
|
|
}
|
|
|
|
//----------------------------------------------------------------------------------
|
|
void tst_QTcpServer::ipv6Server()
|
|
{
|
|
//### need to enter the event loop for the server to get the connection ?? ( windows)
|
|
QTcpServer server;
|
|
if (!server.listen(QHostAddress::LocalHostIPv6, 8944)) {
|
|
QVERIFY(server.serverError() == QAbstractSocket::UnsupportedSocketOperationError);
|
|
return;
|
|
}
|
|
|
|
QVERIFY(server.serverPort() == 8944);
|
|
QVERIFY(server.serverAddress() == QHostAddress::LocalHostIPv6);
|
|
|
|
QTcpSocket client;
|
|
client.connectToHost("::1", 8944);
|
|
QVERIFY(client.waitForConnected(5000));
|
|
|
|
QVERIFY(server.waitForNewConnection());
|
|
QVERIFY(server.hasPendingConnections());
|
|
|
|
QTcpSocket *serverSocket = 0;
|
|
QVERIFY((serverSocket = server.nextPendingConnection()));
|
|
serverSocket->close();
|
|
delete serverSocket;
|
|
}
|
|
|
|
Q_DECLARE_METATYPE(QHostAddress);
|
|
|
|
void tst_QTcpServer::dualStack_data()
|
|
{
|
|
QTest::addColumn<QHostAddress>("bindAddress");
|
|
QTest::addColumn<bool>("v4ok");
|
|
QTest::addColumn<bool>("v6ok");
|
|
QTest::newRow("any") << QHostAddress(QHostAddress::Any) << true << true;
|
|
QTest::newRow("anyIPv4") << QHostAddress(QHostAddress::AnyIPv4) << true << false;
|
|
QTest::newRow("anyIPv6") << QHostAddress(QHostAddress::AnyIPv6) << false << true;
|
|
}
|
|
|
|
void tst_QTcpServer::dualStack()
|
|
{
|
|
QFETCH_GLOBAL(bool, setProxy);
|
|
if (setProxy)
|
|
QSKIP("test server proxy doesn't support ipv6");
|
|
QFETCH(QHostAddress, bindAddress);
|
|
QFETCH(bool, v4ok);
|
|
QFETCH(bool, v6ok);
|
|
|
|
QTcpServer server;
|
|
QVERIFY(server.listen(bindAddress));
|
|
|
|
QTcpSocket v4client;
|
|
v4client.connectToHost(QHostAddress::LocalHost, server.serverPort());
|
|
|
|
QTcpSocket v6client;
|
|
v6client.connectToHost(QHostAddress::LocalHostIPv6, server.serverPort());
|
|
|
|
QCOMPARE(v4client.waitForConnected(5000), v4ok);
|
|
QCOMPARE(v6client.waitForConnected(5000), v6ok);
|
|
}
|
|
|
|
//----------------------------------------------------------------------------------
|
|
void tst_QTcpServer::ipv6ServerMapped()
|
|
{
|
|
QFETCH_GLOBAL(bool, setProxy);
|
|
if (setProxy)
|
|
return;
|
|
|
|
QTcpServer server;
|
|
QVERIFY(server.listen(QHostAddress::LocalHost));
|
|
|
|
// let's try the normal case
|
|
QTcpSocket client1;
|
|
client1.connectToHost("127.0.0.1", server.serverPort());
|
|
QVERIFY(server.waitForNewConnection(5000));
|
|
delete server.nextPendingConnection();
|
|
|
|
// let's try the mapped one in the nice format
|
|
QTcpSocket client2;
|
|
client2.connectToHost("::ffff:127.0.0.1", server.serverPort());
|
|
QVERIFY(server.waitForNewConnection(5000));
|
|
delete server.nextPendingConnection();
|
|
|
|
// let's try the mapped in hex format
|
|
QTcpSocket client3;
|
|
client3.connectToHost("::ffff:7F00:0001", server.serverPort());
|
|
QVERIFY(server.waitForNewConnection(5000));
|
|
delete server.nextPendingConnection();
|
|
|
|
// However connecting to the v6 localhost should not work
|
|
QTcpSocket client4;
|
|
client4.connectToHost("::1", server.serverPort());
|
|
QVERIFY(!server.waitForNewConnection(5000));
|
|
}
|
|
|
|
//----------------------------------------------------------------------------------
|
|
void tst_QTcpServer::crashTests()
|
|
{
|
|
QTcpServer server;
|
|
server.close();
|
|
QVERIFY(server.listen());
|
|
}
|
|
|
|
//----------------------------------------------------------------------------------
|
|
void tst_QTcpServer::maxPendingConnections()
|
|
{
|
|
QFETCH_GLOBAL(bool, setProxy);
|
|
if (setProxy) {
|
|
QFETCH_GLOBAL(int, proxyType);
|
|
if (proxyType == QNetworkProxy::Socks5Proxy)
|
|
QSKIP("With socks5 only 1 connection is allowed ever");
|
|
}
|
|
//### sees to fail sometimes ... a timing issue with the test on windows
|
|
QTcpServer server;
|
|
server.setMaxPendingConnections(2);
|
|
|
|
QTcpSocket socket1;
|
|
QTcpSocket socket2;
|
|
QTcpSocket socket3;
|
|
|
|
QVERIFY(server.listen());
|
|
|
|
socket1.connectToHost(QHostAddress::LocalHost, server.serverPort());
|
|
socket2.connectToHost(QHostAddress::LocalHost, server.serverPort());
|
|
socket3.connectToHost(QHostAddress::LocalHost, server.serverPort());
|
|
|
|
QVERIFY(server.waitForNewConnection(5000));
|
|
|
|
QVERIFY(server.hasPendingConnections());
|
|
QVERIFY(server.nextPendingConnection());
|
|
QVERIFY(server.hasPendingConnections());
|
|
QVERIFY(server.nextPendingConnection());
|
|
QVERIFY(!server.hasPendingConnections());
|
|
QCOMPARE(server.nextPendingConnection(), (QTcpSocket*)0);
|
|
|
|
QVERIFY(server.waitForNewConnection(5000));
|
|
|
|
QVERIFY(server.hasPendingConnections());
|
|
QVERIFY(server.nextPendingConnection());
|
|
}
|
|
|
|
//----------------------------------------------------------------------------------
|
|
void tst_QTcpServer::listenError()
|
|
{
|
|
QFETCH_GLOBAL(bool, setProxy);
|
|
if (setProxy) {
|
|
QFETCH_GLOBAL(int, proxyType);
|
|
if (proxyType == QNetworkProxy::Socks5Proxy)
|
|
QSKIP("With socks5 we can not make hard requirements on the address or port");
|
|
}
|
|
QTcpServer server;
|
|
QVERIFY(!server.listen(QHostAddress("1.2.3.4"), 0));
|
|
QCOMPARE(server.serverError(), QAbstractSocket::SocketAddressNotAvailableError);
|
|
QCOMPARE(server.errorString().toLatin1().constData(), "The address is not available");
|
|
}
|
|
|
|
class ThreadConnector : public QThread
|
|
{
|
|
public:
|
|
ThreadConnector(const QHostAddress &host, quint16 port)
|
|
: host(host), port(port)
|
|
{ }
|
|
|
|
~ThreadConnector()
|
|
{
|
|
wait();
|
|
}
|
|
|
|
protected:
|
|
void run()
|
|
{
|
|
sleep(2);
|
|
|
|
QTcpSocket socket;
|
|
socket.connectToHost(host, port);
|
|
|
|
QEventLoop loop;
|
|
QTimer::singleShot(5000, &loop, SLOT(quit()));
|
|
loop.exec();
|
|
}
|
|
|
|
private:
|
|
QHostAddress host;
|
|
quint16 port;
|
|
};
|
|
|
|
//----------------------------------------------------------------------------------
|
|
void tst_QTcpServer::waitForConnectionTest()
|
|
{
|
|
|
|
QFETCH_GLOBAL(bool, setProxy);
|
|
if (setProxy) {
|
|
QFETCH_GLOBAL(int, proxyType);
|
|
if (proxyType == QNetworkProxy::Socks5Proxy)
|
|
QSKIP("Localhost servers don't work well with SOCKS5");
|
|
}
|
|
|
|
QTcpSocket findLocalIpSocket;
|
|
findLocalIpSocket.connectToHost(QtNetworkSettings::serverName(), 143);
|
|
QVERIFY(findLocalIpSocket.waitForConnected(5000));
|
|
|
|
QTcpServer server;
|
|
bool timeout = false;
|
|
QVERIFY(server.listen(findLocalIpSocket.localAddress()));
|
|
QVERIFY(!server.waitForNewConnection(1000, &timeout));
|
|
QCOMPARE(server.serverError(), QAbstractSocket::SocketTimeoutError);
|
|
QVERIFY(timeout);
|
|
|
|
ThreadConnector connector(findLocalIpSocket.localAddress(), server.serverPort());
|
|
connector.start();
|
|
|
|
#if defined(Q_OS_WINCE)
|
|
QVERIFY(server.waitForNewConnection(9000, &timeout));
|
|
#else
|
|
QVERIFY(server.waitForNewConnection(3000, &timeout));
|
|
#endif
|
|
QVERIFY(!timeout);
|
|
}
|
|
|
|
//----------------------------------------------------------------------------------
|
|
void tst_QTcpServer::setSocketDescriptor()
|
|
{
|
|
QTcpServer server;
|
|
QVERIFY(!server.setSocketDescriptor(42));
|
|
QCOMPARE(server.serverError(), QAbstractSocket::UnsupportedSocketOperationError);
|
|
//adopting Open C sockets is not supported, neither is adopting externally created RSocket
|
|
#ifdef Q_OS_WIN
|
|
// ensure winsock is started
|
|
WSADATA wsaData;
|
|
QVERIFY(WSAStartup(MAKEWORD(2,0), &wsaData) == NO_ERROR);
|
|
#endif
|
|
|
|
SOCKET sock = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
|
|
|
|
QVERIFY(sock != INVALID_SOCKET);
|
|
|
|
sockaddr_in sin;
|
|
memset(&sin, 0, sizeof(sockaddr_in));
|
|
sin.sin_family = AF_INET;
|
|
sin.sin_port = 0;
|
|
sin.sin_addr.s_addr = 0x00000000;
|
|
QVERIFY(::bind(sock, (sockaddr*)&sin, sizeof(sockaddr_in)) == 0);
|
|
QVERIFY(::listen(sock, 10) == 0);
|
|
QVERIFY(server.setSocketDescriptor(sock));
|
|
|
|
#ifdef Q_OS_WIN
|
|
WSACleanup();
|
|
#endif
|
|
}
|
|
|
|
//----------------------------------------------------------------------------------
|
|
void tst_QTcpServer::listenWhileListening()
|
|
{
|
|
QTcpServer server;
|
|
QVERIFY(server.listen());
|
|
QTest::ignoreMessage(QtWarningMsg, "QTcpServer::listen() called when already listening");
|
|
QVERIFY(!server.listen());
|
|
}
|
|
|
|
//----------------------------------------------------------------------------------
|
|
|
|
class SeverWithBlockingSockets : public QTcpServer
|
|
{
|
|
public:
|
|
SeverWithBlockingSockets()
|
|
: ok(false) { }
|
|
|
|
bool ok;
|
|
|
|
protected:
|
|
void incomingConnection(qintptr socketDescriptor)
|
|
{
|
|
// how a user woulddo it (qabstractsocketengine is not public)
|
|
unsigned long arg = 0;
|
|
#if defined(Q_OS_WIN)
|
|
ok = ::ioctlsocket(socketDescriptor, FIONBIO, &arg) == 0;
|
|
::closesocket(socketDescriptor);
|
|
#else
|
|
ok = ::ioctl(socketDescriptor, FIONBIO, &arg) == 0;
|
|
::close(socketDescriptor);
|
|
#endif
|
|
}
|
|
};
|
|
|
|
#ifndef QT_NO_PROCESS
|
|
void tst_QTcpServer::addressReusable()
|
|
{
|
|
QFETCH_GLOBAL(bool, setProxy);
|
|
if (setProxy) {
|
|
QFETCH_GLOBAL(int, proxyType);
|
|
if (proxyType == QNetworkProxy::Socks5Proxy)
|
|
QSKIP("With socks5 this test does not make senans at the momment");
|
|
}
|
|
#if defined(Q_OS_WINCE)
|
|
QString signalName = QString::fromLatin1("/test_signal.txt");
|
|
QFile::remove(signalName);
|
|
// The crashingServer process will crash once it gets a connection.
|
|
QProcess process;
|
|
process.start("crashingServer/crashingServer");
|
|
int waitCount = 5;
|
|
while (waitCount-- && !QFile::exists(signalName))
|
|
QTest::qWait(1000);
|
|
QVERIFY(QFile::exists(signalName));
|
|
QFile::remove(signalName);
|
|
#else
|
|
// The crashingServer process will crash once it gets a connection.
|
|
QProcess process;
|
|
process.start("crashingServer/crashingServer");
|
|
QVERIFY(process.waitForReadyRead(5000));
|
|
#endif
|
|
|
|
QTcpSocket socket;
|
|
socket.connectToHost(QHostAddress::LocalHost, 49199);
|
|
QVERIFY(socket.waitForConnected(5000));
|
|
|
|
QVERIFY(process.waitForFinished(30000));
|
|
|
|
// Give the system some time.
|
|
QTest::qSleep(10);
|
|
|
|
QTcpServer server;
|
|
QVERIFY(server.listen(QHostAddress::LocalHost, 49199));
|
|
}
|
|
#endif
|
|
|
|
void tst_QTcpServer::setNewSocketDescriptorBlocking()
|
|
{
|
|
QFETCH_GLOBAL(bool, setProxy);
|
|
if (setProxy) {
|
|
QFETCH_GLOBAL(int, proxyType);
|
|
if (proxyType == QNetworkProxy::Socks5Proxy)
|
|
QSKIP("With socks5 we can not make the socket descripter blocking");
|
|
}
|
|
SeverWithBlockingSockets server;
|
|
QVERIFY(server.listen());
|
|
|
|
QTcpSocket socket;
|
|
socket.connectToHost(QHostAddress::LocalHost, server.serverPort());
|
|
QVERIFY(server.waitForNewConnection(5000));
|
|
QVERIFY(server.ok);
|
|
}
|
|
|
|
void tst_QTcpServer::invalidProxy_data()
|
|
{
|
|
QTest::addColumn<int>("type");
|
|
QTest::addColumn<QString>("host");
|
|
QTest::addColumn<int>("port");
|
|
QTest::addColumn<int>("expectedError");
|
|
|
|
QString fluke = QHostInfo::fromName(QtNetworkSettings::serverName()).addresses().first().toString();
|
|
QTest::newRow("ftp-proxy") << int(QNetworkProxy::FtpCachingProxy) << fluke << 143
|
|
<< int(QAbstractSocket::UnsupportedSocketOperationError);
|
|
QTest::newRow("http-proxy") << int(QNetworkProxy::HttpProxy) << fluke << 3128
|
|
<< int(QAbstractSocket::UnsupportedSocketOperationError);
|
|
|
|
QTest::newRow("no-such-host") << int(QNetworkProxy::Socks5Proxy)
|
|
<< "this-host-will-never-exist.troll.no" << 1080
|
|
<< int(QAbstractSocket::ProxyNotFoundError);
|
|
QTest::newRow("socks5-on-http") << int(QNetworkProxy::Socks5Proxy) << fluke << 3128
|
|
<< int(QAbstractSocket::SocketTimeoutError);
|
|
}
|
|
|
|
void tst_QTcpServer::invalidProxy()
|
|
{
|
|
QFETCH_GLOBAL(bool, setProxy);
|
|
if (setProxy)
|
|
return;
|
|
|
|
QFETCH(int, type);
|
|
QFETCH(QString, host);
|
|
QFETCH(int, port);
|
|
QNetworkProxy::ProxyType proxyType = QNetworkProxy::ProxyType(type);
|
|
QNetworkProxy proxy(proxyType, host, port);
|
|
|
|
QTcpServer server;
|
|
server.setProxy(proxy);
|
|
bool listenResult = server.listen();
|
|
|
|
QVERIFY(!listenResult);
|
|
QVERIFY(!server.errorString().isEmpty());
|
|
|
|
// note: the following test is not a hard failure.
|
|
// Sometimes, error codes change for the better
|
|
QTEST(int(server.serverError()), "expectedError");
|
|
}
|
|
|
|
// copied from tst_qnetworkreply.cpp
|
|
class MyProxyFactory: public QNetworkProxyFactory
|
|
{
|
|
public:
|
|
int callCount;
|
|
QList<QNetworkProxy> toReturn;
|
|
QNetworkProxyQuery lastQuery;
|
|
inline MyProxyFactory() { clear(); }
|
|
|
|
inline void clear()
|
|
{
|
|
callCount = 0;
|
|
toReturn = QList<QNetworkProxy>() << QNetworkProxy::DefaultProxy;
|
|
lastQuery = QNetworkProxyQuery();
|
|
}
|
|
|
|
virtual QList<QNetworkProxy> queryProxy(const QNetworkProxyQuery &query)
|
|
{
|
|
lastQuery = query;
|
|
++callCount;
|
|
return toReturn;
|
|
}
|
|
};
|
|
|
|
void tst_QTcpServer::proxyFactory_data()
|
|
{
|
|
QTest::addColumn<QList<QNetworkProxy> >("proxyList");
|
|
QTest::addColumn<QNetworkProxy>("proxyUsed");
|
|
QTest::addColumn<bool>("fails");
|
|
QTest::addColumn<int>("expectedError");
|
|
|
|
QList<QNetworkProxy> proxyList;
|
|
|
|
// tests that do get to listen
|
|
|
|
proxyList << QNetworkProxy(QNetworkProxy::Socks5Proxy, QtNetworkSettings::serverName(), 1080);
|
|
QTest::newRow("socks5")
|
|
<< proxyList << proxyList.at(0)
|
|
<< false << int(QAbstractSocket::UnknownSocketError);
|
|
|
|
proxyList.clear();
|
|
proxyList << QNetworkProxy(QNetworkProxy::HttpCachingProxy, QtNetworkSettings::serverName(), 3128)
|
|
<< QNetworkProxy(QNetworkProxy::Socks5Proxy, QtNetworkSettings::serverName(), 1080);
|
|
QTest::newRow("cachinghttp+socks5")
|
|
<< proxyList << proxyList.at(1)
|
|
<< false << int(QAbstractSocket::UnknownSocketError);
|
|
|
|
proxyList.clear();
|
|
proxyList << QNetworkProxy(QNetworkProxy::FtpCachingProxy, QtNetworkSettings::serverName(), 2121)
|
|
<< QNetworkProxy(QNetworkProxy::HttpCachingProxy, QtNetworkSettings::serverName(), 3128)
|
|
<< QNetworkProxy(QNetworkProxy::Socks5Proxy, QtNetworkSettings::serverName(), 1080);
|
|
QTest::newRow("ftp+cachinghttp+socks5")
|
|
<< proxyList << proxyList.at(2)
|
|
<< false << int(QAbstractSocket::UnknownSocketError);
|
|
|
|
// tests that fail to listen
|
|
proxyList.clear();
|
|
proxyList << QNetworkProxy(QNetworkProxy::HttpProxy, QtNetworkSettings::serverName(), 3128);
|
|
QTest::newRow("http")
|
|
<< proxyList << proxyList.at(0)
|
|
<< true << int(QAbstractSocket::UnsupportedSocketOperationError);
|
|
|
|
proxyList.clear();
|
|
proxyList << QNetworkProxy(QNetworkProxy::HttpCachingProxy, QtNetworkSettings::serverName(), 3128);
|
|
QTest::newRow("cachinghttp")
|
|
<< proxyList << QNetworkProxy()
|
|
<< true << int(QAbstractSocket::UnsupportedSocketOperationError);
|
|
|
|
proxyList.clear();
|
|
proxyList << QNetworkProxy(QNetworkProxy::FtpCachingProxy, QtNetworkSettings::serverName(), 2121);
|
|
QTest::newRow("ftp")
|
|
<< proxyList << QNetworkProxy()
|
|
<< true << int(QAbstractSocket::UnsupportedSocketOperationError);
|
|
|
|
proxyList.clear();
|
|
proxyList << QNetworkProxy(QNetworkProxy::FtpCachingProxy, QtNetworkSettings::serverName(), 2121)
|
|
<< QNetworkProxy(QNetworkProxy::HttpCachingProxy, QtNetworkSettings::serverName(), 3128);
|
|
QTest::newRow("ftp+cachinghttp")
|
|
<< proxyList << QNetworkProxy()
|
|
<< true << int(QAbstractSocket::UnsupportedSocketOperationError);
|
|
}
|
|
|
|
void tst_QTcpServer::proxyFactory()
|
|
{
|
|
QFETCH_GLOBAL(bool, setProxy);
|
|
if (setProxy)
|
|
return;
|
|
|
|
QFETCH(QList<QNetworkProxy>, proxyList);
|
|
QFETCH(QNetworkProxy, proxyUsed);
|
|
QFETCH(bool, fails);
|
|
|
|
MyProxyFactory *factory = new MyProxyFactory;
|
|
factory->toReturn = proxyList;
|
|
QNetworkProxyFactory::setApplicationProxyFactory(factory);
|
|
|
|
QTcpServer server;
|
|
bool listenResult = server.listen();
|
|
|
|
// Verify that the factory was called properly
|
|
QCOMPARE(factory->callCount, 1);
|
|
QCOMPARE(factory->lastQuery, QNetworkProxyQuery(0, QString(), QNetworkProxyQuery::TcpServer));
|
|
|
|
QCOMPARE(listenResult, !fails);
|
|
QCOMPARE(server.errorString().isEmpty(), !fails);
|
|
|
|
// note: the following test is not a hard failure.
|
|
// Sometimes, error codes change for the better
|
|
QTEST(int(server.serverError()), "expectedError");
|
|
}
|
|
|
|
class Qtbug14268Helper : public QObject
|
|
{
|
|
Q_OBJECT
|
|
public:
|
|
QByteArray lastDataPeeked;
|
|
public slots:
|
|
void newConnection() {
|
|
QTcpServer* server=static_cast<QTcpServer*>(sender());
|
|
QTcpSocket* s=server->nextPendingConnection();
|
|
connect(s,SIGNAL(readyRead()),this,SLOT(onServerReadyRead()));
|
|
}
|
|
void onServerReadyRead() {
|
|
QTcpSocket* clientSocket=static_cast<QTcpSocket*>(sender());
|
|
lastDataPeeked = clientSocket->peek(128*1024).toHex();
|
|
QTestEventLoop::instance().exitLoop();
|
|
}
|
|
};
|
|
|
|
// there is a similar test inside tst_qtcpsocket that uses the waitFor* functions instead
|
|
void tst_QTcpServer::qtbug14268_peek()
|
|
{
|
|
QFETCH_GLOBAL(bool, setProxy);
|
|
if (setProxy)
|
|
return;
|
|
|
|
QTcpServer server;
|
|
server.listen();
|
|
|
|
Qtbug14268Helper helper;
|
|
QObject::connect(&server, SIGNAL(newConnection()), &helper, SLOT(newConnection()));
|
|
|
|
QTcpSocket client;
|
|
client.connectToHost(QHostAddress::LocalHost, server.serverPort());
|
|
QVERIFY(client.waitForConnected(2000));
|
|
|
|
client.write("abc\n");
|
|
QTestEventLoop::instance().enterLoop(5);
|
|
QVERIFY(!QTestEventLoop::instance().timeout());
|
|
QVERIFY(helper.lastDataPeeked == QByteArray("6162630a"));
|
|
|
|
client.write("def\n");
|
|
QTestEventLoop::instance().enterLoop(5);
|
|
QVERIFY(!QTestEventLoop::instance().timeout());
|
|
QVERIFY(helper.lastDataPeeked == QByteArray("6162630a6465660a"));
|
|
|
|
client.write("ghi\n");
|
|
QTestEventLoop::instance().enterLoop(5);
|
|
QVERIFY(!QTestEventLoop::instance().timeout());
|
|
QVERIFY(helper.lastDataPeeked == QByteArray("6162630a6465660a6768690a"));
|
|
}
|
|
|
|
void tst_QTcpServer::serverAddress_data()
|
|
{
|
|
QTest::addColumn<QHostAddress>("listenAddress");
|
|
QTest::addColumn<QHostAddress>("serverAddress");
|
|
#ifdef Q_OS_WIN
|
|
if (QSysInfo::windowsVersion() < QSysInfo::WV_6_0)
|
|
QTest::newRow("Any") << QHostAddress(QHostAddress::Any) << QHostAddress(QHostAddress::AnyIPv4); //windows XP doesn't support dual stack sockets
|
|
else
|
|
#endif
|
|
QTest::newRow("Any") << QHostAddress(QHostAddress::Any) << QHostAddress(QHostAddress::Any);
|
|
QTest::newRow("AnyIPv4") << QHostAddress(QHostAddress::AnyIPv4) << QHostAddress(QHostAddress::AnyIPv4);
|
|
QTest::newRow("AnyIPv6") << QHostAddress(QHostAddress::AnyIPv6) << QHostAddress(QHostAddress::AnyIPv6);
|
|
foreach (const QHostAddress& addr, QNetworkInterface::allAddresses()) {
|
|
if (addr.isInSubnet(QHostAddress::parseSubnet("fe80::/10"))
|
|
|| addr.isInSubnet(QHostAddress::parseSubnet("169.254/16")))
|
|
continue; //cannot bind on link local addresses
|
|
QTest::newRow(qPrintable(addr.toString())) << addr << addr;
|
|
}
|
|
}
|
|
|
|
void tst_QTcpServer::serverAddress()
|
|
{
|
|
QFETCH_GLOBAL(bool, setProxy);
|
|
if (setProxy)
|
|
return;
|
|
|
|
QFETCH(QHostAddress, listenAddress);
|
|
QFETCH(QHostAddress, serverAddress);
|
|
QTcpServer server;
|
|
if (!server.listen(listenAddress))
|
|
QSKIP(qPrintable(server.errorString()));
|
|
QCOMPARE(server.serverAddress(), serverAddress);
|
|
}
|
|
|
|
QTEST_MAIN(tst_QTcpServer)
|
|
#include "tst_qtcpserver.moc"
|