From 109cf865f62fb8e068ad01837f8f053b91186e17 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Al=D0=B5x=D0=B0nder=20Lysik=D0=BEv?=
 <alexander.lysikov@demlabs.net>
Date: Mon, 21 Sep 2020 23:36:51 +0500
Subject: [PATCH] added command vpn_stat

---
 .../net/stream/session/dap_stream_session.c   | 26 ++++++
 .../session/include/dap_stream_session.h      |  3 +
 modules/service/vpn/dap_chain_net_srv_vpn.c   | 10 ++-
 .../service/vpn/dap_chain_net_srv_vpn_cmd.c   | 89 ++++++++++++++++++-
 .../service/vpn/dap_chain_net_srv_vpn_cmd.h   |  2 +
 5 files changed, 127 insertions(+), 3 deletions(-)

diff --git a/dap-sdk/net/stream/session/dap_stream_session.c b/dap-sdk/net/stream/session/dap_stream_session.c
index 1dcfa0c621..5c1cb1a29a 100644
--- a/dap-sdk/net/stream/session/dap_stream_session.c
+++ b/dap-sdk/net/stream/session/dap_stream_session.c
@@ -64,6 +64,32 @@ void dap_stream_session_deinit()
     pthread_mutex_unlock(&sessions_mutex);
 }
 
+/**
+ *
+ * note: dap_stream_session_get_list_sessions_unlock() must be run after this function
+ */
+dap_list_t* dap_stream_session_get_list_sessions(void)
+{
+    dap_list_t *l_list = NULL;
+    dap_stream_session_t *current, *tmp;
+    pthread_mutex_lock(&sessions_mutex);
+    HASH_ITER(hh, sessions, current, tmp)
+    {
+        l_list = dap_list_append(l_list, current);
+        //dap_chain_net_srv_stream_session_t * l_srv_session = current->_inheritor;
+        //if(l_srv_session) {
+            //dap_net_stats_t *l_stats = DAP_NEW(dap_net_stats_t);
+            //memcpy(l_stats, l_srv_session->stats);
+            //l_list = dap_list_append(l_list, l_stats);
+        //}
+    }
+    return l_list;
+}
+
+void dap_stream_session_get_list_sessions_unlock(void)
+{
+    pthread_mutex_unlock(&sessions_mutex);
+}
 
 static void * session_check(void * data)
 {
diff --git a/dap-sdk/net/stream/session/include/dap_stream_session.h b/dap-sdk/net/stream/session/include/dap_stream_session.h
index 921c9ff700..9106aca423 100644
--- a/dap-sdk/net/stream/session/include/dap_stream_session.h
+++ b/dap-sdk/net/stream/session/include/dap_stream_session.h
@@ -31,6 +31,7 @@
 #include "uthash.h"
 #include "dap_enc_key.h"
 #include "dap_hash.h"
+#include "dap_list.h"
 
 typedef enum stream_session_type {STREAM_SESSION_TYPE_MEDIA=0,STREAM_SESSION_TYPE_VPN} stream_session_type_t;
 typedef enum stream_session_connection_type {STEAM_SESSION_HTTP = 0, STREAM_SESSION_UDP, STREAM_SESSION_END_TYPE} stream_session_connection_type_t;
@@ -69,6 +70,8 @@ typedef struct dap_stream_session dap_stream_session_t;
 
 void dap_stream_session_init();
 void dap_stream_session_deinit();
+dap_list_t* dap_stream_session_get_list_sessions(void);
+void dap_stream_session_get_list_sessions_unlock(void);
 
 dap_stream_session_t * dap_stream_session_pure_new();
 dap_stream_session_t * dap_stream_session_new(unsigned int media_id, bool open_preview);
diff --git a/modules/service/vpn/dap_chain_net_srv_vpn.c b/modules/service/vpn/dap_chain_net_srv_vpn.c
index aaf563d863..4041396e15 100644
--- a/modules/service/vpn/dap_chain_net_srv_vpn.c
+++ b/modules/service/vpn/dap_chain_net_srv_vpn.c
@@ -69,6 +69,8 @@
 #include "dap_chain_net_srv_stream_session.h"
 #include "dap_chain_net_vpn_client.h"
 #include "dap_chain_net_vpn_client_tun.h"
+#include "dap_chain_net_srv_vpn_cmd.h"
+#include "dap_chain_node_cli.h"
 #include "dap_chain_ledger.h"
 #include "dap_events.h"
 
@@ -769,6 +771,10 @@ int dap_chain_net_srv_vpn_init(dap_config_t * g_config) {
     dap_stream_ch_proc_add(DAP_STREAM_CH_ID_NET_SRV_VPN, s_ch_vpn_new, s_ch_vpn_delete, s_ch_packet_in,
             s_ch_packet_out);
 
+    // add console command to display vpn statistics
+    dap_chain_node_cli_cmd_item_create ("vpn_stat", com_vpn_statistics, NULL, "VPN statistics",
+            "vpn_stat -net <net name> [-full]\n"
+            );
     return 0;
 }
 
@@ -934,9 +940,9 @@ void s_ch_vpn_new(dap_stream_ch_t* a_ch, void* a_arg)
  * @param ch
  * @param arg
  */
-void s_ch_vpn_delete(dap_stream_ch_t* ch, void* arg)
+void s_ch_vpn_delete(dap_stream_ch_t* a_ch, void* arg)
 {
-    dap_chain_net_srv_ch_vpn_t * l_ch_vpn = CH_VPN(ch);
+    dap_chain_net_srv_ch_vpn_t * l_ch_vpn = CH_VPN(a_ch);
     dap_chain_net_srv_vpn_t * l_srv_vpn =(dap_chain_net_srv_vpn_t *) l_ch_vpn->net_srv->_inhertor;
 
 
diff --git a/modules/service/vpn/dap_chain_net_srv_vpn_cmd.c b/modules/service/vpn/dap_chain_net_srv_vpn_cmd.c
index d676903d06..59d99cc44c 100644
--- a/modules/service/vpn/dap_chain_net_srv_vpn_cmd.c
+++ b/modules/service/vpn/dap_chain_net_srv_vpn_cmd.c
@@ -1,8 +1,95 @@
-#include <dap_chain_node_cli.h>
+#include "dap_common.h"
+#include "dap_chain_node_cli.h"
 #include "dap_chain_node_cli_cmd.h"
 #include "dap_chain_net_srv_vpn_cmd.h"
 #include "dap_chain_net_vpn_client.h"
 
+
+static char* get_value_text(uintmax_t a_value)
+{
+    if(a_value < 2048)
+        return dap_strdup_printf("%d bytes", a_value);
+    else if(a_value < 2048 * 1024)
+        return dap_strdup_printf("%.2lf Kb", (double) a_value / 1024);
+    else if(a_value < 2048ll * 1024 * 1024)
+        return dap_strdup_printf("%.2lf Mb", (double) a_value / (1024 * 1024));
+    else if(a_value < 2048ll * 1024 * 1024 * 1024)
+        return dap_strdup_printf("%.2lf Gb", (double) a_value / (1024 * 1024 * 1024));
+    return dap_strdup_printf("%.2lf Tb", (double) a_value / (1024ll * 1024 * 1024 * 1024));
+}
+
+static void add_value_text(dap_string_t *l_str, char *l_addstr, uintmax_t a_value)
+{
+    char *l_str_val = get_value_text(a_value);
+    dap_string_append_printf(l_str, "%s.%s\n", l_addstr, l_str_val);
+    DAP_DELETE(l_str_val);
+}
+#include <arpa/inet.h>
+/**
+ * vpn_client command
+ *
+ * VPN statistics
+ */
+int com_vpn_statistics(int a_argc, char ** a_argv, void *arg_func, char **a_str_reply)
+{
+    dap_stream_ch_t* a_ch;
+    dap_stream_t * stream;
+    dap_stream_session_t * session;
+    // get statistics for all actual sessions
+    dap_list_t *l_list = dap_stream_session_get_list_sessions();
+    dap_string_t *l_str = dap_string_new(NULL);
+    int l_conn = 0;
+    // display statistic for all sessions
+    while(l_list) {
+        dap_stream_session_t * l_session = (dap_stream_session_t*) l_list->data;
+        dap_chain_net_srv_stream_session_t * l_srv_str_session = l_session->_inheritor;
+        if(l_srv_str_session) {
+            dap_net_stats_t l_stats = l_srv_str_session->stats; //(dap_net_stats_t*) l_list;
+            dap_string_append_printf(l_str, "VPN connection %d\n", l_conn);
+            l_conn++;
+            // time start/length
+            time_t l_time_len_sec = time(NULL) - l_session->time_created;
+            char l_buf[1024];
+            if(dap_time_to_str_rfc822(l_buf, sizeof(l_buf), l_session->time_created) > 0)
+                dap_string_append_printf(l_str, "  start at %s (length %02d:%02d:%02d)\n", l_buf,
+                        l_time_len_sec / 3600, (l_time_len_sec % 3600) / 60, l_time_len_sec % 60);
+            // client ip
+            const int l_tun_client_addr_str_len = 128;
+            char *l_tun_client_addr_str = DAP_NEW_S_SIZE(char, l_tun_client_addr_str_len);
+            if(inet_ntop(AF_INET, &(l_session->tun_client_addr), l_tun_client_addr_str, l_tun_client_addr_str_len))
+                dap_string_append_printf(l_str, "  client addr........%s\n", l_tun_client_addr_str);
+            else
+                dap_string_append(l_str, "  client addr........???\n");
+            add_value_text(l_str, "  recv..............", l_stats.bytes_recv);
+            add_value_text(l_str, "  recv lost.........", l_stats.bytes_recv_lost);
+            add_value_text(l_str, "  send..............", l_stats.bytes_sent);
+            add_value_text(l_str, "  send lost.........", l_stats.bytes_sent_lost);
+            dap_string_append_printf(l_str, "  packets recv.......%d\n", l_stats.packets_recv);
+            dap_string_append_printf(l_str, "  packets recv lost..%d\n", l_stats.packets_recv_lost);
+            dap_string_append_printf(l_str, "  packets send.......%d\n", l_stats.packets_sent);
+            dap_string_append_printf(l_str, "  packets send lost..%d\n", l_stats.packets_sent_lost);
+            // average bitrate
+            double l_bitrate = (l_stats.bytes_recv - l_stats.bytes_recv_lost +
+                    l_stats.bytes_sent - l_stats.bytes_sent_lost) * 1. / l_time_len_sec;
+            dap_string_append_printf(l_str, "  average bitrate....%.2lf kbps\n", l_bitrate / 1024.);
+            // not add line break after last session
+            if(l_list->next)
+                dap_string_append_printf(l_str, "\n");
+        }
+        // next session
+        l_list = dap_list_next(l_list);
+    }
+    // unlock sessions list
+    dap_stream_session_get_list_sessions_unlock();
+    if(l_conn>0)
+        dap_chain_node_cli_set_reply_text(a_str_reply, l_str->str);
+    else
+        dap_chain_node_cli_set_reply_text(a_str_reply, "No VPN connections");
+    // free tmp memory
+    dap_string_free(l_str, true);
+    return 0;
+}
+
 /**
  * vpn_client command
  *
diff --git a/modules/service/vpn/dap_chain_net_srv_vpn_cmd.h b/modules/service/vpn/dap_chain_net_srv_vpn_cmd.h
index 4ce2243e87..0a70e7791c 100644
--- a/modules/service/vpn/dap_chain_net_srv_vpn_cmd.h
+++ b/modules/service/vpn/dap_chain_net_srv_vpn_cmd.h
@@ -1,4 +1,6 @@
 #pragma once
 
+//  VPN statistics
+int com_vpn_statistics(int a_argc, char ** a_argv, void *arg_func, char **a_str_reply);
 // vpn_client command
 int com_vpn_client(int a_argc, char ** a_argv, void *arg_func, char **a_str_reply);
-- 
GitLab