Add server and client registration and prepare client data multiplexing
This commit is contained in:
parent
3174387e96
commit
56d32bed2b
@ -101,7 +101,7 @@ void Engine::start(ProxyConfiguration *configuration)
|
||||
|
||||
// Tunnel proxy
|
||||
// -------------------------------------
|
||||
m_tunnelProxyManager = new TunnelProxyManager(this);
|
||||
m_tunnelProxyServer = new TunnelProxyServer(this);
|
||||
m_webSocketServerTunnelProxy = new WebSocketServer(m_configuration->sslEnabled(), m_configuration->sslConfiguration(), this);
|
||||
m_tcpSocketServerTunnelProxy = new TcpSocketServer(m_configuration->sslEnabled(), m_configuration->sslConfiguration(), this);
|
||||
|
||||
@ -120,12 +120,12 @@ void Engine::start(ProxyConfiguration *configuration)
|
||||
m_tcpSocketServerTunnelProxy->setServerUrl(tcpSocketServerTunnelProxyUrl);
|
||||
|
||||
// Register the transport interfaces in the proxy server
|
||||
m_tunnelProxyManager->registerTransportInterface(m_webSocketServerTunnelProxy);
|
||||
m_tunnelProxyManager->registerTransportInterface(m_tcpSocketServerTunnelProxy);
|
||||
m_tunnelProxyServer->registerTransportInterface(m_webSocketServerTunnelProxy);
|
||||
m_tunnelProxyServer->registerTransportInterface(m_tcpSocketServerTunnelProxy);
|
||||
|
||||
// Start the server
|
||||
qCDebug(dcEngine()) << "Starting the tunnel proxy manager...";
|
||||
m_tunnelProxyManager->startServer();
|
||||
m_tunnelProxyServer->startServer();
|
||||
|
||||
// Start the monitor server
|
||||
m_monitorServer = new MonitorServer(configuration->monitorSocketFileName(), this);
|
||||
@ -195,9 +195,9 @@ ProxyServer *Engine::proxyServer() const
|
||||
return m_proxyServer;
|
||||
}
|
||||
|
||||
TunnelProxyManager *Engine::tunnelProxyManager() const
|
||||
TunnelProxyServer *Engine::tunnelProxyServer() const
|
||||
{
|
||||
return m_tunnelProxyManager;
|
||||
return m_tunnelProxyServer;
|
||||
}
|
||||
|
||||
TcpSocketServer *Engine::tcpSocketServerProxy() const
|
||||
|
||||
@ -43,7 +43,7 @@
|
||||
#include "server/tcpsocketserver.h"
|
||||
#include "server/websocketserver.h"
|
||||
#include "authentication/authenticator.h"
|
||||
#include "tunnelproxy/tunnelproxymanager.h"
|
||||
#include "tunnelproxy/tunnelproxyserver.h"
|
||||
|
||||
namespace remoteproxy {
|
||||
|
||||
@ -71,7 +71,7 @@ public:
|
||||
Authenticator *authenticator() const;
|
||||
|
||||
ProxyServer *proxyServer() const;
|
||||
TunnelProxyManager *tunnelProxyManager() const;
|
||||
TunnelProxyServer *tunnelProxyServer() const;
|
||||
|
||||
TcpSocketServer *tcpSocketServerProxy() const;
|
||||
WebSocketServer *webSocketServerProxy() const;
|
||||
@ -101,7 +101,7 @@ private:
|
||||
Authenticator *m_authenticator = nullptr;
|
||||
|
||||
ProxyServer *m_proxyServer = nullptr;
|
||||
TunnelProxyManager *m_tunnelProxyManager = nullptr;
|
||||
TunnelProxyServer *m_tunnelProxyServer = nullptr;
|
||||
|
||||
TcpSocketServer *m_tcpSocketServerProxy = nullptr;
|
||||
WebSocketServer *m_webSocketServerProxy = nullptr;
|
||||
|
||||
@ -63,7 +63,7 @@ QString AuthenticationHandler::name() const
|
||||
|
||||
JsonReply *AuthenticationHandler::Authenticate(const QVariantMap ¶ms, TransportClient *transportClient)
|
||||
{
|
||||
QString uuid = params.value("uuid").toString();
|
||||
QUuid uuid = params.value("uuid").toUuid();
|
||||
QString name = params.value("name").toString();
|
||||
QString token = params.value("token").toString();
|
||||
QString nonce = params.value("nonce").toString();
|
||||
|
||||
@ -62,7 +62,7 @@ void JsonTypes::init()
|
||||
// Declare types
|
||||
s_basicType = enumToStrings(JsonTypes::staticMetaObject, "BasicType");
|
||||
s_authenticationError = enumToStrings(Authenticator::staticMetaObject, "AuthenticationError");
|
||||
s_tunnelProxyError = enumToStrings(TunnelProxyManager::staticMetaObject, "Error");
|
||||
s_tunnelProxyError = enumToStrings(TunnelProxyServer::staticMetaObject, "TunnelProxyError");
|
||||
|
||||
s_initialized = true;
|
||||
}
|
||||
|
||||
@ -33,7 +33,7 @@
|
||||
#include <QMetaEnum>
|
||||
#include <QStringList>
|
||||
|
||||
#include "tunnelproxy/tunnelproxymanager.h"
|
||||
#include "tunnelproxy/tunnelproxyserver.h"
|
||||
#include "authentication/authenticator.h"
|
||||
|
||||
namespace remoteproxy {
|
||||
@ -91,7 +91,7 @@ public:
|
||||
// Declare types
|
||||
DECLARE_TYPE(basicType, "BasicType", JsonTypes, BasicType)
|
||||
DECLARE_TYPE(authenticationError, "AuthenticationError", Authenticator, AuthenticationError)
|
||||
DECLARE_TYPE(tunnelProxyError, "TunnelProxyError", TunnelProxyManager, Error)
|
||||
DECLARE_TYPE(tunnelProxyError, "TunnelProxyError", TunnelProxyServer, TunnelProxyError)
|
||||
|
||||
// Declare objects
|
||||
|
||||
|
||||
@ -31,7 +31,7 @@
|
||||
#include "jsontypes.h"
|
||||
#include "loggingcategories.h"
|
||||
|
||||
#include "tunnelproxy/tunnelproxymanager.h"
|
||||
#include "tunnelproxy/tunnelproxyserver.h"
|
||||
|
||||
namespace remoteproxy {
|
||||
|
||||
@ -42,12 +42,38 @@ TunnelProxyHandler::TunnelProxyHandler(QObject *parent) : JsonHandler(parent)
|
||||
|
||||
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("uuid", JsonTypes::basicTypeToString(JsonTypes::String));
|
||||
params.insert("name", JsonTypes::basicTypeToString(JsonTypes::String));
|
||||
params.insert("serverName", JsonTypes::basicTypeToString(JsonTypes::String));
|
||||
params.insert("serverUuid", JsonTypes::basicTypeToString(JsonTypes::Uuid));
|
||||
setParams("RegisterServer", params);
|
||||
returns.insert("tunnelProxyError", JsonTypes::tunnelProxyErrorRef());
|
||||
setReturns("RegisterServer", returns);
|
||||
|
||||
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));
|
||||
params.insert("clientUuid", JsonTypes::basicTypeToString(JsonTypes::Uuid));
|
||||
params.insert("serverUuid", JsonTypes::basicTypeToString(JsonTypes::Uuid));
|
||||
setParams("RegisterClient", params);
|
||||
returns.insert("tunnelProxyError", JsonTypes::tunnelProxyErrorRef());
|
||||
setReturns("RegisterClient", returns);
|
||||
|
||||
// Notifications
|
||||
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.");
|
||||
params.insert("clientId", JsonTypes::basicTypeToString(JsonTypes::UInt));
|
||||
params.insert("name", JsonTypes::basicTypeToString(JsonTypes::String));
|
||||
params.insert("address", JsonTypes::basicTypeToString(JsonTypes::String));
|
||||
setParams("ClientConnected", params);
|
||||
|
||||
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));
|
||||
setParams("ClientDisconnected", params);
|
||||
|
||||
}
|
||||
|
||||
QString TunnelProxyHandler::name() const
|
||||
@ -58,14 +84,46 @@ QString TunnelProxyHandler::name() const
|
||||
JsonReply *TunnelProxyHandler::RegisterServer(const QVariantMap ¶ms, TransportClient *transportClient)
|
||||
{
|
||||
qCDebug(dcJsonRpc()) << name() << "register server" << params << transportClient;
|
||||
QUuid serverUuid = params.value("uuid").toUuid();
|
||||
QString serverName = params.value("name").toString();
|
||||
|
||||
TunnelProxyManager::Error error = Engine::instance()->tunnelProxyManager()->registerServer(transportClient->clientId(), serverUuid, serverName);
|
||||
QUuid serverUuid = params.value("serverUuid").toUuid();
|
||||
TunnelProxyServer::TunnelProxyError error = TunnelProxyServer::TunnelProxyErrorNoError;
|
||||
if (serverUuid.isNull()) {
|
||||
qCWarning(dcJsonRpc()) << "Invalid uuid received" << params.value("serverUuid").toString() << serverUuid;
|
||||
error = TunnelProxyServer::TunnelProxyErrorInvalidUuid;
|
||||
} else {
|
||||
QString serverName = params.value("serverName").toString();
|
||||
error = Engine::instance()->tunnelProxyServer()->registerServer(transportClient->clientId(), serverUuid, serverName);
|
||||
}
|
||||
|
||||
QVariantMap response;
|
||||
response.insert("tunnelProxyError", JsonTypes::tunnelProxyErrorToString(error));
|
||||
return createReply("RegisterServer", response);
|
||||
}
|
||||
|
||||
JsonReply *TunnelProxyHandler::RegisterClient(const QVariantMap ¶ms, TransportClient *transportClient)
|
||||
{
|
||||
qCDebug(dcJsonRpc()) << name() << "register client" << params << transportClient;
|
||||
QString clientName = params.value("clientName").toString();
|
||||
QUuid clientUuid = params.value("clientUuid").toUuid();
|
||||
QUuid serverUuid = params.value("serverUuid").toUuid();
|
||||
TunnelProxyServer::TunnelProxyError error = TunnelProxyServer::TunnelProxyErrorNoError;
|
||||
if (serverUuid.isNull()) {
|
||||
qCWarning(dcJsonRpc()) << "Invalid server uuid received" << params.value("serverUuid").toString() << serverUuid;
|
||||
error = TunnelProxyServer::TunnelProxyErrorInvalidUuid;
|
||||
} else if (clientUuid.isNull()) {
|
||||
qCWarning(dcJsonRpc()) << "Invalid client uuid received" << params.value("clientUuid").toString() << clientUuid;
|
||||
error = TunnelProxyServer::TunnelProxyErrorInvalidUuid;
|
||||
} else {
|
||||
error = Engine::instance()->tunnelProxyServer()->registerClient(transportClient->clientId(), clientUuid, clientName, serverUuid);
|
||||
}
|
||||
|
||||
QVariantMap response;
|
||||
response.insert("tunnelProxyError", JsonTypes::tunnelProxyErrorToString(error));
|
||||
return createReply("RegisterServer", response);
|
||||
}
|
||||
|
||||
//JsonReply *TunnelProxyHandler::RemoveClient(const QVariantMap ¶ms, TransportClient *transportClient)
|
||||
//{
|
||||
|
||||
//}
|
||||
|
||||
}
|
||||
|
||||
@ -46,9 +46,13 @@ public:
|
||||
QString name() const override;
|
||||
|
||||
Q_INVOKABLE JsonReply *RegisterServer(const QVariantMap ¶ms, TransportClient *transportClient);
|
||||
Q_INVOKABLE JsonReply *RegisterClient(const QVariantMap ¶ms, TransportClient *transportClient);
|
||||
|
||||
// Q_INVOKABLE JsonReply *RemoveClient(const QVariantMap ¶ms, TransportClient *transportClient);
|
||||
|
||||
signals:
|
||||
|
||||
void ClientConnected(const QVariantMap ¶ms, TransportClient *transportClient);
|
||||
void ClientDisconnected(const QVariantMap ¶ms, TransportClient *transportClient);
|
||||
|
||||
};
|
||||
|
||||
|
||||
@ -30,8 +30,9 @@ HEADERS += \
|
||||
server/jsonrpcserver.h \
|
||||
server/transportclient.h \
|
||||
server/monitorserver.h \
|
||||
tunnelproxy/tunnelproxyclient.h \
|
||||
tunnelproxy/tunnelproxyclientconnection.h \
|
||||
tunnelproxy/tunnelproxymanager.h \
|
||||
tunnelproxy/tunnelproxyserver.h \
|
||||
tunnelproxy/tunnelproxyserverconnection.h
|
||||
|
||||
SOURCES += \
|
||||
@ -61,8 +62,9 @@ SOURCES += \
|
||||
server/websocketserver.cpp \
|
||||
server/jsonrpcserver.cpp \
|
||||
server/monitorserver.cpp \
|
||||
tunnelproxy/tunnelproxyclient.cpp \
|
||||
tunnelproxy/tunnelproxyclientconnection.cpp \
|
||||
tunnelproxy/tunnelproxymanager.cpp \
|
||||
tunnelproxy/tunnelproxyserver.cpp \
|
||||
tunnelproxy/tunnelproxyserverconnection.cpp
|
||||
|
||||
|
||||
|
||||
@ -39,9 +39,8 @@ Q_LOGGING_CATEGORY(dcWebSocketServerTraffic, "WebSocketServerTraffic")
|
||||
Q_LOGGING_CATEGORY(dcAuthentication, "Authentication")
|
||||
Q_LOGGING_CATEGORY(dcAuthenticationProcess, "AuthenticationProcess")
|
||||
Q_LOGGING_CATEGORY(dcProxyServer, "ProxyServer")
|
||||
Q_LOGGING_CATEGORY(dcTunnelProxyManager, "TunnelProxyManager")
|
||||
Q_LOGGING_CATEGORY(dcProxyTunnelClient, "ProxyTunnelClient")
|
||||
Q_LOGGING_CATEGORY(dcTunnelProxyServer, "TunnelProxyServer")
|
||||
Q_LOGGING_CATEGORY(dcTunnelProxyServerTraffic, "TunnelProxyServerTraffic")
|
||||
Q_LOGGING_CATEGORY(dcProxyServerTraffic, "ProxyServerTraffic")
|
||||
Q_LOGGING_CATEGORY(dcMonitorServer, "MonitorServer")
|
||||
Q_LOGGING_CATEGORY(dcAwsCredentialsProvider, "AwsCredentialsProvider")
|
||||
|
||||
@ -43,10 +43,9 @@ Q_DECLARE_LOGGING_CATEGORY(dcTcpSocketServerTraffic)
|
||||
Q_DECLARE_LOGGING_CATEGORY(dcAuthentication)
|
||||
Q_DECLARE_LOGGING_CATEGORY(dcAuthenticationProcess)
|
||||
Q_DECLARE_LOGGING_CATEGORY(dcProxyServer)
|
||||
Q_DECLARE_LOGGING_CATEGORY(dcTunnelProxyManager)
|
||||
Q_DECLARE_LOGGING_CATEGORY(dcProxyTunnelClient)
|
||||
Q_DECLARE_LOGGING_CATEGORY(dcTunnelProxyServer)
|
||||
Q_DECLARE_LOGGING_CATEGORY(dcProxyServerTraffic)
|
||||
Q_DECLARE_LOGGING_CATEGORY(dcTunnelProxyServer)
|
||||
Q_DECLARE_LOGGING_CATEGORY(dcTunnelProxyServerTraffic)
|
||||
Q_DECLARE_LOGGING_CATEGORY(dcMonitorServer)
|
||||
Q_DECLARE_LOGGING_CATEGORY(dcAwsCredentialsProvider)
|
||||
Q_DECLARE_LOGGING_CATEGORY(dcAwsCredentialsProviderTraffic)
|
||||
|
||||
@ -81,26 +81,6 @@ void ProxyClient::setUserName(const QString &userName)
|
||||
m_userName = userName;
|
||||
}
|
||||
|
||||
QString ProxyClient::uuid() const
|
||||
{
|
||||
return m_uuid;
|
||||
}
|
||||
|
||||
void ProxyClient::setUuid(const QString &uuid)
|
||||
{
|
||||
m_uuid = uuid;
|
||||
}
|
||||
|
||||
QString ProxyClient::name() const
|
||||
{
|
||||
return m_name;
|
||||
}
|
||||
|
||||
void ProxyClient::setName(const QString &name)
|
||||
{
|
||||
m_name = name;
|
||||
}
|
||||
|
||||
QString ProxyClient::tunnelIdentifier() const
|
||||
{
|
||||
return m_token + m_nonce;
|
||||
|
||||
@ -60,13 +60,6 @@ public:
|
||||
QString userName() const;
|
||||
void setUserName(const QString &userName);
|
||||
|
||||
// Properties from auth request
|
||||
QString uuid() const;
|
||||
void setUuid(const QString &uuid);
|
||||
|
||||
QString name() const;
|
||||
void setName(const QString &name);
|
||||
|
||||
QString tunnelIdentifier() const;
|
||||
|
||||
QString token() const;
|
||||
@ -89,8 +82,6 @@ private:
|
||||
bool m_authenticated = false;
|
||||
bool m_tunnelConnected = false;
|
||||
|
||||
QString m_uuid;
|
||||
QString m_name;
|
||||
QString m_token;
|
||||
QString m_nonce;
|
||||
|
||||
|
||||
@ -306,6 +306,7 @@ void JsonRpcServer::unregisterClient(TransportClient *transportClient)
|
||||
qCWarning(dcJsonRpc()) << "Client was not registered" << transportClient;
|
||||
return;
|
||||
}
|
||||
|
||||
m_clients.removeAll(transportClient);
|
||||
|
||||
if (m_asyncReplies.values().contains(transportClient)) {
|
||||
|
||||
@ -66,6 +66,26 @@ TransportInterface *TransportClient::interface() const
|
||||
return m_interface;
|
||||
}
|
||||
|
||||
QUuid TransportClient::uuid() const
|
||||
{
|
||||
return m_uuid;
|
||||
}
|
||||
|
||||
void TransportClient::setUuid(const QUuid &uuid)
|
||||
{
|
||||
m_uuid = uuid;
|
||||
}
|
||||
|
||||
QString TransportClient::name() const
|
||||
{
|
||||
return m_name;
|
||||
}
|
||||
|
||||
void TransportClient::setName(const QString &name)
|
||||
{
|
||||
m_name = name;
|
||||
}
|
||||
|
||||
quint64 TransportClient::rxDataCount() const
|
||||
{
|
||||
return m_rxDataCount;
|
||||
|
||||
@ -52,6 +52,13 @@ public:
|
||||
|
||||
TransportInterface *interface() const;
|
||||
|
||||
// Properties from auth request
|
||||
QUuid uuid() const;
|
||||
void setUuid(const QUuid &uuid);
|
||||
|
||||
QString name() const;
|
||||
void setName(const QString &name);
|
||||
|
||||
quint64 rxDataCount() const;
|
||||
void addRxDataCount(int dataCount);
|
||||
|
||||
@ -74,6 +81,10 @@ protected:
|
||||
QHostAddress m_peerAddress;
|
||||
uint m_creationTimeStamp = 0;
|
||||
|
||||
// Eveyone has to register him self everywhere with a name and a uuid
|
||||
QString m_name;
|
||||
QUuid m_uuid;
|
||||
|
||||
QByteArray m_dataBuffers;
|
||||
|
||||
// Json data information
|
||||
|
||||
62
libnymea-remoteproxy/tunnelproxy/tunnelproxyclient.cpp
Normal file
62
libnymea-remoteproxy/tunnelproxy/tunnelproxyclient.cpp
Normal file
@ -0,0 +1,62 @@
|
||||
#include "tunnelproxyclient.h"
|
||||
#include "server/transportinterface.h"
|
||||
|
||||
namespace remoteproxy {
|
||||
|
||||
TunnelProxyClient::TunnelProxyClient(TransportInterface *interface, const QUuid &clientId, const QHostAddress &address, QObject *parent) :
|
||||
TransportClient(interface, clientId, address, parent)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
TunnelProxyClient::Type TunnelProxyClient::type() const
|
||||
{
|
||||
return m_type;
|
||||
}
|
||||
|
||||
void TunnelProxyClient::setType(Type type)
|
||||
{
|
||||
if (m_type == type)
|
||||
return;
|
||||
|
||||
m_type = type;
|
||||
emit typeChanged(m_type);
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
return packages;
|
||||
}
|
||||
|
||||
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() << ")";
|
||||
return debug.space();
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
41
libnymea-remoteproxy/tunnelproxy/tunnelproxyclient.h
Normal file
41
libnymea-remoteproxy/tunnelproxy/tunnelproxyclient.h
Normal file
@ -0,0 +1,41 @@
|
||||
#ifndef TUNNELPROXYCLIENT_H
|
||||
#define TUNNELPROXYCLIENT_H
|
||||
|
||||
#include <QObject>
|
||||
|
||||
#include "server/transportclient.h"
|
||||
|
||||
namespace remoteproxy {
|
||||
|
||||
class TunnelProxyClient : public TransportClient
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
enum Type {
|
||||
TypeNone,
|
||||
TypeServer,
|
||||
TypeClient
|
||||
};
|
||||
Q_ENUM(Type)
|
||||
|
||||
explicit TunnelProxyClient(TransportInterface *interface, const QUuid &clientId, const QHostAddress &address, QObject *parent = nullptr);
|
||||
|
||||
Type type() const;
|
||||
void setType(Type type);
|
||||
|
||||
// Json server methods
|
||||
QList<QByteArray> processData(const QByteArray &data) override;
|
||||
|
||||
signals:
|
||||
void typeChanged(Type type);
|
||||
|
||||
private:
|
||||
Type m_type = TypeNone;
|
||||
|
||||
};
|
||||
|
||||
QDebug operator<< (QDebug debug, TunnelProxyClient *tunnelProxyClient);
|
||||
|
||||
}
|
||||
|
||||
#endif // TUNNELPROXYCLIENT_H
|
||||
@ -26,12 +26,38 @@
|
||||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||
|
||||
#include "tunnelproxyclientconnection.h"
|
||||
#include "server/transportclient.h"
|
||||
|
||||
namespace remoteproxy {
|
||||
|
||||
TunnelProxyClientConnection::TunnelProxyClientConnection(QObject *parent) : QObject(parent)
|
||||
TunnelProxyClientConnection::TunnelProxyClientConnection(TransportClient *transportClient, const QUuid &clientUuid, const QString &clientName, const QUuid &serverUuid, QObject *parent) :
|
||||
QObject(parent),
|
||||
m_transportClient(transportClient),
|
||||
m_clientUuid(clientUuid),
|
||||
m_clientName(clientName),
|
||||
m_serverUuid(serverUuid)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
TransportClient *TunnelProxyClientConnection::transportClient() const
|
||||
{
|
||||
return m_transportClient;
|
||||
}
|
||||
|
||||
QUuid TunnelProxyClientConnection::clientUuid() const
|
||||
{
|
||||
return m_clientUuid;
|
||||
}
|
||||
|
||||
QString TunnelProxyClientConnection::clientName() const
|
||||
{
|
||||
return m_clientName;
|
||||
}
|
||||
|
||||
QUuid TunnelProxyClientConnection::serverUuid() const
|
||||
{
|
||||
return m_serverUuid;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -28,18 +28,34 @@
|
||||
#ifndef TUNNELPROXYCLIENTCONNECTION_H
|
||||
#define TUNNELPROXYCLIENTCONNECTION_H
|
||||
|
||||
#include <QUuid>
|
||||
#include <QObject>
|
||||
|
||||
namespace remoteproxy {
|
||||
|
||||
class TransportClient;
|
||||
|
||||
class TunnelProxyClientConnection : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit TunnelProxyClientConnection(QObject *parent = nullptr);
|
||||
explicit TunnelProxyClientConnection(TransportClient *transportClient, const QUuid &clientUuid, const QString &clientName, const QUuid &serverUuid, QObject *parent = nullptr);
|
||||
|
||||
TransportClient *transportClient() const;
|
||||
|
||||
QUuid clientUuid() const;
|
||||
QString clientName() const;
|
||||
QUuid serverUuid() const;
|
||||
|
||||
signals:
|
||||
|
||||
private:
|
||||
TransportClient *m_transportClient = nullptr;
|
||||
|
||||
QUuid m_clientUuid;
|
||||
QString m_clientName;
|
||||
QUuid m_serverUuid;
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@ -1,163 +0,0 @@
|
||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
*
|
||||
* 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 General Public License Usage
|
||||
* Alternatively, this project may be redistributed and/or modified under
|
||||
* the terms of the GNU General Public License as published by the Free Software Foundation,
|
||||
* GNU 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU 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 "tunnelproxymanager.h"
|
||||
#include "loggingcategories.h"
|
||||
|
||||
#include "jsonrpc/tunnelproxyhandler.h"
|
||||
|
||||
namespace remoteproxy {
|
||||
|
||||
TunnelProxyManager::TunnelProxyManager(QObject *parent) :
|
||||
QObject(parent)
|
||||
{
|
||||
m_jsonRpcServer = new JsonRpcServer(this);
|
||||
m_jsonRpcServer->registerHandler(m_jsonRpcServer);
|
||||
m_jsonRpcServer->registerHandler(new TunnelProxyHandler(this));
|
||||
}
|
||||
|
||||
TunnelProxyManager::~TunnelProxyManager()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
bool TunnelProxyManager::running() const
|
||||
{
|
||||
return m_running;
|
||||
}
|
||||
|
||||
void TunnelProxyManager::setRunning(bool running)
|
||||
{
|
||||
if (m_running == running)
|
||||
return;
|
||||
|
||||
qCDebug(dcTunnelProxyManager()) << "The proxy tunnel manager is" << (running ? "now up and running." : "not running any more.");
|
||||
m_running = running;
|
||||
emit runningChanged(m_running);
|
||||
}
|
||||
|
||||
void TunnelProxyManager::registerTransportInterface(TransportInterface *interface)
|
||||
{
|
||||
qCDebug(dcTunnelProxyManager()) << "Register transport interface" << interface->serverName();
|
||||
|
||||
if (m_transportInterfaces.contains(interface)) {
|
||||
qCWarning(dcTunnelProxyManager()) << "Transport interface already registerd.";
|
||||
return;
|
||||
}
|
||||
|
||||
connect(interface, &TransportInterface::clientConnected, this, &TunnelProxyManager::onClientConnected);
|
||||
connect(interface, &TransportInterface::clientDisconnected, this, &TunnelProxyManager::onClientDisconnected);
|
||||
connect(interface, &TransportInterface::dataAvailable, this, &TunnelProxyManager::onClientDataAvailable);
|
||||
|
||||
m_transportInterfaces.append(interface);
|
||||
}
|
||||
|
||||
TunnelProxyManager::Error TunnelProxyManager::registerServer(const QUuid &clientId, const QUuid &serverUuid, const QString &serverName)
|
||||
{
|
||||
qCDebug(dcTunnelProxyManager()) << "Register new server" << m_proxyClients.value(clientId) << serverName << serverUuid.toString();
|
||||
|
||||
// TODO: check if uuid already exists
|
||||
|
||||
// Check if requested already as client
|
||||
|
||||
|
||||
TunnelProxyServerConnection *proxyServer = new TunnelProxyServerConnection(m_proxyClients.value(clientId), serverUuid, serverName);
|
||||
m_proxyClientsTunnelServer.insert(clientId, proxyServer);
|
||||
m_tunnelServers.insert(proxyServer->serverUuid(), proxyServer);
|
||||
|
||||
return ErrorNoError;
|
||||
}
|
||||
|
||||
void TunnelProxyManager::startServer()
|
||||
{
|
||||
qCDebug(dcTunnelProxyManager()) << "Starting tunnel proxy...";
|
||||
foreach (TransportInterface *interface, m_transportInterfaces) {
|
||||
interface->startServer();
|
||||
}
|
||||
setRunning(true);
|
||||
}
|
||||
|
||||
void TunnelProxyManager::stopServer()
|
||||
{
|
||||
qCDebug(dcTunnelProxyManager()) << "Stopping tunnel proxy...";
|
||||
foreach (TransportInterface *interface, m_transportInterfaces) {
|
||||
interface->stopServer();
|
||||
}
|
||||
setRunning(false);
|
||||
}
|
||||
|
||||
void TunnelProxyManager::tick()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void TunnelProxyManager::onClientConnected(const QUuid &clientId, const QHostAddress &address)
|
||||
{
|
||||
TransportInterface *interface = static_cast<TransportInterface *>(sender());
|
||||
|
||||
qCDebug(dcTunnelProxyManager()) << "New client connected" << interface->serverName() << clientId.toString() << address.toString();
|
||||
|
||||
ProxyClient *proxyClient = new ProxyClient(interface, clientId, address, this);
|
||||
|
||||
m_proxyClients.insert(clientId, proxyClient);
|
||||
m_jsonRpcServer->registerClient(proxyClient);
|
||||
}
|
||||
|
||||
void TunnelProxyManager::onClientDisconnected(const QUuid &clientId)
|
||||
{
|
||||
TransportInterface *interface = static_cast<TransportInterface *>(sender());
|
||||
qCDebug(dcProxyServer()) << "Client disconnected" << interface->serverName() << clientId.toString();
|
||||
|
||||
if (!m_proxyClients.contains(clientId)) {
|
||||
qCWarning(dcProxyServer()) << "Unknown client disconnected from proxy server." << clientId.toString();
|
||||
return;
|
||||
}
|
||||
ProxyClient *proxyClient = m_proxyClients.take(clientId);
|
||||
|
||||
// Unregister from json rpc server
|
||||
m_jsonRpcServer->unregisterClient(proxyClient);
|
||||
|
||||
// Delete the proxy client
|
||||
proxyClient->deleteLater();
|
||||
}
|
||||
|
||||
void TunnelProxyManager::onClientDataAvailable(const QUuid &clientId, const QByteArray &data)
|
||||
{
|
||||
Q_UNUSED(clientId)
|
||||
Q_UNUSED(data)
|
||||
|
||||
ProxyClient *proxyClient = m_proxyClients.value(clientId);
|
||||
if (!proxyClient) {
|
||||
qCWarning(dcProxyServer()) << "Could not find client for uuid" << clientId;
|
||||
return;
|
||||
}
|
||||
|
||||
qCDebug(dcProxyServerTraffic()) << "Client data available" << proxyClient << qUtf8Printable(data);
|
||||
m_jsonRpcServer->processData(proxyClient, data);
|
||||
}
|
||||
|
||||
}
|
||||
238
libnymea-remoteproxy/tunnelproxy/tunnelproxyserver.cpp
Normal file
238
libnymea-remoteproxy/tunnelproxy/tunnelproxyserver.cpp
Normal file
@ -0,0 +1,238 @@
|
||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
*
|
||||
* 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 General Public License Usage
|
||||
* Alternatively, this project may be redistributed and/or modified under
|
||||
* the terms of the GNU General Public License as published by the Free Software Foundation,
|
||||
* GNU 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU 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 "loggingcategories.h"
|
||||
|
||||
#include "jsonrpc/tunnelproxyhandler.h"
|
||||
#include "tunnelproxyserverconnection.h"
|
||||
#include "tunnelproxyclientconnection.h"
|
||||
|
||||
namespace remoteproxy {
|
||||
|
||||
TunnelProxyServer::TunnelProxyServer(QObject *parent) :
|
||||
QObject(parent)
|
||||
{
|
||||
m_jsonRpcServer = new JsonRpcServer(this);
|
||||
m_jsonRpcServer->registerHandler(m_jsonRpcServer);
|
||||
m_jsonRpcServer->registerHandler(new TunnelProxyHandler(this));
|
||||
}
|
||||
|
||||
TunnelProxyServer::~TunnelProxyServer()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
bool TunnelProxyServer::running() const
|
||||
{
|
||||
return m_running;
|
||||
}
|
||||
|
||||
void TunnelProxyServer::setRunning(bool running)
|
||||
{
|
||||
if (m_running == running)
|
||||
return;
|
||||
|
||||
qCDebug(dcTunnelProxyServer()) << "The proxy tunnel manager is" << (running ? "now up and running." : "not running any more.");
|
||||
m_running = running;
|
||||
emit runningChanged(m_running);
|
||||
}
|
||||
|
||||
void TunnelProxyServer::registerTransportInterface(TransportInterface *interface)
|
||||
{
|
||||
qCDebug(dcTunnelProxyServer()) << "Register transport interface" << interface->serverName();
|
||||
|
||||
if (m_transportInterfaces.contains(interface)) {
|
||||
qCWarning(dcTunnelProxyServer()) << "Transport interface already registerd.";
|
||||
return;
|
||||
}
|
||||
|
||||
connect(interface, &TransportInterface::clientConnected, this, &TunnelProxyServer::onClientConnected);
|
||||
connect(interface, &TransportInterface::clientDisconnected, this, &TunnelProxyServer::onClientDisconnected);
|
||||
connect(interface, &TransportInterface::dataAvailable, this, &TunnelProxyServer::onClientDataAvailable);
|
||||
|
||||
m_transportInterfaces.append(interface);
|
||||
}
|
||||
|
||||
TunnelProxyServer::TunnelProxyError TunnelProxyServer::registerServer(const QUuid &clientId, const QUuid &serverUuid, const QString &serverName)
|
||||
{
|
||||
qCDebug(dcTunnelProxyServer()) << "Register new server" << m_proxyClients.value(clientId) << serverName << serverUuid.toString();
|
||||
|
||||
// Check if requested already as client
|
||||
TunnelProxyClient *tunnelProxyClient = m_proxyClients.value(clientId);
|
||||
if (!tunnelProxyClient) {
|
||||
qCWarning(dcTunnelProxyServer()) << "There is no client with client uuid" << clientId.toString();
|
||||
return TunnelProxyServer::TunnelProxyErrorInternalServerError;
|
||||
}
|
||||
|
||||
// Make sure this client has not been registered as client or re-registration has been called...
|
||||
if (tunnelProxyClient->type() != TunnelProxyClient::TypeNone) {
|
||||
qCWarning(dcTunnelProxyServer()) << "Client tried to register as server but has already been registerd as" << tunnelProxyClient->type();
|
||||
return TunnelProxyServer::TunnelProxyErrorAlreadyRegistered;
|
||||
}
|
||||
|
||||
tunnelProxyClient->setType(TunnelProxyClient::TypeServer);
|
||||
tunnelProxyClient->setUuid(serverUuid);
|
||||
tunnelProxyClient->setName(serverName);
|
||||
|
||||
TunnelProxyServerConnection *serverConnection = new TunnelProxyServerConnection(tunnelProxyClient, serverUuid, serverName, this);
|
||||
m_tunnelProxyServerConnections.insert(serverUuid, serverConnection);
|
||||
|
||||
return TunnelProxyServer::TunnelProxyErrorNoError;
|
||||
}
|
||||
|
||||
TunnelProxyServer::TunnelProxyError TunnelProxyServer::registerClient(const QUuid &clientId, const QUuid &clientUuid, const QString &clientName, const QUuid &serverUuid)
|
||||
{
|
||||
qCDebug(dcTunnelProxyServer()) << "Register new client" << m_proxyClients.value(clientId) << clientName << clientUuid.toString() << "--> server" << serverUuid.toString();
|
||||
|
||||
TunnelProxyClient *tunnelProxyClient = m_proxyClients.value(clientId);
|
||||
if (!tunnelProxyClient) {
|
||||
qCWarning(dcTunnelProxyServer()) << "There is no client with client uuid" << clientId.toString();
|
||||
return TunnelProxyServer::TunnelProxyErrorInternalServerError;
|
||||
}
|
||||
|
||||
// Make sure this client has not been registered as client or re-registration has been called...
|
||||
if (tunnelProxyClient->type() != TunnelProxyClient::TypeNone) {
|
||||
qCWarning(dcTunnelProxyServer()) << "Client tried to register as client but has already been registerd as" << tunnelProxyClient->type();
|
||||
return TunnelProxyServer::TunnelProxyErrorAlreadyRegistered;
|
||||
}
|
||||
|
||||
// Get the desired server connection
|
||||
TunnelProxyServerConnection *serverConnection = m_tunnelProxyServerConnections.value(serverUuid);
|
||||
if (!serverConnection) {
|
||||
qCWarning(dcTunnelProxyServer()) << "There is no server registered with server uuid" << serverUuid.toString();
|
||||
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);
|
||||
m_tunnelProxyClientConnections.insert(clientUuid, clientConnection);
|
||||
|
||||
// TODO: register on the server and wait for te aprovement from the server
|
||||
|
||||
return TunnelProxyServer::TunnelProxyErrorNoError;
|
||||
}
|
||||
|
||||
void TunnelProxyServer::startServer()
|
||||
{
|
||||
qCDebug(dcTunnelProxyServer()) << "Starting tunnel proxy...";
|
||||
foreach (TransportInterface *interface, m_transportInterfaces) {
|
||||
interface->startServer();
|
||||
}
|
||||
setRunning(true);
|
||||
}
|
||||
|
||||
void TunnelProxyServer::stopServer()
|
||||
{
|
||||
qCDebug(dcTunnelProxyServer()) << "Stopping tunnel proxy...";
|
||||
foreach (TransportInterface *interface, m_transportInterfaces) {
|
||||
interface->stopServer();
|
||||
}
|
||||
setRunning(false);
|
||||
}
|
||||
|
||||
void TunnelProxyServer::tick()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void TunnelProxyServer::onClientConnected(const QUuid &clientId, const QHostAddress &address)
|
||||
{
|
||||
TransportInterface *interface = static_cast<TransportInterface *>(sender());
|
||||
|
||||
qCDebug(dcTunnelProxyServer()) << "New client connected" << interface->serverName() << clientId.toString() << address.toString();
|
||||
TunnelProxyClient *tunnelProxyClient = new TunnelProxyClient(interface, clientId, address, this);
|
||||
m_proxyClients.insert(clientId, tunnelProxyClient);
|
||||
m_jsonRpcServer->registerClient(tunnelProxyClient);
|
||||
}
|
||||
|
||||
void TunnelProxyServer::onClientDisconnected(const QUuid &clientId)
|
||||
{
|
||||
TransportInterface *interface = static_cast<TransportInterface *>(sender());
|
||||
qCDebug(dcTunnelProxyServer()) << "Client disconnected" << interface->serverName() << clientId.toString();
|
||||
|
||||
TunnelProxyClient *tunnelProxyClient = m_proxyClients.take(clientId);
|
||||
if (!tunnelProxyClient) {
|
||||
qCWarning(dcTunnelProxyServer()) << "Unknown client disconnected from proxy server." << clientId.toString();
|
||||
return;
|
||||
}
|
||||
|
||||
if (tunnelProxyClient->type() == TunnelProxyClient::TypeServer) {
|
||||
TunnelProxyServerConnection *serverConnection = m_tunnelProxyServerConnections.take(tunnelProxyClient->uuid());
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
|
||||
clientConnection->deleteLater();
|
||||
}
|
||||
}
|
||||
|
||||
// Unregister from json rpc server
|
||||
m_jsonRpcServer->unregisterClient(tunnelProxyClient);
|
||||
|
||||
// Delete the proxy client
|
||||
tunnelProxyClient->deleteLater();
|
||||
}
|
||||
|
||||
void TunnelProxyServer::onClientDataAvailable(const QUuid &clientId, const QByteArray &data)
|
||||
{
|
||||
TunnelProxyClient *tunnelProxyClient = m_proxyClients.value(clientId);
|
||||
if (!tunnelProxyClient) {
|
||||
qCWarning(dcTunnelProxyServer()) << "Data received but could not find client for uuid" << clientId;
|
||||
return;
|
||||
}
|
||||
|
||||
qCDebug(dcTunnelProxyServerTraffic()) << "Client data available" << tunnelProxyClient << qUtf8Printable(data);
|
||||
|
||||
// TODO: verify if encoded and for whom this data is... 0x0000 is for the json rpc handler...
|
||||
|
||||
m_jsonRpcServer->processData(tunnelProxyClient, data);
|
||||
}
|
||||
|
||||
}
|
||||
@ -25,37 +25,43 @@
|
||||
*
|
||||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||
|
||||
#ifndef TUNNELPROXYMANAGER_H
|
||||
#define TUNNELPROXYMANAGER_H
|
||||
#ifndef TUNNELPROXYSERVER_H
|
||||
#define TUNNELPROXYSERVER_H
|
||||
|
||||
#include <QObject>
|
||||
|
||||
#include "server/jsonrpcserver.h"
|
||||
#include "server/transportinterface.h"
|
||||
|
||||
#include "tunnelproxyserverconnection.h"
|
||||
#include "tunnelproxyclient.h"
|
||||
|
||||
namespace remoteproxy {
|
||||
|
||||
class TunnelProxyManager : public QObject
|
||||
class TunnelProxyServerConnection;
|
||||
class TunnelProxyClientConnection;
|
||||
|
||||
class TunnelProxyServer : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
enum Error {
|
||||
ErrorNoError,
|
||||
ErrorServerNotFound
|
||||
enum TunnelProxyError {
|
||||
TunnelProxyErrorNoError,
|
||||
TunnelProxyErrorInvalidUuid,
|
||||
TunnelProxyErrorInternalServerError,
|
||||
TunnelProxyErrorServerNotFound,
|
||||
TunnelProxyErrorAlreadyRegistered
|
||||
};
|
||||
Q_ENUM(Error)
|
||||
Q_ENUM(TunnelProxyError)
|
||||
|
||||
explicit TunnelProxyManager(QObject *parent = nullptr);
|
||||
~TunnelProxyManager();
|
||||
explicit TunnelProxyServer(QObject *parent = nullptr);
|
||||
~TunnelProxyServer();
|
||||
|
||||
bool running() const;
|
||||
void setRunning(bool running);
|
||||
|
||||
void registerTransportInterface(TransportInterface *interface);
|
||||
|
||||
TunnelProxyManager::Error registerServer(const QUuid &clientId, const QUuid &serverUuid, const QString &serverName);
|
||||
TunnelProxyServer::TunnelProxyError registerServer(const QUuid &clientId, const QUuid &serverUuid, const QString &serverName);
|
||||
TunnelProxyServer::TunnelProxyError registerClient(const QUuid &clientId, const QUuid &clientUuid, const QString &clientName, const QUuid &serverUuid);
|
||||
|
||||
public slots:
|
||||
void startServer();
|
||||
@ -71,23 +77,20 @@ private slots:
|
||||
void onClientDisconnected(const QUuid &clientId);
|
||||
void onClientDataAvailable(const QUuid &clientId, const QByteArray &data);
|
||||
|
||||
// void onTunnelProxyServerRegistered();
|
||||
// void onProxyTunnelClientRegistered();
|
||||
|
||||
private:
|
||||
JsonRpcServer *m_jsonRpcServer = nullptr;
|
||||
QList<TransportInterface *> m_transportInterfaces;
|
||||
|
||||
bool m_running = false;
|
||||
|
||||
QHash<QUuid, ProxyClient *> m_proxyClients; // clients
|
||||
QHash<QUuid, TunnelProxyClient *> m_proxyClients; // clientId, object
|
||||
|
||||
// Server connections
|
||||
QHash<QUuid, TunnelProxyServerConnection *> m_proxyClientsTunnelServer; // clientUuid, object
|
||||
QHash<QUuid, TunnelProxyServerConnection *> m_tunnelServers; // server uuid, object
|
||||
QHash<QUuid, TunnelProxyServerConnection *> m_tunnelProxyServerConnections; // server uuid, object
|
||||
QHash<QUuid, TunnelProxyClientConnection *> m_tunnelProxyClientConnections; // client uuid, object
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // TUNNELPROXYMANAGER_H
|
||||
#endif // TUNNELPROXYSERVER_H
|
||||
@ -26,21 +26,22 @@
|
||||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||
|
||||
#include "tunnelproxyserverconnection.h"
|
||||
#include "server/transportclient.h"
|
||||
|
||||
namespace remoteproxy {
|
||||
|
||||
TunnelProxyServerConnection::TunnelProxyServerConnection(ProxyClient *proxyClient, const QUuid &serverUuid, const QString &serverName, QObject *parent) :
|
||||
TunnelProxyServerConnection::TunnelProxyServerConnection(TransportClient *transportClient, const QUuid &serverUuid, const QString &serverName, QObject *parent) :
|
||||
QObject(parent),
|
||||
m_proxyClient(proxyClient),
|
||||
m_transportClient(transportClient),
|
||||
m_serverUuid(serverUuid),
|
||||
m_serverName(serverName)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
ProxyClient *TunnelProxyServerConnection::proxyClient() const
|
||||
TransportClient *TunnelProxyServerConnection::transportClient() const
|
||||
{
|
||||
return m_proxyClient;
|
||||
return m_transportClient;
|
||||
}
|
||||
|
||||
QUuid TunnelProxyServerConnection::serverUuid() const
|
||||
|
||||
@ -28,27 +28,30 @@
|
||||
#ifndef TUNNELPROXYSERVERCONNECTION_H
|
||||
#define TUNNELPROXYSERVERCONNECTION_H
|
||||
|
||||
#include <QUuid>
|
||||
#include <QObject>
|
||||
|
||||
#include "proxy/proxyclient.h"
|
||||
|
||||
namespace remoteproxy {
|
||||
|
||||
class TransportClient;
|
||||
|
||||
class TunnelProxyServerConnection : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit TunnelProxyServerConnection(ProxyClient *proxyClient, const QUuid &serverUuid, const QString &serverName, QObject *parent = nullptr);
|
||||
explicit TunnelProxyServerConnection(TransportClient *transportClient, const QUuid &serverUuid, const QString &serverName, QObject *parent = nullptr);
|
||||
|
||||
ProxyClient *proxyClient() const;
|
||||
TransportClient *transportClient() const;
|
||||
|
||||
QUuid serverUuid() const;
|
||||
QString serverName() const;
|
||||
|
||||
|
||||
|
||||
signals:
|
||||
|
||||
private:
|
||||
ProxyClient *m_proxyClient = nullptr;
|
||||
TransportClient *m_transportClient = nullptr;
|
||||
|
||||
QUuid m_serverUuid;
|
||||
QString m_serverName;
|
||||
|
||||
@ -199,4 +199,140 @@ void RemoteProxyTestsTunnelProxy::apiBasicCalls()
|
||||
stopServer();
|
||||
}
|
||||
|
||||
|
||||
void RemoteProxyTestsTunnelProxy::registerServer_data()
|
||||
{
|
||||
QTest::addColumn<QString>("name");
|
||||
QTest::addColumn<QString>("uuid");
|
||||
QTest::addColumn<TunnelProxyServer::TunnelProxyError>("expectedError");
|
||||
|
||||
QTest::newRow("valid call") << "valid server" << QUuid::createUuid().toString() << TunnelProxyServer::TunnelProxyErrorNoError;
|
||||
QTest::newRow("valid uuid with brackets") << "valid server" << "{00323a95-d1ab-4752-88d4-dbc8b9015b0f}" << TunnelProxyServer::TunnelProxyErrorNoError;
|
||||
QTest::newRow("valid uuid without brackets") << "valid server" << "00323a95-d1ab-4752-88d4-dbc8b9015b0f" << TunnelProxyServer::TunnelProxyErrorNoError;
|
||||
QTest::newRow("invalid null uuid") << "valid server" << QUuid().toString() << TunnelProxyServer::TunnelProxyErrorInvalidUuid;
|
||||
QTest::newRow("invalid null uuid") << "valid server" << "foo" << TunnelProxyServer::TunnelProxyErrorInvalidUuid;
|
||||
}
|
||||
|
||||
|
||||
void RemoteProxyTestsTunnelProxy::registerServer()
|
||||
{
|
||||
QFETCH(QString, name);
|
||||
QFETCH(QString, uuid);
|
||||
QFETCH(TunnelProxyServer::TunnelProxyError, expectedError);
|
||||
|
||||
// Start the server
|
||||
startServer();
|
||||
|
||||
resetDebugCategories();
|
||||
addDebugCategory("TunnelProxyServer.debug=true");
|
||||
|
||||
// Register a new server
|
||||
QVariantMap params;
|
||||
params.insert("serverName", name);
|
||||
params.insert("serverUuid", uuid);
|
||||
|
||||
// Websocket
|
||||
QVariantMap response = invokeWebSocketTunnelProxyApiCall("TunnelProxy.RegisterServer", params).toMap();
|
||||
|
||||
QVERIFY(!response.isEmpty());
|
||||
QVERIFY(response.value("status").toString() == "success");
|
||||
QVERIFY(response.value("params").toMap().contains("tunnelProxyError"));
|
||||
verifyTunnelProxyError(response, expectedError);
|
||||
|
||||
// TCP Socket
|
||||
response = invokeTcpSocketTunnelProxyApiCall("TunnelProxy.RegisterServer", params).toMap();
|
||||
QVERIFY(!response.isEmpty());
|
||||
QVERIFY(response.value("status").toString() == "success");
|
||||
QVERIFY(response.value("params").toMap().contains("tunnelProxyError"));
|
||||
verifyTunnelProxyError(response, expectedError);
|
||||
|
||||
// Clean up
|
||||
stopServer();
|
||||
}
|
||||
|
||||
void RemoteProxyTestsTunnelProxy::registerServerDuplicated()
|
||||
{
|
||||
// Start the server
|
||||
startServer();
|
||||
|
||||
resetDebugCategories();
|
||||
addDebugCategory("TunnelProxyServer.debug=true");
|
||||
|
||||
// Register a new server
|
||||
QString serverName = "tunnel proxy server awesome nymea installation";
|
||||
QUuid serverUuid = QUuid::createUuid();
|
||||
|
||||
QVariantMap params;
|
||||
params.insert("serverName", serverName);
|
||||
params.insert("serverUuid", serverUuid.toString());
|
||||
|
||||
// TCP socket
|
||||
QPair<QVariant, QSslSocket *> result = invokeTcpSocketTunnelProxyApiCallPersistant("TunnelProxy.RegisterServer", params);
|
||||
QVariantMap response = result.first.toMap();
|
||||
QSslSocket *socket = result.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
|
||||
result = invokeTcpSocketTunnelProxyApiCallPersistant("TunnelProxy.RegisterServer", params, socket);
|
||||
response = result.first.toMap();
|
||||
QVERIFY(response.value("status").toString() == "success");
|
||||
QVERIFY(response.value("params").toMap().contains("tunnelProxyError"));
|
||||
verifyTunnelProxyError(response, TunnelProxyServer::TunnelProxyErrorAlreadyRegistered);
|
||||
|
||||
// Try to register an invalid server uuid
|
||||
QVariantMap paramsInvalidUuid;
|
||||
paramsInvalidUuid.insert("serverName", serverName);
|
||||
paramsInvalidUuid.insert("serverUuid", QUuid().toString());
|
||||
result = invokeTcpSocketTunnelProxyApiCallPersistant("TunnelProxy.RegisterServer", paramsInvalidUuid, socket);
|
||||
response = result.first.toMap();
|
||||
QVERIFY(response.value("status").toString() == "success");
|
||||
QVERIFY(response.value("params").toMap().contains("tunnelProxyError"));
|
||||
verifyTunnelProxyError(response, TunnelProxyServer::TunnelProxyErrorInvalidUuid);
|
||||
|
||||
// Close the tcp socket
|
||||
socket->close();
|
||||
delete socket;
|
||||
|
||||
QTest::qWait(100);
|
||||
|
||||
// WebSocket
|
||||
// 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, webSocket);
|
||||
response = resultWebSocket.first.toMap();
|
||||
QVERIFY(response.value("status").toString() == "success");
|
||||
QVERIFY(response.value("params").toMap().contains("tunnelProxyError"));
|
||||
verifyTunnelProxyError(response, TunnelProxyServer::TunnelProxyErrorAlreadyRegistered);
|
||||
|
||||
// Try to register an invalid server uuid
|
||||
resultWebSocket = invokeWebSocketTunnelProxyApiCallPersistant("TunnelProxy.RegisterServer", paramsInvalidUuid, webSocket);
|
||||
response = resultWebSocket.first.toMap();
|
||||
QVERIFY(response.value("status").toString() == "success");
|
||||
QVERIFY(response.value("params").toMap().contains("tunnelProxyError"));
|
||||
verifyTunnelProxyError(response, TunnelProxyServer::TunnelProxyErrorInvalidUuid);
|
||||
|
||||
webSocket->close();
|
||||
delete webSocket;
|
||||
|
||||
QTest::qWait(100);
|
||||
|
||||
resetDebugCategories();
|
||||
|
||||
// Clean up
|
||||
stopServer();
|
||||
}
|
||||
|
||||
|
||||
QTEST_MAIN(RemoteProxyTestsTunnelProxy)
|
||||
|
||||
@ -54,6 +54,12 @@ private slots:
|
||||
void apiBasicCallsTcp_data();
|
||||
void apiBasicCallsTcp();
|
||||
|
||||
void registerServer_data();
|
||||
void registerServer();
|
||||
|
||||
void registerServerDuplicated();
|
||||
|
||||
|
||||
};
|
||||
|
||||
#endif // REMOTEPROXYTESTSTUNNELPROXY_H
|
||||
|
||||
@ -42,7 +42,7 @@
|
||||
BaseTest::BaseTest(QObject *parent) :
|
||||
QObject(parent)
|
||||
{
|
||||
|
||||
resetDebugCategories();
|
||||
}
|
||||
|
||||
void BaseTest::loadConfiguration(const QString &fileName)
|
||||
@ -52,6 +52,19 @@ void BaseTest::loadConfiguration(const QString &fileName)
|
||||
//restartEngine();
|
||||
}
|
||||
|
||||
void BaseTest::resetDebugCategories()
|
||||
{
|
||||
m_currentDebugCategories = m_defaultDebugCategories;
|
||||
QLoggingCategory::setFilterRules(m_currentDebugCategories);
|
||||
}
|
||||
|
||||
void BaseTest::addDebugCategory(const QString &debugCategory)
|
||||
{
|
||||
m_currentDebugCategories += debugCategory + "\n";
|
||||
//qDebug() << m_currentDebugCategories;
|
||||
QLoggingCategory::setFilterRules(m_currentDebugCategories);
|
||||
}
|
||||
|
||||
void BaseTest::cleanUpEngine()
|
||||
{
|
||||
qDebug() << "Clean up engine";
|
||||
@ -87,8 +100,6 @@ void BaseTest::restartEngine()
|
||||
|
||||
void BaseTest::startEngine()
|
||||
{
|
||||
QLoggingCategory::setFilterRules("*.debug=false\ndefault.debug=true\nApplication.debug=true");
|
||||
|
||||
m_configuration = new ProxyConfiguration(this);
|
||||
loadConfiguration(":/test-configuration.conf");
|
||||
|
||||
@ -302,8 +313,8 @@ bool BaseTest::createRemoteConnection(const QString &token, const QString &nonce
|
||||
QString nameConnectionTwo = "Test client two";
|
||||
QUuid uuidConnectionTwo = QUuid::createUuid();
|
||||
|
||||
// QByteArray dataOne = "Hello from client one :-)";
|
||||
// QByteArray dataTwo = "Hello from client two :-)";
|
||||
// QByteArray dataOne = "Hello from client one :-)";
|
||||
// QByteArray dataTwo = "Hello from client two :-)";
|
||||
|
||||
// Create two connection
|
||||
RemoteProxyConnection *connectionOne = new RemoteProxyConnection(uuidConnectionOne, nameConnectionOne, parent);
|
||||
@ -466,6 +477,7 @@ QVariant BaseTest::invokeWebSocketTunnelProxyApiCall(const QString &method, cons
|
||||
socket->open(Engine::instance()->webSocketServerTunnelProxy()->serverUrl());
|
||||
spyConnection.wait();
|
||||
if (spyConnection.count() == 0) {
|
||||
qWarning() << "Failed to connect websocket on tunnel proxy";
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
@ -473,8 +485,10 @@ QVariant BaseTest::invokeWebSocketTunnelProxyApiCall(const QString &method, cons
|
||||
socket->sendTextMessage(QString(jsonDoc.toJson(QJsonDocument::Compact)));
|
||||
dataSpy.wait();
|
||||
|
||||
socket->close();
|
||||
socket->deleteLater();
|
||||
if (!remainsConnected) {
|
||||
socket->close();
|
||||
socket->deleteLater();
|
||||
}
|
||||
|
||||
for (int i = 0; i < dataSpy.count(); i++) {
|
||||
// Make sure the response ends with '}\n'
|
||||
@ -651,6 +665,125 @@ QVariant BaseTest::injectTcpSocketTunnelProxyData(const QByteArray &data)
|
||||
return jsonDoc.toVariant();
|
||||
}
|
||||
|
||||
QPair<QVariant, QSslSocket *> BaseTest::invokeTcpSocketTunnelProxyApiCallPersistant(const QString &method, const QVariantMap params, QSslSocket *existingSocket)
|
||||
{
|
||||
QSslSocket *socket = nullptr;
|
||||
if (!existingSocket) {
|
||||
socket = new QSslSocket(this);
|
||||
typedef void (QSslSocket:: *sslErrorsSignal)(const QList<QSslError> &);
|
||||
QObject::connect(socket, static_cast<sslErrorsSignal>(&QSslSocket::sslErrors), this, &BaseTest::sslSocketSslErrors);
|
||||
|
||||
QSignalSpy spyConnection(socket, &QSslSocket::connected);
|
||||
socket->connectToHostEncrypted(Engine::instance()->tcpSocketServerTunnelProxy()->serverUrl().host(),
|
||||
static_cast<quint16>(Engine::instance()->tcpSocketServerTunnelProxy()->serverUrl().port()));
|
||||
spyConnection.wait();
|
||||
if (spyConnection.count() == 0) {
|
||||
return QPair<QVariant, QSslSocket *>(QVariant(), socket);
|
||||
}
|
||||
} else {
|
||||
socket = existingSocket;
|
||||
}
|
||||
|
||||
QVariantMap request;
|
||||
request.insert("id", m_commandCounter);
|
||||
request.insert("method", method);
|
||||
request.insert("params", params);
|
||||
QJsonDocument jsonDoc = QJsonDocument::fromVariant(request);
|
||||
|
||||
|
||||
QSignalSpy dataSpy(socket, &QSslSocket::readyRead);
|
||||
socket->write(jsonDoc.toJson(QJsonDocument::Compact) + '\n');
|
||||
// FIXME: check why it waits the full time here
|
||||
dataSpy.wait(500);
|
||||
if (dataSpy.count() != 1) {
|
||||
qWarning() << "No data received";
|
||||
return QPair<QVariant, QSslSocket *>(QVariant(), socket);
|
||||
}
|
||||
|
||||
QByteArray data = socket->readAll();
|
||||
|
||||
// Make sure the response ends with '}\n'
|
||||
if (!data.endsWith("}\n")) {
|
||||
qWarning() << "JSON data does not end with \"}\n\"";
|
||||
return QPair<QVariant, QSslSocket *>(QVariant(), socket);
|
||||
}
|
||||
|
||||
// Make sure the response it a valid JSON string
|
||||
QJsonParseError error;
|
||||
jsonDoc = QJsonDocument::fromJson(data, &error);
|
||||
if (error.error != QJsonParseError::NoError) {
|
||||
qWarning() << "JSON parser error" << error.errorString();
|
||||
return QPair<QVariant, QSslSocket *>(QVariant(), socket);
|
||||
}
|
||||
|
||||
QVariantMap response = jsonDoc.toVariant().toMap();
|
||||
|
||||
if (response.value("id").toInt() == m_commandCounter) {
|
||||
m_commandCounter++;
|
||||
return QPair<QVariant, QSslSocket *>(jsonDoc.toVariant(), socket);
|
||||
}
|
||||
|
||||
m_commandCounter++;
|
||||
return QPair<QVariant, QSslSocket *>(QVariant(), socket);
|
||||
}
|
||||
|
||||
QPair<QVariant, QWebSocket *> BaseTest::invokeWebSocketTunnelProxyApiCallPersistant(const QString &method, const QVariantMap params, QWebSocket *existingSocket)
|
||||
{
|
||||
QWebSocket *socket = nullptr;
|
||||
if (!existingSocket) {
|
||||
socket = new QWebSocket("tunnelproxy-testclient", QWebSocketProtocol::Version13);
|
||||
connect(socket, &QWebSocket::sslErrors, this, &BaseTest::sslErrors);
|
||||
QSignalSpy spyConnection(socket, SIGNAL(connected()));
|
||||
socket->open(Engine::instance()->webSocketServerTunnelProxy()->serverUrl());
|
||||
spyConnection.wait();
|
||||
if (spyConnection.count() == 0) {
|
||||
qWarning() << "Failed to connect websocket on tunnel proxy";
|
||||
return QPair<QVariant, QWebSocket *>(QVariant(), socket);
|
||||
}
|
||||
} else {
|
||||
socket = existingSocket;
|
||||
}
|
||||
|
||||
QVariantMap request;
|
||||
request.insert("id", m_commandCounter);
|
||||
request.insert("method", method);
|
||||
request.insert("params", params);
|
||||
QJsonDocument jsonDoc = QJsonDocument::fromVariant(request);
|
||||
|
||||
QSignalSpy dataSpy(socket, SIGNAL(textMessageReceived(QString)));
|
||||
socket->sendTextMessage(QString(jsonDoc.toJson(QJsonDocument::Compact)));
|
||||
dataSpy.wait();
|
||||
|
||||
for (int i = 0; i < dataSpy.count(); i++) {
|
||||
// Make sure the response ends with '}\n'
|
||||
if (!dataSpy.at(i).last().toByteArray().endsWith("}\n")) {
|
||||
qWarning() << "JSON data does not end with \"}\n\"";
|
||||
return QPair<QVariant, QWebSocket *>(QVariant(), socket);
|
||||
}
|
||||
|
||||
// Make sure the response it a valid JSON string
|
||||
QJsonParseError error;
|
||||
jsonDoc = QJsonDocument::fromJson(dataSpy.at(i).last().toByteArray(), &error);
|
||||
if (error.error != QJsonParseError::NoError) {
|
||||
qWarning() << "JSON parser error" << error.errorString();
|
||||
return QPair<QVariant, QWebSocket *>(QVariant(), socket);
|
||||
}
|
||||
QVariantMap response = jsonDoc.toVariant().toMap();
|
||||
|
||||
// skip notifications
|
||||
if (response.contains("notification"))
|
||||
continue;
|
||||
|
||||
if (response.value("id").toInt() == m_commandCounter) {
|
||||
m_commandCounter++;
|
||||
return QPair<QVariant, QWebSocket *>(jsonDoc.toVariant(), socket);
|
||||
}
|
||||
}
|
||||
|
||||
m_commandCounter++;
|
||||
return QPair<QVariant, QWebSocket *>(QVariant(), socket);
|
||||
}
|
||||
|
||||
void BaseTest::initTestCase()
|
||||
{
|
||||
qRegisterMetaType<RemoteProxyConnection::State>();
|
||||
|
||||
@ -76,6 +76,9 @@ protected:
|
||||
void loadConfiguration(const QString &fileName);
|
||||
void setAuthenticator(Authenticator *authenticator);
|
||||
|
||||
void resetDebugCategories();
|
||||
void addDebugCategory(const QString &debugCategory);
|
||||
|
||||
void cleanUpEngine();
|
||||
void restartEngine();
|
||||
void startEngine();
|
||||
@ -94,6 +97,9 @@ protected:
|
||||
QVariant invokeTcpSocketTunnelProxyApiCall(const QString &method, const QVariantMap params = QVariantMap(), bool remainsConnected = true);
|
||||
QVariant injectTcpSocketTunnelProxyData(const QByteArray &data);
|
||||
|
||||
QPair<QVariant, QSslSocket *> invokeTcpSocketTunnelProxyApiCallPersistant(const QString &method, const QVariantMap params = QVariantMap(), QSslSocket *existingSocket = nullptr);
|
||||
QPair<QVariant, QWebSocket *> invokeWebSocketTunnelProxyApiCallPersistant(const QString &method, const QVariantMap params = QVariantMap(), QWebSocket *existingSocket = nullptr);
|
||||
|
||||
|
||||
bool createRemoteConnection(const QString &token, const QString &nonce, QObject *parent);
|
||||
|
||||
@ -137,6 +143,13 @@ public slots:
|
||||
verifyError(response, "authenticationError", JsonTypes::authenticationErrorToString(error));
|
||||
}
|
||||
|
||||
inline void verifyTunnelProxyError(const QVariant &response, TunnelProxyServer::TunnelProxyError error = TunnelProxyServer::TunnelProxyErrorNoError) {
|
||||
verifyError(response, "tunnelProxyError", JsonTypes::tunnelProxyErrorToString(error));
|
||||
}
|
||||
|
||||
private:
|
||||
QString m_defaultDebugCategories = "*.debug=false\ndefault.debug=true\nApplication.debug=true\n";
|
||||
QString m_currentDebugCategories;
|
||||
};
|
||||
|
||||
#endif // BASETEST_H
|
||||
|
||||
Reference in New Issue
Block a user