Improve monitor and implement server statistics

This commit is contained in:
Simon Stürz 2018-09-04 21:02:30 +02:00
parent 6869b18ad9
commit 2173d8e61f
12 changed files with 168 additions and 55 deletions

View File

@ -56,6 +56,8 @@ void AwsAuthenticator::onAuthenticationProcessFinished(Authenticator::Authentica
qCDebug(dcAuthentication()) << name() << reply->proxyClient() << "finished with error" << error;
}
reply->proxyClient()->setUserName(userInformation.email());
setReplyError(reply, error);
setReplyFinished(reply);
}

View File

@ -43,6 +43,8 @@ AuthenticationReply *DummyAuthenticator::authenticate(ProxyClient *proxyClient)
qCWarning(dcAuthentication()) << "Attention: This authenticator will always succeed! This is a security risk and was explicitly enabled!";
AuthenticationReply *reply = createAuthenticationReply(proxyClient, this);
proxyClient->setUserName("dummy@example.com");
setReplyError(reply, AuthenticationErrorNoError);
setReplyFinished(reply);
return reply;

View File

@ -157,7 +157,13 @@ MonitorServer *Engine::monitorServer() const
Engine::Engine(QObject *parent) :
QObject(parent)
{
m_lastTimeStamp = QDateTime::currentDateTime().toMSecsSinceEpoch();
m_timer = new QTimer(this);
m_timer->setSingleShot(false);
m_timer->setInterval(50);
connect(m_timer, &QTimer::timeout, this, &Engine::onTimerTick);
}
Engine::~Engine()
@ -165,6 +171,31 @@ Engine::~Engine()
stop();
}
QVariantMap Engine::createServerStatistic()
{
QVariantMap monitorData;
monitorData.insert("serverName", m_configuration->serverName());
monitorData.insert("serverVersion", SERVER_VERSION_STRING);
monitorData.insert("apiVersion", API_VERSION_STRING);
monitorData.insert("proxyStatistic", proxyServer()->currentStatistics());
return monitorData;
}
void Engine::onTimerTick()
{
qint64 timestamp = QDateTime::currentDateTime().toMSecsSinceEpoch();
qint64 deltaTime = timestamp - m_lastTimeStamp;
m_lastTimeStamp = timestamp;
m_currentTimeCounter += deltaTime;
if (m_currentTimeCounter >= 1000) {
// One second passed, do second tick
m_proxyServer->tick();
m_monitorServer->updateClients(createServerStatistic());
m_currentTimeCounter = 0;
}
}
void Engine::clean()
{
if (m_monitorServer) {
@ -195,9 +226,14 @@ void Engine::setRunning(bool running)
if (m_running == running)
return;
//qCDebug(dcEngine()) << "----------------------------------------------------------";
qCDebug(dcEngine()) << "Engine is" << (running ? "now running." : "not running any more.");
//qCDebug(dcEngine()) << "----------------------------------------------------------";
if (running) {
m_timer->start();
} else {
m_timer->stop();
}
m_running = running;
emit runningChanged(m_running);
}

View File

@ -23,7 +23,9 @@
#define ENGINE_H
#include <QUrl>
#include <QTimer>
#include <QObject>
#include <QDateTime>
#include <QHostAddress>
#include <QSslConfiguration>
@ -66,6 +68,11 @@ private:
~Engine();
static Engine *s_instance;
QTimer *m_timer = nullptr;
qint64 m_lastTimeStamp = 0;
int m_currentTimeCounter = 0;
qint64 m_runTime = 0;
bool m_running = false;
bool m_developerMode = false;
@ -75,10 +82,13 @@ private:
WebSocketServer *m_webSocketServer = nullptr;
MonitorServer *m_monitorServer = nullptr;
QVariantMap createServerStatistic();
signals:
void runningChanged(bool running);
private slots:
void onTimerTick();
void clean();
void setRunning(bool running);

View File

@ -32,10 +32,7 @@ MonitorServer::MonitorServer(const QString &serverName, QObject *parent) :
QObject(parent),
m_serverName(serverName)
{
m_timer = new QTimer(this);
m_timer->setInterval(1000);
m_timer->setSingleShot(false);
connect(m_timer, &QTimer::timeout, this, &MonitorServer::onTimeout);
}
MonitorServer::~MonitorServer()
@ -51,36 +48,12 @@ bool MonitorServer::running() const
return m_server->isListening();
}
QVariantMap MonitorServer::createMonitorData()
{
QVariantMap monitorData;
monitorData.insert("serverName", Engine::instance()->configuration()->serverName());
monitorData.insert("serverVersion", SERVER_VERSION_STRING);
monitorData.insert("apiVersion", API_VERSION_STRING);
monitorData.insert("proxyStatistic", Engine::instance()->proxyServer()->currentStatistics());
return monitorData;
}
void MonitorServer::sendMonitorData(QLocalSocket *clientConnection, const QVariantMap &dataMap)
{
clientConnection->write(QJsonDocument::fromVariant(dataMap).toJson(QJsonDocument::Compact) + '\n');
clientConnection->flush();
}
void MonitorServer::onTimeout()
{
// If no client left or no server running, stop the timer
if (m_clients.isEmpty() || !m_server)
m_timer->stop();
QVariantMap dataMap = createMonitorData();
// Send each monitor the current data
foreach (QLocalSocket *clientConnection, m_clients) {
sendMonitorData(clientConnection, dataMap);
}
}
void MonitorServer::onMonitorConnected()
{
QLocalSocket *clientConnection = m_server->nextPendingConnection();
@ -89,12 +62,6 @@ void MonitorServer::onMonitorConnected()
m_clients.append(clientConnection);
qCDebug(dcMonitorServer()) << "New monitor connected.";
if (!m_timer->isActive()) {
// Send the data right the way
onTimeout();
m_timer->start();
}
}
void MonitorServer::onMonitorDisconnected()
@ -131,7 +98,6 @@ void MonitorServer::startServer()
void MonitorServer::stopServer()
{
m_timer->stop();
if (!m_server)
return;
@ -145,4 +111,12 @@ void MonitorServer::stopServer()
m_server = nullptr;
}
void MonitorServer::updateClients(const QVariantMap &dataMap)
{
// Send each monitor the current data
foreach (QLocalSocket *clientConnection, m_clients) {
sendMonitorData(clientConnection, dataMap);
}
}
}

View File

@ -41,20 +41,19 @@ public:
private:
QString m_serverName;
QLocalServer *m_server = nullptr;
QTimer *m_timer = nullptr;
QList<QLocalSocket *> m_clients;
QVariantMap createMonitorData();
void sendMonitorData(QLocalSocket *clientConnection, const QVariantMap &dataMap);
private slots:
void onTimeout();
void onMonitorConnected();
void onMonitorDisconnected();
public slots:
void startServer();
void stopServer();
void updateClients(const QVariantMap &dataMap);
};
}

View File

@ -88,6 +88,16 @@ void ProxyClient::setTunnelConnected(bool isTunnelConnected)
}
}
QString ProxyClient::userName() const
{
return m_userName;
}
void ProxyClient::setUserName(const QString &userName)
{
m_userName = userName;
}
TransportInterface *ProxyClient::interface() const
{
return m_interface;
@ -133,6 +143,26 @@ void ProxyClient::setNonce(const QString &nonce)
m_nonce = nonce;
}
quint64 ProxyClient::rxDataCount() const
{
return m_rxDataCount;
}
void ProxyClient::addRxDataCount(int dataCount)
{
m_rxDataCount += static_cast<quint64>(dataCount);
}
quint64 ProxyClient::txDataCount() const
{
return m_txDataCount;
}
void ProxyClient::addTxDataCount(int dataCount)
{
m_txDataCount += static_cast<quint64>(dataCount);
}
void ProxyClient::sendData(const QByteArray &data)
{
if (!m_interface)
@ -157,6 +187,7 @@ QDebug operator<<(QDebug debug, ProxyClient *proxyClient)
}
debug.nospace() << proxyClient->interface()->serverName();
debug.nospace() << ", " << proxyClient->clientId().toString();
debug.nospace() << ", " << proxyClient->userName();
debug.nospace() << ", " << proxyClient->peerAddress().toString();
debug.nospace() << ", " << proxyClient->creationTimeString() << ") ";
return debug;

View File

@ -51,6 +51,9 @@ public:
bool isTunnelConnected() const;
void setTunnelConnected(bool isTunnelConnected);
QString userName() const;
void setUserName(const QString &userName);
TransportInterface *interface() const;
// Properties from auth request
@ -66,6 +69,12 @@ public:
QString nonce() const;
void setNonce(const QString &nonce);
quint64 rxDataCount() const;
void addRxDataCount(int dataCount);
quint64 txDataCount() const;
void addTxDataCount(int dataCount);
// Actions for this client
void sendData(const QByteArray &data);
void killConnection(const QString &reason);
@ -86,6 +95,11 @@ private:
QString m_token;
QString m_nonce;
QString m_userName;
quint64 m_rxDataCount = 0;
quint64 m_txDataCount = 0;
signals:
void authenticated();
void tunnelConnected();

View File

@ -65,6 +65,7 @@ QVariantMap ProxyServer::currentStatistics()
QVariantMap statisticsMap;
statisticsMap.insert("clientCount", m_proxyClients.count());
statisticsMap.insert("tunnelCount", m_tunnels.count());
statisticsMap.insert("troughput", m_troughput);
// Create client list
QVariantList clientList;
@ -76,7 +77,10 @@ QVariantMap ProxyServer::currentStatistics()
clientMap.insert("authenticated", client->isAuthenticated());
clientMap.insert("tunnelConnected", client->isTunnelConnected());
clientMap.insert("name", client->name());
clientMap.insert("userName", client->userName());
clientMap.insert("uuid", client->uuid());
clientMap.insert("rxDataCount", client->rxDataCount());
clientMap.insert("txDataCount", client->txDataCount());
clientList.append(clientMap);
}
statisticsMap.insert("clients", clientList);
@ -242,6 +246,11 @@ void ProxyServer::onClientDataAvailable(const QUuid &clientId, const QByteArray
Q_ASSERT_X(remoteClient, "ProxyServer", "Tunnel existing but not tunnel client available");
Q_ASSERT_X(m_tunnels.contains(proxyClient->token()), "ProxyServer", "Tunnel connect but not existing");
// Calculate server statisitcs
m_troughputCounter += data.count();
proxyClient->addRxDataCount(data.count());
remoteClient->addTxDataCount(data.count());
qCDebug(dcProxyServerTraffic()) << "Pipe tunnel data:";
qCDebug(dcProxyServerTraffic()) << " --> from" << proxyClient;
qCDebug(dcProxyServerTraffic()) << " --> to" << remoteClient;
@ -338,4 +347,10 @@ void ProxyServer::stopServer()
setRunning(false);
}
void ProxyServer::tick()
{
m_troughput = m_troughputCounter;
m_troughputCounter = 0;
}
}

View File

@ -63,6 +63,10 @@ private:
// Token, Tunnel
QHash<QString, TunnelConnection> m_tunnels;
// Statistic measurments
int m_troughput = 0;
int m_troughputCounter = 0;
void setRunning(bool running);
ProxyClient *getRemoteClient(ProxyClient *proxyClient);
@ -84,6 +88,8 @@ public slots:
void startServer();
void stopServer();
void tick();
};
}

View File

@ -105,6 +105,22 @@ QString TerminalWindow::getDurationString(uint timestamp)
return res.sprintf("%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;
@ -146,12 +162,13 @@ void TerminalWindow::drawWindowBorder(WINDOW *window)
void TerminalWindow::paintHeader()
{
QString headerString = QString(" Server: %1 %2 | API version %3 | Clients: %4 | Tunnels %5 | %6 ")
QString headerString = QString(" Server: %1 %2 | API version %3 | Clients: %4 | Tunnels %5 | %6 | %7 ")
.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("tunnelCount", 0).toInt())
.arg(humanReadableTraffic(m_dataMap.value("proxyStatistic").toMap().value("troughput", 0).toInt()) + " / s", - 13)
.arg((m_view == ViewClients ? "-- Clients --" : "-- Tunnels --"));
int delta = m_terminalSizeX - headerString.count();
@ -164,7 +181,6 @@ void TerminalWindow::paintHeader()
wattron(m_headerWindow, A_BOLD | COLOR_PAIR(1));
mvwprintw(m_headerWindow, 1, 2, convertString(headerString));
wattroff(m_headerWindow, A_BOLD | COLOR_PAIR(1));
drawWindowBorder(m_headerWindow);
}
void TerminalWindow::paintContentClients()
@ -179,11 +195,15 @@ void TerminalWindow::paintContentClients()
uint timeStamp = clientMap.value("timestamp").toUInt();
QString clientConnectionTime = QDateTime::fromTime_t(timeStamp).toString("dd.MM.yyyy hh:mm:ss");
QString clientPrint = QString("%1 | %2 | %3 | %4 | %5 | %6 | %7")
int rxDataCountBytes = clientMap.value("rxDataCount").toInt();
int txDataCountBytes = clientMap.value("txDataCount").toInt();
QString clientPrint = QString("%1 | %2 | %3 | RX: %4 | TX: %5 | %6 | %7 | %8")
.arg(clientConnectionTime)
.arg(clientMap.value("duration").toString())
.arg(clientMap.value("address").toString(), - 16)
.arg(clientMap.value("uuid").toString())
.arg(humanReadableTraffic(rxDataCountBytes), - 10)
.arg(humanReadableTraffic(txDataCountBytes), - 10)
.arg((clientMap.value("authenticated").toBool() ? "A" : "-"))
.arg((clientMap.value("tunnelConnected").toBool() ? "T" : "-"))
.arg(clientMap.value("name").toString(), -30);
@ -192,8 +212,6 @@ void TerminalWindow::paintContentClients()
i++;
}
// Draw borders
drawWindowBorder(m_contentWindow);
}
void TerminalWindow::paintContentTunnels()
@ -209,21 +227,21 @@ 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")
QString tunnelPrint = QString("%1 | %2 | %3 | %4 | %5 (%6) <---> %7 (%8)")
.arg(tunnelConnectionTime)
.arg(clientOne.value("address").toString(), - 16)
.arg(getDurationString(timeStamp))
.arg(humanReadableTraffic(clientOne.value("rxDataCount").toInt() + clientOne.value("txDataCount").toInt()), - 10)
.arg(clientOne.value("userName").toString())
.arg(clientOne.value("name").toString())
.arg(" <---> ")
.arg(clientTwo.value("address").toString(), - 16)
.arg(clientOne.value("address").toString())
.arg(clientTwo.value("name").toString())
.arg(clientTwo.value("address").toString())
;
mvwprintw(m_contentWindow, i, 2, convertString(tunnelPrint));
i++;
}
// Draw borders
drawWindowBorder(m_contentWindow);
}
void TerminalWindow::eventLoop()
@ -232,7 +250,7 @@ void TerminalWindow::eventLoop()
werase(m_headerWindow);
werase(m_contentWindow);
resizeWindow();
resizeWindow();
int keyInteger = getch();
switch (keyInteger) {
@ -268,9 +286,13 @@ void TerminalWindow::eventLoop()
break;
}
// Draw borders
drawWindowBorder(m_headerWindow);
drawWindowBorder(m_contentWindow);
wrefresh(m_headerWindow);
wrefresh(m_contentWindow);
//refresh();
refresh();
// Reinvoke the method for the next event loop run
//QMetaObject::invokeMethod(this, "eventLoop", Qt::QueuedConnection);

View File

@ -59,6 +59,8 @@ private:
const char *convertString(const QString &string);
QString getDurationString(uint timestamp);
QString humanReadableTraffic(int bytes);
// content paint methods
void resizeWindow();
void drawWindowBorder(WINDOW *window);