From f0cdb2706b887d419d1fbcc448f2aa0d64bad9e1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20St=C3=BCrz?= Date: Fri, 30 Jul 2021 13:12:42 +0200 Subject: [PATCH] Prepare client library for tunnel proxy --- docs/remote-connection-basic-flow.png | Bin 92607 -> 106255 bytes docs/remote-connection-basic-flow.svg | 2 +- docs/remote-connection-basic-flow.txt | 32 +-- libnymea-remoteproxy/engine.cpp | 22 ++ libnymea-remoteproxy/engine.h | 1 - .../jsonrpc/tunnelproxyhandler.cpp | 4 + libnymea-remoteproxy/server/jsonrpcserver.cpp | 3 + .../server/tcpsocketserver.cpp | 2 +- .../server/websocketserver.cpp | 1 + .../tunnelproxy/tunnelproxyclient.cpp | 50 ++-- .../tunnelproxy/tunnelproxyclient.h | 4 + .../tunnelproxyclientconnection.cpp | 17 +- .../tunnelproxy/tunnelproxyclientconnection.h | 11 +- .../tunnelproxy/tunnelproxyserver.cpp | 45 +++- .../tunnelproxyserverconnection.cpp | 20 ++ .../tunnelproxy/tunnelproxyserverconnection.h | 11 +- .../libnymea-remoteproxyclient.pri | 32 +-- .../tunnelproxy/tunnelproxyjsonrpcclient.cpp | 37 +++ .../tunnelproxy/tunnelproxyjsonrpcclient.h | 48 ++++ .../tunnelproxy/tunnelproxyserver.cpp | 84 +++++++ .../tunnelproxy/tunnelproxyserver.h | 90 ++++++++ .../tunnelproxy/tunnelproxysocket.cpp | 37 +++ .../tunnelproxy/tunnelproxysocket.h | 47 ++++ nymea-remoteproxy.pri | 2 +- tests/test-proxy/remoteproxytestsproxy.cpp | 16 +- .../remoteproxyteststunnelproxy.cpp | 213 +++++++++++++++++- .../remoteproxyteststunnelproxy.h | 7 +- tests/testbase/basetest.cpp | 25 +- tests/testbase/basetest.h | 8 +- 29 files changed, 777 insertions(+), 94 deletions(-) create mode 100644 libnymea-remoteproxyclient/tunnelproxy/tunnelproxyjsonrpcclient.cpp create mode 100644 libnymea-remoteproxyclient/tunnelproxy/tunnelproxyjsonrpcclient.h create mode 100644 libnymea-remoteproxyclient/tunnelproxy/tunnelproxyserver.cpp create mode 100644 libnymea-remoteproxyclient/tunnelproxy/tunnelproxyserver.h create mode 100644 libnymea-remoteproxyclient/tunnelproxy/tunnelproxysocket.cpp create mode 100644 libnymea-remoteproxyclient/tunnelproxy/tunnelproxysocket.h diff --git a/docs/remote-connection-basic-flow.png b/docs/remote-connection-basic-flow.png index 11b041a8aab98dc4185060cf891930eaf520b828..50480023bcadfc3617bd0ddf3d114c13f57b5ef5 100644 GIT binary patch literal 106255 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ⅇ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

PmX?Z51S6 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 diff --git a/docs/remote-connection-basic-flow.svg b/docs/remote-connection-basic-flow.svg index f8a29ea..1d5a26c 100644 --- a/docs/remote-connection-basic-flow.svg +++ b/docs/remote-connection-basic-flow.svg @@ -1 +1 @@ -title%20Remote%20tunnel%20proxy%0A%0Anymea-%3Eproxy%3A%20RegisterProxyTunnelServer(uuid%2C%20name)%0A%0Anote%20over%20proxy%3A%20Register%20the%20server%20using%20the%20uuid%0A%0Anymea%3C-proxy%3A%20Success%0A%0Anote%20over%20nymea%2C%20proxy%3A%20Protocol%20from%20now%20on%20SLIP%5CnThe%20proxy%20is%20client%200x0000%0A%0Anote%20over%20nymea%2C%20proxy%3A%20SLIP%20encoded%20data%3A%202%20Bytes%20address%20%2B%20data%0A%0Aproxy%3C-client%3A%20ConnectProxyTunnelClient(uuid%2C%20name%2C%20serverUuid)%0A%0Anote%20over%20proxy%3A%20Search%20server%20using%20uuid%0A%0Anote%20over%20proxy%3A%20Server%3A%20Assign%20address%200x0001%20for%20this%20client%20socket%0A%0Aproxy-%3Enymea%3A%20SLIP%3A0x0000%3A%20ProxyTunnelClientConnected%20(address%3A%200x0001)%0A%0Aproxy%3C-nymea%3A%20SLIP%3A0x0000%3A%20AckProxyTunnelClient%20(address%3A%200x0001)%0A%0Aproxy-%3Eclient%3A%20ProxyTunnelEstablished(uuid%2C%20name%2C%20serverUuid)%0A%0Anote%20over%20proxy%2C%20client%3A%20Protocol%20from%20now%20on%20SLIP%20encoded%5CnThe%20proxy%20is%20client%200x0000%5CnThe%20connected%20server%20is%200xFFFF%0A%0Anote%20over%20proxy%2C%20client%3A%20SLIP%20encoded%20data%3A%202%20Bytes%20address%20%2B%20data%0A%0Anote%20over%20nymea%2C%20client%3A%20Connected%3A%20The%20client%20can%20now%20communicate%20with%20nymea%20directly.%0A%0Anote%20over%20nymea%2C%20client%3A%20nymea%20sends%20SLIP%20encoded%20data%20with%20address%200x0001%20-%3E%20client%0A%0Anote%20over%20nymea%2C%20client%3A%20client%20sends%20SLIP%20endcoded%20data%20with%20address%200xFFFF%20-%3E%20nymeaRemote tunnel proxynymeaproxyclientRegisterProxyTunnelServer(uuid, name)Register the server using the uuidSuccessProtocol from now on SLIPThe proxy is client 0x0000SLIP encoded data: 2 Bytes address + dataConnectProxyTunnelClient(uuid, name, serverUuid)Search server using uuidServer: Assign address 0x0001 for this client socketSLIP:0x0000: ProxyTunnelClientConnected (address: 0x0001)SLIP:0x0000: AckProxyTunnelClient (address: 0x0001)ProxyTunnelEstablished(uuid, name, serverUuid)Protocol from now on SLIP encodedThe proxy is client 0x0000The connected server is 0xFFFFSLIP encoded data: 2 Bytes address + dataConnected: The client can now communicate with nymea directly.nymea sends SLIP encoded data with address 0x0001 -> clientclient sends SLIP endcoded data with address 0xFFFF -> nymea \ No newline at end of file +title%20Remote%20tunnel%20proxy%0A%0Anymea-%3Eproxy%3A%20TunnelProxy.RegisterServer(serverUuid%2C%20serverName)%0A%0Anote%20over%20proxy%3A%20Register%20the%20server%20using%20the%20uuid%0A%0Anymea%3C-proxy%3A%20TunnelProxyErrorNoError%0A%0Anote%20over%20nymea%2C%20proxy%3A%20Protocol%20from%20now%20on%20SLIP%5CnThe%20proxy%20is%20client%200x0000%0A%0Anote%20over%20nymea%2C%20proxy%3A%20SLIP%20encoded%20data%3A%202%20Bytes%20address%20%2B%20data%0A%0Aproxy%3C-client%3A%20TunnelProxy.RegisterClient(clientUuid%2C%20clientName%2C%20serverUuid)%0A%0Anote%20over%20proxy%3A%20Search%20server%20with%20given%20uuid%0A%0Anote%20over%20proxy%3A%20Server%3A%20Assign%20address%20for%20this%20client%20socket%20(0x0001)%0A%0Aproxy-%3Enymea%3A%20SLIP%3A0x0000%3A%20ProxyTunnel.ClientConnected%20(address%3A%200x0001)%0A%0Aproxy%3C-nymea%3A%20SLIP%3A0x0000%3A%20ProxyTunnel.AcceptClient%20(address%3A%200x0001)%0A%0Aproxy-%3Enymea%3A%20TunnelProxyErrorNoError%0A%0Aproxy-%3Eclient%3A%20ProxyTunnel.ConfirmClient(uuid%2C%20name%2C%20serverUuid)%0A%0Anote%20over%20client%3A%20Connected%5CnAny%20incomming%20and%20outgoing%20data%20will%5Cnbe%20from%20the%20connected%20nymea%20instance%5Cnuntil%20disconnected.%0A%0Anote%20over%20nymea%2C%20client%3A%20Connected%3A%20The%20client%20can%20now%20communicate%20with%20nymea%20directly.%5CnThe%20proxy%20will%20not%20interpret%20any%20data%20from%20the%20client%2C%20and%20from%20the%20server%20only%5Cnthe%20transmission%20frame%20(SLIP%20%2B%202%20bytes%20of%20address)%0A%0A%0A%0Aproxy%3C-client%3A%20%22data%22%0A%0Anymea%3C-proxy%3A%20SLIP%3A0x0001%20%22data%22%0A%0Anymea-%3Eproxy%3A%20SLIP%3A0x0001%20%22data%22%0A%0Aproxy-%3Eclient%3A%20%22data%22%0ARemote tunnel proxynymeaproxyclientTunnelProxy.RegisterServer(serverUuid, serverName)Register the server using the uuidTunnelProxyErrorNoErrorProtocol from now on SLIPThe proxy is client 0x0000SLIP encoded data: 2 Bytes address + dataTunnelProxy.RegisterClient(clientUuid, clientName, serverUuid)Search server with given uuidServer: Assign address for this client socket (0x0001)SLIP:0x0000: ProxyTunnel.ClientConnected (address: 0x0001)SLIP:0x0000: ProxyTunnel.AcceptClient (address: 0x0001)TunnelProxyErrorNoErrorProxyTunnel.ConfirmClient(uuid, name, serverUuid)ConnectedAny incomming and outgoing data willbe from the connected nymea instanceuntil disconnected.Connected: The client can now communicate with nymea directly.The proxy will not interpret any data from the client, and from the server onlythe transmission frame (SLIP + 2 bytes of address)"data"SLIP:0x0001 "data"SLIP:0x0001 "data""data" \ No newline at end of file diff --git a/docs/remote-connection-basic-flow.txt b/docs/remote-connection-basic-flow.txt index 24bb29e..29b93a8 100644 --- a/docs/remote-connection-basic-flow.txt +++ b/docs/remote-connection-basic-flow.txt @@ -1,33 +1,39 @@ title Remote tunnel proxy -nymea->proxy: RegisterProxyTunnelServer(uuid, name) +nymea->proxy: TunnelProxy.RegisterServer(serverUuid, serverName) note over proxy: Register the server using the uuid -nymea<-proxy: Success +nymea<-proxy: TunnelProxyErrorNoError note over nymea, proxy: Protocol from now on SLIP\nThe proxy is client 0x0000 note over nymea, proxy: SLIP encoded data: 2 Bytes address + data -proxy<-client: ConnectProxyTunnelClient(uuid, name, serverUuid) +proxy<-client: TunnelProxy.RegisterClient(clientUuid, clientName, serverUuid) -note over proxy: Search server using uuid +note over proxy: Search server with given uuid -note over proxy: Server: Assign address 0x0001 for this client socket +note over proxy: Server: Assign address for this client socket (0x0001) -proxy->nymea: SLIP:0x0000: ProxyTunnelClientConnected (address: 0x0001) +proxy->nymea: SLIP:0x0000: ProxyTunnel.ClientConnected (address: 0x0001) -proxy<-nymea: SLIP:0x0000: AckProxyTunnelClient (address: 0x0001) +proxy<-nymea: SLIP:0x0000: ProxyTunnel.AcceptClient (address: 0x0001) -proxy->client: ProxyTunnelEstablished(uuid, name, serverUuid) +proxy->nymea: TunnelProxyErrorNoError -note over proxy, client: Protocol from now on SLIP encoded\nThe proxy is client 0x0000\nThe connected server is 0xFFFF +proxy->client: ProxyTunnel.ConfirmClient(uuid, name, serverUuid) -note over proxy, client: SLIP encoded data: 2 Bytes address + data +note over client: Connected\nAny incomming and outgoing data will\nbe from the connected nymea instance\nuntil disconnected. -note over nymea, client: Connected: The client can now communicate with nymea directly. +note over nymea, client: Connected: The client can now communicate with nymea directly.\nThe proxy will not interpret any data from the client, and from the server only\nthe transmission frame (SLIP + 2 bytes of address) -note over nymea, client: nymea sends SLIP encoded data with address 0x0001 -> client -note over nymea, client: client sends SLIP endcoded data with address 0xFFFF -> nymea + +proxy<-client: "data" + +nymea<-proxy: SLIP:0x0001 "data" + +nymea->proxy: SLIP:0x0001 "data" + +proxy->client: "data" diff --git a/libnymea-remoteproxy/engine.cpp b/libnymea-remoteproxy/engine.cpp index bf0b1dc..1169d93 100644 --- a/libnymea-remoteproxy/engine.cpp +++ b/libnymea-remoteproxy/engine.cpp @@ -294,12 +294,34 @@ void Engine::clean() m_proxyServer = nullptr; } + if (m_tunnelProxyServer) { + m_tunnelProxyServer->stopServer(); + delete m_tunnelProxyServer; + m_tunnelProxyServer = nullptr; + } + + if (m_tcpSocketServerProxy) { + delete m_tcpSocketServerProxy; + m_tcpSocketServerProxy = nullptr; + } + if (m_webSocketServerProxy) { delete m_webSocketServerProxy; m_webSocketServerProxy = nullptr; } + if (m_tcpSocketServerTunnelProxy) { + delete m_tcpSocketServerTunnelProxy; + m_tcpSocketServerTunnelProxy = nullptr; + } + + if (m_webSocketServerTunnelProxy) { + delete m_webSocketServerTunnelProxy; + m_webSocketServerTunnelProxy = nullptr; + } + if (m_configuration) { + delete m_configuration; m_configuration = nullptr; } } diff --git a/libnymea-remoteproxy/engine.h b/libnymea-remoteproxy/engine.h index 6d55e6d..ecf1eea 100644 --- a/libnymea-remoteproxy/engine.h +++ b/libnymea-remoteproxy/engine.h @@ -83,7 +83,6 @@ public: MonitorServer *monitorServer() const; LogEngine *logEngine() const; - private: explicit Engine(QObject *parent = nullptr); ~Engine(); diff --git a/libnymea-remoteproxy/jsonrpc/tunnelproxyhandler.cpp b/libnymea-remoteproxy/jsonrpc/tunnelproxyhandler.cpp index c753a0f..277397d 100644 --- a/libnymea-remoteproxy/jsonrpc/tunnelproxyhandler.cpp +++ b/libnymea-remoteproxy/jsonrpc/tunnelproxyhandler.cpp @@ -40,6 +40,7 @@ TunnelProxyHandler::TunnelProxyHandler(QObject *parent) : JsonHandler(parent) // Methods QVariantMap params; QVariantMap returns; + // Server params.clear(); returns.clear(); setDescription("RegisterServer", "Register a new TunnelProxy server on this instance. Multiple TunnelProxy clients can be connected to the registered server on success."); params.insert("serverName", JsonTypes::basicTypeToString(JsonTypes::String)); @@ -48,6 +49,7 @@ TunnelProxyHandler::TunnelProxyHandler(QObject *parent) : JsonHandler(parent) returns.insert("tunnelProxyError", JsonTypes::tunnelProxyErrorRef()); setReturns("RegisterServer", returns); + // Client params.clear(); returns.clear(); setDescription("RegisterClient", "Register a new TunnelProxy client on TunnelProxy server with the given serverUuid.."); params.insert("clientName", JsonTypes::basicTypeToString(JsonTypes::String)); @@ -58,6 +60,8 @@ TunnelProxyHandler::TunnelProxyHandler(QObject *parent) : JsonHandler(parent) setReturns("RegisterClient", returns); // Notifications + + // Server params.clear(); returns.clear(); setDescription("ClientConnected", "Emitted whenever a new client has been connected to a registered server. " "Only tunnel proxy clients registered as server will receive this notification."); diff --git a/libnymea-remoteproxy/server/jsonrpcserver.cpp b/libnymea-remoteproxy/server/jsonrpcserver.cpp index acc39e3..c1b6c5e 100644 --- a/libnymea-remoteproxy/server/jsonrpcserver.cpp +++ b/libnymea-remoteproxy/server/jsonrpcserver.cpp @@ -247,6 +247,9 @@ void JsonRpcServer::processDataPackage(TransportClient *transportClient, const Q reply->setClientId(transportClient->clientId()); reply->setCommandId(commandId); sendResponse(transportClient, commandId, reply->data()); + + // TODO: check if the client should be disconnected after this response + reply->deleteLater(); } } diff --git a/libnymea-remoteproxy/server/tcpsocketserver.cpp b/libnymea-remoteproxy/server/tcpsocketserver.cpp index af7ebbf..aef4c95 100644 --- a/libnymea-remoteproxy/server/tcpsocketserver.cpp +++ b/libnymea-remoteproxy/server/tcpsocketserver.cpp @@ -65,6 +65,7 @@ void TcpSocketServer::killClientConnection(const QUuid &clientId, const QString return; qCWarning(dcTcpSocketServer()) << "Killing client connection" << clientId.toString() << "Reason:" << killReason; + client->flush(); client->close(); } @@ -139,7 +140,6 @@ SslServer::SslServer(bool sslEnabled, const QSslConfiguration &config, QObject * QTcpServer(parent), m_sslEnabled(sslEnabled), m_config(config) - { } diff --git a/libnymea-remoteproxy/server/websocketserver.cpp b/libnymea-remoteproxy/server/websocketserver.cpp index d7ffa66..402acf2 100644 --- a/libnymea-remoteproxy/server/websocketserver.cpp +++ b/libnymea-remoteproxy/server/websocketserver.cpp @@ -77,6 +77,7 @@ void WebSocketServer::killClientConnection(const QUuid &clientId, const QString return; qCWarning(dcWebSocketServer()) << "Killing client connection" << clientId.toString() << "Reason:" << killReason; + client->flush(); client->close(QWebSocketProtocol::CloseCodeBadOperation, killReason); } diff --git a/libnymea-remoteproxy/tunnelproxy/tunnelproxyclient.cpp b/libnymea-remoteproxy/tunnelproxy/tunnelproxyclient.cpp index 322413d..ce46ba4 100644 --- a/libnymea-remoteproxy/tunnelproxy/tunnelproxyclient.cpp +++ b/libnymea-remoteproxy/tunnelproxy/tunnelproxyclient.cpp @@ -23,22 +23,36 @@ void TunnelProxyClient::setType(Type type) emit typeChanged(m_type); } +bool TunnelProxyClient::slipEnabled() const +{ + return m_slipEnabled; +} + +void TunnelProxyClient::setSlipEnabled(bool slipEnabled) +{ + m_slipEnabled = slipEnabled; +} + QList TunnelProxyClient::processData(const QByteArray &data) { // TODO: unescape if this data is for the json handler QList packages; - // Handle packet fragmentation - m_dataBuffers.append(data); - int splitIndex = m_dataBuffers.indexOf("}\n{"); - while (splitIndex > -1) { - packages.append(m_dataBuffers.left(splitIndex + 1)); - m_dataBuffers = m_dataBuffers.right(m_dataBuffers.length() - splitIndex - 2); - splitIndex = m_dataBuffers.indexOf("}\n{"); - } - if (m_dataBuffers.trimmed().endsWith("}")) { - packages.append(m_dataBuffers); - m_dataBuffers.clear(); + if (m_slipEnabled) { + + } else { + // Handle json packet fragmentation + m_dataBuffers.append(data); + int splitIndex = m_dataBuffers.indexOf("}\n{"); + while (splitIndex > -1) { + packages.append(m_dataBuffers.left(splitIndex + 1)); + m_dataBuffers = m_dataBuffers.right(m_dataBuffers.length() - splitIndex - 2); + splitIndex = m_dataBuffers.indexOf("}\n{"); + } + if (m_dataBuffers.trimmed().endsWith("}")) { + packages.append(m_dataBuffers); + m_dataBuffers.clear(); + } } return packages; @@ -47,16 +61,12 @@ QList TunnelProxyClient::processData(const QByteArray &data) QDebug operator<<(QDebug debug, TunnelProxyClient *tunnelProxyClient) { debug.nospace() << "TunnelProxyClient("; - if (!tunnelProxyClient->name().isEmpty()) { - debug.nospace() << tunnelProxyClient->name() << ", "; - } - - debug.nospace() << tunnelProxyClient->interface()->serverName(); - debug.nospace() << ", " << tunnelProxyClient->clientId().toString(); - debug.nospace() << ", " << tunnelProxyClient->peerAddress().toString(); - debug.nospace() << ", " << tunnelProxyClient->creationTimeString() << ")"; + debug.nospace() << tunnelProxyClient->name() << ", "; + debug.nospace() << tunnelProxyClient->interface()->serverName()<< ", "; + debug.nospace() << tunnelProxyClient->clientId().toString()<< ", "; + debug.nospace() << tunnelProxyClient->peerAddress().toString() << ", "; + debug.nospace() << tunnelProxyClient->creationTimeString() << ")"; return debug.space(); - } } diff --git a/libnymea-remoteproxy/tunnelproxy/tunnelproxyclient.h b/libnymea-remoteproxy/tunnelproxy/tunnelproxyclient.h index 832be0a..ede50de 100644 --- a/libnymea-remoteproxy/tunnelproxy/tunnelproxyclient.h +++ b/libnymea-remoteproxy/tunnelproxy/tunnelproxyclient.h @@ -23,6 +23,9 @@ public: Type type() const; void setType(Type type); + bool slipEnabled() const; + void setSlipEnabled(bool slipEnabled); + // Json server methods QList processData(const QByteArray &data) override; @@ -31,6 +34,7 @@ signals: private: Type m_type = TypeNone; + bool m_slipEnabled = false; }; diff --git a/libnymea-remoteproxy/tunnelproxy/tunnelproxyclientconnection.cpp b/libnymea-remoteproxy/tunnelproxy/tunnelproxyclientconnection.cpp index db078c6..3279be1 100644 --- a/libnymea-remoteproxy/tunnelproxy/tunnelproxyclientconnection.cpp +++ b/libnymea-remoteproxy/tunnelproxy/tunnelproxyclientconnection.cpp @@ -30,9 +30,10 @@ namespace remoteproxy { -TunnelProxyClientConnection::TunnelProxyClientConnection(TransportClient *transportClient, const QUuid &clientUuid, const QString &clientName, const QUuid &serverUuid, QObject *parent) : +TunnelProxyClientConnection::TunnelProxyClientConnection(TransportClient *transportClient, TunnelProxyServerConnection *serverConnection, const QUuid &clientUuid, const QString &clientName, const QUuid &serverUuid, QObject *parent) : QObject(parent), m_transportClient(transportClient), + m_serverConnection(serverConnection), m_clientUuid(clientUuid), m_clientName(clientName), m_serverUuid(serverUuid) @@ -45,6 +46,11 @@ TransportClient *TunnelProxyClientConnection::transportClient() const return m_transportClient; } +TunnelProxyServerConnection *TunnelProxyClientConnection::serverConnection() const +{ + return m_serverConnection; +} + QUuid TunnelProxyClientConnection::clientUuid() const { return m_clientUuid; @@ -60,4 +66,13 @@ QUuid TunnelProxyClientConnection::serverUuid() const return m_serverUuid; } +QDebug operator<<(QDebug debug, TunnelProxyClientConnection *clientConnection) +{ + debug.nospace() << "TunnelProxyClientConnection("; + debug.nospace() << clientConnection->clientName() << ", "; + debug.nospace() << clientConnection->clientUuid().toString() << ", "; + debug.nospace() << clientConnection->transportClient() << ")"; + return debug.space(); +} + } diff --git a/libnymea-remoteproxy/tunnelproxy/tunnelproxyclientconnection.h b/libnymea-remoteproxy/tunnelproxy/tunnelproxyclientconnection.h index 56086d8..b52b121 100644 --- a/libnymea-remoteproxy/tunnelproxy/tunnelproxyclientconnection.h +++ b/libnymea-remoteproxy/tunnelproxy/tunnelproxyclientconnection.h @@ -30,27 +30,30 @@ #include #include +#include namespace remoteproxy { class TransportClient; +class TunnelProxyServerConnection; class TunnelProxyClientConnection : public QObject { Q_OBJECT public: - explicit TunnelProxyClientConnection(TransportClient *transportClient, const QUuid &clientUuid, const QString &clientName, const QUuid &serverUuid, QObject *parent = nullptr); + explicit TunnelProxyClientConnection(TransportClient *transportClient, TunnelProxyServerConnection *serverConnection, const QUuid &clientUuid, const QString &clientName, const QUuid &serverUuid, QObject *parent = nullptr); TransportClient *transportClient() const; + TunnelProxyServerConnection *serverConnection() const; + QUuid clientUuid() const; QString clientName() const; QUuid serverUuid() const; -signals: - private: TransportClient *m_transportClient = nullptr; + TunnelProxyServerConnection *m_serverConnection = nullptr; QUuid m_clientUuid; QString m_clientName; @@ -58,6 +61,8 @@ private: }; +QDebug operator<<(QDebug debug, TunnelProxyClientConnection *clientConnection); + } #endif // TUNNELPROXYCLIENTCONNECTION_H diff --git a/libnymea-remoteproxy/tunnelproxy/tunnelproxyserver.cpp b/libnymea-remoteproxy/tunnelproxy/tunnelproxyserver.cpp index 920a823..0924ae9 100644 --- a/libnymea-remoteproxy/tunnelproxy/tunnelproxyserver.cpp +++ b/libnymea-remoteproxy/tunnelproxy/tunnelproxyserver.cpp @@ -99,6 +99,9 @@ TunnelProxyServer::TunnelProxyError TunnelProxyServer::registerServer(const QUui tunnelProxyClient->setUuid(serverUuid); tunnelProxyClient->setName(serverName); + // Enable SLIP from now on +// tunnelProxyClient->setSlipEnabled(true); + TunnelProxyServerConnection *serverConnection = new TunnelProxyServerConnection(tunnelProxyClient, serverUuid, serverName, this); m_tunnelProxyServerConnections.insert(serverUuid, serverConnection); @@ -121,6 +124,11 @@ TunnelProxyServer::TunnelProxyError TunnelProxyServer::registerClient(const QUui return TunnelProxyServer::TunnelProxyErrorAlreadyRegistered; } + if (m_tunnelProxyClientConnections.contains(clientUuid)) { + qCWarning(dcTunnelProxyServer()) << "There is a client already registered with client uuid" << clientUuid.toString(); + return TunnelProxyServer::TunnelProxyErrorAlreadyRegistered; + } + // Get the desired server connection TunnelProxyServerConnection *serverConnection = m_tunnelProxyServerConnections.value(serverUuid); if (!serverConnection) { @@ -128,20 +136,18 @@ TunnelProxyServer::TunnelProxyError TunnelProxyServer::registerClient(const QUui return TunnelProxyServer::TunnelProxyErrorServerNotFound; } - if (m_tunnelProxyClientConnections.contains(clientUuid)) { - qCWarning(dcTunnelProxyServer()) << "There is a client already registered with client uuid" << clientUuid.toString(); - return TunnelProxyServer::TunnelProxyErrorAlreadyRegistered; - } - // Not registered yet, we have a connected server for the requested server uuid tunnelProxyClient->setType(TunnelProxyClient::TypeClient); tunnelProxyClient->setUuid(clientUuid); tunnelProxyClient->setName(clientName); - TunnelProxyClientConnection *clientConnection = new TunnelProxyClientConnection(tunnelProxyClient, clientUuid, clientName, serverUuid); + TunnelProxyClientConnection *clientConnection = new TunnelProxyClientConnection(tunnelProxyClient, serverConnection, clientUuid, clientName, serverUuid); m_tunnelProxyClientConnections.insert(clientUuid, clientConnection); - // TODO: register on the server and wait for te aprovement from the server + qCDebug(dcTunnelProxyServer()) << "Register client" << clientConnection << "-->" << serverConnection; + serverConnection->registerClientConnection(clientConnection); + + // TODO: wait for te aprovement from the server return TunnelProxyServer::TunnelProxyErrorNoError; } @@ -195,6 +201,8 @@ void TunnelProxyServer::onClientDisconnected(const QUuid &clientId) if (!serverConnection) { qCWarning(dcTunnelProxyServer()) << "Could not find server connection for disconnected tunnel proxy client claiming to be a server."; } else { + + // TODO: kill all related clients serverConnection->deleteLater(); @@ -203,11 +211,13 @@ void TunnelProxyServer::onClientDisconnected(const QUuid &clientId) if (tunnelProxyClient->type() == TunnelProxyClient::TypeClient) { TunnelProxyClientConnection *clientConnection = m_tunnelProxyClientConnections.take(tunnelProxyClient->uuid()); - if (!clientConnection) { qCWarning(dcTunnelProxyServer()) << "Could not find client connection for disconnected tunnel proxy client claiming to be a client."; } else { - // TODO: remove from server + if (clientConnection->serverConnection()) { + clientConnection->serverConnection()->unregisterClientConnection(clientConnection); + // TODO: Send client disconnected to the server + } clientConnection->deleteLater(); } @@ -229,10 +239,23 @@ void TunnelProxyServer::onClientDataAvailable(const QUuid &clientId, const QByte } qCDebug(dcTunnelProxyServerTraffic()) << "Client data available" << tunnelProxyClient << qUtf8Printable(data); + if (tunnelProxyClient->type() == TunnelProxyClient::TypeClient) { + // Send the data to the server using slip + frame - // TODO: verify if encoded and for whom this data is... 0x0000 is for the json rpc handler... - m_jsonRpcServer->processData(tunnelProxyClient, data); + } else if (tunnelProxyClient->type() == TunnelProxyClient::TypeServer) { + if (tunnelProxyClient->slipEnabled()) { + + } else { + m_jsonRpcServer->processData(tunnelProxyClient, data); + } + // Unpack SLIP data, get address, pipe to client or give it to the json rpc server if address 0x0000 + + } else { + // Not registered yet or doing other stuff...let the JSON RPC handle this data + m_jsonRpcServer->processData(tunnelProxyClient, data); + } + } } diff --git a/libnymea-remoteproxy/tunnelproxy/tunnelproxyserverconnection.cpp b/libnymea-remoteproxy/tunnelproxy/tunnelproxyserverconnection.cpp index 3f190fa..4451977 100644 --- a/libnymea-remoteproxy/tunnelproxy/tunnelproxyserverconnection.cpp +++ b/libnymea-remoteproxy/tunnelproxy/tunnelproxyserverconnection.cpp @@ -27,6 +27,7 @@ #include "tunnelproxyserverconnection.h" #include "server/transportclient.h" +#include "tunnelproxyclientconnection.h" namespace remoteproxy { @@ -54,4 +55,23 @@ QString TunnelProxyServerConnection::serverName() const return m_serverName; } +void TunnelProxyServerConnection::registerClientConnection(TunnelProxyClientConnection *clientConnection) +{ + m_clientConnections.insert(clientConnection->clientUuid(), clientConnection); +} + +void TunnelProxyServerConnection::unregisterClientConnection(TunnelProxyClientConnection *clientConnection) +{ + m_clientConnections.remove(clientConnection->clientUuid()); +} + +QDebug operator<<(QDebug debug, TunnelProxyServerConnection *serverConnection) +{ + debug.nospace() << "TunnelProxyServerConnection("; + debug.nospace() << serverConnection->serverName() << ", "; + debug.nospace() << serverConnection->serverUuid().toString() << ", "; + debug.nospace() << serverConnection->transportClient() << ")"; + return debug.space(); +} + } diff --git a/libnymea-remoteproxy/tunnelproxy/tunnelproxyserverconnection.h b/libnymea-remoteproxy/tunnelproxy/tunnelproxyserverconnection.h index 2293930..3fdaf71 100644 --- a/libnymea-remoteproxy/tunnelproxy/tunnelproxyserverconnection.h +++ b/libnymea-remoteproxy/tunnelproxy/tunnelproxyserverconnection.h @@ -30,10 +30,12 @@ #include #include +#include namespace remoteproxy { class TransportClient; +class TunnelProxyClientConnection; class TunnelProxyServerConnection : public QObject { @@ -46,17 +48,22 @@ public: QUuid serverUuid() const; QString serverName() const; - + void registerClientConnection(TunnelProxyClientConnection *clientConnection); + void unregisterClientConnection(TunnelProxyClientConnection *clientConnection); signals: private: TransportClient *m_transportClient = nullptr; - QUuid m_serverUuid; QString m_serverName; + + QHash m_clientConnections; + }; +QDebug operator<<(QDebug debug, TunnelProxyServerConnection *serverConnection); + } #endif // TUNNELPROXYSERVERCONNECTION_H diff --git a/libnymea-remoteproxyclient/libnymea-remoteproxyclient.pri b/libnymea-remoteproxyclient/libnymea-remoteproxyclient.pri index d1d89c8..92e3a0e 100644 --- a/libnymea-remoteproxyclient/libnymea-remoteproxyclient.pri +++ b/libnymea-remoteproxyclient/libnymea-remoteproxyclient.pri @@ -1,18 +1,24 @@ -INCLUDEPATH += $${PWD} +INCLUDEPATH += $$PWD HEADERS += \ - $${PWD}/tcpsocketconnection.h \ - $${PWD}/proxyjsonrpcclient.h \ - $${PWD}/jsonreply.h \ - $${PWD}/remoteproxyconnection.h \ - $${PWD}/proxyconnection.h \ - $${PWD}/websocketconnection.h + $$PWD/tunnelproxy/tunnelproxyjsonrpcclient.h \ + $$PWD/tunnelproxy/tunnelproxysocket.h \ + $$PWD/tunnelproxy/tunnelproxyserver.h \ + $$PWD/tcpsocketconnection.h \ + $$PWD/proxyjsonrpcclient.h \ + $$PWD/jsonreply.h \ + $$PWD/remoteproxyconnection.h \ + $$PWD/proxyconnection.h \ + $$PWD/websocketconnection.h SOURCES += \ - $${PWD}/tcpsocketconnection.cpp \ - $${PWD}/proxyjsonrpcclient.cpp \ - $${PWD}/jsonreply.cpp \ - $${PWD}/remoteproxyconnection.cpp \ - $${PWD}/proxyconnection.cpp \ - $${PWD}/websocketconnection.cpp + $$PWD/tunnelproxy/tunnelproxyjsonrpcclient.cpp \ + $$PWD/tunnelproxy/tunnelproxysocket.cpp \ + $$PWD/tunnelproxy/tunnelproxyserver.cpp \ + $$PWD/tcpsocketconnection.cpp \ + $$PWD/proxyjsonrpcclient.cpp \ + $$PWD/jsonreply.cpp \ + $$PWD/remoteproxyconnection.cpp \ + $$PWD/proxyconnection.cpp \ + $$PWD/websocketconnection.cpp diff --git a/libnymea-remoteproxyclient/tunnelproxy/tunnelproxyjsonrpcclient.cpp b/libnymea-remoteproxyclient/tunnelproxy/tunnelproxyjsonrpcclient.cpp new file mode 100644 index 0000000..83a1778 --- /dev/null +++ b/libnymea-remoteproxyclient/tunnelproxy/tunnelproxyjsonrpcclient.cpp @@ -0,0 +1,37 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +* +* Copyright 2013 - 2021, nymea GmbH +* Contact: contact@nymea.io +* +* This file is part of nymea. +* This project including source code and documentation is protected by copyright law, and +* remains the property of nymea GmbH. All rights, including reproduction, publication, +* editing and translation, are reserved. The use of this project is subject to the terms of a +* license agreement to be concluded with nymea GmbH in accordance with the terms +* of use of nymea GmbH, available under https://nymea.io/license +* +* GNU Lesser General Public License Usage +* Alternatively, this project may be redistributed and/or modified under the terms of the GNU +* Lesser General Public License as published by the Free Software Foundation; version 3. +* this project is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; +* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +* See the GNU Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public License along with this project. +* If not, see . +* +* For any further details and any questions please contact us under contact@nymea.io +* or see our FAQ/Licensing Information on https://nymea.io/license/faq +* +* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#include "tunnelproxyjsonrpcclient.h" + +namespace remoteproxyclient { + +TunnelProxyJsonRpcClient::TunnelProxyJsonRpcClient(QObject *parent) : QObject(parent) +{ + +} + +} diff --git a/libnymea-remoteproxyclient/tunnelproxy/tunnelproxyjsonrpcclient.h b/libnymea-remoteproxyclient/tunnelproxy/tunnelproxyjsonrpcclient.h new file mode 100644 index 0000000..0c4b0b0 --- /dev/null +++ b/libnymea-remoteproxyclient/tunnelproxy/tunnelproxyjsonrpcclient.h @@ -0,0 +1,48 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +* +* Copyright 2013 - 2021, nymea GmbH +* Contact: contact@nymea.io +* +* This file is part of nymea. +* This project including source code and documentation is protected by copyright law, and +* remains the property of nymea GmbH. All rights, including reproduction, publication, +* editing and translation, are reserved. The use of this project is subject to the terms of a +* license agreement to be concluded with nymea GmbH in accordance with the terms +* of use of nymea GmbH, available under https://nymea.io/license +* +* GNU Lesser General Public License Usage +* Alternatively, this project may be redistributed and/or modified under the terms of the GNU +* Lesser General Public License as published by the Free Software Foundation; version 3. +* this project is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; +* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +* See the GNU Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public License along with this project. +* If not, see . +* +* For any further details and any questions please contact us under contact@nymea.io +* or see our FAQ/Licensing Information on https://nymea.io/license/faq +* +* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#ifndef TUNNELPROXYJSONRPCCLIENT_H +#define TUNNELPROXYJSONRPCCLIENT_H + +#include + +namespace remoteproxyclient { + +class TunnelProxyJsonRpcClient : public QObject +{ + Q_OBJECT + +public: + explicit TunnelProxyJsonRpcClient(QObject *parent = nullptr); + +signals: + +}; + +} + +#endif // TUNNELPROXYJSONRPCCLIENT_H diff --git a/libnymea-remoteproxyclient/tunnelproxy/tunnelproxyserver.cpp b/libnymea-remoteproxyclient/tunnelproxy/tunnelproxyserver.cpp new file mode 100644 index 0000000..c0f22f2 --- /dev/null +++ b/libnymea-remoteproxyclient/tunnelproxy/tunnelproxyserver.cpp @@ -0,0 +1,84 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +* +* Copyright 2013 - 2021, nymea GmbH +* Contact: contact@nymea.io +* +* This file is part of nymea. +* This project including source code and documentation is protected by copyright law, and +* remains the property of nymea GmbH. All rights, including reproduction, publication, +* editing and translation, are reserved. The use of this project is subject to the terms of a +* license agreement to be concluded with nymea GmbH in accordance with the terms +* of use of nymea GmbH, available under https://nymea.io/license +* +* GNU Lesser General Public License Usage +* Alternatively, this project may be redistributed and/or modified under the terms of the GNU +* Lesser General Public License as published by the Free Software Foundation; version 3. +* this project is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; +* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +* See the GNU Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public License along with this project. +* If not, see . +* +* For any further details and any questions please contact us under contact@nymea.io +* or see our FAQ/Licensing Information on https://nymea.io/license/faq +* +* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#include "tunnelproxyserver.h" +#include "proxyconnection.h" +#include "tcpsocketconnection.h" +#include "websocketconnection.h" + +namespace remoteproxyclient { + +TunnelProxyServer::TunnelProxyServer(const QUuid &serverUuid, const QString &serverName, QObject *parent) : + QObject(parent), + m_serverUuid(serverUuid), + m_serverName(serverName) +{ + +} + +TunnelProxyServer::TunnelProxyServer(const QUuid &serverUuid, const QString &serverName, ConnectionType connectionType, QObject *parent) : + QObject(parent), + m_serverUuid(serverUuid), + m_serverName(serverName), + m_connectionType(connectionType) +{ + +} + +TunnelProxyServer::~TunnelProxyServer() +{ + +} + +bool TunnelProxyServer::running() const +{ + return m_running; +} + +void TunnelProxyServer::ignoreSslErrors() +{ + m_connection->ignoreSslErrors(); + +} + +void TunnelProxyServer::ignoreSslErrors(const QList &errors) +{ + m_connection->ignoreSslErrors(errors); +} + +void remoteproxyclient::TunnelProxyServer::startServer(const QUrl &serverUrl) +{ + // Register as server to the remote proxy + m_serverUrl = serverUrl; +} + +void remoteproxyclient::TunnelProxyServer::stopServer() +{ + // Close the server connection and all related sockets +} + +} diff --git a/libnymea-remoteproxyclient/tunnelproxy/tunnelproxyserver.h b/libnymea-remoteproxyclient/tunnelproxy/tunnelproxyserver.h new file mode 100644 index 0000000..6dba0af --- /dev/null +++ b/libnymea-remoteproxyclient/tunnelproxy/tunnelproxyserver.h @@ -0,0 +1,90 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +* +* Copyright 2013 - 2021, nymea GmbH +* Contact: contact@nymea.io +* +* This file is part of nymea. +* This project including source code and documentation is protected by copyright law, and +* remains the property of nymea GmbH. All rights, including reproduction, publication, +* editing and translation, are reserved. The use of this project is subject to the terms of a +* license agreement to be concluded with nymea GmbH in accordance with the terms +* of use of nymea GmbH, available under https://nymea.io/license +* +* GNU Lesser General Public License Usage +* Alternatively, this project may be redistributed and/or modified under the terms of the GNU +* Lesser General Public License as published by the Free Software Foundation; version 3. +* this project is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; +* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +* See the GNU Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public License along with this project. +* If not, see . +* +* 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 +#include +#include + +Q_DECLARE_LOGGING_CATEGORY(dcRemoteProxyTunnelProxyServer) + +#include "proxyconnection.h" +#include "tunnelproxysocket.h" + +namespace remoteproxyclient { + +class ProxyConnection; +class TunnelProxyJsonRpcClient; + +class TunnelProxyServer : public QObject +{ + Q_OBJECT +public: + enum ConnectionType { + ConnectionTypeWebSocket, + ConnectionTypeTcpSocket + }; + Q_ENUM(ConnectionType) + + explicit TunnelProxyServer(const QUuid &serverUuid, const QString &serverName, QObject *parent = nullptr); + explicit TunnelProxyServer(const QUuid &serverUuid, const QString &serverName, ConnectionType connectionType, QObject *parent = nullptr); + ~TunnelProxyServer(); + + bool running() const; + + QAbstractSocket::SocketError error() const; + + void ignoreSslErrors(); + void ignoreSslErrors(const QList &errors); + +public slots: + void startServer(const QUrl &serverUrl); + void stopServer(); + +signals: + void runningChanged(bool running); + void sslErrors(const QList &errors); + +private: + QUuid m_serverUuid; + QString m_serverName; + ConnectionType m_connectionType = ConnectionTypeTcpSocket; + + bool m_running = false; + QUrl m_serverUrl; + QAbstractSocket::SocketError m_error = QAbstractSocket::UnknownSocketError; + + ProxyConnection *m_connection = nullptr; + TunnelProxyJsonRpcClient *m_jsonClient = nullptr; + +}; + +} + +#endif // TUNNELPROXYSERVER_H diff --git a/libnymea-remoteproxyclient/tunnelproxy/tunnelproxysocket.cpp b/libnymea-remoteproxyclient/tunnelproxy/tunnelproxysocket.cpp new file mode 100644 index 0000000..b033688 --- /dev/null +++ b/libnymea-remoteproxyclient/tunnelproxy/tunnelproxysocket.cpp @@ -0,0 +1,37 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +* +* Copyright 2013 - 2021, nymea GmbH +* Contact: contact@nymea.io +* +* This file is part of nymea. +* This project including source code and documentation is protected by copyright law, and +* remains the property of nymea GmbH. All rights, including reproduction, publication, +* editing and translation, are reserved. The use of this project is subject to the terms of a +* license agreement to be concluded with nymea GmbH in accordance with the terms +* of use of nymea GmbH, available under https://nymea.io/license +* +* GNU Lesser General Public License Usage +* Alternatively, this project may be redistributed and/or modified under the terms of the GNU +* Lesser General Public License as published by the Free Software Foundation; version 3. +* this project is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; +* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +* See the GNU Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public License along with this project. +* If not, see . +* +* For any further details and any questions please contact us under contact@nymea.io +* or see our FAQ/Licensing Information on https://nymea.io/license/faq +* +* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#include "tunnelproxysocket.h" + +namespace remoteproxyclient { + +TunnelProxySocket::TunnelProxySocket(QObject *parent) : QObject(parent) +{ + +} + +} diff --git a/libnymea-remoteproxyclient/tunnelproxy/tunnelproxysocket.h b/libnymea-remoteproxyclient/tunnelproxy/tunnelproxysocket.h new file mode 100644 index 0000000..bd259f9 --- /dev/null +++ b/libnymea-remoteproxyclient/tunnelproxy/tunnelproxysocket.h @@ -0,0 +1,47 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +* +* Copyright 2013 - 2021, nymea GmbH +* Contact: contact@nymea.io +* +* This file is part of nymea. +* This project including source code and documentation is protected by copyright law, and +* remains the property of nymea GmbH. All rights, including reproduction, publication, +* editing and translation, are reserved. The use of this project is subject to the terms of a +* license agreement to be concluded with nymea GmbH in accordance with the terms +* of use of nymea GmbH, available under https://nymea.io/license +* +* GNU Lesser General Public License Usage +* Alternatively, this project may be redistributed and/or modified under the terms of the GNU +* Lesser General Public License as published by the Free Software Foundation; version 3. +* this project is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; +* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +* See the GNU Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public License along with this project. +* If not, see . +* +* For any further details and any questions please contact us under contact@nymea.io +* or see our FAQ/Licensing Information on https://nymea.io/license/faq +* +* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#ifndef TUNNELPROXYSOCKET_H +#define TUNNELPROXYSOCKET_H + +#include + +namespace remoteproxyclient { + +class TunnelProxySocket : public QObject +{ + Q_OBJECT +public: + explicit TunnelProxySocket(QObject *parent = nullptr); + +signals: + +}; + +} + +#endif // TUNNELPROXYSOCKET_H diff --git a/nymea-remoteproxy.pri b/nymea-remoteproxy.pri index e602747..54e509c 100644 --- a/nymea-remoteproxy.pri +++ b/nymea-remoteproxy.pri @@ -4,7 +4,7 @@ QT -= gui # Define versions SERVER_NAME=nymea-remoteproxy API_VERSION_MAJOR=0 -API_VERSION_MINOR=3 +API_VERSION_MINOR=4 SERVER_VERSION=0.2.0 DEFINES += SERVER_NAME_STRING=\\\"$${SERVER_NAME}\\\" \ diff --git a/tests/test-proxy/remoteproxytestsproxy.cpp b/tests/test-proxy/remoteproxytestsproxy.cpp index d9fddd0..9a57216 100644 --- a/tests/test-proxy/remoteproxytestsproxy.cpp +++ b/tests/test-proxy/remoteproxytestsproxy.cpp @@ -45,12 +45,24 @@ RemoteProxyTestsProxy::RemoteProxyTestsProxy(QObject *parent) : void RemoteProxyTestsProxy::startStopServer() { + resetDebugCategories(); + addDebugCategory("ProxyServer.debug=true"); + addDebugCategory("Engine.debug=true"); + addDebugCategory("JsonRpc.debug=true"); + addDebugCategory("TcpSocketServer.debug=true"); + addDebugCategory("WebSocketServer.debug=true"); + startServer(); stopServer(); + + resetDebugCategories(); } void RemoteProxyTestsProxy::dummyAuthenticator() { + resetDebugCategories(); + addDebugCategory("ProxyServer.debug=true"); + cleanUpEngine(); m_configuration = new ProxyConfiguration(this); @@ -411,7 +423,7 @@ void RemoteProxyTestsProxy::getHello() // WebSocket response = invokeWebSocketProxyApiCall("RemoteProxy.Hello").toMap(); - //qDebug() << qUtf8Printable(QJsonDocument::fromVariant(response).toJson(QJsonDocument::Indented)); + qDebug() << qUtf8Printable(QJsonDocument::fromVariant(response).toJson(QJsonDocument::Indented)); // Verify data QVERIFY(!response.isEmpty()); @@ -423,7 +435,7 @@ void RemoteProxyTestsProxy::getHello() // TCP response.clear(); response = invokeTcpSocketProxyApiCall("RemoteProxy.Hello").toMap(); - //qDebug() << qUtf8Printable(QJsonDocument::fromVariant(response).toJson(QJsonDocument::Indented)); + qDebug() << qUtf8Printable(QJsonDocument::fromVariant(response).toJson(QJsonDocument::Indented)); // Verify data QVERIFY(!response.isEmpty()); diff --git a/tests/test-tunnelproxy/remoteproxyteststunnelproxy.cpp b/tests/test-tunnelproxy/remoteproxyteststunnelproxy.cpp index 725eee7..6d049b7 100644 --- a/tests/test-tunnelproxy/remoteproxyteststunnelproxy.cpp +++ b/tests/test-tunnelproxy/remoteproxyteststunnelproxy.cpp @@ -122,10 +122,9 @@ void RemoteProxyTestsTunnelProxy::getHello() { // Start the server startServer(); - QVariantMap response; // WebSocket - response = invokeWebSocketTunnelProxyApiCall("RemoteProxy.Hello").toMap(); + QVariantMap response = invokeWebSocketTunnelProxyApiCall("RemoteProxy.Hello").toMap(); qDebug() << qUtf8Printable(QJsonDocument::fromVariant(response).toJson(QJsonDocument::Indented)); // Verify data @@ -147,7 +146,6 @@ void RemoteProxyTestsTunnelProxy::getHello() QCOMPARE(response.value("params").toMap().value("version").toString(), QString(SERVER_VERSION_STRING)); QCOMPARE(response.value("params").toMap().value("apiVersion").toString(), QString(API_VERSION_STRING)); - // Clean up stopServer(); } @@ -250,6 +248,88 @@ void RemoteProxyTestsTunnelProxy::registerServer() stopServer(); } +void RemoteProxyTestsTunnelProxy::registerClient_data() +{ + QTest::addColumn("name"); + QTest::addColumn("uuid"); + QTest::addColumn("expectedError"); + QTest::addColumn("serverExists"); + QTest::addColumn("serverUuid"); + QTest::addColumn("expectedServerError"); + + QTest::newRow("valid client: valid server") << "Friendly client" << QUuid::createUuid().toString() << TunnelProxyServer::TunnelProxyErrorNoError << true << QUuid::createUuid().toString() << TunnelProxyServer::TunnelProxyErrorNoError; + QTest::newRow("valid client: no server") << "Friendly client" << QUuid::createUuid().toString() << TunnelProxyServer::TunnelProxyErrorServerNotFound << false << QUuid::createUuid().toString() << TunnelProxyServer::TunnelProxyErrorNoError; + QTest::newRow("valid client: invalid server uuid") << "Friendly client" << QUuid::createUuid().toString() << TunnelProxyServer::TunnelProxyErrorInvalidUuid << true << QUuid().toString() << TunnelProxyServer::TunnelProxyErrorInvalidUuid; + QTest::newRow("invalid client uuid: valid server uuid") << "Friendly client" << QUuid().toString() << TunnelProxyServer::TunnelProxyErrorInvalidUuid << true << QUuid::createUuid().toString() << TunnelProxyServer::TunnelProxyErrorNoError; + QTest::newRow("invalid client uuid: invalid server uuid") << "Friendly client" << "hello again" << TunnelProxyServer::TunnelProxyErrorInvalidUuid << true << "it's me" << TunnelProxyServer::TunnelProxyErrorInvalidUuid; +} + +void RemoteProxyTestsTunnelProxy::registerClient() +{ + QFETCH(QString, name); + QFETCH(QString, uuid); + QFETCH(TunnelProxyServer::TunnelProxyError, expectedError); + QFETCH(bool, serverExists); + QFETCH(QString, serverUuid); + QFETCH(TunnelProxyServer::TunnelProxyError, expectedServerError); + + // Start the server + startServer(); + + resetDebugCategories(); + addDebugCategory("TunnelProxyServer.debug=true"); + + QSslSocket *socket = nullptr; + if (serverExists) { + QVariantMap serverParams; + serverParams.insert("serverName", "dummy server"); + serverParams.insert("serverUuid", serverUuid); + + // TCP socket + QPair result = invokeTcpSocketTunnelProxyApiCallPersistant("TunnelProxy.RegisterServer", serverParams); + QVariantMap response = result.first.toMap(); + socket = result.second; + + QVERIFY(!response.isEmpty()); + QVERIFY(response.value("status").toString() == "success"); + QVERIFY(response.value("params").toMap().contains("tunnelProxyError")); + verifyTunnelProxyError(response, expectedServerError); + } + + // Register a new client + QVariantMap params; + params.insert("clientName", name); + params.insert("clientUuid", uuid); + params.insert("serverUuid", serverUuid); + + // Websocket + QVariantMap response = invokeWebSocketTunnelProxyApiCall("TunnelProxy.RegisterClient", params).toMap(); + QVERIFY(!response.isEmpty()); + QVERIFY(response.value("status").toString() == "success"); + QVERIFY(response.value("params").toMap().contains("tunnelProxyError")); + verifyTunnelProxyError(response, expectedError); + + QTest::qWait(100); + + // TCP Socket + response = invokeTcpSocketTunnelProxyApiCall("TunnelProxy.RegisterClient", params).toMap(); + QVERIFY(!response.isEmpty()); + QVERIFY(response.value("status").toString() == "success"); + QVERIFY(response.value("params").toMap().contains("tunnelProxyError")); + verifyTunnelProxyError(response, expectedError); + + QTest::qWait(100); + + if (socket) { + // Close the tcp socket + socket->close(); + delete socket; + } + + // Clean up + stopServer(); +} + void RemoteProxyTestsTunnelProxy::registerServerDuplicated() { // Start the server @@ -257,6 +337,7 @@ void RemoteProxyTestsTunnelProxy::registerServerDuplicated() resetDebugCategories(); addDebugCategory("TunnelProxyServer.debug=true"); + addDebugCategory("JsonRpcTraffic.debug=true"); // Register a new server QString serverName = "tunnel proxy server awesome nymea installation"; @@ -334,5 +415,131 @@ void RemoteProxyTestsTunnelProxy::registerServerDuplicated() stopServer(); } +void RemoteProxyTestsTunnelProxy::registerClientDuplicated() +{ + // Start the server + startServer(); + + resetDebugCategories(); + addDebugCategory("TunnelProxyServer.debug=true"); + addDebugCategory("JsonRpcTraffic.debug=true"); + + + // Create the server and keep it up + QString serverName = "creative server name"; + QUuid serverUuid = QUuid::createUuid(); + QVariantMap serverParams; + serverParams.insert("serverName", serverName); + serverParams.insert("serverUuid", serverUuid.toString()); + + // TCP socket + QPair serverResult = invokeTcpSocketTunnelProxyApiCallPersistant("TunnelProxy.RegisterServer", serverParams); + QVariantMap response = serverResult.first.toMap(); + QSslSocket *serverSocket = serverResult.second; + + QVERIFY(!response.isEmpty()); + QVERIFY(response.value("status").toString() == "success"); + QVERIFY(response.value("params").toMap().contains("tunnelProxyError")); + verifyTunnelProxyError(response); + + // Connect a client TCP + QString clientName = "creative server name"; + QUuid clientUuid = QUuid::createUuid(); + QVariantMap clientParams; + clientParams.insert("clientName", serverName); + clientParams.insert("clientUuid", clientUuid.toString()); + clientParams.insert("serverUuid", serverUuid.toString()); + + QPair clientResult = invokeTcpSocketTunnelProxyApiCallPersistant("TunnelProxy.RegisterClient", clientParams); + response = clientResult.first.toMap(); + QSslSocket *clientSocketTcp = clientResult.second; + QVERIFY(!response.isEmpty()); + QVERIFY(response.value("status").toString() == "success"); + QVERIFY(response.value("params").toMap().contains("tunnelProxyError")); + verifyTunnelProxyError(response); + + // Connect another client WebSocket + QPair clientResultWS = invokeTcpSocketTunnelProxyApiCallPersistant("TunnelProxy.RegisterClient", clientParams); + response = clientResultWS.first.toMap(); + QSslSocket *clientSocketWs = clientResultWS.second; + QVERIFY(!response.isEmpty()); + QVERIFY(response.value("status").toString() == "success"); + QVERIFY(response.value("params").toMap().contains("tunnelProxyError")); + verifyTunnelProxyError(response, TunnelProxyServer::TunnelProxyErrorAlreadyRegistered); + + + // CleanUp + if (clientSocketTcp) { + // Close the tcp socket + clientSocketTcp->close(); + delete clientSocketTcp; + } + + if (clientSocketWs) { + // Close the tcp socket + clientSocketWs->close(); + delete clientSocketWs; + } + + if (serverSocket) { + // Close the tcp socket + serverSocket->close(); + delete serverSocket; + } + + resetDebugCategories(); + + // Clean up + stopServer(); +} + +void RemoteProxyTestsTunnelProxy::crossRegisterServerClient() +{ + // Start the server + startServer(); + + resetDebugCategories(); + addDebugCategory("TunnelProxyServer.debug=true"); + addDebugCategory("JsonRpcTraffic.debug=true"); + + // Create the server and keep it up + QString serverName = "creative server name"; + QUuid serverUuid = QUuid::createUuid(); + QVariantMap serverParams; + serverParams.insert("serverName", serverName); + serverParams.insert("serverUuid", serverUuid.toString()); + + // TCP socket + QPair serverResult = invokeTcpSocketTunnelProxyApiCallPersistant("TunnelProxy.RegisterServer", serverParams); + QVariantMap response = serverResult.first.toMap(); + QSslSocket *serverSocket = serverResult.second; + QVERIFY(!response.isEmpty()); + QVERIFY(response.value("status").toString() == "success"); + QVERIFY(response.value("params").toMap().contains("tunnelProxyError")); + verifyTunnelProxyError(response); + + + // Now try to register as client + QVariantMap clientParams; + clientParams.insert("clientName", "creative client name"); + clientParams.insert("clientUuid", QUuid::createUuid().toString()); + clientParams.insert("serverUuid", serverUuid.toString()); + + QPair result = invokeTcpSocketTunnelProxyApiCallPersistant("TunnelProxy.RegisterClient", clientParams, serverSocket); + response = result.first.toMap(); + QVERIFY(!response.isEmpty()); + QVERIFY(response.value("status").toString() == "success"); + QVERIFY(response.value("params").toMap().contains("tunnelProxyError")); + verifyTunnelProxyError(response, TunnelProxyServer::TunnelProxyErrorAlreadyRegistered); + + serverSocket->close(); + delete serverSocket; + + resetDebugCategories(); + + // Clean up + stopServer(); +} + QTEST_MAIN(RemoteProxyTestsTunnelProxy) diff --git a/tests/test-tunnelproxy/remoteproxyteststunnelproxy.h b/tests/test-tunnelproxy/remoteproxyteststunnelproxy.h index 3a4af35..022036a 100644 --- a/tests/test-tunnelproxy/remoteproxyteststunnelproxy.h +++ b/tests/test-tunnelproxy/remoteproxyteststunnelproxy.h @@ -57,9 +57,14 @@ private slots: void registerServer_data(); void registerServer(); - void registerServerDuplicated(); + void registerClient_data(); + void registerClient(); + void registerServerDuplicated(); + void registerClientDuplicated(); + void crossRegisterServerClient(); + }; #endif // REMOTEPROXYTESTSTUNNELPROXY_H diff --git a/tests/testbase/basetest.cpp b/tests/testbase/basetest.cpp index 2771bd1..320444f 100644 --- a/tests/testbase/basetest.cpp +++ b/tests/testbase/basetest.cpp @@ -87,7 +87,6 @@ void BaseTest::cleanUpEngine() m_authenticator = nullptr; if (m_configuration) { - delete m_configuration; m_configuration = nullptr; } } @@ -132,6 +131,8 @@ void BaseTest::startServer() QVERIFY(Engine::instance()->tcpSocketServerProxy()->running()); QVERIFY(Engine::instance()->webSocketServerTunnelProxy()->running()); QVERIFY(Engine::instance()->tcpSocketServerTunnelProxy()->running()); + QVERIFY(Engine::instance()->proxyServer()->running()); + QVERIFY(Engine::instance()->tunnelProxyServer()->running()); QVERIFY(Engine::instance()->monitorServer()->running()); } @@ -146,10 +147,8 @@ void BaseTest::stopServer() cleanUpEngine(); } -QVariant BaseTest::invokeWebSocketProxyApiCall(const QString &method, const QVariantMap params, bool remainsConnected) +QVariant BaseTest::invokeWebSocketProxyApiCall(const QString &method, const QVariantMap params) { - Q_UNUSED(remainsConnected) - QVariantMap request; request.insert("id", m_commandCounter); request.insert("method", method); @@ -241,10 +240,8 @@ QVariant BaseTest::injectWebSocketProxyData(const QByteArray &data) return QVariant(); } -QVariant BaseTest::invokeTcpSocketProxyApiCall(const QString &method, const QVariantMap params, bool remainsConnected) +QVariant BaseTest::invokeTcpSocketProxyApiCall(const QString &method, const QVariantMap params) { - Q_UNUSED(remainsConnected) - QVariantMap request; request.insert("id", m_commandCounter); request.insert("method", method); @@ -461,10 +458,8 @@ QVariant BaseTest::injectTcpSocketProxyData(const QByteArray &data) return jsonDoc.toVariant(); } -QVariant BaseTest::invokeWebSocketTunnelProxyApiCall(const QString &method, const QVariantMap params, bool remainsConnected) +QVariant BaseTest::invokeWebSocketTunnelProxyApiCall(const QString &method, const QVariantMap params) { - Q_UNUSED(remainsConnected) - QVariantMap request; request.insert("id", m_commandCounter); request.insert("method", method); @@ -485,10 +480,8 @@ QVariant BaseTest::invokeWebSocketTunnelProxyApiCall(const QString &method, cons socket->sendTextMessage(QString(jsonDoc.toJson(QJsonDocument::Compact))); dataSpy.wait(); - if (!remainsConnected) { - socket->close(); - socket->deleteLater(); - } + socket->close(); + socket->deleteLater(); for (int i = 0; i < dataSpy.count(); i++) { // Make sure the response ends with '}\n' @@ -559,10 +552,8 @@ QVariant BaseTest::injectWebSocketTunnelProxyData(const QByteArray &data) return QVariant(); } -QVariant BaseTest::invokeTcpSocketTunnelProxyApiCall(const QString &method, const QVariantMap params, bool remainsConnected) +QVariant BaseTest::invokeTcpSocketTunnelProxyApiCall(const QString &method, const QVariantMap params) { - Q_UNUSED(remainsConnected) - QVariantMap request; request.insert("id", m_commandCounter); request.insert("method", method); diff --git a/tests/testbase/basetest.h b/tests/testbase/basetest.h index 7734b4a..a3c07d1 100644 --- a/tests/testbase/basetest.h +++ b/tests/testbase/basetest.h @@ -85,16 +85,16 @@ protected: void startServer(); void stopServer(); - QVariant invokeWebSocketProxyApiCall(const QString &method, const QVariantMap params = QVariantMap(), bool remainsConnected = true); + QVariant invokeWebSocketProxyApiCall(const QString &method, const QVariantMap params = QVariantMap()); QVariant injectWebSocketProxyData(const QByteArray &data); - QVariant invokeTcpSocketProxyApiCall(const QString &method, const QVariantMap params = QVariantMap(), bool remainsConnected = true); + QVariant invokeTcpSocketProxyApiCall(const QString &method, const QVariantMap params = QVariantMap()); QVariant injectTcpSocketProxyData(const QByteArray &data); - QVariant invokeWebSocketTunnelProxyApiCall(const QString &method, const QVariantMap params = QVariantMap(), bool remainsConnected = true); + QVariant invokeWebSocketTunnelProxyApiCall(const QString &method, const QVariantMap params = QVariantMap()); QVariant injectWebSocketTunnelProxyData(const QByteArray &data); - QVariant invokeTcpSocketTunnelProxyApiCall(const QString &method, const QVariantMap params = QVariantMap(), bool remainsConnected = true); + QVariant invokeTcpSocketTunnelProxyApiCall(const QString &method, const QVariantMap params = QVariantMap()); QVariant injectTcpSocketTunnelProxyData(const QByteArray &data); QPair invokeTcpSocketTunnelProxyApiCallPersistant(const QString &method, const QVariantMap params = QVariantMap(), QSslSocket *existingSocket = nullptr);