Finish and test first working tunnel proxy connection

This commit is contained in:
Simon Stürz 2021-08-04 13:05:37 +02:00
parent 30d6a9dd43
commit b9ebc345a5
28 changed files with 529 additions and 61 deletions

View File

@ -54,6 +54,9 @@ QByteArray SlipDataProcessor::deserializeData(const QByteArray &data)
// If escape byte, the next byte has to be a modified byte
if (byte == ProtocolByteEsc) {
escaped = true;
} else if (byte == ProtocolByteEnd) {
// We are done...lets skip the rest of the data since we got the end byte
break;
} else {
deserializedData.append(static_cast<char>(byte));
}

View File

@ -84,11 +84,8 @@ TunnelProxyHandler::TunnelProxyHandler(QObject *parent) : JsonHandler(parent)
params.clear(); returns.clear();
setDescription("ClientDisconnected", "Emitted whenever a new client has been connected to a registered server. "
"Only tunnel proxy clients registered as server will receive this notification.");
params.insert("clientId", JsonTypes::basicTypeToString(JsonTypes::UInt));
params.insert("name", JsonTypes::basicTypeToString(JsonTypes::String));
params.insert("address", JsonTypes::basicTypeToString(JsonTypes::String));
params.insert("socketAddress", JsonTypes::basicTypeToString(JsonTypes::UInt));
setParams("ClientDisconnected", params);
}
QString TunnelProxyHandler::name() const
@ -148,10 +145,4 @@ JsonReply *TunnelProxyHandler::RegisterClient(const QVariantMap &params, Transpo
return createReply("RegisterClient", response);
}
//JsonReply *TunnelProxyHandler::RemoveClient(const QVariantMap &params, TransportClient *transportClient)
//{
//}
}

View File

@ -45,10 +45,12 @@ public:
QString name() const override;
// Server
Q_INVOKABLE JsonReply *RegisterServer(const QVariantMap &params, TransportClient *transportClient);
Q_INVOKABLE JsonReply *DisconnectClient(const QVariantMap &params, TransportClient *transportClient);
Q_INVOKABLE JsonReply *RegisterClient(const QVariantMap &params, TransportClient *transportClient);
// Client
Q_INVOKABLE JsonReply *RegisterClient(const QVariantMap &params, TransportClient *transportClient);
signals:
void ClientConnected(const QVariantMap &params, TransportClient *transportClient);

View File

@ -87,6 +87,16 @@ bool ProxyConfiguration::loadConfiguration(const QString &fileName)
setTcpServerPort(static_cast<quint16>(settings.value("port", 1213).toInt()));
settings.endGroup();
settings.beginGroup("WebSocketServerTunnelProxy");
setWebSocketServerTunnelProxyHost(QHostAddress(settings.value("host", "127.0.0.1").toString()));
setWebSocketServerTunnelProxyPort(static_cast<quint16>(settings.value("port", 2212).toInt()));
settings.endGroup();
settings.beginGroup("TcpServerTunnelProxy");
setTcpServerTunnelProxyHost(QHostAddress(settings.value("host", "127.0.0.1").toString()));
setTcpServerTunnelProxyPort(static_cast<quint16>(settings.value("port", 2213).toInt()));
settings.endGroup();
// Load SSL configuration
QSslConfiguration sslConfiguration;
sslConfiguration.setPeerVerifyMode(QSslSocket::VerifyNone);

View File

@ -140,10 +140,10 @@ void JsonRpcServer::sendResponse(TransportClient *client, int commandId, const Q
if (client->slipEnabled()) {
SlipDataProcessor::Frame frame;
frame.socketAddress = 0x0000;
frame.data = data;
frame.data = data + '\n';
client->sendData(SlipDataProcessor::serializeData(SlipDataProcessor::buildFrame(frame)));
} else {
client->sendData(data);
client->sendData(data + '\n');
}
}
@ -159,10 +159,10 @@ void JsonRpcServer::sendErrorResponse(TransportClient *client, int commandId, co
if (client->slipEnabled()) {
SlipDataProcessor::Frame frame;
frame.socketAddress = 0x0000;
frame.data = data;
frame.data = data + '\n';
client->sendData(SlipDataProcessor::serializeData(SlipDataProcessor::buildFrame(frame)));
} else {
client->sendData(data);
client->sendData(data + '\n');
}
}
@ -372,12 +372,12 @@ void JsonRpcServer::sendNotification(const QString &nameSpace, const QString &me
if (transportClient->slipEnabled()) {
SlipDataProcessor::Frame frame;
frame.socketAddress = 0x0000;
frame.data = data;
frame.data = data + '\n';
qCDebug(dcJsonRpcTraffic()) << "Sending notification frame:" <<frame.socketAddress << qUtf8Printable(frame.data);
transportClient->sendData(SlipDataProcessor::serializeData(SlipDataProcessor::buildFrame(frame)));
} else {
qCDebug(dcJsonRpcTraffic()) << "Sending notification:" << data;
transportClient->sendData(data);
transportClient->sendData(data + '\n');
}
}

View File

@ -53,7 +53,7 @@ void TcpSocketServer::sendData(const QUuid &clientId, const QByteArray &data)
}
qCDebug(dcTcpSocketServerTraffic()) << "Send data to" << clientId.toString() << data + '\n';
if (client->write(data + '\n') < 0) {
if (client->write(data) < 0) {
qCWarning(dcTcpSocketServer()) << "Could not write data to client socket" << clientId.toString();
}
}
@ -64,8 +64,10 @@ void TcpSocketServer::killClientConnection(const QUuid &clientId, const QString
if (!client)
return;
qCWarning(dcTcpSocketServer()) << "Killing client connection" << clientId.toString() << "Reason:" << killReason;
client->close();
if (client->state() == QAbstractSocket::ConnectedState) {
qCWarning(dcTcpSocketServer()) << "Killing client connection" << clientId.toString() << "Reason:" << killReason;
client->close();
}
}
bool TcpSocketServer::running() const

View File

@ -64,7 +64,7 @@ void WebSocketServer::sendData(const QUuid &clientId, const QByteArray &data)
client = m_clientList.value(clientId);
if (client) {
qCDebug(dcWebSocketServerTraffic()) << "--> Sending data to client:" << data;
client->sendTextMessage(data + '\n');
client->sendTextMessage(data);
} else {
qCWarning(dcWebSocketServer()) << "Client" << clientId << "unknown to this transport";
}

View File

@ -46,6 +46,7 @@ QList<QByteArray> TunnelProxyClient::processData(const QByteArray &data)
} else {
qCDebug(dcTunnelProxyServerTraffic()) << "Frame received";
packages.append(m_dataBuffer);
m_dataBuffer.clear();
}
} else {
m_dataBuffer.append(data.at(i));

View File

@ -81,6 +81,7 @@ QDebug operator<<(QDebug debug, TunnelProxyClientConnection *clientConnection)
debug.nospace() << "TunnelProxyClientConnection(";
debug.nospace() << clientConnection->clientName() << ", ";
debug.nospace() << clientConnection->clientUuid().toString() << ", ";
debug.nospace() << "server: " << clientConnection->serverUuid().toString() << ", ";
debug.nospace() << clientConnection->transportClient() << ")";
return debug.space();
}

View File

@ -265,8 +265,8 @@ void TunnelProxyServer::onClientDisconnected(const QUuid &clientId)
if (clientConnection->serverConnection()) {
QVariantMap params;
params.insert("socketAddress", clientConnection->socketAddress());
m_jsonRpcServer->sendNotification("TunnelProxy", "ClientDisconnected", params, clientConnection->serverConnection()->transportClient());
clientConnection->serverConnection()->unregisterClientConnection(clientConnection);
m_jsonRpcServer->sendNotification("TunnelProxy", "ClientDisconnected", params, clientConnection->serverConnection()->transportClient());
}
clientConnection->deleteLater();
@ -304,8 +304,9 @@ void TunnelProxyServer::onClientDataAvailable(const QUuid &clientId, const QByte
SlipDataProcessor::Frame frame;
frame.socketAddress = clientConnection->socketAddress();
frame.data = data;
qCDebug(dcTunnelProxyServerTraffic()) << "Write client data to server using socket address" << clientConnection->socketAddress();
qCDebug(dcTunnelProxyServerTraffic()) << "--> Tunnel data to server socket address" << clientConnection->socketAddress() << "to" << clientConnection->serverConnection() << qUtf8Printable(data);
clientConnection->serverConnection()->transportClient()->sendData(SlipDataProcessor::serializeData(SlipDataProcessor::buildFrame(frame)));
} else if (tunnelProxyClient->type() == TunnelProxyClient::TypeServer) {
// Data coming from a connected server connection
if (tunnelProxyClient->slipEnabled()) {
@ -334,7 +335,7 @@ void TunnelProxyServer::onClientDataAvailable(const QUuid &clientId, const QByte
return;
}
qCDebug(dcTunnelProxyServerTraffic()) << "Sending data to" << clientConnection << qUtf8Printable(data);
qCDebug(dcTunnelProxyServerTraffic()) << "--> Tunnel data from server socket" << frame.socketAddress << "to" << clientConnection << qUtf8Printable(data);
clientConnection->transportClient()->sendData(frame.data);
}
}

View File

@ -27,6 +27,7 @@
#include "proxyjsonrpcclient.h"
#include "proxyconnection.h"
#include "../common/slipdataprocessor.h"
#include <QJsonDocument>
@ -93,10 +94,30 @@ JsonReply *JsonRpcClient::callRegisterClient(const QUuid &clientUuid, const QStr
return reply;
}
void JsonRpcClient::sendRequest(const QVariantMap &request)
JsonReply *JsonRpcClient::callDisconnectClient(quint16 socketAddress)
{
QByteArray data = QJsonDocument::fromVariant(request).toJson(QJsonDocument::Compact);
qCDebug(dcRemoteProxyClientJsonRpcTraffic()) << "Sending" << data;
QVariantMap params;
params.insert("socketAddress", socketAddress);
JsonReply *reply = new JsonReply(m_commandId, "TunnelProxy", "DisconnectClient", params, this);
qCDebug(dcRemoteProxyClientJsonRpc()) << "Calling" << QString("%1.%2").arg(reply->nameSpace()).arg(reply->method());
sendRequest(reply->requestMap(), true);
m_replies.insert(m_commandId, reply);
return reply;
}
void JsonRpcClient::sendRequest(const QVariantMap &request, bool slipEnabled)
{
QByteArray data = QJsonDocument::fromVariant(request).toJson(QJsonDocument::Compact) + '\n';
if (slipEnabled) {
SlipDataProcessor::Frame frame;
frame.socketAddress = 0x0000;
frame.data = data;
data = SlipDataProcessor::serializeData(SlipDataProcessor::buildFrame(frame));
}
qCDebug(dcRemoteProxyClientJsonRpcTraffic()) << "Sending" << qUtf8Printable(data);
m_connection->sendData(data);
}

View File

@ -66,7 +66,7 @@ private:
QHash<int, JsonReply *> m_replies;
void sendRequest(const QVariantMap &request);
void sendRequest(const QVariantMap &request, bool slipEnabled = false);
void processDataPackage(const QByteArray &data);
signals:

View File

@ -77,6 +77,11 @@ void TunnelProxyRemoteConnection::ignoreSslErrors(const QList<QSslError> &errors
m_connection->ignoreSslErrors(errors);
}
QUrl TunnelProxyRemoteConnection::serverUrl() const
{
return m_serverUrl;
}
QString TunnelProxyRemoteConnection::remoteProxyServer() const
{
return m_remoteProxyServer;
@ -138,6 +143,17 @@ void TunnelProxyRemoteConnection::disconnectServer()
}
}
bool TunnelProxyRemoteConnection::sendData(const QByteArray &data)
{
if (!remoteConnected()) {
qCWarning(dcTunnelProxyRemoteConnection()) << "Could not send data. Not connected.";
return false;
}
m_connection->sendData(data);
return true;
}
void TunnelProxyRemoteConnection::onConnectionChanged(bool connected)
{
if (connected) {

View File

@ -74,6 +74,8 @@ public:
void ignoreSslErrors();
void ignoreSslErrors(const QList<QSslError> &errors);
QUrl serverUrl() const;
QString remoteProxyServer() const;
QString remoteProxyServerName() const;
QString remoteProxyServerVersion() const;
@ -82,6 +84,7 @@ public:
public slots:
bool connectServer(const QUrl &url, const QUuid &serverUuid);
void disconnectServer();
bool sendData(const QByteArray &data);
signals:
void stateChanged(TunnelProxyRemoteConnection::State state);

View File

@ -27,13 +27,15 @@
#include "tunnelproxysocket.h"
#include "proxyconnection.h"
#include "tunnelproxysocketserver.h"
#include "../common/slipdataprocessor.h"
namespace remoteproxyclient {
TunnelProxySocket::TunnelProxySocket(ProxyConnection *connection, const QString &clientName, const QUuid &clientUuid, const QHostAddress &clientPeerAddress, quint16 socketAddress, QObject *parent) :
TunnelProxySocket::TunnelProxySocket(ProxyConnection *connection, TunnelProxySocketServer *socketServer, const QString &clientName, const QUuid &clientUuid, const QHostAddress &clientPeerAddress, quint16 socketAddress, QObject *parent) :
QObject(parent),
m_connection(connection),
m_socketServer(socketServer),
m_clientName(clientName),
m_clientUuid(clientUuid),
m_clientPeerAddress(clientPeerAddress),
@ -62,6 +64,11 @@ quint16 TunnelProxySocket::socketAddress() const
return m_socketAddress;
}
bool TunnelProxySocket::connected() const
{
return m_connected;
}
void TunnelProxySocket::writeData(const QByteArray &data)
{
SlipDataProcessor::Frame frame;
@ -72,7 +79,14 @@ void TunnelProxySocket::writeData(const QByteArray &data)
void TunnelProxySocket::disconnectSocket()
{
m_socketServer->requestSocketDisconnect(m_socketAddress);
}
void TunnelProxySocket::setDisconnected()
{
m_connected = false;
emit connectedChanged(false);
emit disconnected();
}
QDebug operator<<(QDebug debug, TunnelProxySocket *tunnelProxySocket)

View File

@ -35,6 +35,7 @@
namespace remoteproxyclient {
class ProxyConnection;
class TunnelProxySocketServer;
class TunnelProxySocket : public QObject
{
@ -47,25 +48,33 @@ public:
QHostAddress clientPeerAddress() const;
quint16 socketAddress() const;
bool connected() const;
void writeData(const QByteArray &data);
void disconnectSocket();
signals:
void dataReceived(const QByteArray &data);
void connectedChanged(bool connected);
void disconnected();
private:
explicit TunnelProxySocket(ProxyConnection *connection, const QString &clientName, const QUuid &clientUuid, const QHostAddress &clientPeerAddress, quint16 socketAddress, QObject *parent = nullptr);
explicit TunnelProxySocket(ProxyConnection *connection, TunnelProxySocketServer *socketServer, const QString &clientName, const QUuid &clientUuid, const QHostAddress &clientPeerAddress, quint16 socketAddress, QObject *parent = nullptr);
~TunnelProxySocket() = default;
ProxyConnection *m_connection = nullptr;
TunnelProxySocketServer *m_socketServer = nullptr;
bool m_connected = true; // Note: on creatrion, the socket is connected, otherwise it would not have been created
QString m_clientName;
QUuid m_clientUuid;
QHostAddress m_clientPeerAddress;
quint16 m_socketAddress = 0xFFFF;
void setDisconnected();
};
QDebug operator<<(QDebug debug, TunnelProxySocket *tunnelProxySocket);

View File

@ -299,7 +299,7 @@ void TunnelProxySocketServer::onServerRegistrationFinished()
void TunnelProxySocketServer::onTunnelProxyClientConnected(const QString &clientName, const QUuid &clientUuid, const QString &clientPeerAddress, quint16 socketAddress)
{
TunnelProxySocket *tunnelProxySocket = new TunnelProxySocket(m_connection, clientName, clientUuid, QHostAddress(clientPeerAddress), socketAddress, this);
TunnelProxySocket *tunnelProxySocket = new TunnelProxySocket(m_connection, this, clientName, clientUuid, QHostAddress(clientPeerAddress), socketAddress, this);
qCDebug(dcTunnelProxySocketServer()) << "--> New client connected" << tunnelProxySocket;
m_tunnelProxySockets.insert(socketAddress, tunnelProxySocket);
emit clientConnected(tunnelProxySocket);
@ -314,10 +314,24 @@ void TunnelProxySocketServer::onTunnelProxyClientDisconnected(quint16 socketAddr
}
qCDebug(dcTunnelProxySocketServer()) << "--> Client disconnected" << tunnelProxySocket;
emit tunnelProxySocket->disconnected();
tunnelProxySocket->setDisconnected();
emit clientDisconnected(tunnelProxySocket);
tunnelProxySocket->deleteLater();
}
void TunnelProxySocketServer::requestSocketDisconnect(quint16 socketAddress)
{
TunnelProxySocket *socket = m_tunnelProxySockets.value(socketAddress);
qCDebug(dcTunnelProxySocketServer()) << "Request to disconnect socket" << socket;
JsonReply *reply = m_jsonClient->callDisconnectClient(socketAddress);
connect(reply, &JsonReply::finished, this, [=](){
reply->deleteLater();
// TODO: handle errors
qCDebug(dcTunnelProxySocketServer()) << "Request to disconnect client finished" << reply->response();
});
}
void TunnelProxySocketServer::setState(State state)
{
if (m_state == state)

View File

@ -45,6 +45,9 @@ class JsonRpcClient;
class TunnelProxySocketServer : public QObject
{
Q_OBJECT
friend class TunnelProxySocket;
public:
enum State {
StateConnecting,
@ -147,6 +150,8 @@ private:
QByteArray m_dataBuffer;
void requestSocketDisconnect(quint16 socketAddress);
void setState(State state);
void setRunning(bool running);
void setError(QAbstractSocket::SocketError error);

View File

@ -51,7 +51,7 @@ WebSocketConnection::~WebSocketConnection()
void WebSocketConnection::sendData(const QByteArray &data)
{
m_webSocket->sendTextMessage(QString::fromUtf8(data + '\n'));
m_webSocket->sendTextMessage(QString::fromUtf8(data));
}
void WebSocketConnection::ignoreSslErrors()

View File

@ -27,3 +27,12 @@ port=443
[TcpServer]
host=127.0.0.1
port=80
[WebSocketServerTunnelProxy]
host=127.0.0.1
port=2212
[TcpServerTunnelProxy]
host=127.0.0.1
port=2213

View File

@ -16,3 +16,11 @@ port=1212
[TcpServer]
host=127.0.0.1
port=1213
[WebSocketServerTunnelProxy]
host=127.0.0.1
port=2212
[TcpServerTunnelProxy]
host=127.0.0.1
port=2213

View File

@ -16,3 +16,11 @@ port=1212
[TcpServer]
host=127.0.0.1
port=1213
[WebSocketServerTunnelProxy]
host=127.0.0.1
port=2212
[TcpServerTunnelProxy]
host=127.0.0.1
port=2213

View File

@ -16,3 +16,11 @@ port=1212
[TcpServer]
host=127.0.0.1
port=1213
[WebSocketServerTunnelProxy]
host=127.0.0.1
port=2212
[TcpServerTunnelProxy]
host=127.0.0.1
port=2213

View File

@ -16,3 +16,11 @@ port=1212
[TcpServer]
host=127.0.0.1
port=1213
[WebSocketServerTunnelProxy]
host=127.0.0.1
port=2212
[TcpServerTunnelProxy]
host=127.0.0.1
port=2213

View File

@ -20,3 +20,11 @@ port=1212
[TcpServer]
host=127.0.0.1
port=1213
[WebSocketServerTunnelProxy]
host=127.0.0.1
port=2212
[TcpServerTunnelProxy]
host=127.0.0.1
port=2213

View File

@ -30,6 +30,7 @@
#include "engine.h"
#include "loggingcategories.h"
#include "remoteproxyconnection.h"
#include "../common/slipdataprocessor.h"
// Client
#include "tunnelproxy/tunnelproxysocketserver.h"
@ -336,6 +337,34 @@ void RemoteProxyTestsTunnelProxy::registerClient()
stopServer();
}
void RemoteProxyTestsTunnelProxy::testSlip_data()
{
QTest::addColumn<QByteArray>("data");
QTest::addColumn<bool>("success");
QTest::newRow("valid: a lot of special characters") << QByteArray::fromHex("C0AABBCCDDEEFF12A1B2C3D4E5FFC0DBDCDDAA") << true;
QTest::newRow("valid: start and end with END protocol") << QByteArray::fromHex("C0C0C0C0C0C0C0C0C0C0DDDDCDCDCDCDCDCD") << true;
QTest::newRow("valid: normal text with a special characters") << QByteArray("Foo Bar text describing 123456770ß2123#+@$%/(!\"W=$*'*") << true;
QTest::newRow("invalid: escape followed by nor escaped special character") << QByteArray::fromHex("AADB12FFC0") << false;
}
void RemoteProxyTestsTunnelProxy::testSlip()
{
QFETCH(QByteArray, data);
QFETCH(bool, success);
if (success) {
QByteArray serializedData = SlipDataProcessor::serializeData(data);
QVERIFY(serializedData.endsWith(0xC0));
QByteArray deserializedData = SlipDataProcessor::deserializeData(serializedData);
QVERIFY(deserializedData == data);
} else {
QByteArray deserializedData = SlipDataProcessor::deserializeData(data);
QVERIFY(deserializedData.isEmpty());
}
}
void RemoteProxyTestsTunnelProxy::registerServerDuplicated()
{
// Start the server
@ -387,29 +416,11 @@ void RemoteProxyTestsTunnelProxy::registerServerDuplicated()
// Try to register from a websocket with the same uuid
QPair<QVariant, QWebSocket *> resultWebSocket = invokeWebSocketTunnelProxyApiCallPersistant("TunnelProxy.RegisterServer", params);
response = resultWebSocket.first.toMap();
QWebSocket *webSocket = resultWebSocket.second;
QVERIFY(!response.isEmpty());
QVERIFY(response.value("status").toString() == "success");
QVERIFY(response.value("params").toMap().contains("tunnelProxyError"));
verifyTunnelProxyError(response);
// Try to register again with the same uuid on the same socket
resultWebSocket = invokeWebSocketTunnelProxyApiCallPersistant("TunnelProxy.RegisterServer", params, true, webSocket);
response = resultWebSocket.first.toMap();
QVERIFY(response.value("status").toString() == "success");
QVERIFY(response.value("params").toMap().contains("tunnelProxyError"));
verifyTunnelProxyError(response, TunnelProxyServer::TunnelProxyErrorAlreadyRegistered);
QSignalSpy disconnectedWebSocketSpy(webSocket, &QWebSocket::disconnected);
QVERIFY(disconnectedWebSocketSpy.wait());
QVERIFY(disconnectedWebSocketSpy.count() == 1);
webSocket->close();
delete webSocket;
QTest::qWait(100);
resetDebugCategories();
// Clean up
@ -559,6 +570,7 @@ void RemoteProxyTestsTunnelProxy::testTunnelProxyServer()
addDebugCategory("JsonRpcTraffic.debug=true");
addDebugCategory("TunnelProxySocketServer.debug=true");
addDebugCategory("TunnelProxyRemoteConnection.debug=true");
addDebugCategory("TunnelProxyRemoteConnectionTraffic.debug=true");
addDebugCategory("RemoteProxyClientJsonRpcTraffic.debug=true");
// Tunnel proxy socket server
@ -579,6 +591,13 @@ void RemoteProxyTestsTunnelProxy::testTunnelProxyServer()
QVERIFY(arguments.at(0).toBool() == true);
QVERIFY(tunnelProxyServer->running());
QCOMPARE(tunnelProxyServer->serverUrl(), m_serverUrlTunnelProxyTcp);
QCOMPARE(tunnelProxyServer->remoteProxyServer(), QString(SERVER_NAME_STRING));
QCOMPARE(tunnelProxyServer->remoteProxyServerName(), Engine::instance()->configuration()->serverName());
QCOMPARE(tunnelProxyServer->remoteProxyServerVersion(), QString(SERVER_VERSION_STRING));
QCOMPARE(tunnelProxyServer->remoteProxyApiVersion(), QString(API_VERSION_STRING));
// Tunnel proxy client connection
QString clientName = "Awesome client name";
QUuid clientUuid = QUuid::createUuid();
@ -597,22 +616,50 @@ void RemoteProxyTestsTunnelProxy::testTunnelProxyServer()
TunnelProxySocket *tunnelProxySocket = arguments.at(0).value<TunnelProxySocket *>();
QVERIFY(tunnelProxySocket->clientName() == clientName);
QVERIFY(tunnelProxySocket->clientUuid() == clientUuid);
QVERIFY(!tunnelProxySocket->clientPeerAddress().isNull());
QVERIFY(tunnelProxySocket->socketAddress() != 0x0000 && tunnelProxySocket->socketAddress() != 0xFFFF);
QVERIFY(tunnelProxySocket->connected());
QCOMPARE(clientConnection->serverUrl(), m_serverUrlTunnelProxyTcp);
QCOMPARE(clientConnection->remoteProxyServer(), QString(SERVER_NAME_STRING));
QCOMPARE(clientConnection->remoteProxyServerName(), Engine::instance()->configuration()->serverName());
QCOMPARE(clientConnection->remoteProxyServerVersion(), QString(SERVER_VERSION_STRING));
QCOMPARE(clientConnection->remoteProxyApiVersion(), QString(API_VERSION_STRING));
// We have a remote connection, now disconnect the client and verify the socket dissapears on th server side
QSignalSpy clientDisconnectedSpy(tunnelProxyServer, &TunnelProxySocketServer::clientDisconnected);
clientConnection->disconnectServer();
QVERIFY(clientDisconnectedSpy.wait());
QVERIFY(clientDisconnectedSpy.count() == 1);
arguments = clientDisconnectedSpy.takeFirst();
tunnelProxySocket = arguments.at(0).value<TunnelProxySocket *>();
QVERIFY(tunnelProxySocket->clientName() == clientName);
QVERIFY(tunnelProxySocket->clientUuid() == clientUuid);
QVERIFY(!tunnelProxySocket->clientPeerAddress().isNull());
QVERIFY(tunnelProxySocket->socketAddress() != 0x0000 && tunnelProxySocket->socketAddress() != 0xFFFF);
QVERIFY(!tunnelProxySocket->connected());
// Stop the server connection and verify the client gets disconnected
QSignalSpy serverNotRunningSpy(tunnelProxyServer, &TunnelProxySocketServer::runningChanged);
tunnelProxyServer->stopServer();
QSignalSpy disconnectedSpy(clientConnection, &TunnelProxyRemoteConnection::remoteConnectedChanged);
QVERIFY(disconnectedSpy.wait());
QVERIFY(disconnectedSpy.count() == 1);
arguments = disconnectedSpy.takeFirst();
// Verify the remote connection is disconnected
serverNotRunningSpy.wait();
QVERIFY(serverNotRunningSpy.count() == 1);
arguments = serverNotRunningSpy.takeFirst();
QVERIFY(arguments.at(0).toBool() == false);
QVERIFY(!clientConnection->remoteConnected());
QVERIFY(!tunnelProxyServer->running());
// Clean up
tunnelProxyServer->deleteLater();
clientConnection->deleteLater();
resetDebugCategories();
// Clean up
stopServer();
}
@ -647,6 +694,12 @@ void RemoteProxyTestsTunnelProxy::testTunnelProxyClient()
QVERIFY(arguments.at(0).toBool() == true);
QVERIFY(tunnelProxyServer->running());
QCOMPARE(tunnelProxyServer->serverUrl(), m_serverUrlTunnelProxyTcp);
QCOMPARE(tunnelProxyServer->remoteProxyServer(), QString(SERVER_NAME_STRING));
QCOMPARE(tunnelProxyServer->remoteProxyServerName(), Engine::instance()->configuration()->serverName());
QCOMPARE(tunnelProxyServer->remoteProxyServerVersion(), QString(SERVER_VERSION_STRING));
QCOMPARE(tunnelProxyServer->remoteProxyApiVersion(), QString(API_VERSION_STRING));
// Tunnel proxy client connection
QString clientName = "Awesome client name";
@ -666,15 +719,276 @@ void RemoteProxyTestsTunnelProxy::testTunnelProxyClient()
QVERIFY(arguments.at(0).toBool() == true);
QVERIFY(clientConnection->remoteConnected());
// Verify server socket connected
QCOMPARE(clientConnection->serverUrl(), m_serverUrlTunnelProxyTcp);
QCOMPARE(clientConnection->remoteProxyServer(), QString(SERVER_NAME_STRING));
QCOMPARE(clientConnection->remoteProxyServerName(), Engine::instance()->configuration()->serverName());
QCOMPARE(clientConnection->remoteProxyServerVersion(), QString(SERVER_VERSION_STRING));
QCOMPARE(clientConnection->remoteProxyApiVersion(), QString(API_VERSION_STRING));
// Stop the server and make sure the client gets disconnected
tunnelProxyServer->stopServer();
QSignalSpy clientRemoteDisonnectedSpy(clientConnection, &TunnelProxyRemoteConnection::remoteConnectedChanged);
QVERIFY(clientRemoteDisonnectedSpy.wait());
QVERIFY(clientRemoteDisonnectedSpy.count() == 1);
arguments = clientRemoteDisonnectedSpy.takeFirst();
QVERIFY(arguments.at(0).toBool() == false);
QVERIFY(!clientConnection->remoteConnected());
// Clean up
tunnelProxyServer->deleteLater();
clientConnection->deleteLater();
resetDebugCategories();
// Clean up
stopServer();
}
void RemoteProxyTestsTunnelProxy::testTunnelProxyServerSocketDisconnect()
{
// Start the server
startServer();
resetDebugCategories();
addDebugCategory("TunnelProxyServer.debug=true");
addDebugCategory("TunnelProxyServerTraffic.debug=true");
addDebugCategory("JsonRpcTraffic.debug=true");
addDebugCategory("TunnelProxySocketServer.debug=true");
addDebugCategory("TunnelProxyRemoteConnection.debug=true");
addDebugCategory("TunnelProxyRemoteConnectionTraffic.debug=true");
addDebugCategory("RemoteProxyClientJsonRpcTraffic.debug=true");
// Tunnel proxy socket server
QString serverName = "SuperDuper server name";
QUuid serverUuid = QUuid::createUuid();
TunnelProxySocketServer *tunnelProxyServer = new TunnelProxySocketServer(serverUuid, serverName, this);
connect(tunnelProxyServer, &TunnelProxySocketServer::sslErrors, this, [=](const QList<QSslError> &errors){
tunnelProxyServer->ignoreSslErrors(errors);
});
tunnelProxyServer->startServer(m_serverUrlTunnelProxyTcp);
QSignalSpy serverRunningSpy(tunnelProxyServer, &TunnelProxySocketServer::runningChanged);
serverRunningSpy.wait();
QVERIFY(serverRunningSpy.count() == 1);
QList<QVariant> arguments = serverRunningSpy.takeFirst();
QVERIFY(arguments.at(0).toBool() == true);
QVERIFY(tunnelProxyServer->running());
QCOMPARE(tunnelProxyServer->serverUrl(), m_serverUrlTunnelProxyTcp);
QCOMPARE(tunnelProxyServer->remoteProxyServer(), QString(SERVER_NAME_STRING));
QCOMPARE(tunnelProxyServer->remoteProxyServerName(), Engine::instance()->configuration()->serverName());
QCOMPARE(tunnelProxyServer->remoteProxyServerVersion(), QString(SERVER_VERSION_STRING));
QCOMPARE(tunnelProxyServer->remoteProxyApiVersion(), QString(API_VERSION_STRING));
// Tunnel proxy client connection
QString clientName = "Awesome client name";
QUuid clientUuid = QUuid::createUuid();
TunnelProxyRemoteConnection *clientConnection = new TunnelProxyRemoteConnection(clientUuid, clientName, this);
connect(clientConnection, &TunnelProxyRemoteConnection::sslErrors, this, [=](const QList<QSslError> &errors){
clientConnection->ignoreSslErrors(errors);
});
clientConnection->connectServer(m_serverUrlTunnelProxyTcp, serverUuid);
QSignalSpy clientConnectedSpy(tunnelProxyServer, &TunnelProxySocketServer::clientConnected);
QVERIFY(clientConnectedSpy.wait());
QVERIFY(clientConnectedSpy.count() == 1);
arguments = clientConnectedSpy.takeFirst();
TunnelProxySocket *tunnelProxySocket = arguments.at(0).value<TunnelProxySocket *>();
QVERIFY(tunnelProxySocket->clientName() == clientName);
QVERIFY(tunnelProxySocket->clientUuid() == clientUuid);
QVERIFY(!tunnelProxySocket->clientPeerAddress().isNull());
QVERIFY(tunnelProxySocket->socketAddress() != 0x0000 && tunnelProxySocket->socketAddress() != 0xFFFF);
QVERIFY(tunnelProxySocket->connected());
QCOMPARE(clientConnection->serverUrl(), m_serverUrlTunnelProxyTcp);
QCOMPARE(clientConnection->remoteProxyServer(), QString(SERVER_NAME_STRING));
QCOMPARE(clientConnection->remoteProxyServerName(), Engine::instance()->configuration()->serverName());
QCOMPARE(clientConnection->remoteProxyServerVersion(), QString(SERVER_VERSION_STRING));
QCOMPARE(clientConnection->remoteProxyApiVersion(), QString(API_VERSION_STRING));
QVERIFY(clientConnection->remoteConnected() == true);
// Now request the TunnelProxySocket to disconnect and verify the client Connection really gets disconnected
QSignalSpy clientRemoteDisonnectedSpy(clientConnection, &TunnelProxyRemoteConnection::remoteConnectedChanged);
tunnelProxySocket->disconnectSocket();
QVERIFY(clientRemoteDisonnectedSpy.wait());
QVERIFY(clientRemoteDisonnectedSpy.count() == 1);
arguments = clientRemoteDisonnectedSpy.takeFirst();
QVERIFY(arguments.at(0).toBool() == false);
QVERIFY(!clientConnection->remoteConnected());
QTest::qWait(100);
// Clean up
tunnelProxyServer->deleteLater();
clientConnection->deleteLater();
resetDebugCategories();
stopServer();
}
void RemoteProxyTestsTunnelProxy::tunnelProxyEndToEndTest()
{
// Start the server
startServer();
resetDebugCategories();
addDebugCategory("TunnelProxyServer.debug=true");
addDebugCategory("TunnelProxyServerTraffic.debug=true");
addDebugCategory("JsonRpcTraffic.debug=true");
addDebugCategory("TunnelProxySocketServer.debug=true");
addDebugCategory("TunnelProxyRemoteConnection.debug=true");
addDebugCategory("TunnelProxyRemoteConnectionTraffic.debug=true");
addDebugCategory("RemoteProxyClientJsonRpcTraffic.debug=true");
// ** Create the server **
QString serverName = "nymea server";
QUuid serverUuid = QUuid::createUuid();
TunnelProxySocketServer *tunnelProxyServer = new TunnelProxySocketServer(serverUuid, serverName, this);
connect(tunnelProxyServer, &TunnelProxySocketServer::sslErrors, this, [=](const QList<QSslError> &errors){
tunnelProxyServer->ignoreSslErrors(errors);
});
tunnelProxyServer->startServer(m_serverUrlTunnelProxyTcp);
QSignalSpy serverRunningSpy(tunnelProxyServer, &TunnelProxySocketServer::runningChanged);
serverRunningSpy.wait();
QVERIFY(serverRunningSpy.count() == 1);
QList<QVariant> arguments = serverRunningSpy.takeFirst();
QVERIFY(arguments.at(0).toBool() == true);
QVERIFY(tunnelProxyServer->running());
QCOMPARE(tunnelProxyServer->serverUrl(), m_serverUrlTunnelProxyTcp);
QCOMPARE(tunnelProxyServer->remoteProxyServer(), QString(SERVER_NAME_STRING));
QCOMPARE(tunnelProxyServer->remoteProxyServerName(), Engine::instance()->configuration()->serverName());
QCOMPARE(tunnelProxyServer->remoteProxyServerVersion(), QString(SERVER_VERSION_STRING));
QCOMPARE(tunnelProxyServer->remoteProxyApiVersion(), QString(API_VERSION_STRING));
// ** Remote connection 1 **
QString clientOneName = "Client one";
QUuid clientOneUuid = QUuid::createUuid();
TunnelProxyRemoteConnection *remoteConnectionOne = new TunnelProxyRemoteConnection(clientOneUuid, clientOneName, this);
connect(remoteConnectionOne, &TunnelProxyRemoteConnection::sslErrors, this, [=](const QList<QSslError> &errors){
remoteConnectionOne->ignoreSslErrors(errors);
});
remoteConnectionOne->connectServer(m_serverUrlTunnelProxyTcp, serverUuid);
// ** Tunnel proxy server socket 1 **
QSignalSpy remoteConnectedOneSpy(tunnelProxyServer, &TunnelProxySocketServer::clientConnected);
QVERIFY(remoteConnectedOneSpy.wait());
QVERIFY(remoteConnectedOneSpy.count() == 1);
arguments = remoteConnectedOneSpy.takeFirst();
TunnelProxySocket *tunnelProxySocketOne = arguments.at(0).value<TunnelProxySocket *>();
QVERIFY(tunnelProxySocketOne->clientName() == clientOneName);
QVERIFY(tunnelProxySocketOne->clientUuid() == clientOneUuid);
QVERIFY(!tunnelProxySocketOne->clientPeerAddress().isNull());
QVERIFY(tunnelProxySocketOne->socketAddress() != 0x0000 && tunnelProxySocketOne->socketAddress() != 0xFFFF);
QVERIFY(tunnelProxySocketOne->connected());
qDebug() << "Have socket one" << tunnelProxySocketOne;
// ** Send data in both directions
QByteArray testData("#sdföiabi23u4b34b598gvndafjibnföQIUH34982HRIPURBFÖWLKDÜOQw9h934utbf ljBiH9FBLAJF RF AF,A§uu)(\"§)§(u$)($=$(((($((!");
// Socket -> Remote connection
QSignalSpy remoteConnectionOneDataSpy(remoteConnectionOne, &TunnelProxyRemoteConnection::dataReady);
tunnelProxySocketOne->writeData(testData);
QVERIFY(remoteConnectionOneDataSpy.wait());
QVERIFY(remoteConnectionOneDataSpy.count() == 1);
arguments = remoteConnectionOneDataSpy.takeFirst();
QByteArray receivedTestData = arguments.at(0).toByteArray();
QVERIFY(receivedTestData == testData);
// Remote connection -> Socket
QByteArray testData2("The biggest decision in life is about changing your life through changing your mind. Albert Schweitzer");
QSignalSpy tunnelProxySocketOneDataSpy(tunnelProxySocketOne, &TunnelProxySocket::dataReceived);
remoteConnectionOne->sendData(testData2);
QVERIFY(tunnelProxySocketOneDataSpy.wait());
QVERIFY(tunnelProxySocketOneDataSpy.count() == 1);
arguments = tunnelProxySocketOneDataSpy.takeFirst();
QByteArray receivedTestData2 = arguments.at(0).toByteArray();
QVERIFY(receivedTestData2 == testData2);
// ** Remote connection 2 **
QString clientTwoName = "Client two";
QUuid clientTwoUuid = QUuid::createUuid();
TunnelProxyRemoteConnection *remoteConnectionTwo = new TunnelProxyRemoteConnection(clientTwoUuid, clientTwoName, this);
connect(remoteConnectionTwo, &TunnelProxyRemoteConnection::sslErrors, this, [=](const QList<QSslError> &errors){
remoteConnectionTwo->ignoreSslErrors(errors);
});
remoteConnectionTwo->connectServer(m_serverUrlTunnelProxyTcp, serverUuid);
// ** Tunnel proxy server socket 2 **
QSignalSpy remoteConnectedTwoSpy(tunnelProxyServer, &TunnelProxySocketServer::clientConnected);
QVERIFY(remoteConnectedTwoSpy.wait());
QVERIFY(remoteConnectedTwoSpy.count() == 1);
arguments = remoteConnectedTwoSpy.takeFirst();
TunnelProxySocket *tunnelProxySocketTwo = arguments.at(0).value<TunnelProxySocket *>();
QVERIFY(tunnelProxySocketTwo->clientName() == clientTwoName);
QVERIFY(tunnelProxySocketTwo->clientUuid() == clientTwoUuid);
QVERIFY(!tunnelProxySocketTwo->clientPeerAddress().isNull());
QVERIFY(tunnelProxySocketTwo->socketAddress() != 0x0000 && tunnelProxySocketTwo->socketAddress() != 0xFFFF);
QVERIFY(tunnelProxySocketTwo->connected());
qDebug() << "Have socket two" << tunnelProxySocketTwo;
// ** Send data in both directions
// Socket -> Remote connection
QSignalSpy remoteConnectionTwoDataSpy(remoteConnectionTwo, &TunnelProxyRemoteConnection::dataReady);
tunnelProxySocketTwo->writeData(testData);
QVERIFY(remoteConnectionTwoDataSpy.wait());
QVERIFY(remoteConnectionTwoDataSpy.count() == 1);
arguments = remoteConnectionTwoDataSpy.takeFirst();
receivedTestData = arguments.at(0).toByteArray();
QVERIFY(receivedTestData == testData);
// Remote connection -> Socket
QSignalSpy tunnelProxySocketTwoDataSpy(tunnelProxySocketTwo, &TunnelProxySocket::dataReceived);
remoteConnectionTwo->sendData(testData2);
QVERIFY(tunnelProxySocketTwoDataSpy.wait());
QVERIFY(tunnelProxySocketTwoDataSpy.count() == 1);
arguments = tunnelProxySocketTwoDataSpy.takeFirst();
receivedTestData2 = arguments.at(0).toByteArray();
QVERIFY(receivedTestData2 == testData2);
Engine::instance()->tunnelProxyServer()->stopServer();
QTest::qWait(100);
QVERIFY(!tunnelProxyServer->running());
QVERIFY(!remoteConnectionOne->remoteConnected());
QVERIFY(!remoteConnectionTwo->remoteConnected());
// Clean up
tunnelProxyServer->deleteLater();
remoteConnectionOne->deleteLater();
remoteConnectionTwo->deleteLater();
resetDebugCategories();
stopServer();
}
QTEST_MAIN(RemoteProxyTestsTunnelProxy)

View File

@ -60,6 +60,9 @@ private slots:
void registerClient_data();
void registerClient();
void testSlip_data();
void testSlip();
void registerServerDuplicated();
void registerClientDuplicated();
void crossRegisterServerClient();
@ -67,6 +70,10 @@ private slots:
// Client classes
void testTunnelProxyServer();
void testTunnelProxyClient();
void testTunnelProxyServerSocketDisconnect();
void tunnelProxyEndToEndTest();
};

View File

@ -715,7 +715,6 @@ QPair<QVariant, QSslSocket *> BaseTest::invokeTcpSocketTunnelProxyApiCallPersist
continue;
break;
messageData.clear();
} else {
messageData.append(rawData.at(i));
}
@ -780,13 +779,19 @@ QPair<QVariant, QWebSocket *> BaseTest::invokeWebSocketTunnelProxyApiCallPersist
QJsonDocument jsonDoc = QJsonDocument::fromVariant(request);
QByteArray payload = jsonDoc.toJson(QJsonDocument::Compact) + '\n';
if (socket->state() != QAbstractSocket::ConnectedState) {
qWarning() << "Socket not connected";
return QPair<QVariant, QWebSocket *>(QVariant(), socket);
}
QSignalSpy dataSpy(socket, SIGNAL(textMessageReceived(QString)));
if (slipEnabled) {
SlipDataProcessor::Frame frame;
frame.socketAddress = 0x0000;
frame.data = payload;
socket->sendTextMessage(QString(SlipDataProcessor::serializeData(SlipDataProcessor::buildFrame(frame))));
socket->sendTextMessage(QString::fromUtf8(SlipDataProcessor::serializeData(SlipDataProcessor::buildFrame(frame))));
} else {
socket->sendTextMessage(QString(payload));
}