Abstract transport interface client and restructure client classes

This commit is contained in:
Simon Stürz 2021-07-29 11:38:55 +02:00
parent acd48bf7bf
commit 24e7c2983f
27 changed files with 479 additions and 262 deletions

18
debian/control vendored
View File

@ -2,10 +2,16 @@ Source: nymea-remoteproxy
Section: utils
Priority: options
Maintainer: Simon Stürz <simon.stuerz@nymea.io>
Build-depends: debhelper (>= 0.0.0),
libqt5websockets5-dev,
libncurses5-dev,
Standards-Version: 3.9.3
Homepage: https://nymea.io
Vcs-Git: https://github.com/nymea/nymea-remoteproxy.git
Build-depends: debhelper (>= 9.0.0),
dpkg-dev (>= 1.16.1~),
pkg-config,
qtbase5-dev,
qtbase5-dev-tools,
libqt5websockets5-dev,
libncurses5-dev
Package: nymea-remoteproxy
@ -31,9 +37,11 @@ Description: The nymea remote proxy server lib
Package: libnymea-remoteproxy-dev
Architecture: any
Section: libdevel
Multi-Arch: same
Depends: ${shlibs:Depends},
${misc:Depends},
libnymea-remoteproxy (= ${binary:Version}),
pkg-config
Description: The nymea remote proxy server lib - development files
The nymea remote proxy server lib - development files
@ -59,9 +67,11 @@ Description: The nymea remote proxy server client lib
Package: libnymea-remoteproxyclient-dev
Architecture: any
Section: libdevel
Multi-Arch: same
Depends: ${shlibs:Depends},
${misc:Depends},
libnymea-remoteproxyclient (= ${binary:Version}),
pkg-config
Description: The nymea remote proxy server client lib - development files
The nymea remote proxy server client lib - development files
@ -81,4 +91,4 @@ Depends: ${shlibs:Depends},
${misc:Depends},
libncurses5,
Description: The nymea remote proxy monitor tool
The nymea remote proxy server tests
The nymea remote proxy server monitor

14
debian/rules vendored
View File

@ -1,7 +1,11 @@
#!/usr/bin/make -f
# -*- makefile -*-
export DH_VERBOSE=1
DEB_HOST_MULTIARCH ?= $(shell dpkg-architecture -qDEB_HOST_MULTIARCH)
include /usr/share/dpkg/buildflags.mk
PREPROCESS_FILES := $(wildcard debian/*.in)
@ -11,17 +15,9 @@ $(PREPROCESS_FILES:.in=): %: %.in
override_dh_install: $(PREPROCESS_FILES:.in=)
dh_install
override_dh_strip:
dh_strip --dbg-package=libnymea-remoteproxy-dbg
dh_strip --dbg-package=libnymea-remoteproxyclient-dbg
#override_dh_auto_test:
# make test
override_dh_auto_clean:
dh_auto_clean
find . -name *.qm -exec rm {} \;
rm -rf $(PREPROCESS_FILES:.in=)
%:
dh $@ --with systemd --parallel
dh $@ --buildsystem=qmake --with systemd --parallel

View File

@ -25,7 +25,7 @@
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#include "proxyclient.h"
#include "proxy/proxyclient.h"
#include "authenticator.h"
#include "authenticationreply.h"

View File

@ -26,7 +26,7 @@
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#include "engine.h"
#include "proxyclient.h"
#include "proxy/proxyclient.h"
#include "awsauthenticator.h"
#include "loggingcategories.h"

View File

@ -30,7 +30,7 @@
#include <QObject>
#include "proxyclient.h"
#include "proxy/proxyclient.h"
#include "authentication/authenticator.h"
namespace remoteproxy {

View File

@ -28,6 +28,7 @@
#include "jsontypes.h"
#include "loggingcategories.h"
#include "authenticationhandler.h"
#include "server/transportclient.h"
#include "engine.h"
@ -60,7 +61,7 @@ QString AuthenticationHandler::name() const
return "Authentication";
}
JsonReply *AuthenticationHandler::Authenticate(const QVariantMap &params, ProxyClient *proxyClient)
JsonReply *AuthenticationHandler::Authenticate(const QVariantMap &params, TransportClient *transportClient)
{
QString uuid = params.value("uuid").toString();
QString name = params.value("name").toString();
@ -71,6 +72,7 @@ JsonReply *AuthenticationHandler::Authenticate(const QVariantMap &params, ProxyC
JsonReply *jsonReply = createAsyncReply("Authenticate");
// Set the token for this proxy client
ProxyClient *proxyClient = qobject_cast<ProxyClient *>(transportClient);
proxyClient->setUuid(uuid);
proxyClient->setName(name);
proxyClient->setToken(token);

View File

@ -35,6 +35,8 @@
namespace remoteproxy {
class TransportClient;
class AuthenticationHandler : public JsonHandler
{
Q_OBJECT
@ -44,7 +46,7 @@ public:
QString name() const override;
Q_INVOKABLE JsonReply *Authenticate(const QVariantMap &params, ProxyClient *proxyClient);
Q_INVOKABLE JsonReply *Authenticate(const QVariantMap &params, TransportClient *transportClient);
private:
QHash<AuthenticationReply *, JsonReply *> m_runningAuthentications;

View File

@ -75,7 +75,7 @@ QVariantMap JsonHandler::introspect(const QMetaMethod::MethodType &type)
}
break;
default:
;;// Nothing to do for slots
break; // Nothing to do for slots
}
}
}

View File

@ -54,8 +54,6 @@ QVariantMap JsonTypes::allTypes()
allTypes.insert("AuthenticationError", authenticationError());
allTypes.insert("TunnelProxyError", tunnelProxyError());
// Types
return allTypes;
}

View File

@ -55,17 +55,16 @@ QString TunnelProxyHandler::name() const
return "TunnelProxy";
}
JsonReply *TunnelProxyHandler::RegisterServer(const QVariantMap &params, ProxyClient *proxyClient)
JsonReply *TunnelProxyHandler::RegisterServer(const QVariantMap &params, TransportClient *transportClient)
{
qCDebug(dcJsonRpc()) << name() << "register server" << params << proxyClient;
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(proxyClient->clientId(), serverUuid, serverName);
TunnelProxyManager::Error error = Engine::instance()->tunnelProxyManager()->registerServer(transportClient->clientId(), serverUuid, serverName);
QVariantMap response;
response.insert("tunnelProxyError", JsonTypes::tunnelProxyErrorToString(error));
return createReply("RegisterServer", response);
}

View File

@ -34,6 +34,8 @@
namespace remoteproxy {
class TransportClient;
class TunnelProxyHandler : public JsonHandler
{
Q_OBJECT
@ -43,7 +45,7 @@ public:
QString name() const override;
Q_INVOKABLE JsonReply *RegisterServer(const QVariantMap &params, ProxyClient *proxyClient);
Q_INVOKABLE JsonReply *RegisterServer(const QVariantMap &params, TransportClient *transportClient);
signals:

View File

@ -5,61 +5,65 @@ TARGET = nymea-remoteproxy
HEADERS += \
engine.h \
logengine.h \
loggingcategories.h \
tunnelproxy/tunnelproxymanager.h \
tunnelproxy/tunnelproxyserver.h \
server/tcpsocketserver.h \
server/transportinterface.h \
server/websocketserver.h \
server/jsonrpcserver.h \
server/monitorserver.h \
proxyclient.h \
proxy/proxyserver.h \
proxy/tunnelconnection.h \
proxyconfiguration.h \
jsonrpc/jsonhandler.h \
jsonrpc/jsonreply.h \
jsonrpc/jsontypes.h \
jsonrpc/authenticationhandler.h \
jsonrpc/tunnelproxyhandler.h \
authentication/authenticator.h \
authentication/authenticationreply.h \
authentication/dummy/dummyauthenticator.h \
authentication/aws/awsauthenticator.h \
authentication/aws/userinformation.h \
authentication/aws/authenticationprocess.h \
authentication/aws/sigv4utils.h \
authentication/aws/awscredentialprovider.h \
logengine.h
authentication/dummy/dummyauthenticator.h \
jsonrpc/jsonhandler.h \
jsonrpc/jsonreply.h \
jsonrpc/jsontypes.h \
jsonrpc/authenticationhandler.h \
jsonrpc/tunnelproxyhandler.h \
proxy/proxyclient.h \
proxy/proxyserver.h \
proxy/tunnelconnection.h \
server/tcpsocketserver.h \
server/transportinterface.h \
server/websocketserver.h \
server/jsonrpcserver.h \
server/transportclient.h \
server/monitorserver.h \
tunnelproxy/tunnelproxyclientconnection.h \
tunnelproxy/tunnelproxymanager.h \
tunnelproxy/tunnelproxyserverconnection.h
SOURCES += \
engine.cpp \
logengine.cpp \
loggingcategories.cpp \
tunnelproxy/tunnelproxymanager.cpp \
tunnelproxy/tunnelproxyserver.cpp \
server/tcpsocketserver.cpp \
server/transportinterface.cpp \
server/websocketserver.cpp \
server/jsonrpcserver.cpp \
server/monitorserver.cpp \
proxyclient.cpp \
proxy/proxyserver.cpp \
proxy/tunnelconnection.cpp \
proxyconfiguration.cpp \
jsonrpc/jsonhandler.cpp \
jsonrpc/jsonreply.cpp \
jsonrpc/jsontypes.cpp \
jsonrpc/authenticationhandler.cpp \
jsonrpc/tunnelproxyhandler.cpp \
authentication/authenticator.cpp \
authentication/authenticationreply.cpp \
authentication/dummy/dummyauthenticator.cpp \
authentication/aws/awsauthenticator.cpp \
authentication/aws/userinformation.cpp \
authentication/aws/authenticationprocess.cpp \
authentication/aws/sigv4utils.cpp \
authentication/aws/awscredentialprovider.cpp \
logengine.cpp
authentication/dummy/dummyauthenticator.cpp \
jsonrpc/jsonhandler.cpp \
jsonrpc/jsonreply.cpp \
jsonrpc/jsontypes.cpp \
jsonrpc/authenticationhandler.cpp \
jsonrpc/tunnelproxyhandler.cpp \
proxy/proxyclient.cpp \
proxy/proxyserver.cpp \
proxy/tunnelconnection.cpp \
server/tcpsocketserver.cpp \
server/transportinterface.cpp \
server/transportclient.cpp \
server/websocketserver.cpp \
server/jsonrpcserver.cpp \
server/monitorserver.cpp \
tunnelproxy/tunnelproxyclientconnection.cpp \
tunnelproxy/tunnelproxymanager.cpp \
tunnelproxy/tunnelproxyserverconnection.cpp
# install header file with relative subdirectory

View File

@ -34,39 +34,14 @@
namespace remoteproxy {
ProxyClient::ProxyClient(TransportInterface *interface, const QUuid &clientId, const QHostAddress &address, QObject *parent) :
QObject(parent),
m_interface(interface),
m_clientId(clientId),
m_peerAddress(address)
TransportClient(interface, clientId, address, parent)
{
m_creationTimeStamp = QDateTime::currentDateTimeUtc().toTime_t();
m_timer = new QTimer(this);
connect(m_timer, &QTimer::timeout, this, &ProxyClient::timeoutOccured);
m_timer->setSingleShot(true);
resetTimer();
}
QUuid ProxyClient::clientId() const
{
return m_clientId;
}
QHostAddress ProxyClient::peerAddress() const
{
return m_peerAddress;
}
uint ProxyClient::creationTime() const
{
return m_creationTimeStamp;
}
QString ProxyClient::creationTimeString() const
{
return QDateTime::fromTime_t(creationTime()).toString("dd.MM.yyyy hh:mm:ss");
}
bool ProxyClient::isAuthenticated() const
{
return m_authenticated;
@ -106,11 +81,6 @@ void ProxyClient::setUserName(const QString &userName)
m_userName = userName;
}
TransportInterface *ProxyClient::interface() const
{
return m_interface;
}
QString ProxyClient::uuid() const
{
return m_uuid;
@ -156,26 +126,6 @@ void ProxyClient::setNonce(const QString &nonce)
m_nonce = nonce;
}
quint64 ProxyClient::rxDataCount() const
{
return m_rxDataCount;
}
void ProxyClient::addRxDataCount(int dataCount)
{
m_rxDataCount += static_cast<quint64>(dataCount);
}
quint64 ProxyClient::txDataCount() const
{
return m_txDataCount;
}
void ProxyClient::addTxDataCount(int dataCount)
{
m_txDataCount += static_cast<quint64>(dataCount);
}
ProxyClient::TimerWaitState ProxyClient::timerWaitState() const
{
return m_timerWaitState;
@ -195,28 +145,6 @@ void ProxyClient::resetTimer()
}
}
void ProxyClient::sendData(const QByteArray &data)
{
if (!m_interface)
return;
m_interface->sendData(m_clientId, data);
}
void ProxyClient::killConnection(const QString &reason)
{
if (!m_interface)
return;
m_interface->killClientConnection(m_clientId, reason);
}
int ProxyClient::generateMessageId()
{
m_messageId++;
return m_messageId;
}
QList<QByteArray> ProxyClient::processData(const QByteArray &data)
{
QList<QByteArray> packages;
@ -237,11 +165,6 @@ QList<QByteArray> ProxyClient::processData(const QByteArray &data)
return packages;
}
int ProxyClient::bufferSize() const
{
return m_dataBuffers.size();
}
QDebug operator<<(QDebug debug, ProxyClient *proxyClient)
{
debug.nospace() << "ProxyClient(";

View File

@ -34,11 +34,11 @@
#include <QTimer>
#include <QHostAddress>
#include "server/transportinterface.h"
#include "server/transportclient.h"
namespace remoteproxy {
class ProxyClient : public QObject
class ProxyClient : public TransportClient
{
Q_OBJECT
@ -51,12 +51,6 @@ public:
explicit ProxyClient(TransportInterface *interface, const QUuid &clientId, const QHostAddress &address, QObject *parent = nullptr);
QUuid clientId() const;
QHostAddress peerAddress() const;
uint creationTime() const;
QString creationTimeString() const;
bool isAuthenticated() const;
void setAuthenticated(bool isAuthenticated);
@ -66,8 +60,6 @@ public:
QString userName() const;
void setUserName(const QString &userName);
TransportInterface *interface() const;
// Properties from auth request
QString uuid() const;
void setUuid(const QString &uuid);
@ -83,32 +75,17 @@ public:
QString nonce() const;
void setNonce(const QString &nonce);
quint64 rxDataCount() const;
void addRxDataCount(int dataCount);
quint64 txDataCount() const;
void addTxDataCount(int dataCount);
// Actions for this client
TimerWaitState timerWaitState() const;
void resetTimer();
void sendData(const QByteArray &data);
void killConnection(const QString &reason);
// Json server methods
int generateMessageId();
QList<QByteArray> processData(const QByteArray &data);
int bufferSize() const;
// Json server methods
QList<QByteArray> processData(const QByteArray &data) override;
private:
TransportInterface *m_interface = nullptr;
QTimer *m_timer = nullptr;
TimerWaitState m_timerWaitState = TimerWaitStateInactive;
QUuid m_clientId;
QHostAddress m_peerAddress;
uint m_creationTimeStamp = 0;
bool m_authenticated = false;
bool m_tunnelConnected = false;
@ -119,14 +96,6 @@ private:
QString m_userName;
// Json data information
int m_messageId = 0;
QByteArray m_dataBuffers;
bool m_bufferSizeViolation = false;
quint64 m_rxDataCount = 0;
quint64 m_txDataCount = 0;
signals:
void authenticated();
void tunnelConnected();

View File

@ -199,13 +199,13 @@ void ProxyServer::establishTunnel(ProxyClient *firstClient, ProxyClient *secondC
Q_ARG(QString, m_jsonRpcServer->name()),
Q_ARG(QString, "TunnelEstablished"),
Q_ARG(QVariantMap, notificationParamsFirst),
Q_ARG(ProxyClient*, tunnel.clientOne()));
Q_ARG(TransportClient*, tunnel.clientOne()));
QMetaObject::invokeMethod(m_jsonRpcServer, QString("sendNotification").toLatin1().data(), Qt::QueuedConnection,
Q_ARG(QString, m_jsonRpcServer->name()),
Q_ARG(QString, "TunnelEstablished"),
Q_ARG(QVariantMap, notificationParamsSecond),
Q_ARG(ProxyClient*, tunnel.clientTwo()));
Q_ARG(TransportClient*, tunnel.clientTwo()));
}
void ProxyServer::onClientConnected(const QUuid &clientId, const QHostAddress &address)
@ -391,7 +391,7 @@ void ProxyServer::onProxyClientTimeoutOccured()
void ProxyServer::startServer()
{
qCDebug(dcProxyServer()) << "Start proxy server.";
qCDebug(dcProxyServer()) << "Starting proxy server...";
foreach (TransportInterface *interface, m_transportInterfaces) {
interface->startServer();
}
@ -400,7 +400,7 @@ void ProxyServer::startServer()
void ProxyServer::stopServer()
{
qCDebug(dcProxyServer()) << "Stop proxy server.";
qCDebug(dcProxyServer()) << "Stopping proxy...";
foreach (TransportInterface *interface, m_transportInterfaces) {
interface->stopServer();
}

View File

@ -85,10 +85,10 @@ QString JsonRpcServer::name() const
return "RemoteProxy";
}
JsonReply *JsonRpcServer::Hello(const QVariantMap &params, ProxyClient *proxyClient) const
JsonReply *JsonRpcServer::Hello(const QVariantMap &params, TransportClient *transportClient) const
{
Q_UNUSED(params)
Q_UNUSED(proxyClient)
Q_UNUSED(transportClient)
QVariantMap data;
data.insert("server", SERVER_NAME_STRING);
@ -99,10 +99,10 @@ JsonReply *JsonRpcServer::Hello(const QVariantMap &params, ProxyClient *proxyCli
return createReply("Hello", data);
}
JsonReply *JsonRpcServer::Introspect(const QVariantMap &params, ProxyClient *proxyClient) const
JsonReply *JsonRpcServer::Introspect(const QVariantMap &params, TransportClient *transportClient) const
{
Q_UNUSED(params)
Q_UNUSED(proxyClient)
Q_UNUSED(transportClient)
qCDebug(dcJsonRpc()) << "Introspect called.";
@ -126,7 +126,7 @@ JsonReply *JsonRpcServer::Introspect(const QVariantMap &params, ProxyClient *pro
return createReply("Introspect", data);
}
void JsonRpcServer::sendResponse(ProxyClient *client, int commandId, const QVariantMap &params)
void JsonRpcServer::sendResponse(TransportClient *client, int commandId, const QVariantMap &params)
{
QVariantMap response;
response.insert("id", commandId);
@ -138,7 +138,7 @@ void JsonRpcServer::sendResponse(ProxyClient *client, int commandId, const QVari
client->sendData(data);
}
void JsonRpcServer::sendErrorResponse(ProxyClient *client, int commandId, const QString &error)
void JsonRpcServer::sendErrorResponse(TransportClient *client, int commandId, const QString &error)
{
QVariantMap errorResponse;
errorResponse.insert("id", commandId);
@ -172,14 +172,14 @@ void JsonRpcServer::unregisterHandler(JsonHandler *handler)
m_handlers.remove(handler->name());
}
void JsonRpcServer::processDataPackage(ProxyClient *proxyClient, const QByteArray &data)
void JsonRpcServer::processDataPackage(TransportClient *transportClient, const QByteArray &data)
{
QJsonParseError error;
QJsonDocument jsonDoc = QJsonDocument::fromJson(data, &error);
if(error.error != QJsonParseError::NoError) {
qCWarning(dcJsonRpc) << "Failed to parse JSON data" << data << ":" << error.errorString();
sendErrorResponse(proxyClient, -1, QString("Failed to parse JSON data: %1").arg(error.errorString()));
proxyClient->killConnection("Invalid JSON data received.");
sendErrorResponse(transportClient, -1, QString("Failed to parse JSON data: %1").arg(error.errorString()));
transportClient->killConnection("Invalid JSON data received.");
return;
}
@ -189,16 +189,16 @@ void JsonRpcServer::processDataPackage(ProxyClient *proxyClient, const QByteArra
int commandId = message.value("id").toInt(&success);
if (!success) {
qCWarning(dcJsonRpc()) << "Error parsing command. Missing \"id\":" << message;
sendErrorResponse(proxyClient, -1, "Error parsing command. Missing 'id'");
proxyClient->killConnection("The id property is missing in the request.");
sendErrorResponse(transportClient, -1, "Error parsing command. Missing 'id'");
transportClient->killConnection("The id property is missing in the request.");
return;
}
QStringList commandList = message.value("method").toString().split('.');
if (commandList.count() != 2) {
qCWarning(dcJsonRpc) << "Error parsing method.\nGot:" << message.value("method").toString() << "\nExpected: \"Namespace.method\"";
sendErrorResponse(proxyClient, commandId, QString("Error parsing method. Got: '%1'', Expected: 'Namespace.method'").arg(message.value("method").toString()));
proxyClient->killConnection("Invalid method passed.");
sendErrorResponse(transportClient, commandId, QString("Error parsing method. Got: '%1'', Expected: 'Namespace.method'").arg(message.value("method").toString()));
transportClient->killConnection("Invalid method passed.");
return;
}
@ -207,30 +207,30 @@ void JsonRpcServer::processDataPackage(ProxyClient *proxyClient, const QByteArra
JsonHandler *handler = m_handlers.value(targetNamespace);
if (!handler) {
sendErrorResponse(proxyClient, commandId, "No such namespace");
proxyClient->killConnection("No such namespace.");
sendErrorResponse(transportClient, commandId, "No such namespace");
transportClient->killConnection("No such namespace.");
return;
}
if (!handler->hasMethod(method)) {
sendErrorResponse(proxyClient, commandId, "No such method");
proxyClient->killConnection("No such method.");
sendErrorResponse(transportClient, commandId, "No such method");
transportClient->killConnection("No such method.");
return;
}
QVariantMap params = message.value("params").toMap();
QPair<bool, QString> validationResult = handler->validateParams(method, params);
if (!validationResult.first) {
sendErrorResponse(proxyClient, commandId, "Invalid params: " + validationResult.second);
proxyClient->killConnection("Invalid params passed.");
sendErrorResponse(transportClient, commandId, "Invalid params: " + validationResult.second);
transportClient->killConnection("Invalid params passed.");
return;
}
JsonReply *reply;
QMetaObject::invokeMethod(handler, method.toLatin1().data(), Q_RETURN_ARG(JsonReply*, reply), Q_ARG(QVariantMap, params), Q_ARG(ProxyClient *, proxyClient));
QMetaObject::invokeMethod(handler, method.toLatin1().data(), Q_RETURN_ARG(JsonReply*, reply), Q_ARG(QVariantMap, params), Q_ARG(TransportClient *, transportClient));
if (reply->type() == JsonReply::TypeAsync) {
m_asyncReplies.insert(reply, proxyClient);
reply->setClientId(proxyClient->clientId());
m_asyncReplies.insert(reply, transportClient);
reply->setClientId(transportClient->clientId());
reply->setCommandId(commandId);
connect(reply, &JsonReply::finished, this, &JsonRpcServer::asyncReplyFinished);
@ -244,9 +244,9 @@ void JsonRpcServer::processDataPackage(ProxyClient *proxyClient, const QByteArra
// qCWarning(dcJsonRpc()) << "Return value validation failed of sync reply. This should never happen. Please check the source code.";
// }
reply->setClientId(proxyClient->clientId());
reply->setClientId(transportClient->clientId());
reply->setCommandId(commandId);
sendResponse(proxyClient, commandId, reply->data());
sendResponse(transportClient, commandId, reply->data());
reply->deleteLater();
}
}
@ -256,10 +256,10 @@ void JsonRpcServer::asyncReplyFinished()
JsonReply *reply = static_cast<JsonReply *>(sender());
reply->deleteLater();
ProxyClient *proxyClient = m_asyncReplies.take(reply);
TransportClient *transportClient = m_asyncReplies.take(reply);
qCDebug(dcJsonRpc()) << "Async reply finished" << reply->handler()->name() << reply->method() << reply->clientId().toString();
if (!proxyClient) {
if (!transportClient) {
qCWarning(dcJsonRpc()) << "Got an async reply but the client does not exist any more.";
return;
}
@ -274,71 +274,71 @@ void JsonRpcServer::asyncReplyFinished()
qCWarning(dcJsonRpc()) << "Return value validation failed. This should never happen. Please check the source code.";
}
sendResponse(proxyClient, reply->commandId(), reply->data());
sendResponse(transportClient, reply->commandId(), reply->data());
if (!reply->success()) {
// Disconnect this client since the request was not successfully
proxyClient->interface()->killClientConnection(proxyClient->clientId(), "API call was not successfully.");
transportClient->interface()->killClientConnection(transportClient->clientId(), "API call was not successfully.");
}
} else {
qCWarning(dcJsonRpc()) << "The reply timeouted.";
sendErrorResponse(proxyClient, reply->commandId(), "Command timed out");
sendErrorResponse(transportClient, reply->commandId(), "Command timed out");
// Disconnect this client since he requested something that created a timeout
proxyClient->killConnection("API call timeouted.");
transportClient->killConnection("API call timeouted.");
}
}
void JsonRpcServer::registerClient(ProxyClient *proxyClient)
void JsonRpcServer::registerClient(TransportClient *transportClient)
{
qCDebug(dcJsonRpc()) << "Register client" << proxyClient;
if (m_clients.contains(proxyClient)) {
qCWarning(dcJsonRpc()) << "Client already registered" << proxyClient;
qCDebug(dcJsonRpc()) << "Register client" << transportClient;
if (m_clients.contains(transportClient)) {
qCWarning(dcJsonRpc()) << "Client already registered" << transportClient;
return;
}
m_clients.append(proxyClient);
m_clients.append(transportClient);
}
void JsonRpcServer::unregisterClient(ProxyClient *proxyClient)
void JsonRpcServer::unregisterClient(TransportClient *transportClient)
{
qCDebug(dcJsonRpc()) << "Unregister client" << proxyClient;
if (!m_clients.contains(proxyClient)) {
qCWarning(dcJsonRpc()) << "Client was not registered" << proxyClient;
qCDebug(dcJsonRpc()) << "Unregister client" << transportClient;
if (!m_clients.contains(transportClient)) {
qCWarning(dcJsonRpc()) << "Client was not registered" << transportClient;
return;
}
m_clients.removeAll(proxyClient);
m_clients.removeAll(transportClient);
if (m_asyncReplies.values().contains(proxyClient)) {
if (m_asyncReplies.values().contains(transportClient)) {
qCWarning(dcJsonRpc()) << "Client was still waiting for a reply. Clean up reply";
JsonReply *reply = m_asyncReplies.key(proxyClient);
JsonReply *reply = m_asyncReplies.key(transportClient);
m_asyncReplies.remove(reply);
// Note: the reply will be deleted in the finished slot
}
}
void JsonRpcServer::processData(ProxyClient *proxyClient, const QByteArray &data)
void JsonRpcServer::processData(TransportClient *transportClient, const QByteArray &data)
{
if (!m_clients.contains(proxyClient))
if (!m_clients.contains(transportClient))
return;
qCDebug(dcJsonRpcTraffic()) << "Incoming data from" << proxyClient << ": " << data;
qCDebug(dcJsonRpcTraffic()) << "Incoming data from" << transportClient << ": " << data;
// Handle package fragmentation
QList<QByteArray> packages = proxyClient->processData(data);
QList<QByteArray> packages = transportClient->processData(data);
// Make sure the buffer size is in range
if (proxyClient->bufferSize() > 1024 * 10) {
qCWarning(dcJsonRpc()) << "Data buffer size violation from" << proxyClient;
proxyClient->killConnection("Data buffer size violation.");
if (transportClient->bufferSize() > 1024 * 10) {
qCWarning(dcJsonRpc()) << "Data buffer size violation from" << transportClient;
transportClient->killConnection("Data buffer size violation.");
return;
}
foreach (const QByteArray &package, packages) {
processDataPackage(proxyClient, package);
processDataPackage(transportClient, package);
}
}
void JsonRpcServer::sendNotification(const QString &nameSpace, const QString &method, const QVariantMap &params, ProxyClient *proxyClient)
void JsonRpcServer::sendNotification(const QString &nameSpace, const QString &method, const QVariantMap &params, TransportClient *transportClient)
{
QVariantMap notification;
notification.insert("id", m_notificationId++);
@ -347,7 +347,7 @@ void JsonRpcServer::sendNotification(const QString &nameSpace, const QString &me
QByteArray data = QJsonDocument::fromVariant(notification).toJson(QJsonDocument::Compact);
qCDebug(dcJsonRpcTraffic()) << "Sending notification:" << data;
proxyClient->sendData(data);
transportClient->sendData(data);
}
}

View File

@ -31,7 +31,7 @@
#include <QObject>
#include <QVariant>
#include "proxyclient.h"
#include "proxy/proxyclient.h"
#include "jsonrpc/jsonreply.h"
#include "transportinterface.h"
#include "jsonrpc/jsonhandler.h"
@ -48,8 +48,8 @@ public:
QString name() const override;
Q_INVOKABLE JsonReply *Hello(const QVariantMap &params, ProxyClient *proxyClient = nullptr) const;
Q_INVOKABLE JsonReply *Introspect(const QVariantMap &params, ProxyClient *proxyClient = nullptr) const;
Q_INVOKABLE JsonReply *Hello(const QVariantMap &params, TransportClient *transportClient = nullptr) const;
Q_INVOKABLE JsonReply *Introspect(const QVariantMap &params, TransportClient *transportClient = nullptr) const;
void registerHandler(JsonHandler *handler);
void unregisterHandler(JsonHandler *handler);
@ -59,29 +59,29 @@ signals:
private:
QHash<QString, JsonHandler *> m_handlers;
QHash<JsonReply *, ProxyClient *> m_asyncReplies;
QList<ProxyClient *> m_clients;
QHash<JsonReply *, TransportClient *> m_asyncReplies;
QList<TransportClient *> m_clients;
int m_notificationId = 0;
void sendResponse(ProxyClient *client, int commandId, const QVariantMap &params = QVariantMap());
void sendErrorResponse(ProxyClient *client, int commandId, const QString &error);
void sendResponse(TransportClient *client, int commandId, const QVariantMap &params = QVariantMap());
void sendErrorResponse(TransportClient *client, int commandId, const QString &error);
QString formatAssertion(const QString &targetNamespace, const QString &method, JsonHandler *handler, const QVariantMap &data) const;
void processDataPackage(ProxyClient *proxyClient, const QByteArray &data);
void processDataPackage(TransportClient *transportClient, const QByteArray &data);
private slots:
void asyncReplyFinished();
public slots:
// Client registration for JSON RPC traffic
void registerClient(ProxyClient *proxyClient);
void unregisterClient(ProxyClient *proxyClient);
void registerClient(TransportClient *transportClient);
void unregisterClient(TransportClient *transportClient);
// Process data from client
void processData(ProxyClient *proxyClient, const QByteArray &data);
void sendNotification(const QString &nameSpace, const QString &method, const QVariantMap &params, ProxyClient *proxyClient = nullptr);
void processData(TransportClient *transportClient, const QByteArray &data);
void sendNotification(const QString &nameSpace, const QString &method, const QVariantMap &params, TransportClient *transportClient = nullptr);
};

View File

@ -0,0 +1,116 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*
* 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 "transportclient.h"
#include "server/transportinterface.h"
#include <QDateTime>
namespace remoteproxy {
TransportClient::TransportClient(TransportInterface *interface, const QUuid &clientId, const QHostAddress &address, QObject *parent) :
QObject(parent),
m_interface(interface),
m_clientId(clientId),
m_peerAddress(address)
{
m_creationTimeStamp = QDateTime::currentDateTimeUtc().toMSecsSinceEpoch() / 1000;
}
QUuid TransportClient::clientId() const
{
return m_clientId;
}
QHostAddress TransportClient::peerAddress() const
{
return m_peerAddress;
}
uint TransportClient::creationTime() const
{
return m_creationTimeStamp;
}
QString TransportClient::creationTimeString() const
{
return QDateTime::fromMSecsSinceEpoch(creationTime() * 1000).toString("dd.MM.yyyy hh:mm:ss");
}
TransportInterface *TransportClient::interface() const
{
return m_interface;
}
quint64 TransportClient::rxDataCount() const
{
return m_rxDataCount;
}
void TransportClient::addRxDataCount(int dataCount)
{
m_rxDataCount += static_cast<quint64>(dataCount);
}
quint64 TransportClient::txDataCount() const
{
return m_txDataCount;
}
void TransportClient::addTxDataCount(int dataCount)
{
m_txDataCount += static_cast<quint64>(dataCount);
}
int TransportClient::bufferSize() const
{
return m_dataBuffers.size();
}
int TransportClient::generateMessageId()
{
m_messageId++;
return m_messageId;
}
void TransportClient::sendData(const QByteArray &data)
{
if (!m_interface)
return;
m_interface->sendData(m_clientId, data);
}
void TransportClient::killConnection(const QString &reason)
{
if (!m_interface)
return;
m_interface->killClientConnection(m_clientId, reason);
}
}

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 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
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#ifndef TRANSPORTCLIENT_H
#define TRANSPORTCLIENT_H
#include <QObject>
#include <QUuid>
#include <QDebug>
#include <QHostAddress>
namespace remoteproxy {
class TransportInterface;
class TransportClient : public QObject
{
Q_OBJECT
public:
explicit TransportClient(TransportInterface *interface, const QUuid &clientId, const QHostAddress &address, QObject *parent = nullptr);
virtual ~TransportClient() = default;
QUuid clientId() const;
QHostAddress peerAddress() const;
uint creationTime() const;
QString creationTimeString() const;
TransportInterface *interface() const;
quint64 rxDataCount() const;
void addRxDataCount(int dataCount);
quint64 txDataCount() const;
void addTxDataCount(int dataCount);
int bufferSize() const;
int generateMessageId();
virtual void sendData(const QByteArray &data);
virtual void killConnection(const QString &reason);
virtual QList<QByteArray> processData(const QByteArray &data) = 0;
protected:
TransportInterface *m_interface = nullptr;
QUuid m_clientId;
QHostAddress m_peerAddress;
uint m_creationTimeStamp = 0;
QByteArray m_dataBuffers;
// Json data information
int m_messageId = 0;
// Statistics info
quint64 m_rxDataCount = 0;
quint64 m_txDataCount = 0;
};
}
#endif // TRANSPORTCLIENT_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 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 "tunnelproxyclientconnection.h"
namespace remoteproxy {
TunnelProxyClientConnection::TunnelProxyClientConnection(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 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
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#ifndef TUNNELPROXYCLIENTCONNECTION_H
#define TUNNELPROXYCLIENTCONNECTION_H
#include <QObject>
namespace remoteproxy {
class TunnelProxyClientConnection : public QObject
{
Q_OBJECT
public:
explicit TunnelProxyClientConnection(QObject *parent = nullptr);
signals:
};
}
#endif // TUNNELPROXYCLIENTCONNECTION_H

View File

@ -38,7 +38,6 @@ TunnelProxyManager::TunnelProxyManager(QObject *parent) :
m_jsonRpcServer = new JsonRpcServer(this);
m_jsonRpcServer->registerHandler(m_jsonRpcServer);
m_jsonRpcServer->registerHandler(new TunnelProxyHandler(this));
}
TunnelProxyManager::~TunnelProxyManager()
@ -86,7 +85,7 @@ TunnelProxyManager::Error TunnelProxyManager::registerServer(const QUuid &client
// Check if requested already as client
TunnelProxyServer *proxyServer = new TunnelProxyServer(m_proxyClients.value(clientId), serverUuid, serverName);
TunnelProxyServerConnection *proxyServer = new TunnelProxyServerConnection(m_proxyClients.value(clientId), serverUuid, serverName);
m_proxyClientsTunnelServer.insert(clientId, proxyServer);
m_tunnelServers.insert(proxyServer->serverUuid(), proxyServer);
@ -95,7 +94,7 @@ TunnelProxyManager::Error TunnelProxyManager::registerServer(const QUuid &client
void TunnelProxyManager::startServer()
{
qCDebug(dcTunnelProxyManager()) << "Starting tunnel proxy manager...";
qCDebug(dcTunnelProxyManager()) << "Starting tunnel proxy...";
foreach (TransportInterface *interface, m_transportInterfaces) {
interface->startServer();
}
@ -104,7 +103,7 @@ void TunnelProxyManager::startServer()
void TunnelProxyManager::stopServer()
{
qCDebug(dcTunnelProxyManager()) << "Stopping tunnel proxy server...";
qCDebug(dcTunnelProxyManager()) << "Stopping tunnel proxy...";
foreach (TransportInterface *interface, m_transportInterfaces) {
interface->stopServer();
}
@ -123,19 +122,42 @@ void TunnelProxyManager::onClientConnected(const QUuid &clientId, const QHostAdd
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)
{
Q_UNUSED(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);
}
}

View File

@ -33,7 +33,7 @@
#include "server/jsonrpcserver.h"
#include "server/transportinterface.h"
#include "tunnelproxyserver.h"
#include "tunnelproxyserverconnection.h"
namespace remoteproxy {
@ -83,8 +83,8 @@ private:
QHash<QUuid, ProxyClient *> m_proxyClients; // clients
// Server connections
QHash<QUuid, TunnelProxyServer *> m_proxyClientsTunnelServer; // clientUuid, object
QHash<QUuid, TunnelProxyServer *> m_tunnelServers; // server uuid, object
QHash<QUuid, TunnelProxyServerConnection *> m_proxyClientsTunnelServer; // clientUuid, object
QHash<QUuid, TunnelProxyServerConnection *> m_tunnelServers; // server uuid, object
};

View File

@ -25,11 +25,11 @@
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#include "tunnelproxyserver.h"
#include "tunnelproxyserverconnection.h"
namespace remoteproxy {
TunnelProxyServer::TunnelProxyServer(ProxyClient *proxyClient, const QUuid &serverUuid, const QString &serverName, QObject *parent) :
TunnelProxyServerConnection::TunnelProxyServerConnection(ProxyClient *proxyClient, const QUuid &serverUuid, const QString &serverName, QObject *parent) :
QObject(parent),
m_proxyClient(proxyClient),
m_serverUuid(serverUuid),
@ -38,17 +38,17 @@ TunnelProxyServer::TunnelProxyServer(ProxyClient *proxyClient, const QUuid &serv
}
ProxyClient *TunnelProxyServer::proxyClient() const
ProxyClient *TunnelProxyServerConnection::proxyClient() const
{
return m_proxyClient;
}
QUuid TunnelProxyServer::serverUuid() const
QUuid TunnelProxyServerConnection::serverUuid() const
{
return m_serverUuid;
}
QString TunnelProxyServer::serverName() const
QString TunnelProxyServerConnection::serverName() const
{
return m_serverName;
}

View File

@ -25,20 +25,20 @@
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#ifndef TUNNELPROXYSERVER_H
#define TUNNELPROXYSERVER_H
#ifndef TUNNELPROXYSERVERCONNECTION_H
#define TUNNELPROXYSERVERCONNECTION_H
#include <QObject>
#include "proxyclient.h"
#include "proxy/proxyclient.h"
namespace remoteproxy {
class TunnelProxyServer : public QObject
class TunnelProxyServerConnection : public QObject
{
Q_OBJECT
public:
explicit TunnelProxyServer(ProxyClient *proxyClient, const QUuid &serverUuid, const QString &serverName, QObject *parent = nullptr);
explicit TunnelProxyServerConnection(ProxyClient *proxyClient, const QUuid &serverUuid, const QString &serverName, QObject *parent = nullptr);
ProxyClient *proxyClient() const;
@ -56,4 +56,4 @@ private:
}
#endif // TUNNELPROXYSERVER_H
#endif // TUNNELPROXYSERVERCONNECTION_H

View File

@ -96,7 +96,7 @@ void RemoteProxyTestsTunnelProxy::getIntrospect()
// WebSocket
response = invokeWebSocketTunnelProxyApiCall("RemoteProxy.Introspect").toMap();
//qDebug() << qUtf8Printable(QJsonDocument::fromVariant(response).toJson(QJsonDocument::Indented));
qDebug() << qUtf8Printable(QJsonDocument::fromVariant(response).toJson(QJsonDocument::Indented));
QVERIFY(!response.isEmpty());
QVERIFY(response.value("status").toString() == "success");
QVERIFY(response.value("params").toMap().contains("methods"));

View File

@ -25,7 +25,7 @@
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#include "proxyclient.h"
#include "proxy/proxyclient.h"
#include "mockauthenticator.h"
#include "loggingcategories.h"
#include "authentication/authenticationreply.h"