diff --git a/libnymea-remoteproxy/engine.cpp b/libnymea-remoteproxy/engine.cpp index 492f865..6c2b733 100644 --- a/libnymea-remoteproxy/engine.cpp +++ b/libnymea-remoteproxy/engine.cpp @@ -77,6 +77,7 @@ void Engine::start(ProxyConfiguration *configuration) m_proxyServer = new ProxyServer(this); m_webSocketServerProxy = new WebSocketServer(m_configuration->sslEnabled(), m_configuration->sslConfiguration(), this); m_tcpSocketServerProxy = new TcpSocketServer(m_configuration->sslEnabled(), m_configuration->sslConfiguration(), this); + m_unixSocketServerProxy = new UnixSocketServer(m_configuration->localSocketFileName(), this); // Configure websocket server QUrl websocketServerUrl; @@ -95,6 +96,7 @@ void Engine::start(ProxyConfiguration *configuration) // Register the transport interfaces in the proxy server m_proxyServer->registerTransportInterface(m_webSocketServerProxy); m_proxyServer->registerTransportInterface(m_tcpSocketServerProxy); + m_proxyServer->registerTransportInterface(m_unixSocketServerProxy); // Start the server qCDebug(dcEngine()) << "Starting the proxy servers..."; @@ -211,6 +213,11 @@ WebSocketServer *Engine::webSocketServerProxy() const return m_webSocketServerProxy; } +UnixSocketServer *Engine::unixSocketServerProxy() const +{ + return m_unixSocketServerProxy; +} + TcpSocketServer *Engine::tcpSocketServerTunnelProxy() const { return m_tcpSocketServerTunnelProxy; diff --git a/libnymea-remoteproxy/engine.h b/libnymea-remoteproxy/engine.h index 18fc3a2..1b73286 100644 --- a/libnymea-remoteproxy/engine.h +++ b/libnymea-remoteproxy/engine.h @@ -42,6 +42,7 @@ #include "server/jsonrpcserver.h" #include "server/tcpsocketserver.h" #include "server/websocketserver.h" +#include "server/unixsocketserver.h" #include "authentication/authenticator.h" #include "tunnelproxy/tunnelproxyserver.h" @@ -75,6 +76,7 @@ public: TcpSocketServer *tcpSocketServerProxy() const; WebSocketServer *webSocketServerProxy() const; + UnixSocketServer *unixSocketServerProxy() const; TcpSocketServer *tcpSocketServerTunnelProxy() const; WebSocketServer *webSocketServerTunnelProxy() const; @@ -103,6 +105,7 @@ private: TcpSocketServer *m_tcpSocketServerProxy = nullptr; WebSocketServer *m_webSocketServerProxy = nullptr; + UnixSocketServer *m_unixSocketServerProxy = nullptr; TcpSocketServer *m_tcpSocketServerTunnelProxy = nullptr; WebSocketServer *m_webSocketServerTunnelProxy = nullptr; diff --git a/libnymea-remoteproxy/libnymea-remoteproxy.pro b/libnymea-remoteproxy/libnymea-remoteproxy.pro index 9d72495..5c4b166 100644 --- a/libnymea-remoteproxy/libnymea-remoteproxy.pro +++ b/libnymea-remoteproxy/libnymea-remoteproxy.pro @@ -27,6 +27,7 @@ HEADERS += \ proxy/tunnelconnection.h \ server/tcpsocketserver.h \ server/transportinterface.h \ + server/unixsocketserver.h \ server/websocketserver.h \ server/jsonrpcserver.h \ server/transportclient.h \ @@ -60,6 +61,7 @@ SOURCES += \ server/tcpsocketserver.cpp \ server/transportinterface.cpp \ server/transportclient.cpp \ + server/unixsocketserver.cpp \ server/websocketserver.cpp \ server/jsonrpcserver.cpp \ server/monitorserver.cpp \ diff --git a/libnymea-remoteproxy/loggingcategories.cpp b/libnymea-remoteproxy/loggingcategories.cpp index beefc73..bca229b 100644 --- a/libnymea-remoteproxy/loggingcategories.cpp +++ b/libnymea-remoteproxy/loggingcategories.cpp @@ -43,5 +43,7 @@ Q_LOGGING_CATEGORY(dcProxyServerTraffic, "ProxyServerTraffic") Q_LOGGING_CATEGORY(dcTunnelProxyServer, "TunnelProxyServer") Q_LOGGING_CATEGORY(dcTunnelProxyServerTraffic, "TunnelProxyServerTraffic") Q_LOGGING_CATEGORY(dcMonitorServer, "MonitorServer") +Q_LOGGING_CATEGORY(dcUnixSocketServer, "UnixSocketServer") +Q_LOGGING_CATEGORY(dcUnixSocketServerTraffic, "UnixSocketServerTraffic") Q_LOGGING_CATEGORY(dcAwsCredentialsProvider, "AwsCredentialsProvider") Q_LOGGING_CATEGORY(dcAwsCredentialsProviderTraffic, "AwsCredentialsProviderTraffic") diff --git a/libnymea-remoteproxy/loggingcategories.h b/libnymea-remoteproxy/loggingcategories.h index 0308fc0..af3d79e 100644 --- a/libnymea-remoteproxy/loggingcategories.h +++ b/libnymea-remoteproxy/loggingcategories.h @@ -47,6 +47,8 @@ Q_DECLARE_LOGGING_CATEGORY(dcProxyServerTraffic) Q_DECLARE_LOGGING_CATEGORY(dcTunnelProxyServer) Q_DECLARE_LOGGING_CATEGORY(dcTunnelProxyServerTraffic) Q_DECLARE_LOGGING_CATEGORY(dcMonitorServer) +Q_DECLARE_LOGGING_CATEGORY(dcUnixSocketServer) +Q_DECLARE_LOGGING_CATEGORY(dcUnixSocketServerTraffic) Q_DECLARE_LOGGING_CATEGORY(dcAwsCredentialsProvider) Q_DECLARE_LOGGING_CATEGORY(dcAwsCredentialsProviderTraffic) diff --git a/libnymea-remoteproxy/proxyconfiguration.cpp b/libnymea-remoteproxy/proxyconfiguration.cpp index a7d4a1c..75fe283 100644 --- a/libnymea-remoteproxy/proxyconfiguration.cpp +++ b/libnymea-remoteproxy/proxyconfiguration.cpp @@ -87,6 +87,10 @@ bool ProxyConfiguration::loadConfiguration(const QString &fileName) setTcpServerPort(static_cast(settings.value("port", 1213).toInt())); settings.endGroup(); + settings.beginGroup("LocalSocketServer"); + setTcpServerHost(QHostAddress(settings.value("localSocketFileName", "/run/nymea-remoteproxy.socket").toString())); + settings.endGroup(); + settings.beginGroup("WebSocketServerTunnelProxy"); setWebSocketServerTunnelProxyHost(QHostAddress(settings.value("host", "127.0.0.1").toString())); setWebSocketServerTunnelProxyPort(static_cast(settings.value("port", 2212).toInt())); @@ -352,6 +356,11 @@ void ProxyConfiguration::setTcpServerPort(quint16 port) m_tcpServerPort = port; } +QString ProxyConfiguration::localSocketFileName() const +{ + return m_localSocketFileName; +} + QHostAddress ProxyConfiguration::webSocketServerTunnelProxyHost() const { return m_webSocketServerTunnelProxyHost; @@ -436,6 +445,8 @@ QDebug operator<<(QDebug debug, ProxyConfiguration *configuration) debug.nospace() << "TcpServer Proxy" << endl; debug.nospace() << " - Host:" << configuration->tcpServerHost().toString() << endl; debug.nospace() << " - Port:" << configuration->tcpServerPort() << endl; + debug.nospace() << "LocalSocket Proxy" << endl; + debug.nospace() << " - Socket file:" << configuration->localSocketFileName() << endl; debug.nospace() << "WebSocketServer TunnelProxy" << endl; debug.nospace() << " - Host:" << configuration->webSocketServerTunnelProxyHost().toString() << endl; debug.nospace() << " - Port:" << configuration->webSocketServerTunnelProxyPort() << endl; diff --git a/libnymea-remoteproxy/proxyconfiguration.h b/libnymea-remoteproxy/proxyconfiguration.h index ee61d05..ecdb5aa 100644 --- a/libnymea-remoteproxy/proxyconfiguration.h +++ b/libnymea-remoteproxy/proxyconfiguration.h @@ -113,6 +113,9 @@ public: quint16 tcpServerPort() const; void setTcpServerPort(quint16 port); + // LocalServer + QString localSocketFileName() const; + // WebSocketServer (tunnel) QHostAddress webSocketServerTunnelProxyHost() const; void setWebSocketServerTunnelProxyHost(const QHostAddress &address); @@ -127,7 +130,6 @@ public: quint16 tcpServerTunnelProxyPort() const; void setTcpServerTunnelProxyPort(quint16 port); - private: // ProxyServer QString m_fileName; @@ -162,11 +164,14 @@ private: QHostAddress m_tcpServerHost = QHostAddress::LocalHost; quint16 m_tcpServerPort = 1213; - // WebSocketServer (proxy) + // LocalSocketServer (proxy) + QString m_localSocketFileName = "/run/nymea-remoteproxy.socket"; + + // WebSocketServer (tunnel) QHostAddress m_webSocketServerTunnelProxyHost = QHostAddress::LocalHost; quint16 m_webSocketServerTunnelProxyPort = 2212; - // TcpServer (proxy) + // TcpServer (tunnel) QHostAddress m_tcpServerTunnelProxyHost = QHostAddress::LocalHost; quint16 m_tcpServerTunnelProxyPort = 2213; diff --git a/libnymea-remoteproxy/server/unixsocketserver.cpp b/libnymea-remoteproxy/server/unixsocketserver.cpp new file mode 100644 index 0000000..12bb63b --- /dev/null +++ b/libnymea-remoteproxy/server/unixsocketserver.cpp @@ -0,0 +1,148 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +* +* Copyright 2013 - 2022, nymea GmbH +* Contact: contact@nymea.io +* +* This file is part of nymea. +* This project including source code and documentation is protected by copyright law, and +* remains the property of nymea GmbH. All rights, including reproduction, publication, +* editing and translation, are reserved. The use of this project is subject to the terms of a +* license agreement to be concluded with nymea GmbH in accordance with the terms +* of use of nymea GmbH, available under https://nymea.io/license +* +* GNU General Public License Usage +* Alternatively, this project may be redistributed and/or modified under +* the terms of the GNU General Public License as published by the Free Software Foundation, +* GNU version 3. this project is distributed in the hope that it will be useful, but WITHOUT ANY +* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +* PURPOSE. See the GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License along with this project. +* If not, see . +* +* 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 "unixsocketserver.h" + +#include + +#include "loggingcategories.h" + +namespace remoteproxy { + +UnixSocketServer::UnixSocketServer(QString socketFileName, QObject *parent) : + TransportInterface(parent), + m_socketFileName(socketFileName) +{ + m_serverName = "LOCAL"; +} + +UnixSocketServer::~UnixSocketServer() +{ + stopServer(); +} + +void UnixSocketServer::sendData(const QUuid &clientId, const QByteArray &data) +{ + QLocalSocket *client = nullptr; + client = m_clientList.value(clientId); + if (!client) { + qCWarning(dcUnixSocketServer()) << "Client" << clientId << "unknown to this transport"; + return; + } + + qCDebug(dcUnixSocketServerTraffic()) << "Send data to" << clientId.toString() << data; + if (client->write(data) < 0) { + qCWarning(dcUnixSocketServer()) << "Could not write data to client socket" << clientId.toString(); + } + client->flush(); +} + +void UnixSocketServer::killClientConnection(const QUuid &clientId, const QString &killReason) +{ + QLocalSocket *client = m_clientList.value(clientId); + if (!client) + return; + + if (client->state() == QLocalSocket::ConnectedState) { + qCWarning(dcUnixSocketServer()) << "Killing client connection" << clientId.toString() << "Reason:" << killReason; + client->close(); + } +} + +bool UnixSocketServer::running() const +{ + if (!m_server) + return false; + + return m_server->isListening(); +} + +bool UnixSocketServer::startServer() +{ + qCDebug(dcUnixSocketServer()) << "Starting server on" << m_socketFileName; + + // Make sure the monitor can be created + if (QFile::exists(m_socketFileName)) { + qCDebug(dcUnixSocketServer()) << "Clean up old unix socket"; + QFile::remove(m_socketFileName); + } + + m_server = new QLocalServer(this); + m_server->setSocketOptions(QLocalServer::UserAccessOption | QLocalServer::GroupAccessOption | QLocalServer::OtherAccessOption); + if (!m_server->listen(m_socketFileName)) { + qCWarning(dcUnixSocketServer()) << "Could not start local server for monitor on" << m_serverName << m_server->errorString(); + delete m_server; + m_server = nullptr; + return false; + } + + connect(m_server, &QLocalServer::newConnection, this, &UnixSocketServer::onClientConnected); + qCDebug(dcUnixSocketServer()) << "Started successfully on" << m_serverName; + return true; +} + +bool UnixSocketServer::stopServer() +{ + if (!m_server) + return true; + + qCDebug(dcUnixSocketServer()) << "Stopping server" << m_serverName; + foreach (QLocalSocket *clientConnection, m_clientList) { + clientConnection->close(); + } + + m_server->close(); + delete m_server; + m_server = nullptr; + + return true; +} + +void UnixSocketServer::onClientConnected() +{ + QLocalSocket *client = m_server->nextPendingConnection(); + QUuid clientId = QUuid::createUuid(); + qCDebug(dcUnixSocketServer()) << "New client connected" << clientId.toString(); + m_clientList.insert(clientId, client); + + connect(client, &QLocalSocket::disconnected, this, [=](){ + QUuid clientId = m_clientList.key(client); + qCDebug(dcUnixSocketServer()) << "Client disconnected:" << clientId.toString(); + if (m_clientList.take(clientId)) { + emit clientDisconnected(clientId); + } + }); + connect(client, &QLocalSocket::readyRead, this, [=](){ + QByteArray data = client->readAll(); + qCDebug(dcUnixSocketServerTraffic()) << "Incomming data from" << clientId.toString() << data; + emit dataAvailable(clientId, data); + }); + + emit clientConnected(clientId, QHostAddress::LocalHost); +} + +} diff --git a/libnymea-remoteproxy/server/unixsocketserver.h b/libnymea-remoteproxy/server/unixsocketserver.h new file mode 100644 index 0000000..5dc672d --- /dev/null +++ b/libnymea-remoteproxy/server/unixsocketserver.h @@ -0,0 +1,68 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +* +* Copyright 2013 - 2022, nymea GmbH +* Contact: contact@nymea.io +* +* This file is part of nymea. +* This project including source code and documentation is protected by copyright law, and +* remains the property of nymea GmbH. All rights, including reproduction, publication, +* editing and translation, are reserved. The use of this project is subject to the terms of a +* license agreement to be concluded with nymea GmbH in accordance with the terms +* of use of nymea GmbH, available under https://nymea.io/license +* +* GNU General Public License Usage +* Alternatively, this project may be redistributed and/or modified under +* the terms of the GNU General Public License as published by the Free Software Foundation, +* GNU version 3. this project is distributed in the hope that it will be useful, but WITHOUT ANY +* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +* PURPOSE. See the GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License along with this project. +* If not, see . +* +* 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 UNIXSOCKETSERVER_H +#define UNIXSOCKETSERVER_H + +#include +#include +#include +#include + +#include "transportinterface.h" + +namespace remoteproxy { + +class UnixSocketServer : public TransportInterface +{ + Q_OBJECT +public: + explicit UnixSocketServer(QString socketFileName, QObject *parent = nullptr); + ~UnixSocketServer() override; + + void sendData(const QUuid &clientId, const QByteArray &data) override; + void killClientConnection(const QUuid &clientId, const QString &killReason) override; + + bool running() const override; + +public slots: + bool startServer() override; + bool stopServer() override; + +private: + QString m_socketFileName; + QLocalServer *m_server = nullptr; + QHash m_clientList; + +private slots: + void onClientConnected(); + +}; + +} + +#endif // UNIXSOCKETSERVER_H diff --git a/nymea-remoteproxy-logging.conf b/nymea-remoteproxy-logging.conf index 9dbac85..d1a75d0 100644 --- a/nymea-remoteproxy-logging.conf +++ b/nymea-remoteproxy-logging.conf @@ -7,10 +7,16 @@ JsonRpc.debug=true JsonRpcTraffic.debug=false WebSocketServer.debug=true WebSocketServerTraffic.debug=false +TcpSocketServer.debug=true +TcpSocketServerTraffic.debug=false +UnixSocketServer.debug=true +UnixSocketServerTraffic.debug=false Authentication.debug=true AuthenticationProcess.debug=false ProxyServer.debug=true ProxyServerTraffic.debug=false +TunnelProxyServer.debug=true +TunnelProxyServerTraffic.debug=false MonitorServer.debug=true AwsCredentialsProvider.debug=false AwsCredentialsProviderTraffic.debug=false diff --git a/nymea-remoteproxy.conf b/nymea-remoteproxy.conf index 6f21594..ef55074 100644 --- a/nymea-remoteproxy.conf +++ b/nymea-remoteproxy.conf @@ -28,6 +28,9 @@ port=443 host=127.0.0.1 port=80 +[LocalSocketServer] +localSocketFileName=/run/nymea-remoteproxy.socket + [WebSocketServerTunnelProxy] host=127.0.0.1 port=2212 diff --git a/server/main.cpp b/server/main.cpp index 17eba19..3da0a76 100644 --- a/server/main.cpp +++ b/server/main.cpp @@ -118,7 +118,7 @@ int main(int argc, char *argv[]) "registered nymea deamons to establish a tunnel connection.\n\n" "Version: %1\n" "API version: %2\n\n" - "Copyright %3 2021 nymea GmbH \n") + "Copyright %3 2022 nymea GmbH \n") .arg(SERVER_VERSION_STRING) .arg(API_VERSION_STRING) .arg(QChar(0xA9))); @@ -175,18 +175,6 @@ int main(int argc, char *argv[]) } } - // Verify webserver configuration - if (configuration->webSocketServerProxyHost().isNull()) { - qCCritical(dcApplication()) << "Invalid web socket host address passed."; - exit(-1); - } - - // Verify tcp server configuration - if (configuration->tcpServerHost().isNull()) { - qCCritical(dcApplication()) << "Invalid TCP server host address passed."; - exit(-1); - } - // Verify SSL configuration if (configuration->sslEnabled() && configuration->sslConfiguration().isNull()) { qCCritical(dcApplication()) << "SSL is enabled but no SSL configuration specified.";