Extend monitor and add test script for connections

This commit is contained in:
Simon Stürz 2022-01-11 09:01:54 +01:00
parent 97514a9504
commit 1ca3119995
8 changed files with 242 additions and 42 deletions

View File

@ -56,7 +56,9 @@ bool MonitorServer::running() const
void MonitorServer::sendMonitorData(QLocalSocket *clientConnection, const QVariantMap &dataMap) 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(); clientConnection->flush();
} }

View File

@ -201,6 +201,7 @@ QVariantMap TunnelProxyServer::currentStatistics()
statisticsMap.insert("totalClientCount", m_proxyClients.count()); statisticsMap.insert("totalClientCount", m_proxyClients.count());
statisticsMap.insert("serverConnectionsCount", m_tunnelProxyServerConnections.count()); statisticsMap.insert("serverConnectionsCount", m_tunnelProxyServerConnections.count());
statisticsMap.insert("clientConnectionsCount", m_tunnelProxyClientConnections.count()); statisticsMap.insert("clientConnectionsCount", m_tunnelProxyClientConnections.count());
statisticsMap.insert("troughput", m_troughput);
QVariantList tunnelConnections; QVariantList tunnelConnections;
foreach (TunnelProxyServerConnection *serverConnection, m_tunnelProxyServerConnections) { foreach (TunnelProxyServerConnection *serverConnection, m_tunnelProxyServerConnections) {
@ -210,6 +211,9 @@ QVariantMap TunnelProxyServer::currentStatistics()
serverMap.insert("timestamp", serverConnection->transportClient()->creationTime()); serverMap.insert("timestamp", serverConnection->transportClient()->creationTime());
serverMap.insert("name", serverConnection->transportClient()->name()); serverMap.insert("name", serverConnection->transportClient()->name());
serverMap.insert("serverUuid", serverConnection->transportClient()->uuid()); serverMap.insert("serverUuid", serverConnection->transportClient()->uuid());
serverMap.insert("rxDataCount", serverConnection->transportClient()->rxDataCount());
serverMap.insert("txDataCount", serverConnection->transportClient()->txDataCount());
QVariantList clientList; QVariantList clientList;
foreach (TunnelProxyClientConnection *clientConnection, serverConnection->clientConnections()) { foreach (TunnelProxyClientConnection *clientConnection, serverConnection->clientConnections()) {
QVariantMap clientMap; QVariantMap clientMap;
@ -218,9 +222,12 @@ QVariantMap TunnelProxyServer::currentStatistics()
clientMap.insert("timestamp", clientConnection->transportClient()->creationTime()); clientMap.insert("timestamp", clientConnection->transportClient()->creationTime());
clientMap.insert("name", clientConnection->transportClient()->name()); clientMap.insert("name", clientConnection->transportClient()->name());
clientMap.insert("clientUuid", clientConnection->transportClient()->uuid()); clientMap.insert("clientUuid", clientConnection->transportClient()->uuid());
clientMap.insert("rxDataCount", clientConnection->transportClient()->rxDataCount());
clientMap.insert("txDataCount", clientConnection->transportClient()->txDataCount());
clientList.append(clientMap); clientList.append(clientMap);
} }
serverMap.insert("clientConnections", clientList); serverMap.insert("clientConnections", clientList);
tunnelConnections.append(serverMap);
} }
statisticsMap.insert("tunnelConnections", tunnelConnections); statisticsMap.insert("tunnelConnections", tunnelConnections);
@ -248,7 +255,8 @@ void TunnelProxyServer::stopServer()
void TunnelProxyServer::tick() void TunnelProxyServer::tick()
{ {
m_troughput = m_troughputCounter;
m_troughputCounter = 0;
} }
void TunnelProxyServer::onClientConnected(const QUuid &clientId, const QHostAddress &address) void TunnelProxyServer::onClientConnected(const QUuid &clientId, const QHostAddress &address)
@ -337,7 +345,7 @@ void TunnelProxyServer::onClientDataAvailable(const QUuid &clientId, const QByte
frame.data = data; frame.data = data;
qCDebug(dcTunnelProxyServerTraffic()) << "--> Tunnel data to server socket address" << clientConnection->socketAddress() << "to" << clientConnection->serverConnection() << "\n" << 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))); clientConnection->serverConnection()->transportClient()->sendData(SlipDataProcessor::serializeData(SlipDataProcessor::buildFrame(frame)));
m_troughputCounter += data.count();
} else if (tunnelProxyClient->type() == TunnelProxyClient::TypeServer) { } else if (tunnelProxyClient->type() == TunnelProxyClient::TypeServer) {
// Data coming from a connected server connection // Data coming from a connected server connection
if (tunnelProxyClient->slipEnabled()) { 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; qCDebug(dcTunnelProxyServerTraffic()) << "--> Tunnel data from server socket" << frame.socketAddress << "to" << clientConnection << "\n" << frame.data;
clientConnection->transportClient()->sendData(frame.data); clientConnection->transportClient()->sendData(frame.data);
m_troughputCounter += data.count();
} }
} }
} else { } else {

View File

@ -95,6 +95,9 @@ private:
QHash<QUuid, TunnelProxyServerConnection *> m_tunnelProxyServerConnections; // server uuid, object QHash<QUuid, TunnelProxyServerConnection *> m_tunnelProxyServerConnections; // server uuid, object
QHash<QUuid, TunnelProxyClientConnection *> m_tunnelProxyClientConnections; // client uuid, object QHash<QUuid, TunnelProxyClientConnection *> m_tunnelProxyClientConnections; // client uuid, object
// Statistic measurments
int m_troughput = 0;
int m_troughputCounter = 0;
}; };
} }

View File

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

View File

@ -35,6 +35,9 @@
TerminalWindow::TerminalWindow(QObject *parent) : TerminalWindow::TerminalWindow(QObject *parent) :
QObject(parent) QObject(parent)
{ {
// Init view tabs
m_tabs << ViewClients << ViewTunnels << ViewTunnelProxy;
// Create main window // Create main window
m_mainWindow = initscr(); m_mainWindow = initscr();
@ -71,7 +74,9 @@ TerminalWindow::TerminalWindow(QObject *parent) :
// Draw borders // Draw borders
drawWindowBorder(m_headerWindow); drawWindowBorder(m_headerWindow);
drawWindowBorder(m_contentWindow); //drawWindowBorder(m_contentWindow);
scrollok(m_contentWindow, true);
//box(m_headerWindow, 0 , 0); //box(m_headerWindow, 0 , 0);
//box(m_contentWindow, 0 , 0); //box(m_contentWindow, 0 , 0);
@ -87,11 +92,7 @@ TerminalWindow::TerminalWindow(QObject *parent) :
TerminalWindow::~TerminalWindow() TerminalWindow::~TerminalWindow()
{ {
clear(); cleanup();
delwin(m_headerWindow);
delwin(m_contentWindow);
delwin(m_mainWindow);
endwin();
} }
const char *TerminalWindow::convertString(const QString &string) 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() void TerminalWindow::paintHeader()
{ {
QString headerString = QString(" Server: %1 (%2) | API: %3 | Clients: %4, %5 | Tunnels: %6, %7 | %8 | %9 | %10") QString windowName;
.arg(m_dataMap.value("serverName", "-").toString()) QString headerString;
.arg(m_dataMap.value("serverVersion", "-").toString()) switch (m_view) {
.arg(m_dataMap.value("apiVersion", "-").toString()) case ViewClients:
.arg(m_dataMap.value("proxyStatistic").toMap().value("clientCount", 0).toInt()) windowName = "-- Clients --";
.arg(m_dataMap.value("proxyStatistic").toMap().value("total").toMap().value("totalClientCount").toInt()) headerString = QString(" Server: %1 (%2) | API: %3 | Clients: %4, %5 | Tunnels: %6, %7 | %8 | %9 | %10")
.arg(m_dataMap.value("proxyStatistic").toMap().value("tunnelCount", 0).toInt()) .arg(m_dataMap.value("serverName", "-").toString())
.arg(m_dataMap.value("proxyStatistic").toMap().value("total").toMap().value("totalTunnelCount").toInt()) .arg(m_dataMap.value("serverVersion", "-").toString())
.arg(humanReadableTraffic(m_dataMap.value("proxyStatistic").toMap().value("troughput", 0).toInt()) + " / s", - 13) .arg(m_dataMap.value("apiVersion", "-").toString())
.arg(humanReadableTraffic(m_dataMap.value("proxyStatistic").toMap().value("total").toMap().value("totalTraffic").toInt()), - 10) .arg(m_dataMap.value("proxyStatistic").toMap().value("clientCount", 0).toInt())
.arg((m_view == ViewClients ? "-- Clients --" : "-- Tunnels --")); .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(); int delta = m_terminalSizeX - headerString.count();
@ -185,10 +239,9 @@ void TerminalWindow::paintHeader()
for (int i = 0; i < delta; i++) for (int i = 0; i < delta; i++)
headerString.append(" "); 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)); 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() void TerminalWindow::paintContentClients()
@ -219,7 +272,6 @@ void TerminalWindow::paintContentClients()
mvwprintw(m_contentWindow, i, 2, convertString(clientPrint.trimmed())); mvwprintw(m_contentWindow, i, 2, convertString(clientPrint.trimmed()));
i++; i++;
} }
} }
void TerminalWindow::paintContentTunnels() void TerminalWindow::paintContentTunnels()
@ -235,7 +287,6 @@ void TerminalWindow::paintContentTunnels()
uint timeStamp = tunnelMap.value("timestamp").toUInt(); uint timeStamp = tunnelMap.value("timestamp").toUInt();
QString tunnelConnectionTime = QDateTime::fromTime_t(timeStamp).toString("dd.MM.yyyy hh:mm:ss"); QString tunnelConnectionTime = QDateTime::fromTime_t(timeStamp).toString("dd.MM.yyyy hh:mm:ss");
QString tunnelPrint = QString("%1 | %2 | %3 | %4 | %5 (%6) <---> %7 (%8)") QString tunnelPrint = QString("%1 | %2 | %3 | %4 | %5 (%6) <---> %7 (%8)")
.arg(tunnelConnectionTime) .arg(tunnelConnectionTime)
.arg(getDurationString(timeStamp)) .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() void TerminalWindow::eventLoop()
{ {
werase(m_headerWindow); werase(m_headerWindow);
werase(m_contentWindow); werase(m_contentWindow);
@ -263,17 +378,13 @@ void TerminalWindow::eventLoop()
int keyInteger = getch(); int keyInteger = getch();
switch (keyInteger) { switch (keyInteger) {
case KEY_LEFT: case KEY_LEFT:
m_view = ViewClients; moveTabLeft();
break; break;
case KEY_RIGHT: case KEY_RIGHT:
m_view = ViewTunnels; moveTabRight();
break; break;
case 27: // Esc case 27: // Esc
clear(); cleanup();
delwin(m_headerWindow);
delwin(m_contentWindow);
delwin(m_mainWindow);
endwin();
qDebug() << "Closing window monitor. Have a nice day!"; qDebug() << "Closing window monitor. Have a nice day!";
exit(0); exit(0);
break; break;
@ -292,11 +403,25 @@ void TerminalWindow::eventLoop()
case ViewTunnels: case ViewTunnels:
paintContentTunnels(); paintContentTunnels();
break; 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 // Draw borders
drawWindowBorder(m_headerWindow); drawWindowBorder(m_headerWindow);
drawWindowBorder(m_contentWindow); //drawWindowBorder(m_contentWindow);
wrefresh(m_headerWindow); wrefresh(m_headerWindow);
wrefresh(m_contentWindow); wrefresh(m_contentWindow);

View File

@ -41,7 +41,8 @@ public:
enum View { enum View {
ViewClients, ViewClients,
ViewTunnels ViewTunnels,
ViewTunnelProxy
}; };
Q_ENUM(View) Q_ENUM(View)
@ -58,6 +59,11 @@ private:
int m_terminalSizeY = 0; int m_terminalSizeY = 0;
View m_view = ViewClients; View m_view = ViewClients;
int m_tunnelProxyScollIndex = 0;
// Tabs
QList<View> m_tabs;
QVariantMap m_dataMap; QVariantMap m_dataMap;
QHash<QString, QVariantMap> m_clientHash; QHash<QString, QVariantMap> m_clientHash;
@ -70,11 +76,15 @@ private:
// content paint methods // content paint methods
void resizeWindow(); void resizeWindow();
void drawWindowBorder(WINDOW *window); void drawWindowBorder(WINDOW *window);
void moveTabRight();
void moveTabLeft();
void paintHeader(); void paintHeader();
void paintContentClients(); void paintContentClients();
void paintContentTunnels(); void paintContentTunnels();
void paintContentTunnelProxy();
signals: void cleanup();
private slots: private slots:
void eventLoop(); void eventLoop();

View File

@ -55,10 +55,6 @@ static void catchUnixSignals(const std::vector<int>& quitSignals, const std::vec
case SIGHUP: case SIGHUP:
qCDebug(dcApplication()) << "Cought SIGHUP quit signal..."; qCDebug(dcApplication()) << "Cought SIGHUP quit signal...";
break; break;
case SIGSEGV: {
qCDebug(dcApplication()) << "Cought SIGSEGV signal. Segmentation fault!";
exit(1);
}
default: default:
break; break;
} }
@ -82,5 +78,5 @@ static void catchUnixSignals(const std::vector<int>& quitSignals, const std::vec
RemoteProxyServerApplication::RemoteProxyServerApplication(int &argc, char **argv) : RemoteProxyServerApplication::RemoteProxyServerApplication(int &argc, char **argv) :
QCoreApplication(argc, argv) QCoreApplication(argc, argv)
{ {
catchUnixSignals({SIGQUIT, SIGINT, SIGTERM, SIGHUP, SIGSEGV}); catchUnixSignals({SIGQUIT, SIGINT, SIGTERM, SIGHUP});
} }

View File

@ -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