diff --git a/docs/remote-connection-basic-flow.png b/docs/remote-connection-basic-flow.png index 11b041a..5048002 100644 Binary files a/docs/remote-connection-basic-flow.png and b/docs/remote-connection-basic-flow.png differ 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);