Extend monitor and add test script for connections
This commit is contained in:
parent
97514a9504
commit
1ca3119995
@ -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();
|
||||
}
|
||||
|
||||
|
||||
@ -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 {
|
||||
|
||||
@ -95,6 +95,9 @@ private:
|
||||
QHash<QUuid, TunnelProxyServerConnection *> m_tunnelProxyServerConnections; // server uuid, object
|
||||
QHash<QUuid, TunnelProxyClientConnection *> m_tunnelProxyClientConnections; // client uuid, object
|
||||
|
||||
// Statistic measurments
|
||||
int m_troughput = 0;
|
||||
int m_troughputCounter = 0;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@ -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 <developer@nymea.io>\n")
|
||||
"Copyright %3 2022 nymea GmbH <developer@nymea.io>\n")
|
||||
.arg(SERVER_VERSION_STRING)
|
||||
.arg(API_VERSION_STRING)
|
||||
.arg(QChar(0xA9)));
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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<View> m_tabs;
|
||||
|
||||
QVariantMap m_dataMap;
|
||||
QHash<QString, QVariantMap> 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();
|
||||
|
||||
@ -55,10 +55,6 @@ static void catchUnixSignals(const std::vector<int>& 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<int>& quitSignals, const std::vec
|
||||
RemoteProxyServerApplication::RemoteProxyServerApplication(int &argc, char **argv) :
|
||||
QCoreApplication(argc, argv)
|
||||
{
|
||||
catchUnixSignals({SIGQUIT, SIGINT, SIGTERM, SIGHUP, SIGSEGV});
|
||||
catchUnixSignals({SIGQUIT, SIGINT, SIGTERM, SIGHUP});
|
||||
}
|
||||
|
||||
55
tests/scripts/create-many-connections.sh
Executable file
55
tests/scripts/create-many-connections.sh
Executable 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
|
||||
Reference in New Issue
Block a user