Add monitor non interactive mode and add traffic counter for tunnel proxy

This commit is contained in:
Simon Stürz 2022-12-15 23:30:23 +01:00
parent 1694a43098
commit 8081c7804e
8 changed files with 253 additions and 49 deletions

View File

@ -328,6 +328,7 @@ void TunnelProxyServer::onClientDataAvailable(const QUuid &clientId, const QByte
}
qCDebug(dcTunnelProxyServerTraffic()) << "Client data available" << tunnelProxyClient << qUtf8Printable(data);
tunnelProxyClient->addRxDataCount(data.count());
if (tunnelProxyClient->type() == TunnelProxyClient::TypeClient) {
// Send the data to the server using slip encoded frame
@ -344,8 +345,11 @@ void TunnelProxyServer::onClientDataAvailable(const QUuid &clientId, const QByte
frame.socketAddress = clientConnection->socketAddress();
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)));
QByteArray rawData = SlipDataProcessor::serializeData(SlipDataProcessor::buildFrame(frame));
clientConnection->serverConnection()->transportClient()->sendData(rawData);
clientConnection->serverConnection()->transportClient()->addTxDataCount(rawData.count());
m_troughputCounter += data.count();
} else if (tunnelProxyClient->type() == TunnelProxyClient::TypeServer) {
// Data coming from a connected server connection
if (tunnelProxyClient->slipEnabled()) {
@ -376,7 +380,8 @@ 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();
clientConnection->transportClient()->addTxDataCount(frame.data.count());
m_troughputCounter += frame.data.count();
}
}
} else {

View File

@ -1,6 +1,6 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*
* Copyright 2013 - 2020, nymea GmbH
* Copyright 2013 - 2022, nymea GmbH
* Contact: contact@nymea.io
*
* This file is part of nymea.
@ -33,6 +33,7 @@
#include <QCommandLineOption>
#include "monitor.h"
#include "noninteractivemonitor.h"
#include "../version.h"
int main(int argc, char *argv[])
@ -58,6 +59,10 @@ int main(int argc, char *argv[])
QCommandLineOption socketOption(QStringList() << "s" << "socket", "The socket descriptor for the nymea-remoteproxy monitor socket. Default is /tmp/nymea-remoteproxy-monitor.sock", "socket");
socketOption.setDefaultValue("/tmp/nymea-remoteproxy-monitor.sock");
parser.addOption(socketOption);
QCommandLineOption noninteractiveOption(QStringList() << "n" << "non-interactive", "Connect to the server, list all data and close the connection. This works only for the tunnelproxy.");
parser.addOption(noninteractiveOption);
parser.process(application);
// Check socket file
@ -72,7 +77,13 @@ int main(int argc, char *argv[])
exit(1);
}
Monitor monitor(parser.value(socketOption));
if (parser.isSet(noninteractiveOption)) {
NonInteractiveMonitor *monitor = new NonInteractiveMonitor(parser.value(socketOption));
Q_UNUSED(monitor);
} else {
Monitor *monitor = new Monitor(parser.value(socketOption));
Q_UNUSED(monitor);
}
return application.exec();
}

View File

@ -5,11 +5,14 @@ TEMPLATE = app
HEADERS += \
monitorclient.h \
noninteractivemonitor.h \
terminalwindow.h \
monitor.h
monitor.h \
utils.h
SOURCES += main.cpp \
monitorclient.cpp \
noninteractivemonitor.cpp \
terminalwindow.cpp \
monitor.cpp

View File

@ -0,0 +1,101 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*
* 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 <https://www.gnu.org/licenses/>.
*
* 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 "noninteractivemonitor.h"
#include "utils.h"
#include <QDebug>
NonInteractiveMonitor::NonInteractiveMonitor(const QString &serverName, QObject *parent)
: QObject{parent}
{
m_monitorClient = new MonitorClient(serverName, this);
connect(m_monitorClient, &MonitorClient::connected, this, &NonInteractiveMonitor::onConnected);
m_monitorClient->connectMonitor();
}
void NonInteractiveMonitor::onConnected()
{
connect(m_monitorClient, &MonitorClient::dataReady, this, [](const QVariantMap &dataMap){
qInfo().noquote() << "---------------------------------------------------------------------";
qInfo().noquote() << "Server name:" << dataMap.value("serverName", "-").toString();
qInfo().noquote() << "Server version:" << dataMap.value("serverVersion", "-").toString();
qInfo().noquote() << "API version:" << dataMap.value("apiVersion", "-").toString();
qInfo().noquote() << "Total client count:" << dataMap.value("tunnelProxyStatistic").toMap().value("totalClientCount", 0).toInt();
qInfo().noquote() << "Server connections:" << dataMap.value("tunnelProxyStatistic").toMap().value("serverConnectionsCount", 0).toInt();
qInfo().noquote() << "Client connections:" << dataMap.value("tunnelProxyStatistic").toMap().value("clientConnectionsCount", 0).toInt();
qInfo().noquote() << "Data troughput:" << Utils::humanReadableTraffic(dataMap.value("tunnelProxyStatistic").toMap().value("troughput", 0).toInt()) + " / s";
qInfo().noquote() << "---------------------------------------------------------------------";
QVariantMap tunnelProxyMap = dataMap.value("tunnelProxyStatistic").toMap();
foreach (const QVariant &serverVariant, tunnelProxyMap.value("tunnelConnections").toList()) {
QVariantMap serverMap = serverVariant.toMap();
QVariantList clientList = serverMap.value("clientConnections").toList();
// Server line
QString serverConnectionTime = QDateTime::fromTime_t(serverMap.value("timestamp").toUInt()).toString("dd.MM.yyyy hh:mm:ss");
QString serverLinePrint;
if (clientList.isEmpty()) {
serverLinePrint.prepend("├──");
} else {
serverLinePrint.prepend("├┬─");
}
serverLinePrint += QString("%1 | %2 RX: %3 TX: %4 | %5")
.arg(serverConnectionTime)
.arg(serverMap.value("address").toString(), - 15)
.arg(Utils::humanReadableTraffic(serverMap.value("rxDataCount").toInt()), - 9)
.arg(Utils::humanReadableTraffic(serverMap.value("txDataCount").toInt()), - 9)
.arg(serverMap.value("name").toString());
qInfo().noquote() << serverLinePrint;
for (int cc = 0; cc < clientList.count(); cc++) {
QVariantMap clientMap = clientList.at(cc).toMap();
QString clientLinePrint;
if (cc >= clientList.count() - 1) {
clientLinePrint.append("│└─");
} else {
clientLinePrint.prepend("│├─");
}
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(), - 15)
.arg(Utils::humanReadableTraffic(serverMap.value("rxDataCount").toInt()), - 9)
.arg(Utils::humanReadableTraffic(serverMap.value("txDataCount").toInt()), - 9)
.arg(clientMap.value("name").toString(), -30);
qInfo().noquote() << clientLinePrint;
}
}
exit(0);
});
}

View File

@ -0,0 +1,48 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*
* 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 <https://www.gnu.org/licenses/>.
*
* 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 NONINTERACTIVEMONITOR_H
#define NONINTERACTIVEMONITOR_H
#include <QObject>
#include "monitorclient.h"
class NonInteractiveMonitor : public QObject
{
Q_OBJECT
public:
explicit NonInteractiveMonitor(const QString &serverName, QObject *parent = nullptr);
private:
MonitorClient *m_monitorClient = nullptr;
private slots:
void onConnected();
};
#endif // NONINTERACTIVEMONITOR_H

View File

@ -26,6 +26,7 @@
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#include "terminalwindow.h"
#include "utils.h"
#include <QTime>
#include <QDebug>
@ -95,33 +96,6 @@ TerminalWindow::~TerminalWindow()
cleanup();
}
QString TerminalWindow::getDurationString(uint timestamp)
{
uint duration = QDateTime::currentDateTimeUtc().toTime_t() - timestamp;
int seconds = static_cast<int>(duration % 60);
duration /= 60;
int minutes = static_cast<int>(duration % 60);
duration /= 60;
int hours = static_cast<int>(duration % 24);
return QString::asprintf("%02d:%02d:%02d", hours, minutes, seconds);
}
QString TerminalWindow::humanReadableTraffic(int bytes)
{
double dataCount = bytes;
QStringList list;
list << "KB" << "MB" << "GB" << "TB";
QStringListIterator i(list);
QString unit("B");
while(dataCount >= 1024.0 && i.hasNext()) {
unit = i.next();
dataCount /= 1024.0;
}
return QString().setNum(dataCount,'f',2) + " " + unit;
}
void TerminalWindow::resizeWindow()
{
int terminalSizeX;
@ -196,8 +170,8 @@ void TerminalWindow::paintHeader()
.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(Utils::humanReadableTraffic(m_dataMap.value("proxyStatistic").toMap().value("troughput", 0).toInt()) + " / s", - 13)
.arg(Utils::humanReadableTraffic(m_dataMap.value("proxyStatistic").toMap().value("total").toMap().value("totalTraffic").toInt()), - 10)
.arg(windowName);
break;
case ViewTunnels:
@ -210,8 +184,8 @@ void TerminalWindow::paintHeader()
.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(Utils::humanReadableTraffic(m_dataMap.value("proxyStatistic").toMap().value("troughput", 0).toInt()) + " / s", - 13)
.arg(Utils::humanReadableTraffic(m_dataMap.value("proxyStatistic").toMap().value("total").toMap().value("totalTraffic").toInt()), - 10)
.arg(windowName);
break;
case ViewTunnelProxy:
@ -223,7 +197,7 @@ void TerminalWindow::paintHeader()
.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(Utils::humanReadableTraffic(m_dataMap.value("tunnelProxyStatistic").toMap().value("troughput", 0).toInt()) + " / s", - 13)
.arg(windowName);
break;
}
@ -258,8 +232,8 @@ void TerminalWindow::paintContentClients()
.arg(clientConnectionTime)
.arg(clientMap.value("duration").toString())
.arg(clientMap.value("address").toString(), - 16)
.arg(humanReadableTraffic(rxDataCountBytes), - 10)
.arg(humanReadableTraffic(txDataCountBytes), - 10)
.arg(Utils::humanReadableTraffic(rxDataCountBytes), - 10)
.arg(Utils::humanReadableTraffic(txDataCountBytes), - 10)
.arg((clientMap.value("authenticated").toBool() ? "A" : "-"))
.arg((clientMap.value("tunnelConnected").toBool() ? "T" : "-"))
.arg(clientMap.value("name").toString(), -30);
@ -284,8 +258,8 @@ void TerminalWindow::paintContentTunnels()
QString tunnelPrint = QString("%1 | %2 | %3 | %4 | %5 (%6) <---> %7 (%8)")
.arg(tunnelConnectionTime)
.arg(getDurationString(timeStamp))
.arg(humanReadableTraffic(clientOne.value("rxDataCount").toInt() + clientOne.value("txDataCount").toInt()), - 10)
.arg(Utils::getDurationString(timeStamp))
.arg(Utils::humanReadableTraffic(clientOne.value("rxDataCount").toInt() + clientOne.value("txDataCount").toInt()), - 10)
.arg(clientOne.value("userName").toString())
.arg(clientOne.value("name").toString())
.arg(clientOne.value("address").toString())
@ -312,8 +286,8 @@ void TerminalWindow::paintContentTunnelProxy()
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(Utils::humanReadableTraffic(rxDataCountBytes), - 10)
.arg(Utils::humanReadableTraffic(txDataCountBytes), - 10)
.arg(serverMap.value("name").toString(), -30);
QVariantList clientList = serverMap.value("clientConnections").toList();
@ -343,8 +317,8 @@ void TerminalWindow::paintContentTunnelProxy()
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(Utils::humanReadableTraffic(clientMap.value("rxDataCount").toInt()), - 10)
.arg(Utils::humanReadableTraffic(clientMap.value("txDataCount").toInt()), - 10)
.arg(clientMap.value("name").toString(), -30);
mvwprintw(m_contentWindow, i, 6, "%s", clientLinePrint.trimmed().toLatin1().constData());
@ -437,7 +411,7 @@ void TerminalWindow::refreshWindow(const QVariantMap &dataMap)
foreach (const QVariant &clientVariant, statisticMap.value("clients").toList()) {
QVariantMap clientMap = clientVariant.toMap();
clientMap.insert("duration", getDurationString(clientMap.value("timestamp").toUInt()));
clientMap.insert("duration", Utils::getDurationString(clientMap.value("timestamp").toUInt()));
m_clientHash.insert(clientMap.value("id").toString(), clientMap);
}
}

View File

@ -68,9 +68,6 @@ private:
QVariantMap m_dataMap;
QHash<QString, QVariantMap> m_clientHash;
QString getDurationString(uint timestamp);
QString humanReadableTraffic(int bytes);
// content paint methods
void resizeWindow();

65
monitor/utils.h Normal file
View File

@ -0,0 +1,65 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*
* 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 <https://www.gnu.org/licenses/>.
*
* 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 UTILS_H
#define UTILS_H
#include <QString>
#include <QDateTime>
class Utils {
public:
Utils() = default;
inline static QString getDurationString(uint timestamp) {
uint duration = QDateTime::currentDateTimeUtc().toTime_t() - timestamp;
int seconds = static_cast<int>(duration % 60);
duration /= 60;
int minutes = static_cast<int>(duration % 60);
duration /= 60;
int hours = static_cast<int>(duration % 24);
return QString::asprintf("%02d:%02d:%02d", hours, minutes, seconds);
}
inline static QString humanReadableTraffic(int bytes) {
double dataCount = bytes;
QStringList list;
list << "KB" << "MB" << "GB" << "TB";
QStringListIterator i(list);
QString unit("B");
while(dataCount >= 1024.0 && i.hasNext()) {
unit = i.next();
dataCount /= 1024.0;
}
return QString().setNum(dataCount,'f',2) + " " + unit;
}
};
#endif // UTILS_H