From 1ca3119995251ab82473b18b341c504a35b1aded Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20St=C3=BCrz?= Date: Tue, 11 Jan 2022 09:01:54 +0100 Subject: [PATCH] Extend monitor and add test script for connections --- libnymea-remoteproxy/server/monitorserver.cpp | 4 +- .../tunnelproxy/tunnelproxyserver.cpp | 13 +- .../tunnelproxy/tunnelproxyserver.h | 3 + monitor/main.cpp | 2 +- monitor/terminalwindow.cpp | 187 +++++++++++++++--- monitor/terminalwindow.h | 14 +- server/remoteproxyserverapplication.cpp | 6 +- tests/scripts/create-many-connections.sh | 55 ++++++ 8 files changed, 242 insertions(+), 42 deletions(-) create mode 100755 tests/scripts/create-many-connections.sh diff --git a/libnymea-remoteproxy/server/monitorserver.cpp b/libnymea-remoteproxy/server/monitorserver.cpp index c993646..9932cb0 100644 --- a/libnymea-remoteproxy/server/monitorserver.cpp +++ b/libnymea-remoteproxy/server/monitorserver.cpp @@ -56,7 +56,9 @@ bool MonitorServer::running() const void MonitorServer::sendMonitorData(QLocalSocket *clientConnection, const QVariantMap &dataMap) { - clientConnection->write(QJsonDocument::fromVariant(dataMap).toJson(QJsonDocument::Compact) + '\n'); + QByteArray data = QJsonDocument::fromVariant(dataMap).toJson(QJsonDocument::Indented) + '\n'; + qCDebug(dcMonitorServer()) << "Sending monitor data" << qUtf8Printable(data); + clientConnection->write(data); clientConnection->flush(); } diff --git a/libnymea-remoteproxy/tunnelproxy/tunnelproxyserver.cpp b/libnymea-remoteproxy/tunnelproxy/tunnelproxyserver.cpp index dacb524..3614c5f 100644 --- a/libnymea-remoteproxy/tunnelproxy/tunnelproxyserver.cpp +++ b/libnymea-remoteproxy/tunnelproxy/tunnelproxyserver.cpp @@ -201,6 +201,7 @@ QVariantMap TunnelProxyServer::currentStatistics() statisticsMap.insert("totalClientCount", m_proxyClients.count()); statisticsMap.insert("serverConnectionsCount", m_tunnelProxyServerConnections.count()); statisticsMap.insert("clientConnectionsCount", m_tunnelProxyClientConnections.count()); + statisticsMap.insert("troughput", m_troughput); QVariantList tunnelConnections; foreach (TunnelProxyServerConnection *serverConnection, m_tunnelProxyServerConnections) { @@ -210,6 +211,9 @@ QVariantMap TunnelProxyServer::currentStatistics() serverMap.insert("timestamp", serverConnection->transportClient()->creationTime()); serverMap.insert("name", serverConnection->transportClient()->name()); serverMap.insert("serverUuid", serverConnection->transportClient()->uuid()); + serverMap.insert("rxDataCount", serverConnection->transportClient()->rxDataCount()); + serverMap.insert("txDataCount", serverConnection->transportClient()->txDataCount()); + QVariantList clientList; foreach (TunnelProxyClientConnection *clientConnection, serverConnection->clientConnections()) { QVariantMap clientMap; @@ -218,9 +222,12 @@ QVariantMap TunnelProxyServer::currentStatistics() clientMap.insert("timestamp", clientConnection->transportClient()->creationTime()); clientMap.insert("name", clientConnection->transportClient()->name()); clientMap.insert("clientUuid", clientConnection->transportClient()->uuid()); + clientMap.insert("rxDataCount", clientConnection->transportClient()->rxDataCount()); + clientMap.insert("txDataCount", clientConnection->transportClient()->txDataCount()); clientList.append(clientMap); } serverMap.insert("clientConnections", clientList); + tunnelConnections.append(serverMap); } statisticsMap.insert("tunnelConnections", tunnelConnections); @@ -248,7 +255,8 @@ void TunnelProxyServer::stopServer() void TunnelProxyServer::tick() { - + m_troughput = m_troughputCounter; + m_troughputCounter = 0; } void TunnelProxyServer::onClientConnected(const QUuid &clientId, const QHostAddress &address) @@ -337,7 +345,7 @@ void TunnelProxyServer::onClientDataAvailable(const QUuid &clientId, const QByte frame.data = data; qCDebug(dcTunnelProxyServerTraffic()) << "--> Tunnel data to server socket address" << clientConnection->socketAddress() << "to" << clientConnection->serverConnection() << "\n" << data; clientConnection->serverConnection()->transportClient()->sendData(SlipDataProcessor::serializeData(SlipDataProcessor::buildFrame(frame))); - + m_troughputCounter += data.count(); } else if (tunnelProxyClient->type() == TunnelProxyClient::TypeServer) { // Data coming from a connected server connection if (tunnelProxyClient->slipEnabled()) { @@ -368,6 +376,7 @@ void TunnelProxyServer::onClientDataAvailable(const QUuid &clientId, const QByte qCDebug(dcTunnelProxyServerTraffic()) << "--> Tunnel data from server socket" << frame.socketAddress << "to" << clientConnection << "\n" << frame.data; clientConnection->transportClient()->sendData(frame.data); + m_troughputCounter += data.count(); } } } else { diff --git a/libnymea-remoteproxy/tunnelproxy/tunnelproxyserver.h b/libnymea-remoteproxy/tunnelproxy/tunnelproxyserver.h index 987390e..14188ed 100644 --- a/libnymea-remoteproxy/tunnelproxy/tunnelproxyserver.h +++ b/libnymea-remoteproxy/tunnelproxy/tunnelproxyserver.h @@ -95,6 +95,9 @@ private: QHash m_tunnelProxyServerConnections; // server uuid, object QHash m_tunnelProxyClientConnections; // client uuid, object + // Statistic measurments + int m_troughput = 0; + int m_troughputCounter = 0; }; } diff --git a/monitor/main.cpp b/monitor/main.cpp index 87bf742..93a3d62 100644 --- a/monitor/main.cpp +++ b/monitor/main.cpp @@ -48,7 +48,7 @@ int main(int argc, char *argv[]) parser.setApplicationDescription(QString("\nThe nymea remote proxy monitor allowes to monitor the live server activity on the a local instance.\n\n" "Server version: %1\n" "API version: %2\n\n" - "Copyright %3 2021 nymea GmbH \n") + "Copyright %3 2022 nymea GmbH \n") .arg(SERVER_VERSION_STRING) .arg(API_VERSION_STRING) .arg(QChar(0xA9))); diff --git a/monitor/terminalwindow.cpp b/monitor/terminalwindow.cpp index 0942f21..845cc33 100644 --- a/monitor/terminalwindow.cpp +++ b/monitor/terminalwindow.cpp @@ -35,6 +35,9 @@ TerminalWindow::TerminalWindow(QObject *parent) : QObject(parent) { + // Init view tabs + m_tabs << ViewClients << ViewTunnels << ViewTunnelProxy; + // Create main window m_mainWindow = initscr(); @@ -71,7 +74,9 @@ TerminalWindow::TerminalWindow(QObject *parent) : // Draw borders drawWindowBorder(m_headerWindow); - drawWindowBorder(m_contentWindow); + //drawWindowBorder(m_contentWindow); + + scrollok(m_contentWindow, true); //box(m_headerWindow, 0 , 0); //box(m_contentWindow, 0 , 0); @@ -87,11 +92,7 @@ TerminalWindow::TerminalWindow(QObject *parent) : TerminalWindow::~TerminalWindow() { - clear(); - delwin(m_headerWindow); - delwin(m_contentWindow); - delwin(m_mainWindow); - endwin(); + cleanup(); } const char *TerminalWindow::convertString(const QString &string) @@ -165,19 +166,72 @@ void TerminalWindow::drawWindowBorder(WINDOW *window) } } +void TerminalWindow::moveTabRight() +{ + int currentIndex = m_tabs.indexOf(m_view); + if (currentIndex + 1 >= m_tabs.count()) { + m_view = m_tabs.at(0); + } else { + m_view = m_tabs.at( currentIndex + 1); + } +} + +void TerminalWindow::moveTabLeft() +{ + int currentIndex = m_tabs.indexOf(m_view); + if (currentIndex - 1 < 0) { + m_view = m_tabs.at(m_tabs.count() - 1); + } else { + m_view = m_tabs.at( currentIndex - 1); + } +} + void TerminalWindow::paintHeader() { - QString headerString = QString(" Server: %1 (%2) | API: %3 | Clients: %4, %5 | Tunnels: %6, %7 | %8 | %9 | %10") - .arg(m_dataMap.value("serverName", "-").toString()) - .arg(m_dataMap.value("serverVersion", "-").toString()) - .arg(m_dataMap.value("apiVersion", "-").toString()) - .arg(m_dataMap.value("proxyStatistic").toMap().value("clientCount", 0).toInt()) - .arg(m_dataMap.value("proxyStatistic").toMap().value("total").toMap().value("totalClientCount").toInt()) - .arg(m_dataMap.value("proxyStatistic").toMap().value("tunnelCount", 0).toInt()) - .arg(m_dataMap.value("proxyStatistic").toMap().value("total").toMap().value("totalTunnelCount").toInt()) - .arg(humanReadableTraffic(m_dataMap.value("proxyStatistic").toMap().value("troughput", 0).toInt()) + " / s", - 13) - .arg(humanReadableTraffic(m_dataMap.value("proxyStatistic").toMap().value("total").toMap().value("totalTraffic").toInt()), - 10) - .arg((m_view == ViewClients ? "-- Clients --" : "-- Tunnels --")); + QString windowName; + QString headerString; + switch (m_view) { + case ViewClients: + windowName = "-- Clients --"; + headerString = QString(" Server: %1 (%2) | API: %3 | Clients: %4, %5 | Tunnels: %6, %7 | %8 | %9 | %10") + .arg(m_dataMap.value("serverName", "-").toString()) + .arg(m_dataMap.value("serverVersion", "-").toString()) + .arg(m_dataMap.value("apiVersion", "-").toString()) + .arg(m_dataMap.value("proxyStatistic").toMap().value("clientCount", 0).toInt()) + .arg(m_dataMap.value("proxyStatistic").toMap().value("total").toMap().value("totalClientCount").toInt()) + .arg(m_dataMap.value("proxyStatistic").toMap().value("tunnelCount", 0).toInt()) + .arg(m_dataMap.value("proxyStatistic").toMap().value("total").toMap().value("totalTunnelCount").toInt()) + .arg(humanReadableTraffic(m_dataMap.value("proxyStatistic").toMap().value("troughput", 0).toInt()) + " / s", - 13) + .arg(humanReadableTraffic(m_dataMap.value("proxyStatistic").toMap().value("total").toMap().value("totalTraffic").toInt()), - 10) + .arg(windowName); + break; + case ViewTunnels: + windowName = "-- Tunnels --"; + headerString = QString(" Server: %1 (%2) | API: %3 | Clients: %4, %5 | Tunnels: %6, %7 | %8 | %9 | %10") + .arg(m_dataMap.value("serverName", "-").toString()) + .arg(m_dataMap.value("serverVersion", "-").toString()) + .arg(m_dataMap.value("apiVersion", "-").toString()) + .arg(m_dataMap.value("proxyStatistic").toMap().value("clientCount", 0).toInt()) + .arg(m_dataMap.value("proxyStatistic").toMap().value("total").toMap().value("totalClientCount").toInt()) + .arg(m_dataMap.value("proxyStatistic").toMap().value("tunnelCount", 0).toInt()) + .arg(m_dataMap.value("proxyStatistic").toMap().value("total").toMap().value("totalTunnelCount").toInt()) + .arg(humanReadableTraffic(m_dataMap.value("proxyStatistic").toMap().value("troughput", 0).toInt()) + " / s", - 13) + .arg(humanReadableTraffic(m_dataMap.value("proxyStatistic").toMap().value("total").toMap().value("totalTraffic").toInt()), - 10) + .arg(windowName); + break; + case ViewTunnelProxy: + windowName = "-- TunnelProxy --"; + headerString = QString(" Server: %1 (%2) | API: %3 | Total: %4 | Servers: %5 | Clients: %6 | %7 | %8") + .arg(m_dataMap.value("serverName", "-").toString()) + .arg(m_dataMap.value("serverVersion", "-").toString()) + .arg(m_dataMap.value("apiVersion", "-").toString()) + .arg(m_dataMap.value("tunnelProxyStatistic").toMap().value("totalClientCount", 0).toInt()) + .arg(m_dataMap.value("tunnelProxyStatistic").toMap().value("serverConnectionsCount", 0).toInt()) + .arg(m_dataMap.value("tunnelProxyStatistic").toMap().value("clientConnectionsCount", 0).toInt()) + .arg(humanReadableTraffic(m_dataMap.value("tunnelProxyStatistic").toMap().value("troughput", 0).toInt()) + " / s", - 13) + .arg(windowName); + break; + } int delta = m_terminalSizeX - headerString.count(); @@ -185,10 +239,9 @@ void TerminalWindow::paintHeader() for (int i = 0; i < delta; i++) headerString.append(" "); - - wattron(m_headerWindow, A_BOLD | COLOR_PAIR(1)); + //wattron(m_headerWindow, A_BOLD | COLOR_PAIR(1)); mvwprintw(m_headerWindow, 1, 2, convertString(headerString)); - wattroff(m_headerWindow, A_BOLD | COLOR_PAIR(1)); + //wattroff(m_headerWindow, A_BOLD | COLOR_PAIR(1)); } void TerminalWindow::paintContentClients() @@ -219,7 +272,6 @@ void TerminalWindow::paintContentClients() mvwprintw(m_contentWindow, i, 2, convertString(clientPrint.trimmed())); i++; } - } void TerminalWindow::paintContentTunnels() @@ -235,7 +287,6 @@ void TerminalWindow::paintContentTunnels() uint timeStamp = tunnelMap.value("timestamp").toUInt(); QString tunnelConnectionTime = QDateTime::fromTime_t(timeStamp).toString("dd.MM.yyyy hh:mm:ss"); - QString tunnelPrint = QString("%1 | %2 | %3 | %4 | %5 (%6) <---> %7 (%8)") .arg(tunnelConnectionTime) .arg(getDurationString(timeStamp)) @@ -252,9 +303,73 @@ void TerminalWindow::paintContentTunnels() } } +void TerminalWindow::paintContentTunnelProxy() +{ + QVariantMap tunnelProxyMap = m_dataMap.value("tunnelProxyStatistic").toMap(); + int i = 1; + + foreach (const QVariant &serverVariant, tunnelProxyMap.value("tunnelConnections").toList()) { + QVariantMap serverMap = serverVariant.toMap(); + uint timeStamp = serverMap.value("timestamp").toUInt(); + QString serverConnectionTime = QDateTime::fromTime_t(timeStamp).toString("dd.MM.yyyy hh:mm:ss"); + int rxDataCountBytes = serverMap.value("rxDataCount").toInt(); + int txDataCountBytes = serverMap.value("txDataCount").toInt(); + QString serverLinePrint = QString("%1 | %2 | RX: %3 | TX: %4 | %5") + .arg(serverConnectionTime) + .arg(serverMap.value("address").toString(), - 16) + .arg(humanReadableTraffic(rxDataCountBytes), - 10) + .arg(humanReadableTraffic(txDataCountBytes), - 10) + .arg(serverMap.value("name").toString(), -30); + + QVariantList clientList = serverMap.value("clientConnections").toList(); + mvwaddch(m_contentWindow, i, 2, ACS_LTEE); + mvwaddch(m_contentWindow, i, 3, ACS_HLINE); + if (clientList.isEmpty()) { + mvwaddch(m_contentWindow, i, 4, ACS_HLINE); + } else { + mvwaddch(m_contentWindow, i, 4, ACS_TTEE); + } + mvwaddch(m_contentWindow, i, 5, ACS_HLINE); + mvwprintw(m_contentWindow, i, 6, convertString(serverLinePrint.trimmed())); + i++; + + for (int cc = 0; cc < clientList.count(); cc++) { + QVariantMap clientMap = clientList.at(cc).toMap(); + + mvwaddch(m_contentWindow, i, 2, ACS_VLINE); + + if (cc >= clientList.count() - 1) { + mvwaddch(m_contentWindow, i, 4, ACS_LLCORNER); + } else { + mvwaddch(m_contentWindow, i, 4, ACS_LTEE); + } + mvwaddch(m_contentWindow, i, 5, ACS_HLINE); + + QString clientLinePrint = QString("%1 | %2 | RX: %3 | TX: %4 | %5") + .arg(QDateTime::fromTime_t(clientMap.value("timestamp").toUInt()).toString("dd.MM.yyyy hh:mm:ss")) + .arg(clientMap.value("address").toString(), - 16) + .arg(humanReadableTraffic(clientMap.value("rxDataCount").toInt()), - 10) + .arg(humanReadableTraffic(clientMap.value("txDataCount").toInt()), - 10) + .arg(clientMap.value("name").toString(), -30); + + mvwprintw(m_contentWindow, i, 6, convertString(clientLinePrint.trimmed())); + + i++; + } + } +} + +void TerminalWindow::cleanup() +{ + clear(); + delwin(m_headerWindow); + delwin(m_contentWindow); + delwin(m_mainWindow); + endwin(); +} + void TerminalWindow::eventLoop() { - werase(m_headerWindow); werase(m_contentWindow); @@ -263,17 +378,13 @@ void TerminalWindow::eventLoop() int keyInteger = getch(); switch (keyInteger) { case KEY_LEFT: - m_view = ViewClients; + moveTabLeft(); break; case KEY_RIGHT: - m_view = ViewTunnels; + moveTabRight(); break; case 27: // Esc - clear(); - delwin(m_headerWindow); - delwin(m_contentWindow); - delwin(m_mainWindow); - endwin(); + cleanup(); qDebug() << "Closing window monitor. Have a nice day!"; exit(0); break; @@ -292,11 +403,25 @@ void TerminalWindow::eventLoop() case ViewTunnels: paintContentTunnels(); break; + case ViewTunnelProxy: + paintContentTunnelProxy(); + break; + } + + switch (keyInteger) { + case KEY_DOWN: + scroll(m_contentWindow); + scrl(1); + break; + case KEY_UP: + scroll(m_contentWindow); + scrl(-1); + break; } // Draw borders drawWindowBorder(m_headerWindow); - drawWindowBorder(m_contentWindow); + //drawWindowBorder(m_contentWindow); wrefresh(m_headerWindow); wrefresh(m_contentWindow); diff --git a/monitor/terminalwindow.h b/monitor/terminalwindow.h index 6bcbbac..7c0b25e 100644 --- a/monitor/terminalwindow.h +++ b/monitor/terminalwindow.h @@ -41,7 +41,8 @@ public: enum View { ViewClients, - ViewTunnels + ViewTunnels, + ViewTunnelProxy }; Q_ENUM(View) @@ -58,6 +59,11 @@ private: int m_terminalSizeY = 0; View m_view = ViewClients; + int m_tunnelProxyScollIndex = 0; + + + // Tabs + QList m_tabs; QVariantMap m_dataMap; QHash m_clientHash; @@ -70,11 +76,15 @@ private: // content paint methods void resizeWindow(); void drawWindowBorder(WINDOW *window); + void moveTabRight(); + void moveTabLeft(); + void paintHeader(); void paintContentClients(); void paintContentTunnels(); + void paintContentTunnelProxy(); -signals: + void cleanup(); private slots: void eventLoop(); diff --git a/server/remoteproxyserverapplication.cpp b/server/remoteproxyserverapplication.cpp index b735a27..28d12a3 100644 --- a/server/remoteproxyserverapplication.cpp +++ b/server/remoteproxyserverapplication.cpp @@ -55,10 +55,6 @@ static void catchUnixSignals(const std::vector& quitSignals, const std::vec case SIGHUP: qCDebug(dcApplication()) << "Cought SIGHUP quit signal..."; break; - case SIGSEGV: { - qCDebug(dcApplication()) << "Cought SIGSEGV signal. Segmentation fault!"; - exit(1); - } default: break; } @@ -82,5 +78,5 @@ static void catchUnixSignals(const std::vector& quitSignals, const std::vec RemoteProxyServerApplication::RemoteProxyServerApplication(int &argc, char **argv) : QCoreApplication(argc, argv) { - catchUnixSignals({SIGQUIT, SIGINT, SIGTERM, SIGHUP, SIGSEGV}); + catchUnixSignals({SIGQUIT, SIGINT, SIGTERM, SIGHUP}); } diff --git a/tests/scripts/create-many-connections.sh b/tests/scripts/create-many-connections.sh new file mode 100755 index 0000000..31816b9 --- /dev/null +++ b/tests/scripts/create-many-connections.sh @@ -0,0 +1,55 @@ +#!/bin/bash + +CHILD_PROCESSES=() +SERVER_URL=tcp://127.0.0.1:2213 + +# Start server: Arguments: serverName serverUuid +function createServer() { + echo "--> Create server" + nymea-remoteproxy-tunnelclient -s -n "$1" --uuid "$2" -u $SERVER_URL -i & CHILD_PROCESSES+=("$!") +} + +# Create client: Arguments: clientName serverUuid +function createClient() { + echo "--> Create client" + nymea-remoteproxy-tunnelclient -c -n "$1" --server-uuid "$2" -u $SERVER_URL -i & CHILD_PROCESSES+=("$!") +} + + +# Arguments: client count +function createTunnelConnections() { + local serverUuid=$(uuidgen) + createServer "Test server $serverUuid " $serverUuid + sleep 0.5 + i=1 + while [[ $i -lt $1 ]] ; do + createClient "Test client $i" $serverUuid + ((i += 1)) + #sleep 0.5 + done + +} + + +function cleanup { + echo "Cleanup" + kill "${CHILD_PROCESSES[@]}" +} + +trap cleanup EXIT + + +createTunnelConnections 5 +createTunnelConnections 3 +createTunnelConnections 9 +createTunnelConnections 6 +createTunnelConnections 4 +createTunnelConnections 3 +createTunnelConnections 2 +createTunnelConnections 1 +createTunnelConnections 3 +createTunnelConnections 2 +createTunnelConnections 1 +createTunnelConnections 8 + +sleep 300