Prepare client library for tunnel proxy

This commit is contained in:
Simon Stürz 2021-07-30 13:12:42 +02:00
parent 56d32bed2b
commit f0cdb2706b
29 changed files with 777 additions and 94 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 90 KiB

After

Width:  |  Height:  |  Size: 104 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 19 KiB

After

Width:  |  Height:  |  Size: 22 KiB

View File

@ -1,33 +1,39 @@
title Remote tunnel proxy
nymea->proxy: RegisterProxyTunnelServer(uuid, name)
nymea->proxy: TunnelProxy.RegisterServer(serverUuid, serverName)
note over proxy: Register the server using the uuid
nymea<-proxy: Success
nymea<-proxy: TunnelProxyErrorNoError
note over nymea, proxy: Protocol from now on SLIP\nThe proxy is client 0x0000
note over nymea, proxy: SLIP encoded data: 2 Bytes address + data
proxy<-client: ConnectProxyTunnelClient(uuid, name, serverUuid)
proxy<-client: TunnelProxy.RegisterClient(clientUuid, clientName, serverUuid)
note over proxy: Search server using uuid
note over proxy: Search server with given uuid
note over proxy: Server: Assign address 0x0001 for this client socket
note over proxy: Server: Assign address for this client socket (0x0001)
proxy->nymea: SLIP:0x0000: ProxyTunnelClientConnected (address: 0x0001)
proxy->nymea: SLIP:0x0000: ProxyTunnel.ClientConnected (address: 0x0001)
proxy<-nymea: SLIP:0x0000: AckProxyTunnelClient (address: 0x0001)
proxy<-nymea: SLIP:0x0000: ProxyTunnel.AcceptClient (address: 0x0001)
proxy->client: ProxyTunnelEstablished(uuid, name, serverUuid)
proxy->nymea: TunnelProxyErrorNoError
note over proxy, client: Protocol from now on SLIP encoded\nThe proxy is client 0x0000\nThe connected server is 0xFFFF
proxy->client: ProxyTunnel.ConfirmClient(uuid, name, serverUuid)
note over proxy, client: SLIP encoded data: 2 Bytes address + data
note over client: Connected\nAny incomming and outgoing data will\nbe from the connected nymea instance\nuntil disconnected.
note over nymea, client: Connected: The client can now communicate with nymea directly.
note over nymea, client: Connected: The client can now communicate with nymea directly.\nThe proxy will not interpret any data from the client, and from the server only\nthe transmission frame (SLIP + 2 bytes of address)
note over nymea, client: nymea sends SLIP encoded data with address 0x0001 -> client
note over nymea, client: client sends SLIP endcoded data with address 0xFFFF -> nymea
proxy<-client: "data"
nymea<-proxy: SLIP:0x0001 "data"
nymea->proxy: SLIP:0x0001 "data"
proxy->client: "data"

View File

@ -294,12 +294,34 @@ void Engine::clean()
m_proxyServer = nullptr;
}
if (m_tunnelProxyServer) {
m_tunnelProxyServer->stopServer();
delete m_tunnelProxyServer;
m_tunnelProxyServer = nullptr;
}
if (m_tcpSocketServerProxy) {
delete m_tcpSocketServerProxy;
m_tcpSocketServerProxy = nullptr;
}
if (m_webSocketServerProxy) {
delete m_webSocketServerProxy;
m_webSocketServerProxy = nullptr;
}
if (m_tcpSocketServerTunnelProxy) {
delete m_tcpSocketServerTunnelProxy;
m_tcpSocketServerTunnelProxy = nullptr;
}
if (m_webSocketServerTunnelProxy) {
delete m_webSocketServerTunnelProxy;
m_webSocketServerTunnelProxy = nullptr;
}
if (m_configuration) {
delete m_configuration;
m_configuration = nullptr;
}
}

View File

@ -83,7 +83,6 @@ public:
MonitorServer *monitorServer() const;
LogEngine *logEngine() const;
private:
explicit Engine(QObject *parent = nullptr);
~Engine();

View File

@ -40,6 +40,7 @@ TunnelProxyHandler::TunnelProxyHandler(QObject *parent) : JsonHandler(parent)
// Methods
QVariantMap params; QVariantMap returns;
// Server
params.clear(); returns.clear();
setDescription("RegisterServer", "Register a new TunnelProxy server on this instance. Multiple TunnelProxy clients can be connected to the registered server on success.");
params.insert("serverName", JsonTypes::basicTypeToString(JsonTypes::String));
@ -48,6 +49,7 @@ TunnelProxyHandler::TunnelProxyHandler(QObject *parent) : JsonHandler(parent)
returns.insert("tunnelProxyError", JsonTypes::tunnelProxyErrorRef());
setReturns("RegisterServer", returns);
// Client
params.clear(); returns.clear();
setDescription("RegisterClient", "Register a new TunnelProxy client on TunnelProxy server with the given serverUuid..");
params.insert("clientName", JsonTypes::basicTypeToString(JsonTypes::String));
@ -58,6 +60,8 @@ TunnelProxyHandler::TunnelProxyHandler(QObject *parent) : JsonHandler(parent)
setReturns("RegisterClient", returns);
// Notifications
// Server
params.clear(); returns.clear();
setDescription("ClientConnected", "Emitted whenever a new client has been connected to a registered server. "
"Only tunnel proxy clients registered as server will receive this notification.");

View File

@ -247,6 +247,9 @@ void JsonRpcServer::processDataPackage(TransportClient *transportClient, const Q
reply->setClientId(transportClient->clientId());
reply->setCommandId(commandId);
sendResponse(transportClient, commandId, reply->data());
// TODO: check if the client should be disconnected after this response
reply->deleteLater();
}
}

View File

@ -65,6 +65,7 @@ void TcpSocketServer::killClientConnection(const QUuid &clientId, const QString
return;
qCWarning(dcTcpSocketServer()) << "Killing client connection" << clientId.toString() << "Reason:" << killReason;
client->flush();
client->close();
}
@ -139,7 +140,6 @@ SslServer::SslServer(bool sslEnabled, const QSslConfiguration &config, QObject *
QTcpServer(parent),
m_sslEnabled(sslEnabled),
m_config(config)
{
}

View File

@ -77,6 +77,7 @@ void WebSocketServer::killClientConnection(const QUuid &clientId, const QString
return;
qCWarning(dcWebSocketServer()) << "Killing client connection" << clientId.toString() << "Reason:" << killReason;
client->flush();
client->close(QWebSocketProtocol::CloseCodeBadOperation, killReason);
}

View File

@ -23,22 +23,36 @@ void TunnelProxyClient::setType(Type type)
emit typeChanged(m_type);
}
bool TunnelProxyClient::slipEnabled() const
{
return m_slipEnabled;
}
void TunnelProxyClient::setSlipEnabled(bool slipEnabled)
{
m_slipEnabled = slipEnabled;
}
QList<QByteArray> TunnelProxyClient::processData(const QByteArray &data)
{
// TODO: unescape if this data is for the json handler
QList<QByteArray> packages;
// Handle packet fragmentation
m_dataBuffers.append(data);
int splitIndex = m_dataBuffers.indexOf("}\n{");
while (splitIndex > -1) {
packages.append(m_dataBuffers.left(splitIndex + 1));
m_dataBuffers = m_dataBuffers.right(m_dataBuffers.length() - splitIndex - 2);
splitIndex = m_dataBuffers.indexOf("}\n{");
}
if (m_dataBuffers.trimmed().endsWith("}")) {
packages.append(m_dataBuffers);
m_dataBuffers.clear();
if (m_slipEnabled) {
} else {
// Handle json packet fragmentation
m_dataBuffers.append(data);
int splitIndex = m_dataBuffers.indexOf("}\n{");
while (splitIndex > -1) {
packages.append(m_dataBuffers.left(splitIndex + 1));
m_dataBuffers = m_dataBuffers.right(m_dataBuffers.length() - splitIndex - 2);
splitIndex = m_dataBuffers.indexOf("}\n{");
}
if (m_dataBuffers.trimmed().endsWith("}")) {
packages.append(m_dataBuffers);
m_dataBuffers.clear();
}
}
return packages;
@ -47,16 +61,12 @@ QList<QByteArray> TunnelProxyClient::processData(const QByteArray &data)
QDebug operator<<(QDebug debug, TunnelProxyClient *tunnelProxyClient)
{
debug.nospace() << "TunnelProxyClient(";
if (!tunnelProxyClient->name().isEmpty()) {
debug.nospace() << tunnelProxyClient->name() << ", ";
}
debug.nospace() << tunnelProxyClient->interface()->serverName();
debug.nospace() << ", " << tunnelProxyClient->clientId().toString();
debug.nospace() << ", " << tunnelProxyClient->peerAddress().toString();
debug.nospace() << ", " << tunnelProxyClient->creationTimeString() << ")";
debug.nospace() << tunnelProxyClient->name() << ", ";
debug.nospace() << tunnelProxyClient->interface()->serverName()<< ", ";
debug.nospace() << tunnelProxyClient->clientId().toString()<< ", ";
debug.nospace() << tunnelProxyClient->peerAddress().toString() << ", ";
debug.nospace() << tunnelProxyClient->creationTimeString() << ")";
return debug.space();
}
}

View File

@ -23,6 +23,9 @@ public:
Type type() const;
void setType(Type type);
bool slipEnabled() const;
void setSlipEnabled(bool slipEnabled);
// Json server methods
QList<QByteArray> processData(const QByteArray &data) override;
@ -31,6 +34,7 @@ signals:
private:
Type m_type = TypeNone;
bool m_slipEnabled = false;
};

View File

@ -30,9 +30,10 @@
namespace remoteproxy {
TunnelProxyClientConnection::TunnelProxyClientConnection(TransportClient *transportClient, const QUuid &clientUuid, const QString &clientName, const QUuid &serverUuid, QObject *parent) :
TunnelProxyClientConnection::TunnelProxyClientConnection(TransportClient *transportClient, TunnelProxyServerConnection *serverConnection, const QUuid &clientUuid, const QString &clientName, const QUuid &serverUuid, QObject *parent) :
QObject(parent),
m_transportClient(transportClient),
m_serverConnection(serverConnection),
m_clientUuid(clientUuid),
m_clientName(clientName),
m_serverUuid(serverUuid)
@ -45,6 +46,11 @@ TransportClient *TunnelProxyClientConnection::transportClient() const
return m_transportClient;
}
TunnelProxyServerConnection *TunnelProxyClientConnection::serverConnection() const
{
return m_serverConnection;
}
QUuid TunnelProxyClientConnection::clientUuid() const
{
return m_clientUuid;
@ -60,4 +66,13 @@ QUuid TunnelProxyClientConnection::serverUuid() const
return m_serverUuid;
}
QDebug operator<<(QDebug debug, TunnelProxyClientConnection *clientConnection)
{
debug.nospace() << "TunnelProxyClientConnection(";
debug.nospace() << clientConnection->clientName() << ", ";
debug.nospace() << clientConnection->clientUuid().toString() << ", ";
debug.nospace() << clientConnection->transportClient() << ")";
return debug.space();
}
}

View File

@ -30,27 +30,30 @@
#include <QUuid>
#include <QObject>
#include <QDebug>
namespace remoteproxy {
class TransportClient;
class TunnelProxyServerConnection;
class TunnelProxyClientConnection : public QObject
{
Q_OBJECT
public:
explicit TunnelProxyClientConnection(TransportClient *transportClient, const QUuid &clientUuid, const QString &clientName, const QUuid &serverUuid, QObject *parent = nullptr);
explicit TunnelProxyClientConnection(TransportClient *transportClient, TunnelProxyServerConnection *serverConnection, const QUuid &clientUuid, const QString &clientName, const QUuid &serverUuid, QObject *parent = nullptr);
TransportClient *transportClient() const;
TunnelProxyServerConnection *serverConnection() const;
QUuid clientUuid() const;
QString clientName() const;
QUuid serverUuid() const;
signals:
private:
TransportClient *m_transportClient = nullptr;
TunnelProxyServerConnection *m_serverConnection = nullptr;
QUuid m_clientUuid;
QString m_clientName;
@ -58,6 +61,8 @@ private:
};
QDebug operator<<(QDebug debug, TunnelProxyClientConnection *clientConnection);
}
#endif // TUNNELPROXYCLIENTCONNECTION_H

View File

@ -99,6 +99,9 @@ TunnelProxyServer::TunnelProxyError TunnelProxyServer::registerServer(const QUui
tunnelProxyClient->setUuid(serverUuid);
tunnelProxyClient->setName(serverName);
// Enable SLIP from now on
// tunnelProxyClient->setSlipEnabled(true);
TunnelProxyServerConnection *serverConnection = new TunnelProxyServerConnection(tunnelProxyClient, serverUuid, serverName, this);
m_tunnelProxyServerConnections.insert(serverUuid, serverConnection);
@ -121,6 +124,11 @@ TunnelProxyServer::TunnelProxyError TunnelProxyServer::registerClient(const QUui
return TunnelProxyServer::TunnelProxyErrorAlreadyRegistered;
}
if (m_tunnelProxyClientConnections.contains(clientUuid)) {
qCWarning(dcTunnelProxyServer()) << "There is a client already registered with client uuid" << clientUuid.toString();
return TunnelProxyServer::TunnelProxyErrorAlreadyRegistered;
}
// Get the desired server connection
TunnelProxyServerConnection *serverConnection = m_tunnelProxyServerConnections.value(serverUuid);
if (!serverConnection) {
@ -128,20 +136,18 @@ TunnelProxyServer::TunnelProxyError TunnelProxyServer::registerClient(const QUui
return TunnelProxyServer::TunnelProxyErrorServerNotFound;
}
if (m_tunnelProxyClientConnections.contains(clientUuid)) {
qCWarning(dcTunnelProxyServer()) << "There is a client already registered with client uuid" << clientUuid.toString();
return TunnelProxyServer::TunnelProxyErrorAlreadyRegistered;
}
// Not registered yet, we have a connected server for the requested server uuid
tunnelProxyClient->setType(TunnelProxyClient::TypeClient);
tunnelProxyClient->setUuid(clientUuid);
tunnelProxyClient->setName(clientName);
TunnelProxyClientConnection *clientConnection = new TunnelProxyClientConnection(tunnelProxyClient, clientUuid, clientName, serverUuid);
TunnelProxyClientConnection *clientConnection = new TunnelProxyClientConnection(tunnelProxyClient, serverConnection, clientUuid, clientName, serverUuid);
m_tunnelProxyClientConnections.insert(clientUuid, clientConnection);
// TODO: register on the server and wait for te aprovement from the server
qCDebug(dcTunnelProxyServer()) << "Register client" << clientConnection << "-->" << serverConnection;
serverConnection->registerClientConnection(clientConnection);
// TODO: wait for te aprovement from the server
return TunnelProxyServer::TunnelProxyErrorNoError;
}
@ -195,6 +201,8 @@ void TunnelProxyServer::onClientDisconnected(const QUuid &clientId)
if (!serverConnection) {
qCWarning(dcTunnelProxyServer()) << "Could not find server connection for disconnected tunnel proxy client claiming to be a server.";
} else {
// TODO: kill all related clients
serverConnection->deleteLater();
@ -203,11 +211,13 @@ void TunnelProxyServer::onClientDisconnected(const QUuid &clientId)
if (tunnelProxyClient->type() == TunnelProxyClient::TypeClient) {
TunnelProxyClientConnection *clientConnection = m_tunnelProxyClientConnections.take(tunnelProxyClient->uuid());
if (!clientConnection) {
qCWarning(dcTunnelProxyServer()) << "Could not find client connection for disconnected tunnel proxy client claiming to be a client.";
} else {
// TODO: remove from server
if (clientConnection->serverConnection()) {
clientConnection->serverConnection()->unregisterClientConnection(clientConnection);
// TODO: Send client disconnected to the server
}
clientConnection->deleteLater();
}
@ -229,10 +239,23 @@ void TunnelProxyServer::onClientDataAvailable(const QUuid &clientId, const QByte
}
qCDebug(dcTunnelProxyServerTraffic()) << "Client data available" << tunnelProxyClient << qUtf8Printable(data);
if (tunnelProxyClient->type() == TunnelProxyClient::TypeClient) {
// Send the data to the server using slip + frame
// TODO: verify if encoded and for whom this data is... 0x0000 is for the json rpc handler...
m_jsonRpcServer->processData(tunnelProxyClient, data);
} else if (tunnelProxyClient->type() == TunnelProxyClient::TypeServer) {
if (tunnelProxyClient->slipEnabled()) {
} else {
m_jsonRpcServer->processData(tunnelProxyClient, data);
}
// Unpack SLIP data, get address, pipe to client or give it to the json rpc server if address 0x0000
} else {
// Not registered yet or doing other stuff...let the JSON RPC handle this data
m_jsonRpcServer->processData(tunnelProxyClient, data);
}
}
}

View File

@ -27,6 +27,7 @@
#include "tunnelproxyserverconnection.h"
#include "server/transportclient.h"
#include "tunnelproxyclientconnection.h"
namespace remoteproxy {
@ -54,4 +55,23 @@ QString TunnelProxyServerConnection::serverName() const
return m_serverName;
}
void TunnelProxyServerConnection::registerClientConnection(TunnelProxyClientConnection *clientConnection)
{
m_clientConnections.insert(clientConnection->clientUuid(), clientConnection);
}
void TunnelProxyServerConnection::unregisterClientConnection(TunnelProxyClientConnection *clientConnection)
{
m_clientConnections.remove(clientConnection->clientUuid());
}
QDebug operator<<(QDebug debug, TunnelProxyServerConnection *serverConnection)
{
debug.nospace() << "TunnelProxyServerConnection(";
debug.nospace() << serverConnection->serverName() << ", ";
debug.nospace() << serverConnection->serverUuid().toString() << ", ";
debug.nospace() << serverConnection->transportClient() << ")";
return debug.space();
}
}

View File

@ -30,10 +30,12 @@
#include <QUuid>
#include <QObject>
#include <QDebug>
namespace remoteproxy {
class TransportClient;
class TunnelProxyClientConnection;
class TunnelProxyServerConnection : public QObject
{
@ -46,17 +48,22 @@ public:
QUuid serverUuid() const;
QString serverName() const;
void registerClientConnection(TunnelProxyClientConnection *clientConnection);
void unregisterClientConnection(TunnelProxyClientConnection *clientConnection);
signals:
private:
TransportClient *m_transportClient = nullptr;
QUuid m_serverUuid;
QString m_serverName;
QHash<QUuid, TunnelProxyClientConnection *> m_clientConnections;
};
QDebug operator<<(QDebug debug, TunnelProxyServerConnection *serverConnection);
}
#endif // TUNNELPROXYSERVERCONNECTION_H

View File

@ -1,18 +1,24 @@
INCLUDEPATH += $${PWD}
INCLUDEPATH += $$PWD
HEADERS += \
$${PWD}/tcpsocketconnection.h \
$${PWD}/proxyjsonrpcclient.h \
$${PWD}/jsonreply.h \
$${PWD}/remoteproxyconnection.h \
$${PWD}/proxyconnection.h \
$${PWD}/websocketconnection.h
$$PWD/tunnelproxy/tunnelproxyjsonrpcclient.h \
$$PWD/tunnelproxy/tunnelproxysocket.h \
$$PWD/tunnelproxy/tunnelproxyserver.h \
$$PWD/tcpsocketconnection.h \
$$PWD/proxyjsonrpcclient.h \
$$PWD/jsonreply.h \
$$PWD/remoteproxyconnection.h \
$$PWD/proxyconnection.h \
$$PWD/websocketconnection.h
SOURCES += \
$${PWD}/tcpsocketconnection.cpp \
$${PWD}/proxyjsonrpcclient.cpp \
$${PWD}/jsonreply.cpp \
$${PWD}/remoteproxyconnection.cpp \
$${PWD}/proxyconnection.cpp \
$${PWD}/websocketconnection.cpp
$$PWD/tunnelproxy/tunnelproxyjsonrpcclient.cpp \
$$PWD/tunnelproxy/tunnelproxysocket.cpp \
$$PWD/tunnelproxy/tunnelproxyserver.cpp \
$$PWD/tcpsocketconnection.cpp \
$$PWD/proxyjsonrpcclient.cpp \
$$PWD/jsonreply.cpp \
$$PWD/remoteproxyconnection.cpp \
$$PWD/proxyconnection.cpp \
$$PWD/websocketconnection.cpp

View File

@ -0,0 +1,37 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*
* Copyright 2013 - 2021, nymea GmbH
* Contact: contact@nymea.io
*
* This file is part of nymea.
* This project including source code and documentation is protected by copyright law, and
* remains the property of nymea GmbH. All rights, including reproduction, publication,
* editing and translation, are reserved. The use of this project is subject to the terms of a
* license agreement to be concluded with nymea GmbH in accordance with the terms
* of use of nymea GmbH, available under https://nymea.io/license
*
* GNU Lesser General Public License Usage
* Alternatively, this project may be redistributed and/or modified under the terms of the GNU
* Lesser General Public License as published by the Free Software Foundation; version 3.
* this project is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License along with this project.
* If not, see <https://www.gnu.org/licenses/>.
*
* For any further details and any questions please contact us under contact@nymea.io
* or see our FAQ/Licensing Information on https://nymea.io/license/faq
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#include "tunnelproxyjsonrpcclient.h"
namespace remoteproxyclient {
TunnelProxyJsonRpcClient::TunnelProxyJsonRpcClient(QObject *parent) : QObject(parent)
{
}
}

View File

@ -0,0 +1,48 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*
* Copyright 2013 - 2021, nymea GmbH
* Contact: contact@nymea.io
*
* This file is part of nymea.
* This project including source code and documentation is protected by copyright law, and
* remains the property of nymea GmbH. All rights, including reproduction, publication,
* editing and translation, are reserved. The use of this project is subject to the terms of a
* license agreement to be concluded with nymea GmbH in accordance with the terms
* of use of nymea GmbH, available under https://nymea.io/license
*
* GNU Lesser General Public License Usage
* Alternatively, this project may be redistributed and/or modified under the terms of the GNU
* Lesser General Public License as published by the Free Software Foundation; version 3.
* this project is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License along with this project.
* If not, see <https://www.gnu.org/licenses/>.
*
* For any further details and any questions please contact us under contact@nymea.io
* or see our FAQ/Licensing Information on https://nymea.io/license/faq
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#ifndef TUNNELPROXYJSONRPCCLIENT_H
#define TUNNELPROXYJSONRPCCLIENT_H
#include <QObject>
namespace remoteproxyclient {
class TunnelProxyJsonRpcClient : public QObject
{
Q_OBJECT
public:
explicit TunnelProxyJsonRpcClient(QObject *parent = nullptr);
signals:
};
}
#endif // TUNNELPROXYJSONRPCCLIENT_H

View File

@ -0,0 +1,84 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*
* Copyright 2013 - 2021, nymea GmbH
* Contact: contact@nymea.io
*
* This file is part of nymea.
* This project including source code and documentation is protected by copyright law, and
* remains the property of nymea GmbH. All rights, including reproduction, publication,
* editing and translation, are reserved. The use of this project is subject to the terms of a
* license agreement to be concluded with nymea GmbH in accordance with the terms
* of use of nymea GmbH, available under https://nymea.io/license
*
* GNU Lesser General Public License Usage
* Alternatively, this project may be redistributed and/or modified under the terms of the GNU
* Lesser General Public License as published by the Free Software Foundation; version 3.
* this project is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License along with this project.
* If not, see <https://www.gnu.org/licenses/>.
*
* For any further details and any questions please contact us under contact@nymea.io
* or see our FAQ/Licensing Information on https://nymea.io/license/faq
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#include "tunnelproxyserver.h"
#include "proxyconnection.h"
#include "tcpsocketconnection.h"
#include "websocketconnection.h"
namespace remoteproxyclient {
TunnelProxyServer::TunnelProxyServer(const QUuid &serverUuid, const QString &serverName, QObject *parent) :
QObject(parent),
m_serverUuid(serverUuid),
m_serverName(serverName)
{
}
TunnelProxyServer::TunnelProxyServer(const QUuid &serverUuid, const QString &serverName, ConnectionType connectionType, QObject *parent) :
QObject(parent),
m_serverUuid(serverUuid),
m_serverName(serverName),
m_connectionType(connectionType)
{
}
TunnelProxyServer::~TunnelProxyServer()
{
}
bool TunnelProxyServer::running() const
{
return m_running;
}
void TunnelProxyServer::ignoreSslErrors()
{
m_connection->ignoreSslErrors();
}
void TunnelProxyServer::ignoreSslErrors(const QList<QSslError> &errors)
{
m_connection->ignoreSslErrors(errors);
}
void remoteproxyclient::TunnelProxyServer::startServer(const QUrl &serverUrl)
{
// Register as server to the remote proxy
m_serverUrl = serverUrl;
}
void remoteproxyclient::TunnelProxyServer::stopServer()
{
// Close the server connection and all related sockets
}
}

View File

@ -0,0 +1,90 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*
* Copyright 2013 - 2021, nymea GmbH
* Contact: contact@nymea.io
*
* This file is part of nymea.
* This project including source code and documentation is protected by copyright law, and
* remains the property of nymea GmbH. All rights, including reproduction, publication,
* editing and translation, are reserved. The use of this project is subject to the terms of a
* license agreement to be concluded with nymea GmbH in accordance with the terms
* of use of nymea GmbH, available under https://nymea.io/license
*
* GNU Lesser General Public License Usage
* Alternatively, this project may be redistributed and/or modified under the terms of the GNU
* Lesser General Public License as published by the Free Software Foundation; version 3.
* this project is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License along with this project.
* If not, see <https://www.gnu.org/licenses/>.
*
* For any further details and any questions please contact us under contact@nymea.io
* or see our FAQ/Licensing Information on https://nymea.io/license/faq
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#ifndef TUNNELPROXYSERVER_H
#define TUNNELPROXYSERVER_H
#include <QUuid>
#include <QObject>
#include <QLoggingCategory>
Q_DECLARE_LOGGING_CATEGORY(dcRemoteProxyTunnelProxyServer)
#include "proxyconnection.h"
#include "tunnelproxysocket.h"
namespace remoteproxyclient {
class ProxyConnection;
class TunnelProxyJsonRpcClient;
class TunnelProxyServer : public QObject
{
Q_OBJECT
public:
enum ConnectionType {
ConnectionTypeWebSocket,
ConnectionTypeTcpSocket
};
Q_ENUM(ConnectionType)
explicit TunnelProxyServer(const QUuid &serverUuid, const QString &serverName, QObject *parent = nullptr);
explicit TunnelProxyServer(const QUuid &serverUuid, const QString &serverName, ConnectionType connectionType, QObject *parent = nullptr);
~TunnelProxyServer();
bool running() const;
QAbstractSocket::SocketError error() const;
void ignoreSslErrors();
void ignoreSslErrors(const QList<QSslError> &errors);
public slots:
void startServer(const QUrl &serverUrl);
void stopServer();
signals:
void runningChanged(bool running);
void sslErrors(const QList<QSslError> &errors);
private:
QUuid m_serverUuid;
QString m_serverName;
ConnectionType m_connectionType = ConnectionTypeTcpSocket;
bool m_running = false;
QUrl m_serverUrl;
QAbstractSocket::SocketError m_error = QAbstractSocket::UnknownSocketError;
ProxyConnection *m_connection = nullptr;
TunnelProxyJsonRpcClient *m_jsonClient = nullptr;
};
}
#endif // TUNNELPROXYSERVER_H

View File

@ -0,0 +1,37 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*
* Copyright 2013 - 2021, nymea GmbH
* Contact: contact@nymea.io
*
* This file is part of nymea.
* This project including source code and documentation is protected by copyright law, and
* remains the property of nymea GmbH. All rights, including reproduction, publication,
* editing and translation, are reserved. The use of this project is subject to the terms of a
* license agreement to be concluded with nymea GmbH in accordance with the terms
* of use of nymea GmbH, available under https://nymea.io/license
*
* GNU Lesser General Public License Usage
* Alternatively, this project may be redistributed and/or modified under the terms of the GNU
* Lesser General Public License as published by the Free Software Foundation; version 3.
* this project is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License along with this project.
* If not, see <https://www.gnu.org/licenses/>.
*
* For any further details and any questions please contact us under contact@nymea.io
* or see our FAQ/Licensing Information on https://nymea.io/license/faq
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#include "tunnelproxysocket.h"
namespace remoteproxyclient {
TunnelProxySocket::TunnelProxySocket(QObject *parent) : QObject(parent)
{
}
}

View File

@ -0,0 +1,47 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*
* Copyright 2013 - 2021, nymea GmbH
* Contact: contact@nymea.io
*
* This file is part of nymea.
* This project including source code and documentation is protected by copyright law, and
* remains the property of nymea GmbH. All rights, including reproduction, publication,
* editing and translation, are reserved. The use of this project is subject to the terms of a
* license agreement to be concluded with nymea GmbH in accordance with the terms
* of use of nymea GmbH, available under https://nymea.io/license
*
* GNU Lesser General Public License Usage
* Alternatively, this project may be redistributed and/or modified under the terms of the GNU
* Lesser General Public License as published by the Free Software Foundation; version 3.
* this project is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License along with this project.
* If not, see <https://www.gnu.org/licenses/>.
*
* For any further details and any questions please contact us under contact@nymea.io
* or see our FAQ/Licensing Information on https://nymea.io/license/faq
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#ifndef TUNNELPROXYSOCKET_H
#define TUNNELPROXYSOCKET_H
#include <QObject>
namespace remoteproxyclient {
class TunnelProxySocket : public QObject
{
Q_OBJECT
public:
explicit TunnelProxySocket(QObject *parent = nullptr);
signals:
};
}
#endif // TUNNELPROXYSOCKET_H

View File

@ -4,7 +4,7 @@ QT -= gui
# Define versions
SERVER_NAME=nymea-remoteproxy
API_VERSION_MAJOR=0
API_VERSION_MINOR=3
API_VERSION_MINOR=4
SERVER_VERSION=0.2.0
DEFINES += SERVER_NAME_STRING=\\\"$${SERVER_NAME}\\\" \

View File

@ -45,12 +45,24 @@ RemoteProxyTestsProxy::RemoteProxyTestsProxy(QObject *parent) :
void RemoteProxyTestsProxy::startStopServer()
{
resetDebugCategories();
addDebugCategory("ProxyServer.debug=true");
addDebugCategory("Engine.debug=true");
addDebugCategory("JsonRpc.debug=true");
addDebugCategory("TcpSocketServer.debug=true");
addDebugCategory("WebSocketServer.debug=true");
startServer();
stopServer();
resetDebugCategories();
}
void RemoteProxyTestsProxy::dummyAuthenticator()
{
resetDebugCategories();
addDebugCategory("ProxyServer.debug=true");
cleanUpEngine();
m_configuration = new ProxyConfiguration(this);
@ -411,7 +423,7 @@ void RemoteProxyTestsProxy::getHello()
// WebSocket
response = invokeWebSocketProxyApiCall("RemoteProxy.Hello").toMap();
//qDebug() << qUtf8Printable(QJsonDocument::fromVariant(response).toJson(QJsonDocument::Indented));
qDebug() << qUtf8Printable(QJsonDocument::fromVariant(response).toJson(QJsonDocument::Indented));
// Verify data
QVERIFY(!response.isEmpty());
@ -423,7 +435,7 @@ void RemoteProxyTestsProxy::getHello()
// TCP
response.clear();
response = invokeTcpSocketProxyApiCall("RemoteProxy.Hello").toMap();
//qDebug() << qUtf8Printable(QJsonDocument::fromVariant(response).toJson(QJsonDocument::Indented));
qDebug() << qUtf8Printable(QJsonDocument::fromVariant(response).toJson(QJsonDocument::Indented));
// Verify data
QVERIFY(!response.isEmpty());

View File

@ -122,10 +122,9 @@ void RemoteProxyTestsTunnelProxy::getHello()
{
// Start the server
startServer();
QVariantMap response;
// WebSocket
response = invokeWebSocketTunnelProxyApiCall("RemoteProxy.Hello").toMap();
QVariantMap response = invokeWebSocketTunnelProxyApiCall("RemoteProxy.Hello").toMap();
qDebug() << qUtf8Printable(QJsonDocument::fromVariant(response).toJson(QJsonDocument::Indented));
// Verify data
@ -147,7 +146,6 @@ void RemoteProxyTestsTunnelProxy::getHello()
QCOMPARE(response.value("params").toMap().value("version").toString(), QString(SERVER_VERSION_STRING));
QCOMPARE(response.value("params").toMap().value("apiVersion").toString(), QString(API_VERSION_STRING));
// Clean up
stopServer();
}
@ -250,6 +248,88 @@ void RemoteProxyTestsTunnelProxy::registerServer()
stopServer();
}
void RemoteProxyTestsTunnelProxy::registerClient_data()
{
QTest::addColumn<QString>("name");
QTest::addColumn<QString>("uuid");
QTest::addColumn<TunnelProxyServer::TunnelProxyError>("expectedError");
QTest::addColumn<bool>("serverExists");
QTest::addColumn<QString>("serverUuid");
QTest::addColumn<TunnelProxyServer::TunnelProxyError>("expectedServerError");
QTest::newRow("valid client: valid server") << "Friendly client" << QUuid::createUuid().toString() << TunnelProxyServer::TunnelProxyErrorNoError << true << QUuid::createUuid().toString() << TunnelProxyServer::TunnelProxyErrorNoError;
QTest::newRow("valid client: no server") << "Friendly client" << QUuid::createUuid().toString() << TunnelProxyServer::TunnelProxyErrorServerNotFound << false << QUuid::createUuid().toString() << TunnelProxyServer::TunnelProxyErrorNoError;
QTest::newRow("valid client: invalid server uuid") << "Friendly client" << QUuid::createUuid().toString() << TunnelProxyServer::TunnelProxyErrorInvalidUuid << true << QUuid().toString() << TunnelProxyServer::TunnelProxyErrorInvalidUuid;
QTest::newRow("invalid client uuid: valid server uuid") << "Friendly client" << QUuid().toString() << TunnelProxyServer::TunnelProxyErrorInvalidUuid << true << QUuid::createUuid().toString() << TunnelProxyServer::TunnelProxyErrorNoError;
QTest::newRow("invalid client uuid: invalid server uuid") << "Friendly client" << "hello again" << TunnelProxyServer::TunnelProxyErrorInvalidUuid << true << "it's me" << TunnelProxyServer::TunnelProxyErrorInvalidUuid;
}
void RemoteProxyTestsTunnelProxy::registerClient()
{
QFETCH(QString, name);
QFETCH(QString, uuid);
QFETCH(TunnelProxyServer::TunnelProxyError, expectedError);
QFETCH(bool, serverExists);
QFETCH(QString, serverUuid);
QFETCH(TunnelProxyServer::TunnelProxyError, expectedServerError);
// Start the server
startServer();
resetDebugCategories();
addDebugCategory("TunnelProxyServer.debug=true");
QSslSocket *socket = nullptr;
if (serverExists) {
QVariantMap serverParams;
serverParams.insert("serverName", "dummy server");
serverParams.insert("serverUuid", serverUuid);
// TCP socket
QPair<QVariant, QSslSocket *> result = invokeTcpSocketTunnelProxyApiCallPersistant("TunnelProxy.RegisterServer", serverParams);
QVariantMap response = result.first.toMap();
socket = result.second;
QVERIFY(!response.isEmpty());
QVERIFY(response.value("status").toString() == "success");
QVERIFY(response.value("params").toMap().contains("tunnelProxyError"));
verifyTunnelProxyError(response, expectedServerError);
}
// Register a new client
QVariantMap params;
params.insert("clientName", name);
params.insert("clientUuid", uuid);
params.insert("serverUuid", serverUuid);
// Websocket
QVariantMap response = invokeWebSocketTunnelProxyApiCall("TunnelProxy.RegisterClient", params).toMap();
QVERIFY(!response.isEmpty());
QVERIFY(response.value("status").toString() == "success");
QVERIFY(response.value("params").toMap().contains("tunnelProxyError"));
verifyTunnelProxyError(response, expectedError);
QTest::qWait(100);
// TCP Socket
response = invokeTcpSocketTunnelProxyApiCall("TunnelProxy.RegisterClient", params).toMap();
QVERIFY(!response.isEmpty());
QVERIFY(response.value("status").toString() == "success");
QVERIFY(response.value("params").toMap().contains("tunnelProxyError"));
verifyTunnelProxyError(response, expectedError);
QTest::qWait(100);
if (socket) {
// Close the tcp socket
socket->close();
delete socket;
}
// Clean up
stopServer();
}
void RemoteProxyTestsTunnelProxy::registerServerDuplicated()
{
// Start the server
@ -257,6 +337,7 @@ void RemoteProxyTestsTunnelProxy::registerServerDuplicated()
resetDebugCategories();
addDebugCategory("TunnelProxyServer.debug=true");
addDebugCategory("JsonRpcTraffic.debug=true");
// Register a new server
QString serverName = "tunnel proxy server awesome nymea installation";
@ -334,5 +415,131 @@ void RemoteProxyTestsTunnelProxy::registerServerDuplicated()
stopServer();
}
void RemoteProxyTestsTunnelProxy::registerClientDuplicated()
{
// Start the server
startServer();
resetDebugCategories();
addDebugCategory("TunnelProxyServer.debug=true");
addDebugCategory("JsonRpcTraffic.debug=true");
// Create the server and keep it up
QString serverName = "creative server name";
QUuid serverUuid = QUuid::createUuid();
QVariantMap serverParams;
serverParams.insert("serverName", serverName);
serverParams.insert("serverUuid", serverUuid.toString());
// TCP socket
QPair<QVariant, QSslSocket *> serverResult = invokeTcpSocketTunnelProxyApiCallPersistant("TunnelProxy.RegisterServer", serverParams);
QVariantMap response = serverResult.first.toMap();
QSslSocket *serverSocket = serverResult.second;
QVERIFY(!response.isEmpty());
QVERIFY(response.value("status").toString() == "success");
QVERIFY(response.value("params").toMap().contains("tunnelProxyError"));
verifyTunnelProxyError(response);
// Connect a client TCP
QString clientName = "creative server name";
QUuid clientUuid = QUuid::createUuid();
QVariantMap clientParams;
clientParams.insert("clientName", serverName);
clientParams.insert("clientUuid", clientUuid.toString());
clientParams.insert("serverUuid", serverUuid.toString());
QPair<QVariant, QSslSocket *> clientResult = invokeTcpSocketTunnelProxyApiCallPersistant("TunnelProxy.RegisterClient", clientParams);
response = clientResult.first.toMap();
QSslSocket *clientSocketTcp = clientResult.second;
QVERIFY(!response.isEmpty());
QVERIFY(response.value("status").toString() == "success");
QVERIFY(response.value("params").toMap().contains("tunnelProxyError"));
verifyTunnelProxyError(response);
// Connect another client WebSocket
QPair<QVariant, QSslSocket *> clientResultWS = invokeTcpSocketTunnelProxyApiCallPersistant("TunnelProxy.RegisterClient", clientParams);
response = clientResultWS.first.toMap();
QSslSocket *clientSocketWs = clientResultWS.second;
QVERIFY(!response.isEmpty());
QVERIFY(response.value("status").toString() == "success");
QVERIFY(response.value("params").toMap().contains("tunnelProxyError"));
verifyTunnelProxyError(response, TunnelProxyServer::TunnelProxyErrorAlreadyRegistered);
// CleanUp
if (clientSocketTcp) {
// Close the tcp socket
clientSocketTcp->close();
delete clientSocketTcp;
}
if (clientSocketWs) {
// Close the tcp socket
clientSocketWs->close();
delete clientSocketWs;
}
if (serverSocket) {
// Close the tcp socket
serverSocket->close();
delete serverSocket;
}
resetDebugCategories();
// Clean up
stopServer();
}
void RemoteProxyTestsTunnelProxy::crossRegisterServerClient()
{
// Start the server
startServer();
resetDebugCategories();
addDebugCategory("TunnelProxyServer.debug=true");
addDebugCategory("JsonRpcTraffic.debug=true");
// Create the server and keep it up
QString serverName = "creative server name";
QUuid serverUuid = QUuid::createUuid();
QVariantMap serverParams;
serverParams.insert("serverName", serverName);
serverParams.insert("serverUuid", serverUuid.toString());
// TCP socket
QPair<QVariant, QSslSocket *> serverResult = invokeTcpSocketTunnelProxyApiCallPersistant("TunnelProxy.RegisterServer", serverParams);
QVariantMap response = serverResult.first.toMap();
QSslSocket *serverSocket = serverResult.second;
QVERIFY(!response.isEmpty());
QVERIFY(response.value("status").toString() == "success");
QVERIFY(response.value("params").toMap().contains("tunnelProxyError"));
verifyTunnelProxyError(response);
// Now try to register as client
QVariantMap clientParams;
clientParams.insert("clientName", "creative client name");
clientParams.insert("clientUuid", QUuid::createUuid().toString());
clientParams.insert("serverUuid", serverUuid.toString());
QPair<QVariant, QSslSocket *> result = invokeTcpSocketTunnelProxyApiCallPersistant("TunnelProxy.RegisterClient", clientParams, serverSocket);
response = result.first.toMap();
QVERIFY(!response.isEmpty());
QVERIFY(response.value("status").toString() == "success");
QVERIFY(response.value("params").toMap().contains("tunnelProxyError"));
verifyTunnelProxyError(response, TunnelProxyServer::TunnelProxyErrorAlreadyRegistered);
serverSocket->close();
delete serverSocket;
resetDebugCategories();
// Clean up
stopServer();
}
QTEST_MAIN(RemoteProxyTestsTunnelProxy)

View File

@ -57,9 +57,14 @@ private slots:
void registerServer_data();
void registerServer();
void registerServerDuplicated();
void registerClient_data();
void registerClient();
void registerServerDuplicated();
void registerClientDuplicated();
void crossRegisterServerClient();
};
#endif // REMOTEPROXYTESTSTUNNELPROXY_H

View File

@ -87,7 +87,6 @@ void BaseTest::cleanUpEngine()
m_authenticator = nullptr;
if (m_configuration) {
delete m_configuration;
m_configuration = nullptr;
}
}
@ -132,6 +131,8 @@ void BaseTest::startServer()
QVERIFY(Engine::instance()->tcpSocketServerProxy()->running());
QVERIFY(Engine::instance()->webSocketServerTunnelProxy()->running());
QVERIFY(Engine::instance()->tcpSocketServerTunnelProxy()->running());
QVERIFY(Engine::instance()->proxyServer()->running());
QVERIFY(Engine::instance()->tunnelProxyServer()->running());
QVERIFY(Engine::instance()->monitorServer()->running());
}
@ -146,10 +147,8 @@ void BaseTest::stopServer()
cleanUpEngine();
}
QVariant BaseTest::invokeWebSocketProxyApiCall(const QString &method, const QVariantMap params, bool remainsConnected)
QVariant BaseTest::invokeWebSocketProxyApiCall(const QString &method, const QVariantMap params)
{
Q_UNUSED(remainsConnected)
QVariantMap request;
request.insert("id", m_commandCounter);
request.insert("method", method);
@ -241,10 +240,8 @@ QVariant BaseTest::injectWebSocketProxyData(const QByteArray &data)
return QVariant();
}
QVariant BaseTest::invokeTcpSocketProxyApiCall(const QString &method, const QVariantMap params, bool remainsConnected)
QVariant BaseTest::invokeTcpSocketProxyApiCall(const QString &method, const QVariantMap params)
{
Q_UNUSED(remainsConnected)
QVariantMap request;
request.insert("id", m_commandCounter);
request.insert("method", method);
@ -461,10 +458,8 @@ QVariant BaseTest::injectTcpSocketProxyData(const QByteArray &data)
return jsonDoc.toVariant();
}
QVariant BaseTest::invokeWebSocketTunnelProxyApiCall(const QString &method, const QVariantMap params, bool remainsConnected)
QVariant BaseTest::invokeWebSocketTunnelProxyApiCall(const QString &method, const QVariantMap params)
{
Q_UNUSED(remainsConnected)
QVariantMap request;
request.insert("id", m_commandCounter);
request.insert("method", method);
@ -485,10 +480,8 @@ QVariant BaseTest::invokeWebSocketTunnelProxyApiCall(const QString &method, cons
socket->sendTextMessage(QString(jsonDoc.toJson(QJsonDocument::Compact)));
dataSpy.wait();
if (!remainsConnected) {
socket->close();
socket->deleteLater();
}
socket->close();
socket->deleteLater();
for (int i = 0; i < dataSpy.count(); i++) {
// Make sure the response ends with '}\n'
@ -559,10 +552,8 @@ QVariant BaseTest::injectWebSocketTunnelProxyData(const QByteArray &data)
return QVariant();
}
QVariant BaseTest::invokeTcpSocketTunnelProxyApiCall(const QString &method, const QVariantMap params, bool remainsConnected)
QVariant BaseTest::invokeTcpSocketTunnelProxyApiCall(const QString &method, const QVariantMap params)
{
Q_UNUSED(remainsConnected)
QVariantMap request;
request.insert("id", m_commandCounter);
request.insert("method", method);

View File

@ -85,16 +85,16 @@ protected:
void startServer();
void stopServer();
QVariant invokeWebSocketProxyApiCall(const QString &method, const QVariantMap params = QVariantMap(), bool remainsConnected = true);
QVariant invokeWebSocketProxyApiCall(const QString &method, const QVariantMap params = QVariantMap());
QVariant injectWebSocketProxyData(const QByteArray &data);
QVariant invokeTcpSocketProxyApiCall(const QString &method, const QVariantMap params = QVariantMap(), bool remainsConnected = true);
QVariant invokeTcpSocketProxyApiCall(const QString &method, const QVariantMap params = QVariantMap());
QVariant injectTcpSocketProxyData(const QByteArray &data);
QVariant invokeWebSocketTunnelProxyApiCall(const QString &method, const QVariantMap params = QVariantMap(), bool remainsConnected = true);
QVariant invokeWebSocketTunnelProxyApiCall(const QString &method, const QVariantMap params = QVariantMap());
QVariant injectWebSocketTunnelProxyData(const QByteArray &data);
QVariant invokeTcpSocketTunnelProxyApiCall(const QString &method, const QVariantMap params = QVariantMap(), bool remainsConnected = true);
QVariant invokeTcpSocketTunnelProxyApiCall(const QString &method, const QVariantMap params = QVariantMap());
QVariant injectTcpSocketTunnelProxyData(const QByteArray &data);
QPair<QVariant, QSslSocket *> invokeTcpSocketTunnelProxyApiCallPersistant(const QString &method, const QVariantMap params = QVariantMap(), QSslSocket *existingSocket = nullptr);