Restructure the project and introduce the new tunnel proxy

This commit is contained in:
Simon Stürz 2021-07-28 14:55:18 +02:00
parent ec011a8962
commit acd48bf7bf
53 changed files with 1490 additions and 330 deletions

141
README.md
View File

@ -112,7 +112,7 @@ In order to get information about the server you can start the command with the
Version: 0.1.5
API version: 0.3
Copyright © 2018 Simon Stürz <simon.stuerz@guh.io>
Copyright © 2018 Simon Stürz <simon.stuerz@nymea.io>
Options:
@ -131,7 +131,7 @@ In order to get information about the server you can start the command with the
--verbose Print more verbose.
# Server API
# Proxy server API
Once a client connects to the proxy server, he must authenticate him self by passing the token received from the nymea-cloud mqtt connection request.
@ -208,6 +208,9 @@ If anything goes wrong, or the tunnel partner disconnects from the proxy, the se
"status": "success"
}
# Proxy server
## Authenticate the connection
The first data a client **must** send to the proxy server is the authentication request. This request contains the `token` which will be verified agains the nymea-cloud infrastructure and a `nonce` which has to be uniq for each connection attempt and shared between the 2 clients. The `uuid` should be a persistant uuid for this client and the name should make clear which type of connection this is and which client is connecting. The name and uuid will be sent to the tunnel partner during the tunnel establishmend.
@ -270,76 +273,82 @@ Once the other client is here and ready, the server will send a notification to
#### Response
"id": 1,
"params": {
"methods": {
"Authentication.Authenticate": {
"description": "Authenticate this connection. The returned AuthenticationError informs about the result. If the authentication was not successfull, the server will close the connection immediatly after sending the error response. The given id should be a unique id the other tunnel client can understand. Once the authentication was successfull, you can wait for the RemoteProxy.TunnelEstablished notification. If you send any data before getting this notification, the server will close the connection. If the tunnel client does not show up within 10 seconds, the server will close the connection.",
"params": {
"name": "String",
"o:nonce": "String",
"token": "String",
"uuid": "String"
{
"id": 1,
"params": {
"methods": {
"Authentication.Authenticate": {
"description": "Authenticate this connection. The returned AuthenticationError informs about the result. If the authentication was not successfull, the server will close the connection immediatly after sending the error response. The given id should be a unique id the other tunnel client can understand. Once the authentication was successfull, you can wait for the RemoteProxy.TunnelEstablished notification. If you send any data before getting this notification, the server will close the connection. If the tunnel client does not show up within 10 seconds, the server will close the connection.",
"params": {
"name": "String",
"o:nonce": "String",
"token": "String",
"uuid": "String"
},
"returns": {
"authenticationError": "$ref:AuthenticationError"
}
},
"returns": {
"authenticationError": "$ref:AuthenticationError"
"RemoteProxy.Hello": {
"description": "Once connected to this server, a client can get information about the server by saying Hello. The response informs the client about this proxy server.",
"params": {
},
"returns": {
"apiVersion": "String",
"name": "String",
"server": "String",
"version": "String"
}
},
"RemoteProxy.Introspect": {
"description": "Introspect this API.",
"params": {
},
"returns": {
"methods": "Object",
"notifications": "Object",
"types": "Object"
}
}
},
"RemoteProxy.Hello": {
"description": "Once connected to this server, a client can get information about the server by saying Hello. The response informs the client about this proxy server.",
"params": {
},
"returns": {
"apiVersion": "String",
"name": "String",
"server": "String",
"version": "String"
"notifications": {
"RemoteProxy.TunnelEstablished": {
"description": "Emitted whenever the tunnel has been established successfully. This is the last message from the remote proxy server! Any following data will be from the other tunnel client until the connection will be closed. The parameter contain some information about the other tunnel client.",
"params": {
"name": "String",
"uuid": "String"
}
}
},
"RemoteProxy.Introspect": {
"description": "Introspect this API.",
"params": {
},
"returns": {
"methods": "Object",
"notifications": "Object",
"types": "Object"
}
"types": {
"AuthenticationError": [
"AuthenticationErrorNoError",
"AuthenticationErrorUnknown",
"AuthenticationErrorTimeout",
"AuthenticationErrorAborted",
"AuthenticationErrorAuthenticationFailed",
"AuthenticationErrorProxyError"
],
"BasicType": [
"Uuid",
"String",
"Int",
"UInt",
"Double",
"Bool",
"Variant",
"Object"
]
}
},
"notifications": {
"RemoteProxy.TunnelEstablished": {
"description": "Emitted whenever the tunnel has been established successfully. This is the last message from the remote proxy server! Any following data will be from the other tunnel client until the connection will be closed. The parameter contain some information about the other tunnel client.",
"params": {
"name": "String",
"uuid": "String"
}
}
},
"types": {
"AuthenticationError": [
"AuthenticationErrorNoError",
"AuthenticationErrorUnknown",
"AuthenticationErrorTimeout",
"AuthenticationErrorAborted",
"AuthenticationErrorAuthenticationFailed",
"AuthenticationErrorProxyError"
],
"BasicType": [
"Uuid",
"String",
"Int",
"UInt",
"Double",
"Bool",
"Variant",
"Object"
]
}
},
"status": "success"
}
"status": "success"
}
# Proxy server
# Server monitor
The server provides a live monitor interface on a local socket server. You can follow the monitor data with:
@ -358,7 +367,7 @@ There is also the package `nymea-remoteproxy-monitor` package and application wh
Server version: 0.1.5
API version: 0.3
Copyright © 2018 Simon Stürz <simon.stuerz@guh.io>
Copyright © 2018 Simon Stürz <simon.stuerz@nymea.io>
Options:
@ -384,7 +393,7 @@ The client allowes you to test the proxy server and create a dummy client for te
Version: 0.1.5
API version: 0.3
Copyright © 2018 Simon Stürz <simon.stuerz@guh.io>
Copyright © 2018 Simon Stürz <simon.stuerz@nymea.io>
Options:

25
debian/control vendored
View File

@ -1,12 +1,13 @@
Source: nymea-remoteproxy
Section: utils
Priority: options
Maintainer: Simon Stürz <simon.stürz@guh.io>
Maintainer: Simon Stürz <simon.stuerz@nymea.io>
Build-depends: debhelper (>= 0.0.0),
libqt5websockets5-dev,
libncurses5-dev,
Standards-Version: 3.9.3
Package: nymea-remoteproxy
Architecture: any
Depends: ${shlibs:Depends},
@ -17,6 +18,7 @@ Suggests: nymea-remoteproxy-monitor (= ${binary:Version})
Description: The nymea remote proxy server
The nymea remote proxy server
Package: libnymea-remoteproxy
Architecture: any
Section: libs
@ -25,6 +27,7 @@ Depends: ${shlibs:Depends},
Description: The nymea remote proxy server lib
The nymea remote proxy server lib
Package: libnymea-remoteproxy-dev
Architecture: any
Section: libdevel
@ -34,15 +37,6 @@ Depends: ${shlibs:Depends},
Description: The nymea remote proxy server lib - development files
The nymea remote proxy server lib - development files
Package: libnymea-remoteproxy-dbg
Architecture: any
Section: debug
Depends: ${shlibs:Depends},
${misc:Depends},
libnymea-remoteproxy (= ${binary:Version}),
Description: The nymea remote proxy server lib - debug symbols
The nymea remote proxy server lib - debug symbols
Package: nymea-remoteproxy-client
Architecture: any
@ -52,6 +46,7 @@ Depends: ${shlibs:Depends},
Description: The nymea remote proxy client for testing
The nymea remote proxy client for testing
Package: libnymea-remoteproxyclient
Architecture: any
Section: libs
@ -60,6 +55,7 @@ Depends: ${shlibs:Depends},
Description: The nymea remote proxy server client lib
The nymea remote proxy server client lib
Package: libnymea-remoteproxyclient-dev
Architecture: any
Section: libdevel
@ -69,14 +65,6 @@ Depends: ${shlibs:Depends},
Description: The nymea remote proxy server client lib - development files
The nymea remote proxy server client lib - development files
Package: libnymea-remoteproxyclient-dbg
Architecture: any
Section: debug
Depends: ${shlibs:Depends},
${misc:Depends},
libnymea-remoteproxyclient (= ${binary:Version}),
Description: The nymea remote proxy server client lib - debug symbols
The nymea remote proxy server client lib - debug symbols
Package: nymea-remoteproxy-tests
Architecture: any
@ -86,6 +74,7 @@ Depends: ${shlibs:Depends},
Description: The nymea remote proxy server tests
The nymea remote proxy server tests
Package: nymea-remoteproxy-monitor
Architecture: any
Depends: ${shlibs:Depends},

23
debian/copyright vendored
View File

@ -1,10 +1,9 @@
Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
Upstream-Name: nymea-remoteproxy
Upstream-Contact: Simon Stürz <simon.stuerz@guh.io>
Copyright: 2018, guh GmbH
Download: http://www.github.com/guh/nymea-remoteproxy
Source: https://github.com/guh/nymea-remoteproxy.git
Upstream-Contact: Simon Stürz <simon.stuerz@nymea.io>
Copyright: 2018 - 2021, nymea GmbH
Download: http://www.github.com/nymea/nymea-remoteproxy
Source: https://github.com/nymea/nymea-remoteproxy.git
License: GPL-3
On Debian systems, the complete text of the GNU General
@ -17,20 +16,24 @@ License: LGPL-3
Files: libnymea-remoteproxyclient/*
License: LGPL-3
Copyright: 2018 - 2010, nymea GmbH <contact@nymea.io>
Copyright: 2018 - 2021, nymea GmbH <contact@nymea.io>
Files: libnymea-remoteproxy/*
License: GPL-3
Copyright: 2018 - 2010, nymea GmbH <contact@nymea.io>
Copyright: 2018 - 2021, nymea GmbH <contact@nymea.io>
Files: client/*
License: GPL-3
Copyright: 2018 - 2010, nymea GmbH <contact@nymea.io>
Copyright: 2018 - 2021, nymea GmbH <contact@nymea.io>
Files: monitor/*
License: GPL-3
Copyright: 2018 - 2010, nymea GmbH <contact@nymea.io>
Copyright: 2018 - 2021, nymea GmbH <contact@nymea.io>
Files: server/*
License: GPL-3
Copyright: 2018 - 2010, nymea GmbH <contact@nymea.io>
Copyright: 2018 - 2021, nymea GmbH <contact@nymea.io>
Files: tests/*
License: GPL-3
Copyright: 2018 - 2021, nymea GmbH <contact@nymea.io>

View File

@ -1 +1,2 @@
usr/bin/nymea-remoteproxy-tests-offline
usr/bin/nymea-remoteproxy-proxy-tests
usr/bin/nymea-remoteproxy-tunnelproxy-tests

Binary file not shown.

After

Width:  |  Height:  |  Size: 90 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 19 KiB

View File

@ -0,0 +1,33 @@
title Remote tunnel proxy
nymea->proxy: RegisterProxyTunnelServer(uuid, name)
note over proxy: Register the server using the uuid
nymea<-proxy: Success
note over nymea, proxy: Protocol from now on SLIP\nThe proxy is client 0x0000
note over nymea, proxy: SLIP encoded data: 2 Bytes address + data
proxy<-client: ConnectProxyTunnelClient(uuid, name, serverUuid)
note over proxy: Search server using uuid
note over proxy: Server: Assign address 0x0001 for this client socket
proxy->nymea: SLIP:0x0000: ProxyTunnelClientConnected (address: 0x0001)
proxy<-nymea: SLIP:0x0000: AckProxyTunnelClient (address: 0x0001)
proxy->client: ProxyTunnelEstablished(uuid, name, serverUuid)
note over proxy, client: Protocol from now on SLIP encoded\nThe proxy is client 0x0000\nThe connected server is 0xFFFF
note over proxy, client: SLIP encoded data: 2 Bytes address + data
note over nymea, client: Connected: The client can now communicate with nymea directly.
note over nymea, client: nymea sends SLIP encoded data with address 0x0001 -> client
note over nymea, client: client sends SLIP endcoded data with address 0xFFFF -> nymea

View File

@ -71,32 +71,62 @@ void Engine::start(ProxyConfiguration *configuration)
// Make sure an authenticator was registered
Q_ASSERT_X(m_authenticator != nullptr, "Engine", "There is no authenticator registerd.");
// Proxy
// -------------------------------------
m_proxyServer = new ProxyServer(this);
m_webSocketServer = new WebSocketServer(m_configuration->sslEnabled(), m_configuration->sslConfiguration(), this);
m_tcpSocketServer = new TcpSocketServer(m_configuration->sslEnabled(), m_configuration->sslConfiguration(), this);
m_webSocketServerProxy = new WebSocketServer(m_configuration->sslEnabled(), m_configuration->sslConfiguration(), this);
m_tcpSocketServerProxy = new TcpSocketServer(m_configuration->sslEnabled(), m_configuration->sslConfiguration(), this);
// Configure websocket server
QUrl websocketServerUrl;
websocketServerUrl.setScheme(m_configuration->sslEnabled() ? "wss" : "ws");
websocketServerUrl.setHost(m_configuration->webSocketServerHost().toString());
websocketServerUrl.setPort(m_configuration->webSocketServerPort());
m_webSocketServer->setServerUrl(websocketServerUrl);
websocketServerUrl.setHost(m_configuration->webSocketServerProxyHost().toString());
websocketServerUrl.setPort(m_configuration->webSocketServerProxyPort());
m_webSocketServerProxy->setServerUrl(websocketServerUrl);
// Configure tcp socket server
QUrl tcpSocketServerUrl;
tcpSocketServerUrl.setScheme(m_configuration->sslEnabled() ? "ssl" : "tcp");
tcpSocketServerUrl.setHost(m_configuration->tcpServerHost().toString());
tcpSocketServerUrl.setPort(m_configuration->tcpServerPort());
m_tcpSocketServer->setServerUrl(tcpSocketServerUrl);
QUrl tcpSocketServerProxyUrl;
tcpSocketServerProxyUrl.setScheme(m_configuration->sslEnabled() ? "ssl" : "tcp");
tcpSocketServerProxyUrl.setHost(m_configuration->tcpServerHost().toString());
tcpSocketServerProxyUrl.setPort(m_configuration->tcpServerPort());
m_tcpSocketServerProxy->setServerUrl(tcpSocketServerProxyUrl);
// Register the transport interfaces in the proxy server
m_proxyServer->registerTransportInterface(m_webSocketServer);
m_proxyServer->registerTransportInterface(m_tcpSocketServer);
m_proxyServer->registerTransportInterface(m_webSocketServerProxy);
m_proxyServer->registerTransportInterface(m_tcpSocketServerProxy);
// Start the server
qCDebug(dcEngine()) << "Starting proxy server";
qCDebug(dcEngine()) << "Starting the proxy servers...";
m_proxyServer->startServer();
// Tunnel proxy
// -------------------------------------
m_tunnelProxyManager = new TunnelProxyManager(this);
m_webSocketServerTunnelProxy = new WebSocketServer(m_configuration->sslEnabled(), m_configuration->sslConfiguration(), this);
m_tcpSocketServerTunnelProxy = new TcpSocketServer(m_configuration->sslEnabled(), m_configuration->sslConfiguration(), this);
// Configure websocket server
QUrl websocketServerTunnelProxyUrl;
websocketServerTunnelProxyUrl.setScheme(m_configuration->sslEnabled() ? "wss" : "ws");
websocketServerTunnelProxyUrl.setHost(m_configuration->webSocketServerTunnelProxyHost().toString());
websocketServerTunnelProxyUrl.setPort(m_configuration->webSocketServerTunnelProxyPort());
m_webSocketServerTunnelProxy->setServerUrl(websocketServerTunnelProxyUrl);
// Configure tcp socket server
QUrl tcpSocketServerTunnelProxyUrl;
tcpSocketServerTunnelProxyUrl.setScheme(m_configuration->sslEnabled() ? "ssl" : "tcp");
tcpSocketServerTunnelProxyUrl.setHost(m_configuration->tcpServerTunnelProxyHost().toString());
tcpSocketServerTunnelProxyUrl.setPort(m_configuration->tcpServerTunnelProxyPort());
m_tcpSocketServerTunnelProxy->setServerUrl(tcpSocketServerTunnelProxyUrl);
// Register the transport interfaces in the proxy server
m_tunnelProxyManager->registerTransportInterface(m_webSocketServerTunnelProxy);
m_tunnelProxyManager->registerTransportInterface(m_tcpSocketServerTunnelProxy);
// Start the server
qCDebug(dcEngine()) << "Starting the tunnel proxy manager...";
m_tunnelProxyManager->startServer();
// Start the monitor server
m_monitorServer = new MonitorServer(configuration->monitorSocketFileName(), this);
m_monitorServer->startServer();
@ -165,14 +195,29 @@ ProxyServer *Engine::proxyServer() const
return m_proxyServer;
}
TcpSocketServer *Engine::tcpSocketServer() const
TunnelProxyManager *Engine::tunnelProxyManager() const
{
return m_tcpSocketServer;
return m_tunnelProxyManager;
}
WebSocketServer *Engine::webSocketServer() const
TcpSocketServer *Engine::tcpSocketServerProxy() const
{
return m_webSocketServer;
return m_tcpSocketServerProxy;
}
WebSocketServer *Engine::webSocketServerProxy() const
{
return m_webSocketServerProxy;
}
TcpSocketServer *Engine::tcpSocketServerTunnelProxy() const
{
return m_tcpSocketServerTunnelProxy;
}
WebSocketServer *Engine::webSocketServerTunnelProxy() const
{
return m_webSocketServerTunnelProxy;
}
MonitorServer *Engine::monitorServer() const
@ -188,7 +233,7 @@ LogEngine *Engine::logEngine() const
Engine::Engine(QObject *parent) :
QObject(parent)
{
m_lastTimeStamp = QDateTime::currentDateTime().toMSecsSinceEpoch();
m_lastTimeStamp = QDateTime::currentDateTimeUtc().toMSecsSinceEpoch();
m_timer = new QTimer(this);
m_timer->setSingleShot(false);
@ -216,7 +261,7 @@ QVariantMap Engine::createServerStatistic()
void Engine::onTimerTick()
{
qint64 timestamp = QDateTime::currentDateTime().toMSecsSinceEpoch();
qint64 timestamp = QDateTime::currentDateTimeUtc().toMSecsSinceEpoch();
qint64 deltaTime = timestamp - m_lastTimeStamp;
m_lastTimeStamp = timestamp;
@ -249,9 +294,9 @@ void Engine::clean()
m_proxyServer = nullptr;
}
if (m_webSocketServer) {
delete m_webSocketServer;
m_webSocketServer = nullptr;
if (m_webSocketServerProxy) {
delete m_webSocketServerProxy;
m_webSocketServerProxy = nullptr;
}
if (m_configuration) {
@ -265,6 +310,9 @@ void Engine::setRunning(bool running)
if (m_running == running)
return;
if (m_proxyServer)
m_proxyServer->setRunning(running);
qCDebug(dcEngine()) << "Engine is" << (running ? "now running." : "not running any more.");
if (running) {

View File

@ -36,12 +36,14 @@
#include <QSslConfiguration>
#include "logengine.h"
#include "proxyserver.h"
#include "monitorserver.h"
#include "tcpsocketserver.h"
#include "websocketserver.h"
#include "proxy/proxyserver.h"
#include "proxyconfiguration.h"
#include "server/monitorserver.h"
#include "server/jsonrpcserver.h"
#include "server/tcpsocketserver.h"
#include "server/websocketserver.h"
#include "authentication/authenticator.h"
#include "tunnelproxy/tunnelproxymanager.h"
namespace remoteproxy {
@ -67,9 +69,17 @@ public:
ProxyConfiguration *configuration() const;
Authenticator *authenticator() const;
ProxyServer *proxyServer() const;
TcpSocketServer *tcpSocketServer() const;
WebSocketServer *webSocketServer() const;
TunnelProxyManager *tunnelProxyManager() const;
TcpSocketServer *tcpSocketServerProxy() const;
WebSocketServer *webSocketServerProxy() const;
TcpSocketServer *tcpSocketServerTunnelProxy() const;
WebSocketServer *webSocketServerTunnelProxy() const;
MonitorServer *monitorServer() const;
LogEngine *logEngine() const;
@ -89,9 +99,16 @@ private:
ProxyConfiguration *m_configuration = nullptr;
Authenticator *m_authenticator = nullptr;
ProxyServer *m_proxyServer = nullptr;
TcpSocketServer *m_tcpSocketServer = nullptr;
WebSocketServer *m_webSocketServer = nullptr;
TunnelProxyManager *m_tunnelProxyManager = nullptr;
TcpSocketServer *m_tcpSocketServerProxy = nullptr;
WebSocketServer *m_webSocketServerProxy = nullptr;
TcpSocketServer *m_tcpSocketServerTunnelProxy = nullptr;
WebSocketServer *m_webSocketServerTunnelProxy = nullptr;
MonitorServer *m_monitorServer = nullptr;
LogEngine *m_logEngine = nullptr;

View File

@ -106,7 +106,7 @@ void AuthenticationHandler::onAuthenticationFinished()
jsonReply->setData(errorToReply(authenticationReply->error()));
}
jsonReply->finished();
emit jsonReply->finished();
}
}

View File

@ -40,11 +40,11 @@ QString JsonTypes::s_lastError;
// Types
QVariantList JsonTypes::s_basicType;
QVariantList JsonTypes::s_authenticationError;
QVariantList JsonTypes::s_tunnelProxyError;
// Objects
QVariantMap JsonTypes::allTypes()
{
QVariantMap allTypes;
@ -52,6 +52,7 @@ QVariantMap JsonTypes::allTypes()
// Enums
allTypes.insert("BasicType", basicType());
allTypes.insert("AuthenticationError", authenticationError());
allTypes.insert("TunnelProxyError", tunnelProxyError());
// Types
@ -63,6 +64,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_initialized = true;
}
@ -124,10 +126,17 @@ QPair<bool, QString> JsonTypes::validateVariant(const QVariant &templateVariant,
qCWarning(dcJsonRpc()) << QString("Value %1 not allowed in %2").arg(variant.toString()).arg(authenticationErrorRef());
return result;
}
} else if (refName == tunnelProxyErrorRef()) {
QPair<bool, QString> result = validateEnum(s_tunnelProxyError, variant);
if (!result.first) {
qCWarning(dcJsonRpc()) << QString("Value %1 not allowed in %2").arg(variant.toString()).arg(tunnelProxyErrorRef());
return result;
}
} else {
Q_ASSERT_X(false, "JsonTypes", QString("Unhandled ref: %1").arg(refName).toLatin1().data());
return report(false, QString("Unhandled ref %1. Server implementation incomplete.").arg(refName));
}
} else {
QPair<bool, QString> result = JsonTypes::validateProperty(templateVariant, variant);
if (!result.first) {

View File

@ -33,6 +33,7 @@
#include <QMetaEnum>
#include <QStringList>
#include "tunnelproxy/tunnelproxymanager.h"
#include "authentication/authenticator.h"
namespace remoteproxy {
@ -90,6 +91,7 @@ public:
// Declare types
DECLARE_TYPE(basicType, "BasicType", JsonTypes, BasicType)
DECLARE_TYPE(authenticationError, "AuthenticationError", Authenticator, AuthenticationError)
DECLARE_TYPE(tunnelProxyError, "TunnelProxyError", TunnelProxyManager, Error)
// Declare objects

View File

@ -0,0 +1,72 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*
* 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 "tunnelproxyhandler.h"
#include "engine.h"
#include "jsontypes.h"
#include "loggingcategories.h"
#include "tunnelproxy/tunnelproxymanager.h"
namespace remoteproxy {
TunnelProxyHandler::TunnelProxyHandler(QObject *parent) : JsonHandler(parent)
{
// Methods
QVariantMap params; QVariantMap returns;
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));
setParams("RegisterServer", params);
returns.insert("tunnelProxyError", JsonTypes::tunnelProxyErrorRef());
setReturns("RegisterServer", returns);
}
QString TunnelProxyHandler::name() const
{
return "TunnelProxy";
}
JsonReply *TunnelProxyHandler::RegisterServer(const QVariantMap &params, ProxyClient *proxyClient)
{
qCDebug(dcJsonRpc()) << name() << "register server" << params << proxyClient;
QUuid serverUuid = params.value("uuid").toUuid();
QString serverName = params.value("name").toString();
TunnelProxyManager::Error error = Engine::instance()->tunnelProxyManager()->registerServer(proxyClient->clientId(), serverUuid, serverName);
QVariantMap response;
response.insert("tunnelProxyError", JsonTypes::tunnelProxyErrorToString(error));
return createReply("RegisterServer", response);
}
}

View File

@ -0,0 +1,55 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*
* 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 TUNNELPROXYHANDLER_H
#define TUNNELPROXYHANDLER_H
#include <QObject>
#include "jsonhandler.h"
namespace remoteproxy {
class TunnelProxyHandler : public JsonHandler
{
Q_OBJECT
public:
explicit TunnelProxyHandler(QObject *parent = nullptr);
~TunnelProxyHandler() override = default;
QString name() const override;
Q_INVOKABLE JsonReply *RegisterServer(const QVariantMap &params, ProxyClient *proxyClient);
signals:
};
}
#endif // TUNNELPROXYHANDLER_H

View File

@ -6,19 +6,22 @@ TARGET = nymea-remoteproxy
HEADERS += \
engine.h \
loggingcategories.h \
tcpsocketserver.h \
transportinterface.h \
websocketserver.h \
tunnelproxy/tunnelproxymanager.h \
tunnelproxy/tunnelproxyserver.h \
server/tcpsocketserver.h \
server/transportinterface.h \
server/websocketserver.h \
server/jsonrpcserver.h \
server/monitorserver.h \
proxyclient.h \
proxyserver.h \
monitorserver.h \
proxy/proxyserver.h \
proxy/tunnelconnection.h \
proxyconfiguration.h \
tunnelconnection.h \
jsonrpcserver.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 \
@ -32,19 +35,22 @@ HEADERS += \
SOURCES += \
engine.cpp \
loggingcategories.cpp \
tcpsocketserver.cpp \
transportinterface.cpp \
websocketserver.cpp \
tunnelproxy/tunnelproxymanager.cpp \
tunnelproxy/tunnelproxyserver.cpp \
server/tcpsocketserver.cpp \
server/transportinterface.cpp \
server/websocketserver.cpp \
server/jsonrpcserver.cpp \
server/monitorserver.cpp \
proxyclient.cpp \
proxyserver.cpp \
monitorserver.cpp \
proxy/proxyserver.cpp \
proxy/tunnelconnection.cpp \
proxyconfiguration.cpp \
tunnelconnection.cpp \
jsonrpcserver.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 \
@ -57,7 +63,7 @@ SOURCES += \
# install header file with relative subdirectory
for(header, HEADERS) {
for (header, HEADERS) {
path = $$[QT_INSTALL_PREFIX]/include/nymea-remoteproxy/$${dirname(header)}
eval(headers_$${path}.files += $${header})
eval(headers_$${path}.path = $${path})

View File

@ -34,7 +34,7 @@ namespace remoteproxy {
LogEngine::LogEngine(QObject *parent) : QObject(parent)
{
m_currentDay = QDateTime::currentDateTime().date().day();
m_currentDay = QDateTime::currentDateTimeUtc().date().day();
m_tunnelsFileName = "/var/log/nymea-remoteproxy-tunnels";
m_statisticsFileName = "/var/log/nymea-remoteproxy-statistics";
}
@ -79,9 +79,9 @@ void LogEngine::logStatistics(int tunnelCount, int connectionCount, int troughpu
textStream << logString.join(" ") << endl;
// Check if we have to rotate the logfile
if (m_currentDay != QDateTime::currentDateTime().date().day()) {
if (m_currentDay != QDateTime::currentDateTimeUtc().date().day()) {
// Day changed
m_currentDay = QDateTime::currentDateTime().date().day();
m_currentDay = QDateTime::currentDateTimeUtc().date().day();
rotateLogs();
}
}
@ -98,7 +98,7 @@ void LogEngine::rotateLogs()
m_statisticsFile.close();
// Rename the current files
QString postfix = "-" + QDateTime::currentDateTime().toString("yyyyMMddhhmmss") + ".log";
QString postfix = "-" + QDateTime::currentDateTimeUtc().toString("yyyyMMddhhmmss") + ".log";
m_tunnelsFile.rename(m_tunnelsFileName + postfix);
qCDebug(dcApplication()) << "Rotate logfile" << m_tunnelsFile.fileName();
@ -120,7 +120,7 @@ void LogEngine::rotateLogs()
QString LogEngine::createTimestamp()
{
return QString::number(QDateTime::currentDateTime().toTime_t());
return QString::number(QDateTime::currentDateTimeUtc().toTime_t());
}
void LogEngine::enable()

View File

@ -31,7 +31,7 @@
#include <QFile>
#include <QObject>
#include "tunnelconnection.h"
#include "proxy/tunnelconnection.h"
namespace remoteproxy {

View File

@ -1,6 +1,6 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*
* Copyright 2013 - 2020, nymea GmbH
* Copyright 2013 - 2021, nymea GmbH
* Contact: contact@nymea.io
*
* This file is part of nymea.
@ -39,6 +39,9 @@ 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(dcProxyServerTraffic, "ProxyServerTraffic")
Q_LOGGING_CATEGORY(dcMonitorServer, "MonitorServer")
Q_LOGGING_CATEGORY(dcAwsCredentialsProvider, "AwsCredentialsProvider")

View File

@ -1,6 +1,6 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*
* Copyright 2013 - 2020, nymea GmbH
* Copyright 2013 - 2021, nymea GmbH
* Contact: contact@nymea.io
*
* This file is part of nymea.
@ -43,6 +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(dcMonitorServer)
Q_DECLARE_LOGGING_CATEGORY(dcAwsCredentialsProvider)

View File

@ -36,10 +36,13 @@
namespace remoteproxy {
ProxyServer::ProxyServer(QObject *parent) : QObject(parent)
ProxyServer::ProxyServer(QObject *parent) :
QObject(parent)
{
qRegisterMetaType<ProxyClient *>("ProxyClient *");
m_jsonRpcServer = new JsonRpcServer(this);
m_jsonRpcServer->registerHandler(m_jsonRpcServer);
m_jsonRpcServer->registerHandler(new AuthenticationHandler(this));
loadStatistics();
}
@ -120,7 +123,7 @@ void ProxyServer::setRunning(bool running)
if (m_running == running)
return;
qCDebug(dcProxyServer()) << "The proxy server is now up and running";
qCDebug(dcProxyServer()) << "The proxy server is" << (running ? "up and running." : "not running any more.");
m_running = running;
emit runningChanged();
}
@ -196,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(ProxyClient*, 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(ProxyClient*, tunnel.clientTwo()));
}
void ProxyServer::onClientConnected(const QUuid &clientId, const QHostAddress &address)

View File

@ -33,9 +33,9 @@
#include <QObject>
#include "proxyclient.h"
#include "jsonrpcserver.h"
#include "tunnelconnection.h"
#include "transportinterface.h"
#include "server/jsonrpcserver.h"
#include "server/transportinterface.h"
namespace remoteproxy {
@ -47,6 +47,8 @@ public:
~ProxyServer();
bool running() const;
void setRunning(bool running);
void registerTransportInterface(TransportInterface *interface);
QVariantMap currentStatistics();
@ -78,10 +80,6 @@ private:
int m_totalTunnelCount = 0;
int m_totalTraffic = 0;
// Set private properties
void setRunning(bool running);
void loadStatistics();
void saveStatistics();

View File

@ -35,7 +35,7 @@ TunnelConnection::TunnelConnection(ProxyClient *clientOne, ProxyClient *clientTw
m_clientOne(clientOne),
m_clientTwo(clientTwo)
{
m_creationTimeStamp = QDateTime::currentDateTime().toTime_t();
m_creationTimeStamp = QDateTime::currentDateTimeUtc().toTime_t();
}
QString TunnelConnection::token() const

View File

@ -39,7 +39,7 @@ ProxyClient::ProxyClient(TransportInterface *interface, const QUuid &clientId, c
m_clientId(clientId),
m_peerAddress(address)
{
m_creationTimeStamp = QDateTime::currentDateTime().toTime_t();
m_creationTimeStamp = QDateTime::currentDateTimeUtc().toTime_t();
m_timer = new QTimer(this);
connect(m_timer, &QTimer::timeout, this, &ProxyClient::timeoutOccured);

View File

@ -34,7 +34,7 @@
#include <QTimer>
#include <QHostAddress>
#include "transportinterface.h"
#include "server/transportinterface.h"
namespace remoteproxy {

View File

@ -302,24 +302,24 @@ QSslConfiguration ProxyConfiguration::sslConfiguration() const
return m_sslConfiguration;
}
QHostAddress ProxyConfiguration::webSocketServerHost() const
QHostAddress ProxyConfiguration::webSocketServerProxyHost() const
{
return m_webSocketServerHost;
return m_webSocketServerProxyHost;
}
void ProxyConfiguration::setWebSocketServerHost(const QHostAddress &address)
{
m_webSocketServerHost = address;
m_webSocketServerProxyHost = address;
}
quint16 ProxyConfiguration::webSocketServerPort() const
quint16 ProxyConfiguration::webSocketServerProxyPort() const
{
return m_webSocketServerPort;
return m_webSocketServerProxyPort;
}
void ProxyConfiguration::setWebSocketServerPort(quint16 port)
{
m_webSocketServerPort = port;
m_webSocketServerProxyPort = port;
}
QHostAddress ProxyConfiguration::tcpServerHost() const
@ -342,6 +342,46 @@ void ProxyConfiguration::setTcpServerPort(quint16 port)
m_tcpServerPort = port;
}
QHostAddress ProxyConfiguration::webSocketServerTunnelProxyHost() const
{
return m_webSocketServerTunnelProxyHost;
}
void ProxyConfiguration::setWebSocketServerTunnelProxyHost(const QHostAddress &address)
{
m_webSocketServerTunnelProxyHost = address;
}
quint16 ProxyConfiguration::webSocketServerTunnelProxyPort() const
{
return m_webSocketServerTunnelProxyPort;
}
void ProxyConfiguration::setWebSocketServerTunnelProxyPort(quint16 port)
{
m_webSocketServerTunnelProxyPort = port;
}
QHostAddress ProxyConfiguration::tcpServerTunnelProxyHost() const
{
return m_tcpServerTunnelProxyHost;
}
void ProxyConfiguration::setTcpServerTunnelProxyHost(const QHostAddress &address)
{
m_tcpServerTunnelProxyHost = address;
}
quint16 ProxyConfiguration::tcpServerTunnelProxyPort() const
{
return m_tcpServerTunnelProxyPort;
}
void ProxyConfiguration::setTcpServerTunnelProxyPort(quint16 port)
{
m_tcpServerTunnelProxyPort = port;
}
QDebug operator<<(QDebug debug, ProxyConfiguration *configuration)
{
debug.nospace() << endl << "========== ProxyConfiguration ==========" << endl;
@ -380,12 +420,18 @@ QDebug operator<<(QDebug debug, ProxyConfiguration *configuration)
debug.nospace() << " Locality name:" << configuration->sslConfiguration().localCertificate().issuerInfo(QSslCertificate::LocalityName) << endl;
debug.nospace() << " State/Province:" << configuration->sslConfiguration().localCertificate().issuerInfo(QSslCertificate::StateOrProvinceName) << endl;
debug.nospace() << " Email address:" << configuration->sslConfiguration().localCertificate().issuerInfo(QSslCertificate::EmailAddress) << endl;
debug.nospace() << "WebSocketServer configuration" << endl;
debug.nospace() << " - Host:" << configuration->webSocketServerHost().toString() << endl;
debug.nospace() << " - Port:" << configuration->webSocketServerPort() << endl;
debug.nospace() << "TcpServer" << endl;
debug.nospace() << "WebSocketServer Proxy" << endl;
debug.nospace() << " - Host:" << configuration->webSocketServerProxyHost().toString() << endl;
debug.nospace() << " - Port:" << configuration->webSocketServerProxyPort() << endl;
debug.nospace() << "TcpServer Proxy" << endl;
debug.nospace() << " - Host:" << configuration->tcpServerHost().toString() << endl;
debug.nospace() << " - Port:" << configuration->tcpServerPort() << endl;
debug.nospace() << "WebSocketServer TunnelProxy" << endl;
debug.nospace() << " - Host:" << configuration->webSocketServerTunnelProxyHost().toString() << endl;
debug.nospace() << " - Port:" << configuration->webSocketServerTunnelProxyPort() << endl;
debug.nospace() << "TcpServer TunnelProxy" << endl;
debug.nospace() << " - Host:" << configuration->tcpServerTunnelProxyHost().toString() << endl;
debug.nospace() << " - Port:" << configuration->tcpServerTunnelProxyPort() << endl;
debug.nospace() << "========== ProxyConfiguration ==========";
return debug;
}

View File

@ -100,10 +100,10 @@ public:
QSslConfiguration sslConfiguration() const;
// WebSocketServer
QHostAddress webSocketServerHost() const;
QHostAddress webSocketServerProxyHost() const;
void setWebSocketServerHost(const QHostAddress &address);
quint16 webSocketServerPort() const;
quint16 webSocketServerProxyPort() const;
void setWebSocketServerPort(quint16 port);
// TcpServer
@ -113,6 +113,21 @@ public:
quint16 tcpServerPort() const;
void setTcpServerPort(quint16 port);
// WebSocketServer (tunnel)
QHostAddress webSocketServerTunnelProxyHost() const;
void setWebSocketServerTunnelProxyHost(const QHostAddress &address);
quint16 webSocketServerTunnelProxyPort() const;
void setWebSocketServerTunnelProxyPort(quint16 port);
// TcpServer (tunnel)
QHostAddress tcpServerTunnelProxyHost() const;
void setTcpServerTunnelProxyHost(const QHostAddress &address);
quint16 tcpServerTunnelProxyPort() const;
void setTcpServerTunnelProxyPort(quint16 port);
private:
// ProxyServer
QString m_fileName;
@ -139,14 +154,23 @@ private:
QString m_sslCertificateChainFileName;
QSslConfiguration m_sslConfiguration;
// WebSocketServer
QHostAddress m_webSocketServerHost = QHostAddress::LocalHost;
quint16 m_webSocketServerPort = 1212;
// WebSocketServer (proxy)
QHostAddress m_webSocketServerProxyHost = QHostAddress::LocalHost;
quint16 m_webSocketServerProxyPort = 1212;
// TcpServer
// TcpServer (proxy)
QHostAddress m_tcpServerHost = QHostAddress::LocalHost;
quint16 m_tcpServerPort = 1213;
// WebSocketServer (proxy)
QHostAddress m_webSocketServerTunnelProxyHost = QHostAddress::LocalHost;
quint16 m_webSocketServerTunnelProxyPort = 2212;
// TcpServer (proxy)
QHostAddress m_tcpServerTunnelProxyHost = QHostAddress::LocalHost;
quint16 m_tcpServerTunnelProxyPort = 2213;
};
QDebug operator<< (QDebug debug, ProxyConfiguration *configuration);

View File

@ -70,7 +70,6 @@ JsonRpcServer::JsonRpcServer(QObject *parent) :
params.insert("name", JsonTypes::basicTypeToString(JsonTypes::String));
setParams("TunnelEstablished", params);
QMetaObject::invokeMethod(this, "setup", Qt::QueuedConnection);
}
JsonRpcServer::~JsonRpcServer()
@ -252,12 +251,6 @@ void JsonRpcServer::processDataPackage(ProxyClient *proxyClient, const QByteArra
}
}
void JsonRpcServer::setup()
{
registerHandler(this);
registerHandler(new AuthenticationHandler(this));
}
void JsonRpcServer::asyncReplyFinished()
{
JsonReply *reply = static_cast<JsonReply *>(sender());

View File

@ -51,6 +51,9 @@ public:
Q_INVOKABLE JsonReply *Hello(const QVariantMap &params, ProxyClient *proxyClient = nullptr) const;
Q_INVOKABLE JsonReply *Introspect(const QVariantMap &params, ProxyClient *proxyClient = nullptr) const;
void registerHandler(JsonHandler *handler);
void unregisterHandler(JsonHandler *handler);
signals:
void TunnelEstablished(const QVariantMap &params);
@ -66,12 +69,9 @@ private:
QString formatAssertion(const QString &targetNamespace, const QString &method, JsonHandler *handler, const QVariantMap &data) const;
void registerHandler(JsonHandler *handler);
void unregisterHandler(JsonHandler *handler);
void processDataPackage(ProxyClient *proxyClient, const QByteArray &data);
private slots:
void setup();
void asyncReplyFinished();
public slots:

View File

@ -1,23 +1,29 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* *
* Copyright (C) 2019 Simon Stürz <simon.stuerz@guh.io> *
* *
* This file is part of nymea-remoteproxy. *
* *
* This program is free software: you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation, either version 3 of the License, or *
* (at your option) any later version. *
* *
* This program 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 program. If not, see <http://www.gnu.org/licenses/>. *
* *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*
* Copyright 2013 - 2020, 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 "tcpsocketserver.h"
#include "loggingcategories.h"
@ -106,7 +112,7 @@ bool TcpSocketServer::startServer()
}
connect(m_server, &SslServer::clientConnected, this, &TcpSocketServer::onClientConnected);
connect(m_server, SIGNAL(clientDisconnected(QSslSocket *)), SLOT(onClientDisconnected(QSslSocket *)));
connect(m_server, SIGNAL(clientDisconnected(QSslSocket*)), SLOT(onClientDisconnected(QSslSocket*)));
connect(m_server, &SslServer::dataAvailable, this, &TcpSocketServer::onDataAvailable);
qCDebug(dcTcpSocketServer()) << "Server started successfully.";
return true;
@ -144,7 +150,7 @@ void SslServer::incomingConnection(qintptr socketDescriptor)
qCDebug(dcTcpSocketServer()) << "Incomming connection" << sslSocket;
connect(sslSocket, &QSslSocket::readyRead, this, &SslServer::onSocketReadyRead);
connect(sslSocket, &QSslSocket::disconnected, this, &SslServer::onClientDisconnected);
connect(sslSocket, &QSslSocket::encrypted, [this, sslSocket](){
connect(sslSocket, &QSslSocket::encrypted, this, [this, sslSocket](){
qCDebug(dcTcpSocketServer()) << "SSL encryption established for" << sslSocket;
emit clientConnected(sslSocket);
});

View File

@ -0,0 +1,141 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*
* 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
TunnelProxyServer *proxyServer = new TunnelProxyServer(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 manager...";
foreach (TransportInterface *interface, m_transportInterfaces) {
interface->startServer();
}
setRunning(true);
}
void TunnelProxyManager::stopServer()
{
qCDebug(dcTunnelProxyManager()) << "Stopping tunnel proxy server...";
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)
{
Q_UNUSED(clientId)
}
void TunnelProxyManager::onClientDataAvailable(const QUuid &clientId, const QByteArray &data)
{
Q_UNUSED(clientId)
Q_UNUSED(data)
}
}

View File

@ -0,0 +1,93 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*
* 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 TUNNELPROXYMANAGER_H
#define TUNNELPROXYMANAGER_H
#include <QObject>
#include "server/jsonrpcserver.h"
#include "server/transportinterface.h"
#include "tunnelproxyserver.h"
namespace remoteproxy {
class TunnelProxyManager : public QObject
{
Q_OBJECT
public:
enum Error {
ErrorNoError,
ErrorServerNotFound
};
Q_ENUM(Error)
explicit TunnelProxyManager(QObject *parent = nullptr);
~TunnelProxyManager();
bool running() const;
void setRunning(bool running);
void registerTransportInterface(TransportInterface *interface);
TunnelProxyManager::Error registerServer(const QUuid &clientId, const QUuid &serverUuid, const QString &serverName);
public slots:
void startServer();
void stopServer();
void tick();
signals:
void runningChanged(bool running);
private slots:
void onClientConnected(const QUuid &clientId, const QHostAddress &address);
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
// Server connections
QHash<QUuid, TunnelProxyServer *> m_proxyClientsTunnelServer; // clientUuid, object
QHash<QUuid, TunnelProxyServer *> m_tunnelServers; // server uuid, object
};
}
#endif // TUNNELPROXYMANAGER_H

View File

@ -0,0 +1,56 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*
* 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"
namespace remoteproxy {
TunnelProxyServer::TunnelProxyServer(ProxyClient *proxyClient, const QUuid &serverUuid, const QString &serverName, QObject *parent) :
QObject(parent),
m_proxyClient(proxyClient),
m_serverUuid(serverUuid),
m_serverName(serverName)
{
}
ProxyClient *TunnelProxyServer::proxyClient() const
{
return m_proxyClient;
}
QUuid TunnelProxyServer::serverUuid() const
{
return m_serverUuid;
}
QString TunnelProxyServer::serverName() const
{
return m_serverName;
}
}

View File

@ -0,0 +1,59 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*
* 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 TUNNELPROXYSERVER_H
#define TUNNELPROXYSERVER_H
#include <QObject>
#include "proxyclient.h"
namespace remoteproxy {
class TunnelProxyServer : public QObject
{
Q_OBJECT
public:
explicit TunnelProxyServer(ProxyClient *proxyClient, const QUuid &serverUuid, const QString &serverName, QObject *parent = nullptr);
ProxyClient *proxyClient() const;
QUuid serverUuid() const;
QString serverName() const;
signals:
private:
ProxyClient *m_proxyClient = nullptr;
QUuid m_serverUuid;
QString m_serverName;
};
}
#endif // TUNNELPROXYSERVER_H

View File

@ -48,7 +48,7 @@ int main(int argc, char *argv[])
parser.setApplicationDescription(QString("\nThe nymea remote proxy monitor allowes to monitor the live server activity on the a local instance.\n\n"
"Server version: %1\n"
"API version: %2\n\n"
"Copyright %3 2018 Simon Stürz <simon.stuerz@guh.io>\n")
"Copyright %3 2021 nymea GmbH <developer@nymea.io>\n")
.arg(SERVER_VERSION_STRING)
.arg(API_VERSION_STRING)
.arg(QChar(0xA9)));

View File

@ -101,7 +101,7 @@ const char *TerminalWindow::convertString(const QString &string)
QString TerminalWindow::getDurationString(uint timestamp)
{
uint duration = QDateTime::currentDateTime().toTime_t() - timestamp;
uint duration = QDateTime::currentDateTimeUtc().toTime_t() - timestamp;
int seconds = static_cast<int>(duration % 60);
duration /= 60;
int minutes = static_cast<int>(duration % 60);

View File

@ -65,7 +65,7 @@ static const char *const error = "\e[31m";
static void consoleLogHandler(QtMsgType type, const QMessageLogContext& context, const QString& message)
{
QString messageString;
QString timeString = QDateTime::currentDateTime().toString("yyyy.MM.dd hh:mm:ss.zzz");
QString timeString = QDateTime::currentDateTimeUtc().toString("yyyy.MM.dd hh:mm:ss.zzz");
switch (type) {
case QtInfoMsg:
messageString = QString(" I %1 | %2: %3").arg(timeString).arg(context.category).arg(message);
@ -174,7 +174,7 @@ int main(int argc, char *argv[])
}
// Verify webserver configuration
if (configuration->webSocketServerHost().isNull()) {
if (configuration->webSocketServerProxyHost().isNull()) {
qCCritical(dcApplication()) << "Invalid web socket host address passed.";
exit(-1);
}

View File

@ -25,7 +25,7 @@
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#include "nymea-remoteproxy-tests-offline.h"
#include "remoteproxytestsproxy.h"
#include "engine.h"
#include "loggingcategories.h"
@ -37,19 +37,19 @@
#include <QJsonDocument>
#include <QWebSocketServer>
RemoteProxyOfflineTests::RemoteProxyOfflineTests(QObject *parent) :
RemoteProxyTestsProxy::RemoteProxyTestsProxy(QObject *parent) :
BaseTest(parent)
{
}
void RemoteProxyOfflineTests::startStopServer()
void RemoteProxyTestsProxy::startStopServer()
{
startServer();
stopServer();
}
void RemoteProxyOfflineTests::dummyAuthenticator()
void RemoteProxyTestsProxy::dummyAuthenticator()
{
cleanUpEngine();
@ -69,7 +69,7 @@ void RemoteProxyOfflineTests::dummyAuthenticator()
// Make sure the server is running
QVERIFY(Engine::instance()->running());
QVERIFY(Engine::instance()->webSocketServer()->running());
QVERIFY(Engine::instance()->webSocketServerProxy()->running());
QVERIFY(Engine::instance()->proxyServer()->running());
// Create request
@ -78,7 +78,7 @@ void RemoteProxyOfflineTests::dummyAuthenticator()
params.insert("name", "test");
params.insert("token", "foobar");
QVariant response = invokeWebSocketApiCall("Authentication.Authenticate", params);
QVariant response = invokeWebSocketProxyApiCall("Authentication.Authenticate", params);
qDebug() << qUtf8Printable(QJsonDocument::fromVariant(response).toJson(QJsonDocument::Indented));
verifyAuthenticationError(response);
@ -86,7 +86,7 @@ void RemoteProxyOfflineTests::dummyAuthenticator()
}
void RemoteProxyOfflineTests::monitorServer()
void RemoteProxyTestsProxy::monitorServer()
{
// Start the server
startServer();
@ -188,7 +188,7 @@ void RemoteProxyOfflineTests::monitorServer()
stopServer();
}
void RemoteProxyOfflineTests::configuration_data()
void RemoteProxyTestsProxy::configuration_data()
{
QTest::addColumn<QString>("fileName");
QTest::addColumn<bool>("success");
@ -201,7 +201,7 @@ void RemoteProxyOfflineTests::configuration_data()
QTest::newRow("faulty chain") << ":/test-configuration-faulty-chain.conf" << false;
}
void RemoteProxyOfflineTests::configuration()
void RemoteProxyTestsProxy::configuration()
{
QFETCH(QString, fileName);
QFETCH(bool, success);
@ -210,7 +210,7 @@ void RemoteProxyOfflineTests::configuration()
QCOMPARE(configuration.loadConfiguration(fileName), success);
}
void RemoteProxyOfflineTests::serverPortBlocked()
void RemoteProxyTestsProxy::serverPortBlocked()
{
cleanUpEngine();
@ -222,7 +222,7 @@ void RemoteProxyOfflineTests::serverPortBlocked()
// Create a dummy server which blocks the port
QWebSocketServer dummyServer("dummy-server", QWebSocketServer::NonSecureMode);
QVERIFY(dummyServer.listen(QHostAddress::LocalHost, m_configuration->webSocketServerPort()));
QVERIFY(dummyServer.listen(QHostAddress::LocalHost, m_configuration->webSocketServerProxyPort()));
// Start proxy webserver
QSignalSpy runningSpy(Engine::instance(), &Engine::runningChanged);
@ -235,7 +235,7 @@ void RemoteProxyOfflineTests::serverPortBlocked()
QVERIFY(Engine::instance()->running());
// Make sure the websocket server is not running
QVERIFY(!Engine::instance()->webSocketServer()->running());
QVERIFY(!Engine::instance()->webSocketServerProxy()->running());
QSignalSpy closedSpy(&dummyServer, &QWebSocketServer::closed);
dummyServer.close();
@ -272,7 +272,7 @@ void RemoteProxyOfflineTests::serverPortBlocked()
QVERIFY(Engine::instance()->running());
// Make sure the TCP server is not running
QVERIFY(!Engine::instance()->tcpSocketServer()->running());
QVERIFY(!Engine::instance()->tcpSocketServerProxy()->running());
tcpDummyServer->close();
delete tcpDummyServer;
@ -281,14 +281,14 @@ void RemoteProxyOfflineTests::serverPortBlocked()
startServer();
// Make sure the TCP server is not running
QVERIFY(Engine::instance()->webSocketServer()->running());
QVERIFY(Engine::instance()->tcpSocketServer()->running());
QVERIFY(Engine::instance()->webSocketServerProxy()->running());
QVERIFY(Engine::instance()->tcpSocketServerProxy()->running());
// Clean up
stopServer();
}
void RemoteProxyOfflineTests::websocketBinaryData()
void RemoteProxyTestsProxy::websocketBinaryData()
{
// Start the server
startServer();
@ -296,7 +296,7 @@ void RemoteProxyOfflineTests::websocketBinaryData()
QWebSocket *client = new QWebSocket("bad-client", QWebSocketProtocol::Version13);
connect(client, &QWebSocket::sslErrors, this, &BaseTest::sslErrors);
QSignalSpy spyConnection(client, SIGNAL(connected()));
client->open(Engine::instance()->webSocketServer()->serverUrl());
client->open(Engine::instance()->webSocketServerProxy()->serverUrl());
spyConnection.wait();
// Send binary data and make sure the server disconnects this socket
@ -309,7 +309,7 @@ void RemoteProxyOfflineTests::websocketBinaryData()
stopServer();
}
void RemoteProxyOfflineTests::websocketPing()
void RemoteProxyTestsProxy::websocketPing()
{
// Start the server
startServer();
@ -317,7 +317,7 @@ void RemoteProxyOfflineTests::websocketPing()
QWebSocket *client = new QWebSocket("bad-client", QWebSocketProtocol::Version13);
connect(client, &QWebSocket::sslErrors, this, &BaseTest::sslErrors);
QSignalSpy spyConnection(client, SIGNAL(connected()));
client->open(Engine::instance()->webSocketServer()->serverUrl());
client->open(Engine::instance()->webSocketServerProxy()->serverUrl());
spyConnection.wait();
QVERIFY(spyConnection.count() == 1);
@ -334,45 +334,45 @@ void RemoteProxyOfflineTests::websocketPing()
stopServer();
}
//void RemoteProxyOfflineTests::apiBasicCallsTcp_data()
//{
// QTest::addColumn<QByteArray>("data");
// QTest::addColumn<int>("responseId");
// QTest::addColumn<QString>("responseStatus");
void RemoteProxyTestsProxy::apiBasicCallsTcp_data()
{
QTest::addColumn<QByteArray>("data");
QTest::addColumn<int>("responseId");
QTest::addColumn<QString>("responseStatus");
// QTest::newRow("valid call") << QByteArray("{\"id\":42, \"method\":\"RemoteProxy.Hello\"}") << 42 << "success";
// QTest::newRow("missing id") << QByteArray("{\"method\":\"RemoteProxy.Hello\"}") << -1 << "error";
// QTest::newRow("missing method") << QByteArray("{\"id\":42}") << 42 << "error";
// QTest::newRow("invalid json") << QByteArray("{\"id\":42, \"method\":\"RemoteProx") << -1 << "error";
// QTest::newRow("invalid function") << QByteArray("{\"id\":42, \"method\":\"RemoteProxy.Explode\"}") << 42 << "error";
// QTest::newRow("invalid namespace") << QByteArray("{\"id\":42, \"method\":\"ProxyRemote.Hello\"}") << 42 << "error";
// QTest::newRow("missing dot") << QByteArray("{\"id\":42, \"method\":\"RemoteProxyHello\"}") << 42 << "error";
// QTest::newRow("invalid params") << QByteArray("{\"id\":42, \"method\":\"RemoteProxy.Hello\", \"params\":{\"törööö\":\"chooo-chooo\"}}") << 42 << "error";
// QTest::newRow("invalid authentication params") << QByteArray("{\"id\":42, \"method\":\"Authentication.Authenticate\", \"params\":{\"your\":\"mamma\"}}") << 42 << "error";
//}
QTest::newRow("valid call") << QByteArray("{\"id\":42, \"method\":\"RemoteProxy.Hello\"}") << 42 << "success";
QTest::newRow("missing id") << QByteArray("{\"method\":\"RemoteProxy.Hello\"}") << -1 << "error";
QTest::newRow("missing method") << QByteArray("{\"id\":42}") << 42 << "error";
//QTest::newRow("invalid json") << QByteArray("{\"id\":42, \"method\":\"RemoteProx") << -1 << "error";
QTest::newRow("invalid function") << QByteArray("{\"id\":42, \"method\":\"RemoteProxy.Explode\"}") << 42 << "error";
QTest::newRow("invalid namespace") << QByteArray("{\"id\":42, \"method\":\"ProxyRemote.Hello\"}") << 42 << "error";
QTest::newRow("missing dot") << QByteArray("{\"id\":42, \"method\":\"RemoteProxyHello\"}") << 42 << "error";
QTest::newRow("invalid params") << QByteArray("{\"id\":42, \"method\":\"RemoteProxy.Hello\", \"params\":{\"törööö\":\"chooo-chooo\"}}") << 42 << "error";
QTest::newRow("invalid authentication params") << QByteArray("{\"id\":42, \"method\":\"Authentication.Authenticate\", \"params\":{\"your\":\"mamma\"}}") << 42 << "error";
}
//void RemoteProxyOfflineTests::apiBasicCallsTcp()
//{
// QFETCH(QByteArray, data);
// QFETCH(int, responseId);
// QFETCH(QString, responseStatus);
void RemoteProxyTestsProxy::apiBasicCallsTcp()
{
QFETCH(QByteArray, data);
QFETCH(int, responseId);
QFETCH(QString, responseStatus);
// // Start the server
// startServer();
// Start the server
startServer();
// QVariant response = injectTcpSocketData(data);
// QVERIFY(!response.isNull());
QVariant response = injectTcpSocketProxyData(data);
QVERIFY(!response.isNull());
// qDebug() << qUtf8Printable(QJsonDocument::fromVariant(response).toJson(QJsonDocument::Indented));
qDebug() << qUtf8Printable(QJsonDocument::fromVariant(response).toJson(QJsonDocument::Indented));
// QCOMPARE(response.toMap().value("id").toInt(), responseId);
// QCOMPARE(response.toMap().value("status").toString(), responseStatus);
QCOMPARE(response.toMap().value("id").toInt(), responseId);
QCOMPARE(response.toMap().value("status").toString(), responseStatus);
// // Clean up
// stopServer();
//}
// Clean up
stopServer();
}
void RemoteProxyOfflineTests::getIntrospect()
void RemoteProxyTestsProxy::getIntrospect()
{
// Start the server
startServer();
@ -380,7 +380,7 @@ void RemoteProxyOfflineTests::getIntrospect()
QVariantMap response;
// WebSocket
response = invokeWebSocketApiCall("RemoteProxy.Introspect").toMap();
response = invokeWebSocketProxyApiCall("RemoteProxy.Introspect").toMap();
//qDebug() << qUtf8Printable(QJsonDocument::fromVariant(response).toJson(QJsonDocument::Indented));
QVERIFY(!response.isEmpty());
QVERIFY(response.value("status").toString() == "success");
@ -390,7 +390,7 @@ void RemoteProxyOfflineTests::getIntrospect()
// Tcp
response.clear();
response = invokeTcpSocketApiCall("RemoteProxy.Introspect").toMap();
response = invokeTcpSocketProxyApiCall("RemoteProxy.Introspect").toMap();
//qDebug() << qUtf8Printable(QJsonDocument::fromVariant(response).toJson(QJsonDocument::Indented));
QVERIFY(!response.isEmpty());
@ -403,14 +403,14 @@ void RemoteProxyOfflineTests::getIntrospect()
stopServer();
}
void RemoteProxyOfflineTests::getHello()
void RemoteProxyTestsProxy::getHello()
{
// Start the server
startServer();
QVariantMap response;
// WebSocket
response = invokeWebSocketApiCall("RemoteProxy.Hello").toMap();
response = invokeWebSocketProxyApiCall("RemoteProxy.Hello").toMap();
//qDebug() << qUtf8Printable(QJsonDocument::fromVariant(response).toJson(QJsonDocument::Indented));
// Verify data
@ -422,7 +422,7 @@ void RemoteProxyOfflineTests::getHello()
// TCP
response.clear();
response = invokeTcpSocketApiCall("RemoteProxy.Hello").toMap();
response = invokeTcpSocketProxyApiCall("RemoteProxy.Hello").toMap();
//qDebug() << qUtf8Printable(QJsonDocument::fromVariant(response).toJson(QJsonDocument::Indented));
// Verify data
@ -437,7 +437,7 @@ void RemoteProxyOfflineTests::getHello()
stopServer();
}
void RemoteProxyOfflineTests::apiBasicCalls_data()
void RemoteProxyTestsProxy::apiBasicCalls_data()
{
QTest::addColumn<QByteArray>("data");
QTest::addColumn<int>("responseId");
@ -454,7 +454,7 @@ void RemoteProxyOfflineTests::apiBasicCalls_data()
QTest::newRow("invalid authentication params") << QByteArray("{\"id\":42, \"method\":\"Authentication.Authenticate\", \"params\":{\"your\":\"mamma\"}}") << 42 << "error";
}
void RemoteProxyOfflineTests::apiBasicCalls()
void RemoteProxyTestsProxy::apiBasicCalls()
{
QFETCH(QByteArray, data);
QFETCH(int, responseId);
@ -466,7 +466,7 @@ void RemoteProxyOfflineTests::apiBasicCalls()
QVariantMap response;
// Websocket
response = injectWebSocketData(data).toMap();
response = injectWebSocketProxyData(data).toMap();
//qDebug() << qUtf8Printable(QJsonDocument::fromVariant(response).toJson(QJsonDocument::Indented));
QVERIFY(!response.isEmpty());
QCOMPARE(response.value("id").toInt(), responseId);
@ -474,7 +474,7 @@ void RemoteProxyOfflineTests::apiBasicCalls()
// TCP
response.clear();
response = injectTcpSocketData(data).toMap();
response = injectTcpSocketProxyData(data).toMap();
//qDebug() << qUtf8Printable(QJsonDocument::fromVariant(response).toJson(QJsonDocument::Indented));
QVERIFY(!response.isEmpty());
QCOMPARE(response.value("id").toInt(), responseId);
@ -484,7 +484,7 @@ void RemoteProxyOfflineTests::apiBasicCalls()
stopServer();
}
void RemoteProxyOfflineTests::authenticate_data()
void RemoteProxyTestsProxy::authenticate_data()
{
QTest::addColumn<QString>("uuid");
QTest::addColumn<QString>("name");
@ -518,7 +518,7 @@ void RemoteProxyOfflineTests::authenticate_data()
}
void RemoteProxyOfflineTests::authenticate()
void RemoteProxyTestsProxy::authenticate()
{
QFETCH(QString, uuid);
QFETCH(QString, name);
@ -543,19 +543,19 @@ void RemoteProxyOfflineTests::authenticate()
// WebSocket
QVariantMap response;
response = invokeWebSocketApiCall("Authentication.Authenticate", params).toMap();
response = invokeWebSocketProxyApiCall("Authentication.Authenticate", params).toMap();
//qDebug() << qUtf8Printable(QJsonDocument::fromVariant(response).toJson(QJsonDocument::Indented));
verifyAuthenticationError(response, expectedError);
// TCP
response = invokeTcpSocketApiCall("Authentication.Authenticate", params).toMap();
response = invokeTcpSocketProxyApiCall("Authentication.Authenticate", params).toMap();
verifyAuthenticationError(response, expectedError);
// Clean up
stopServer();
}
void RemoteProxyOfflineTests::authenticateNonce()
void RemoteProxyTestsProxy::authenticateNonce()
{
// Start the server
startServer();
@ -651,7 +651,7 @@ void RemoteProxyOfflineTests::authenticateNonce()
stopServer();
}
void RemoteProxyOfflineTests::authenticateSendData()
void RemoteProxyTestsProxy::authenticateSendData()
{
// Start the server
startServer();
@ -675,7 +675,7 @@ void RemoteProxyOfflineTests::authenticateSendData()
QWebSocket *socket = new QWebSocket("proxy-testclient", QWebSocketProtocol::Version13);
connect(socket, &QWebSocket::sslErrors, this, &BaseTest::sslErrors);
QSignalSpy spyConnection(socket, &QWebSocket::connected);
socket->open(Engine::instance()->webSocketServer()->serverUrl());
socket->open(Engine::instance()->webSocketServerProxy()->serverUrl());
spyConnection.wait();
QVERIFY(spyConnection.count() == 1);
@ -697,7 +697,7 @@ void RemoteProxyOfflineTests::authenticateSendData()
stopServer();
}
void RemoteProxyOfflineTests::clientConnectionWebSocket()
void RemoteProxyTestsProxy::clientConnectionWebSocket()
{
// Start the server
startServer();
@ -747,7 +747,7 @@ void RemoteProxyOfflineTests::clientConnectionWebSocket()
stopServer();
}
void RemoteProxyOfflineTests::clientConnectionTcpSocket()
void RemoteProxyTestsProxy::clientConnectionTcpSocket()
{
// Start the server
startServer();
@ -797,7 +797,7 @@ void RemoteProxyOfflineTests::clientConnectionTcpSocket()
stopServer();
}
void RemoteProxyOfflineTests::remoteConnection()
void RemoteProxyTestsProxy::remoteConnection()
{
// Start the server
startServer();
@ -890,7 +890,7 @@ void RemoteProxyOfflineTests::remoteConnection()
stopServer();
}
void RemoteProxyOfflineTests::multipleRemoteConnection()
void RemoteProxyTestsProxy::multipleRemoteConnection()
{
// Start the server
startServer();
@ -920,7 +920,7 @@ void RemoteProxyOfflineTests::multipleRemoteConnection()
stopServer();
}
void RemoteProxyOfflineTests::trippleConnection()
void RemoteProxyTestsProxy::trippleConnection()
{
// Start the server
startServer();
@ -1005,7 +1005,7 @@ void RemoteProxyOfflineTests::trippleConnection()
stopServer();
}
void RemoteProxyOfflineTests::duplicateUuid()
void RemoteProxyTestsProxy::duplicateUuid()
{
// Start the server
startServer();
@ -1067,7 +1067,7 @@ void RemoteProxyOfflineTests::duplicateUuid()
stopServer();
}
void RemoteProxyOfflineTests::sslConfigurations()
void RemoteProxyTestsProxy::sslConfigurations()
{
// Start the server
startServer();
@ -1098,7 +1098,7 @@ void RemoteProxyOfflineTests::sslConfigurations()
stopServer();
}
void RemoteProxyOfflineTests::jsonRpcTimeout()
void RemoteProxyTestsProxy::jsonRpcTimeout()
{
// Start the server
startServer();
@ -1120,7 +1120,7 @@ void RemoteProxyOfflineTests::jsonRpcTimeout()
params.insert("name", "name");
params.insert("token", "token");
QVariant response = invokeWebSocketApiCall("Authentication.Authenticate", params);
QVariant response = invokeWebSocketProxyApiCall("Authentication.Authenticate", params);
qDebug() << qUtf8Printable(QJsonDocument::fromVariant(response).toJson(QJsonDocument::Indented));
QVERIFY(response.toMap().value("status").toString() == "error");
@ -1129,7 +1129,7 @@ void RemoteProxyOfflineTests::jsonRpcTimeout()
stopServer();
}
void RemoteProxyOfflineTests::inactiveTimeout()
void RemoteProxyTestsProxy::inactiveTimeout()
{
// Start the server
startServer();
@ -1152,7 +1152,7 @@ void RemoteProxyOfflineTests::inactiveTimeout()
stopServer();
}
void RemoteProxyOfflineTests::authenticationReplyTimeout()
void RemoteProxyTestsProxy::authenticationReplyTimeout()
{
// Start the server
startServer();
@ -1171,7 +1171,7 @@ void RemoteProxyOfflineTests::authenticationReplyTimeout()
params.insert("name", "Sleepy test client");
params.insert("token", "sleepy token zzzZZZ");
QVariant response = invokeWebSocketApiCall("Authentication.Authenticate", params);
QVariant response = invokeWebSocketProxyApiCall("Authentication.Authenticate", params);
qDebug() << qUtf8Printable(QJsonDocument::fromVariant(response).toJson(QJsonDocument::Indented));
verifyAuthenticationError(response, Authenticator::AuthenticationErrorTimeout);
@ -1179,7 +1179,7 @@ void RemoteProxyOfflineTests::authenticationReplyTimeout()
stopServer();
}
void RemoteProxyOfflineTests::authenticationReplyConnection()
void RemoteProxyTestsProxy::authenticationReplyConnection()
{
// Start the server
startServer();
@ -1212,7 +1212,7 @@ void RemoteProxyOfflineTests::authenticationReplyConnection()
stopServer();
}
void RemoteProxyOfflineTests::tcpRemoteConnection()
void RemoteProxyTestsProxy::tcpRemoteConnection()
{
// Start the server
startServer();
@ -1306,7 +1306,7 @@ void RemoteProxyOfflineTests::tcpRemoteConnection()
stopServer();
}
void RemoteProxyOfflineTests::tcpWebsocketRemoteConnection()
void RemoteProxyTestsProxy::tcpWebsocketRemoteConnection()
{
// Start the server
startServer();
@ -1400,4 +1400,4 @@ void RemoteProxyOfflineTests::tcpWebsocketRemoteConnection()
stopServer();
}
QTEST_MAIN(RemoteProxyOfflineTests)
QTEST_MAIN(RemoteProxyTestsProxy)

View File

@ -25,20 +25,20 @@
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#ifndef NYMEA_REMOTEPROXY_TESTS_OFFLINE_H
#define NYMEA_REMOTEPROXY_TESTS_OFFLINE_H
#ifndef REMOTEPROXYTESTSPROXY_H
#define REMOTEPROXYTESTSPROXY_H
#include "basetest.h"
using namespace remoteproxy;
using namespace remoteproxyclient;
class RemoteProxyOfflineTests : public BaseTest
class RemoteProxyTestsProxy : public BaseTest
{
Q_OBJECT
public:
explicit RemoteProxyOfflineTests(QObject *parent = nullptr);
~RemoteProxyOfflineTests() = default;
explicit RemoteProxyTestsProxy(QObject *parent = nullptr);
~RemoteProxyTestsProxy() = default;
private slots:
// Basic stuff
@ -61,6 +61,9 @@ private slots:
void apiBasicCalls_data();
void apiBasicCalls();
void apiBasicCallsTcp_data();
void apiBasicCallsTcp();
void authenticate_data();
void authenticate();
@ -87,4 +90,4 @@ private slots:
};
#endif // NYMEA_REMOTEPROXY_TESTS_OFFLINE_H
#endif // REMOTEPROXYTESTSPROXY_H

View File

@ -4,11 +4,11 @@ include(../testbase/testbase.pri)
CONFIG += testcase
QT += testlib
TARGET = nymea-remoteproxy-tests-offline
TARGET = nymea-remoteproxy-proxy-tests
HEADERS += nymea-remoteproxy-tests-offline.h
HEADERS += remoteproxytestsproxy.h
SOURCES += nymea-remoteproxy-tests-offline.cpp
SOURCES += remoteproxytestsproxy.cpp
target.path = $$[QT_INSTALL_PREFIX]/bin
INSTALLS += target

View File

@ -0,0 +1,202 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*
* 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 "remoteproxyteststunnelproxy.h"
#include "engine.h"
#include "loggingcategories.h"
#include "remoteproxyconnection.h"
#include <QMetaType>
#include <QSignalSpy>
#include <QWebSocket>
#include <QJsonDocument>
#include <QWebSocketServer>
RemoteProxyTestsTunnelProxy::RemoteProxyTestsTunnelProxy(QObject *parent) :
BaseTest(parent)
{
}
void RemoteProxyTestsTunnelProxy::startStopServer()
{
startServer();
stopServer();
}
void RemoteProxyTestsTunnelProxy::apiBasicCallsTcp_data()
{
QTest::addColumn<QByteArray>("data");
QTest::addColumn<int>("responseId");
QTest::addColumn<QString>("responseStatus");
QTest::newRow("valid call") << QByteArray("{\"id\":42, \"method\":\"RemoteProxy.Hello\"}") << 42 << "success";
QTest::newRow("missing id") << QByteArray("{\"method\":\"RemoteProxy.Hello\"}") << -1 << "error";
QTest::newRow("missing method") << QByteArray("{\"id\":42}") << 42 << "error";
//QTest::newRow("invalid json") << QByteArray("{\"id\":42, \"method\":\"RemoteProx") << -1 << "error";
QTest::newRow("invalid function") << QByteArray("{\"id\":42, \"method\":\"RemoteProxy.Explode\"}") << 42 << "error";
QTest::newRow("invalid namespace") << QByteArray("{\"id\":42, \"method\":\"ProxyRemote.Hello\"}") << 42 << "error";
QTest::newRow("missing dot") << QByteArray("{\"id\":42, \"method\":\"RemoteProxyHello\"}") << 42 << "error";
QTest::newRow("invalid params") << QByteArray("{\"id\":42, \"method\":\"RemoteProxy.Hello\", \"params\":{\"törööö\":\"chooo-chooo\"}}") << 42 << "error";
QTest::newRow("invalid authentication params") << QByteArray("{\"id\":42, \"method\":\"Authentication.Authenticate\", \"params\":{\"your\":\"mamma\"}}") << 42 << "error";
}
void RemoteProxyTestsTunnelProxy::apiBasicCallsTcp()
{
QFETCH(QByteArray, data);
QFETCH(int, responseId);
QFETCH(QString, responseStatus);
// Start the server
startServer();
QVariant response = injectTcpSocketProxyData(data);
QVERIFY(!response.isNull());
qDebug() << qUtf8Printable(QJsonDocument::fromVariant(response).toJson(QJsonDocument::Indented));
QCOMPARE(response.toMap().value("id").toInt(), responseId);
QCOMPARE(response.toMap().value("status").toString(), responseStatus);
// Clean up
stopServer();
}
void RemoteProxyTestsTunnelProxy::getIntrospect()
{
// Start the server
startServer();
QVariantMap response;
// WebSocket
response = invokeWebSocketTunnelProxyApiCall("RemoteProxy.Introspect").toMap();
//qDebug() << qUtf8Printable(QJsonDocument::fromVariant(response).toJson(QJsonDocument::Indented));
QVERIFY(!response.isEmpty());
QVERIFY(response.value("status").toString() == "success");
QVERIFY(response.value("params").toMap().contains("methods"));
QVERIFY(response.value("params").toMap().contains("notifications"));
QVERIFY(response.value("params").toMap().contains("types"));
// Tcp
response.clear();
response = invokeTcpSocketTunnelProxyApiCall("RemoteProxy.Introspect").toMap();
//qDebug() << qUtf8Printable(QJsonDocument::fromVariant(response).toJson(QJsonDocument::Indented));
QVERIFY(!response.isEmpty());
QVERIFY(response.value("status").toString() == "success");
QVERIFY(response.value("params").toMap().contains("methods"));
QVERIFY(response.value("params").toMap().contains("notifications"));
QVERIFY(response.value("params").toMap().contains("types"));
// Clean up
stopServer();
}
void RemoteProxyTestsTunnelProxy::getHello()
{
// Start the server
startServer();
QVariantMap response;
// WebSocket
response = invokeWebSocketTunnelProxyApiCall("RemoteProxy.Hello").toMap();
qDebug() << qUtf8Printable(QJsonDocument::fromVariant(response).toJson(QJsonDocument::Indented));
// Verify data
QVERIFY(!response.isEmpty());
QCOMPARE(response.value("params").toMap().value("name").toString(), Engine::instance()->configuration()->serverName());
QCOMPARE(response.value("params").toMap().value("server").toString(), QString(SERVER_NAME_STRING));
QCOMPARE(response.value("params").toMap().value("version").toString(), QString(SERVER_VERSION_STRING));
QCOMPARE(response.value("params").toMap().value("apiVersion").toString(), QString(API_VERSION_STRING));
// TCP
response.clear();
response = invokeTcpSocketTunnelProxyApiCall("RemoteProxy.Hello").toMap();
//qDebug() << qUtf8Printable(QJsonDocument::fromVariant(response).toJson(QJsonDocument::Indented));
// Verify data
QVERIFY(!response.isEmpty());
QCOMPARE(response.value("params").toMap().value("name").toString(), Engine::instance()->configuration()->serverName());
QCOMPARE(response.value("params").toMap().value("server").toString(), QString(SERVER_NAME_STRING));
QCOMPARE(response.value("params").toMap().value("version").toString(), QString(SERVER_VERSION_STRING));
QCOMPARE(response.value("params").toMap().value("apiVersion").toString(), QString(API_VERSION_STRING));
// Clean up
stopServer();
}
void RemoteProxyTestsTunnelProxy::apiBasicCalls_data()
{
QTest::addColumn<QByteArray>("data");
QTest::addColumn<int>("responseId");
QTest::addColumn<QString>("responseStatus");
QTest::newRow("valid call") << QByteArray("{\"id\":42, \"method\":\"RemoteProxy.Hello\"}") << 42 << "success";
QTest::newRow("missing id") << QByteArray("{\"method\":\"RemoteProxy.Hello\"}") << -1 << "error";
QTest::newRow("missing method") << QByteArray("{\"id\":42}") << 42 << "error";
QTest::newRow("invalid json") << QByteArray("{\"id\":42, \"method\":\"RemoteProx}") << -1 << "error";
QTest::newRow("invalid function") << QByteArray("{\"id\":42, \"method\":\"RemoteProxy.Explode\"}") << 42 << "error";
QTest::newRow("invalid namespace") << QByteArray("{\"id\":42, \"method\":\"ProxyRemote.Hello\"}") << 42 << "error";
QTest::newRow("missing dot") << QByteArray("{\"id\":42, \"method\":\"RemoteProxyHello\"}") << 42 << "error";
QTest::newRow("invalid params") << QByteArray("{\"id\":42, \"method\":\"RemoteProxy.Hello\", \"params\":{\"törööö\":\"chooo-chooo\"}}") << 42 << "error";
QTest::newRow("invalid authentication params") << QByteArray("{\"id\":42, \"method\":\"Authentication.Authenticate\", \"params\":{\"your\":\"mamma\"}}") << 42 << "error";
}
void RemoteProxyTestsTunnelProxy::apiBasicCalls()
{
QFETCH(QByteArray, data);
QFETCH(int, responseId);
QFETCH(QString, responseStatus);
// Start the server
startServer();
QVariantMap response;
// Websocket
response = injectWebSocketTunnelProxyData(data).toMap();
//qDebug() << qUtf8Printable(QJsonDocument::fromVariant(response).toJson(QJsonDocument::Indented));
QVERIFY(!response.isEmpty());
QCOMPARE(response.value("id").toInt(), responseId);
QCOMPARE(response.value("status").toString(), responseStatus);
// TCP
response.clear();
response = injectTcpSocketTunnelProxyData(data).toMap();
//qDebug() << qUtf8Printable(QJsonDocument::fromVariant(response).toJson(QJsonDocument::Indented));
QVERIFY(!response.isEmpty());
QCOMPARE(response.value("id").toInt(), responseId);
QCOMPARE(response.value("status").toString(), responseStatus);
// Clean up
stopServer();
}
QTEST_MAIN(RemoteProxyTestsTunnelProxy)

View File

@ -0,0 +1,59 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*
* 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 REMOTEPROXYTESTSTUNNELPROXY_H
#define REMOTEPROXYTESTSTUNNELPROXY_H
#include "basetest.h"
using namespace remoteproxy;
using namespace remoteproxyclient;
class RemoteProxyTestsTunnelProxy : public BaseTest
{
Q_OBJECT
public:
explicit RemoteProxyTestsTunnelProxy(QObject *parent = nullptr);
~RemoteProxyTestsTunnelProxy() = default;
private slots:
// Basic stuff
void startStopServer();
// WebSocket connection API
void getIntrospect();
void getHello();
void apiBasicCalls_data();
void apiBasicCalls();
void apiBasicCallsTcp_data();
void apiBasicCallsTcp();
};
#endif // REMOTEPROXYTESTSTUNNELPROXY_H

View File

@ -0,0 +1,14 @@
include(../../nymea-remoteproxy.pri)
include(../testbase/testbase.pri)
CONFIG += testcase
QT += testlib
TARGET = nymea-remoteproxy-tunnelproxy-tests
HEADERS += remoteproxyteststunnelproxy.h
SOURCES += remoteproxyteststunnelproxy.cpp
target.path = $$[QT_INSTALL_PREFIX]/bin
INSTALLS += target

View File

@ -115,8 +115,10 @@ void BaseTest::startServer()
QVERIFY(Engine::instance()->running());
QVERIFY(Engine::instance()->developerMode());
QVERIFY(Engine::instance()->webSocketServer()->running());
QVERIFY(Engine::instance()->tcpSocketServer()->running());
QVERIFY(Engine::instance()->webSocketServerProxy()->running());
QVERIFY(Engine::instance()->tcpSocketServerProxy()->running());
QVERIFY(Engine::instance()->webSocketServerTunnelProxy()->running());
QVERIFY(Engine::instance()->tcpSocketServerTunnelProxy()->running());
QVERIFY(Engine::instance()->monitorServer()->running());
}
@ -131,7 +133,7 @@ void BaseTest::stopServer()
cleanUpEngine();
}
QVariant BaseTest::invokeWebSocketApiCall(const QString &method, const QVariantMap params, bool remainsConnected)
QVariant BaseTest::invokeWebSocketProxyApiCall(const QString &method, const QVariantMap params, bool remainsConnected)
{
Q_UNUSED(remainsConnected)
@ -144,7 +146,7 @@ QVariant BaseTest::invokeWebSocketApiCall(const QString &method, const QVariantM
QWebSocket *socket = new QWebSocket("proxy-testclient", QWebSocketProtocol::Version13);
connect(socket, &QWebSocket::sslErrors, this, &BaseTest::sslErrors);
QSignalSpy spyConnection(socket, SIGNAL(connected()));
socket->open(Engine::instance()->webSocketServer()->serverUrl());
socket->open(Engine::instance()->webSocketServerProxy()->serverUrl());
spyConnection.wait();
if (spyConnection.count() == 0) {
return QVariant();
@ -187,13 +189,13 @@ QVariant BaseTest::invokeWebSocketApiCall(const QString &method, const QVariantM
return QVariant();
}
QVariant BaseTest::injectWebSocketData(const QByteArray &data)
QVariant BaseTest::injectWebSocketProxyData(const QByteArray &data)
{
QWebSocket *socket = new QWebSocket("proxy-testclient", QWebSocketProtocol::Version13);
connect(socket, &QWebSocket::sslErrors, this, &BaseTest::sslErrors);
QSignalSpy spyConnection(socket, SIGNAL(connected()));
socket->open(Engine::instance()->webSocketServer()->serverUrl());
socket->open(Engine::instance()->webSocketServerProxy()->serverUrl());
spyConnection.wait();
if (spyConnection.count() == 0) {
return QVariant();
@ -226,7 +228,7 @@ QVariant BaseTest::injectWebSocketData(const QByteArray &data)
return QVariant();
}
QVariant BaseTest::invokeTcpSocketApiCall(const QString &method, const QVariantMap params, bool remainsConnected)
QVariant BaseTest::invokeTcpSocketProxyApiCall(const QString &method, const QVariantMap params, bool remainsConnected)
{
Q_UNUSED(remainsConnected)
@ -241,8 +243,8 @@ QVariant BaseTest::invokeTcpSocketApiCall(const QString &method, const QVariantM
QObject::connect(socket, static_cast<sslErrorsSignal>(&QSslSocket::sslErrors), this, &BaseTest::sslSocketSslErrors);
QSignalSpy spyConnection(socket, &QSslSocket::connected);
socket->connectToHostEncrypted(Engine::instance()->tcpSocketServer()->serverUrl().host(),
static_cast<quint16>(Engine::instance()->tcpSocketServer()->serverUrl().port()));
socket->connectToHostEncrypted(Engine::instance()->tcpSocketServerProxy()->serverUrl().host(),
static_cast<quint16>(Engine::instance()->tcpSocketServerProxy()->serverUrl().port()));
spyConnection.wait();
if (spyConnection.count() == 0) {
return QVariant();
@ -298,8 +300,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);
@ -400,15 +402,216 @@ bool BaseTest::createRemoteConnection(const QString &token, const QString &nonce
}
QVariant BaseTest::injectTcpSocketData(const QByteArray &data)
QVariant BaseTest::injectTcpSocketProxyData(const QByteArray &data)
{
QSslSocket *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()->tcpSocketServer()->serverUrl().host(),
static_cast<quint16>(Engine::instance()->tcpSocketServer()->serverUrl().port()));
socket->connectToHostEncrypted(Engine::instance()->tcpSocketServerProxy()->serverUrl().host(),
static_cast<quint16>(Engine::instance()->tcpSocketServerProxy()->serverUrl().port()));
spyConnection.wait();
if (spyConnection.count() == 0) {
return QVariant();
}
QSignalSpy dataSpy(socket, &QSslSocket::readyRead);
socket->write(data + '\n');
dataSpy.wait();
// FIXME: check why it waits the full time here
dataSpy.wait(500);
if (dataSpy.count() != 1) {
qWarning() << "No data received";
return QVariant();
}
QByteArray socketData = socket->readAll();
socket->close();
socket->deleteLater();
// Make sure the response ends with '}\n'
if (!socketData.endsWith("}\n")) {
qWarning() << "JSON data does not end with \"}\n\"";
return QVariant();
}
// Make sure the response it a valid JSON string
QJsonParseError error;
QJsonDocument jsonDoc = QJsonDocument::fromJson(socketData, &error);
if (error.error != QJsonParseError::NoError) {
qWarning() << "JSON parser error" << error.errorString();
return QVariant();
}
m_commandCounter++;
return jsonDoc.toVariant();
}
QVariant BaseTest::invokeWebSocketTunnelProxyApiCall(const QString &method, const QVariantMap params, bool remainsConnected)
{
Q_UNUSED(remainsConnected)
QVariantMap request;
request.insert("id", m_commandCounter);
request.insert("method", method);
request.insert("params", params);
QJsonDocument jsonDoc = QJsonDocument::fromVariant(request);
QWebSocket *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) {
return QVariant();
}
QSignalSpy dataSpy(socket, SIGNAL(textMessageReceived(QString)));
socket->sendTextMessage(QString(jsonDoc.toJson(QJsonDocument::Compact)));
dataSpy.wait();
socket->close();
socket->deleteLater();
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 QVariant();
}
// 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 QVariant();
}
QVariantMap response = jsonDoc.toVariant().toMap();
// skip notifications
if (response.contains("notification"))
continue;
if (response.value("id").toInt() == m_commandCounter) {
m_commandCounter++;
return jsonDoc.toVariant();
}
}
m_commandCounter++;
return QVariant();
}
QVariant BaseTest::injectWebSocketTunnelProxyData(const QByteArray &data)
{
QWebSocket *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) {
return QVariant();
}
QSignalSpy spy(socket, SIGNAL(textMessageReceived(QString)));
socket->sendTextMessage(QString(data));
spy.wait();
socket->close();
socket->deleteLater();
for (int i = 0; i < spy.count(); i++) {
// Make sure the response ends with '}\n'
if (!spy.at(i).last().toByteArray().endsWith("}\n")) {
qWarning() << "JSON data does not end with \"}\n\"";
return QVariant();
}
// Make sure the response it a valid JSON string
QJsonParseError error;
QJsonDocument jsonDoc = QJsonDocument::fromJson(spy.at(i).last().toByteArray(), &error);
if (error.error != QJsonParseError::NoError) {
qWarning() << "JSON parser error" << error.errorString();
return QVariant();
}
return jsonDoc.toVariant();
}
m_commandCounter++;
return QVariant();
}
QVariant BaseTest::invokeTcpSocketTunnelProxyApiCall(const QString &method, const QVariantMap params, bool remainsConnected)
{
Q_UNUSED(remainsConnected)
QVariantMap request;
request.insert("id", m_commandCounter);
request.insert("method", method);
request.insert("params", params);
QJsonDocument jsonDoc = QJsonDocument::fromVariant(request);
QSslSocket *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 QVariant();
}
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 QVariant();
}
QByteArray data = socket->readAll();
socket->close();
socket->deleteLater();
// Make sure the response ends with '}\n'
if (!data.endsWith("}\n")) {
qWarning() << "JSON data does not end with \"}\n\"";
return QVariant();
}
// 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 QVariant();
}
QVariantMap response = jsonDoc.toVariant().toMap();
if (response.value("id").toInt() == m_commandCounter) {
m_commandCounter++;
return jsonDoc.toVariant();
}
m_commandCounter++;
return QVariant();
}
QVariant BaseTest::injectTcpSocketTunnelProxyData(const QByteArray &data)
{
QSslSocket *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 QVariant();
@ -465,7 +668,6 @@ void BaseTest::initTestCase()
"T_xh6pMkOhE6g";
qCDebug(dcApplication()) << "Init test case done.";
//restartEngine();
}
void BaseTest::cleanupTestCase()

View File

@ -59,6 +59,9 @@ protected:
QUrl m_serverUrl = QUrl("wss://127.0.0.1:1212");
QUrl m_serverUrlTcp = QUrl("ssl://127.0.0.1:1213");
QUrl m_serverUrlTunnel = QUrl("wss://127.0.0.1:2212");
QUrl m_serverUrlTunnelTcp = QUrl("ssl://127.0.0.1:2213");
QSslConfiguration m_sslConfiguration;
Authenticator *m_authenticator = nullptr;
@ -79,11 +82,18 @@ protected:
void startServer();
void stopServer();
QVariant invokeWebSocketApiCall(const QString &method, const QVariantMap params = QVariantMap(), bool remainsConnected = true);
QVariant injectWebSocketData(const QByteArray &data);
QVariant invokeWebSocketProxyApiCall(const QString &method, const QVariantMap params = QVariantMap(), bool remainsConnected = true);
QVariant injectWebSocketProxyData(const QByteArray &data);
QVariant invokeTcpSocketProxyApiCall(const QString &method, const QVariantMap params = QVariantMap(), bool remainsConnected = true);
QVariant injectTcpSocketProxyData(const QByteArray &data);
QVariant invokeWebSocketTunnelProxyApiCall(const QString &method, const QVariantMap params = QVariantMap(), bool remainsConnected = true);
QVariant injectWebSocketTunnelProxyData(const QByteArray &data);
QVariant invokeTcpSocketTunnelProxyApiCall(const QString &method, const QVariantMap params = QVariantMap(), bool remainsConnected = true);
QVariant injectTcpSocketTunnelProxyData(const QByteArray &data);
QVariant invokeTcpSocketApiCall(const QString &method, const QVariantMap params = QVariantMap(), bool remainsConnected = true);
QVariant injectTcpSocketData(const QByteArray &data);
bool createRemoteConnection(const QString &token, const QString &nonce, QObject *parent);

View File

@ -1,10 +1,10 @@
include(../nymea-remoteproxy.pri)
TEMPLATE=subdirs
SUBDIRS += test-offline
SUBDIRS += test-proxy test-tunnelproxy
online {
message("Online tests enabled")
SUBDIRS += test-online
}
#online {
# message("Online tests enabled")
# SUBDIRS += test-online
#}