From 8469023d0df2ff9b52e29aa4c59f7de264a4a0ab Mon Sep 17 00:00:00 2001
From: Aleksandr Lysikov <lysikov@inbox.ru>
Date: Tue, 5 Feb 2019 22:57:51 +0500
Subject: [PATCH] add ping command on unix-socket server side

---
 dap_chain_node_cli.c  | 162 ++++++++++++++++++++++++++++++++----------
 iputils/ping.c        |  22 ++++--
 iputils/ping_common.c |   1 +
 3 files changed, 140 insertions(+), 45 deletions(-)

diff --git a/dap_chain_node_cli.c b/dap_chain_node_cli.c
index 2a4e82cab1..62233c7483 100644
--- a/dap_chain_node_cli.c
+++ b/dap_chain_node_cli.c
@@ -46,6 +46,7 @@ typedef int SOCKET;
 #include <WS2tcpip.h>
 #endif
 
+#include "iputils/iputils.h"
 #include "dap_common.h"
 #include "dap_chain_node_cli.h"
 
@@ -55,13 +56,47 @@ typedef int SOCKET;
 
 static SOCKET server_sockfd = -1;
 
-int com_global_db(int argc, const char ** argv, char **str_reply)
+/**
+ * find option value
+ */
+static bool find_option_val(const char** argv, int arg_start, int arg_end, const char *opt_name, const char **opt_value)
+{
+    int arg_index = arg_start;
+    int arg_character, on_or_off, next_arg, i;
+    char *arg_string;
+
+    while(arg_index < arg_end)
+    {
+        arg_string = (char *) argv[arg_index];
+        // find opt_name
+        if(arg_string && opt_name && !strcmp(arg_string, opt_name)) {
+            // find opt_value
+            if(opt_value) {
+                arg_string = (char *) argv[++arg_index];
+                if(arg_string) {
+                    *opt_value = arg_string;
+                    return true;
+                }
+            }
+            else
+                // need only opt_name
+                return true;
+        }
+        arg_index++;
+    }
+    return false;
+}
+
+static int com_global_db(int argc, const char ** argv, char **str_reply)
 {
     printf("com_global_db\n");
     return 0;
 }
 
-int com_node(int argc, const char ** argv, char **str_reply)
+/**
+ * Node command
+ */
+static int com_node(int argc, const char ** argv, char **str_reply)
 {
     for(int i = 0; i < argc; i++)
         printf("com_node i=%d str=%s\n", i, argv[i]);
@@ -70,7 +105,55 @@ int com_node(int argc, const char ** argv, char **str_reply)
     return 0;
 }
 
-int com_help(int argc, const char ** argv, char **str_reply)
+/**
+ * Ping command
+ */
+static int com_ping(int argc, const char** argv, char **str_reply)
+{
+    const char *addr = NULL;
+    int n = 4;
+    if(argc > 1)
+        addr = argv[1];
+    const char *n_str = NULL;
+    if(find_option_val(argv, 2, argc, "-n", &n_str))
+        n = (n_str) ? atoi(n_str) : 4;
+    else if(find_option_val(argv, 2, argc, "-c", &n_str))
+        n = (n_str) ? atoi(n_str) : 4;
+    if(n <= 1)
+        n = 1;
+    iputils_set_verbose();
+    int res = (addr) ? ping_util(addr, n) : -EADDRNOTAVAIL;
+    if(res >= 0) {
+        if(str_reply)
+            *str_reply = g_strdup_printf("ping %s time=%.1lf ms", addr, res * 1. / 1000);
+    }
+    else {
+        if(str_reply)
+        {
+            switch (-res)
+            {
+            case EDESTADDRREQ:
+                *str_reply = g_strdup_printf("ping %s error: %s", addr, "Destination address required");
+                break;
+            case EADDRNOTAVAIL:
+                *str_reply = g_strdup_printf("ping %s error: %s", (addr) ? addr : "",
+                        (addr) ? "Host not found" : "Host not defined");
+                break;
+            case EPFNOSUPPORT:
+                *str_reply = g_strdup_printf("ping %s error: %s", addr, "Unknown protocol family");
+                break;
+            default:
+                *str_reply = g_strdup_printf("ping %s error(%d)", addr, -res);
+            }
+        }
+    }
+    return res;
+}
+
+/**
+ * Help command
+ */
+static int com_help(int argc, const char ** argv, char **str_reply)
 {
     if(argc > 1) {
         const COMMAND *cmd = find_command(argv[1]);
@@ -88,9 +171,10 @@ int com_help(int argc, const char ** argv, char **str_reply)
     return -1;
 }
 
-COMMAND commands[] = {
+static const COMMAND commands[] = {
     { "global_db", com_global_db, "Work with database" },
     { "node", com_node, "Work with node" },
+    { "ping", com_ping, "Ping utility" },
     { "help", com_help, "Display this text" },
     { "?", com_help, "Synonym for `help'" },
     { (char *) NULL, (cmdfunc_t *) NULL, (char *) NULL }
@@ -125,13 +209,13 @@ static int s_poll(int socket, int timeout)
     struct pollfd fds;
     int res;
     fds.fd = socket;
-    // POLLIN - received data
-    // POLLNVAL - closed the socket on our side
-    // POLLHUP - closed the socket on another side (does not work! Received POLLIN and the next reading returns 0 bytes)
+// POLLIN - received data
+// POLLNVAL - closed the socket on our side
+// POLLHUP - closed the socket on another side (does not work! Received POLLIN and the next reading returns 0 bytes)
     fds.events = POLLIN; // | | POLLNVAL | POLLHUP | POLLERR | POLLPRI
     res = poll(&fds, 1, timeout);
 
-    // since POLLIN=(POLLRDNORM | POLLRDBAND), then maybe revents=POLLRDNORM
+// since POLLIN=(POLLRDNORM | POLLRDBAND), then maybe revents=POLLRDNORM
     if(res == 1 && !(fds.revents & POLLIN)) //if(res==1 && fds.revents!=POLLIN)
         return -1;
     return res;
@@ -145,25 +229,25 @@ static bool is_valid_socket(SOCKET sock)
     struct pollfd fds;
     fds.fd = sock;
     fds.events = POLLIN;
-    // return: -1 err, 0 timeout, 1 waited
+// return: -1 err, 0 timeout, 1 waited
     int count_desc = poll(&fds, 1, 0);
-    // error
+// error
     if(count_desc == -1)
         return false;
-    // event with an error code
+// event with an error code
     if(count_desc > 0)
             {
-        // feature of disconnection under Windows
-        // under Windows, with socket closed fds.revents=POLLHUP, in Unix fds.events = POLLIN
+// feature of disconnection under Windows
+// under Windows, with socket closed fds.revents=POLLHUP, in Unix fds.events = POLLIN
         if(fds.revents & (POLLERR | POLLHUP | POLLNVAL))
             return false;
-        // feature of disconnection under Unix (QNX)
-        // under Windows, with socket closed res = 0, in Unix res = -1
+// feature of disconnection under Unix (QNX)
+// under Windows, with socket closed res = 0, in Unix res = -1
         char buf[2];
         int res = recv(sock, buf, 1, MSG_PEEK); // MSG_PEEK  The data is treated as unread and the next recv() function shall still return this data.
         if(res < 0)
             return false;
-        // data in the buffer must be(count_desc>0), but read 0 bytes(res=0)
+// data in the buffer must be(count_desc>0), but read 0 bytes(res=0)
         if(!res && (fds.revents & POLLIN))
             return false;
     }
@@ -211,29 +295,29 @@ char* s_get_next_str(SOCKET nSocket, int *dwLen, const char *stop_str, bool del_
     bool bSuccess = false;
     int nRecv = 0; // count of bytes received
     int stop_str_len = (stop_str) ? strlen(stop_str) : 0;
-    // if there is nothing to look for
+// if there is nothing to look for
     if(!stop_str_len)
         return NULL;
     int lpszBuffer_len = 256;
     char *lpszBuffer = calloc(1, lpszBuffer_len);
-    // received string will not be larger than MAX_REPLY_LEN
+// received string will not be larger than MAX_REPLY_LEN
     while(1) //nRecv < MAX_REPLY_LEN)
     {
-        // read one byte
+// read one byte
         int ret = s_recv(nSocket, (unsigned char *) (lpszBuffer + nRecv), 1, timeout);
-        //int ret = recv(nSocket,lpszBuffer+nRecv,1, 0);
+//int ret = recv(nSocket,lpszBuffer+nRecv,1, 0);
         if(ret <= 0)
                 {
             break;
         }
         nRecv += ret;
-        //printf("**debug** socket=%d read  %d bytes '%0s'",nSocket, ret, (lpszBuffer + nRecv));
+//printf("**debug** socket=%d read  %d bytes '%0s'",nSocket, ret, (lpszBuffer + nRecv));
         while((nRecv + 1) >= lpszBuffer_len)
         {
             lpszBuffer_len *= 2;
             lpszBuffer = (char*) realloc(lpszBuffer, lpszBuffer_len);
         }
-        // search for the required string
+// search for the required string
         if(nRecv >= stop_str_len) {
             // found the required string
             if(!strncasecmp(lpszBuffer + nRecv - stop_str_len, stop_str, stop_str_len)) {
@@ -242,9 +326,9 @@ char* s_get_next_str(SOCKET nSocket, int *dwLen, const char *stop_str, bool del_
             }
         }
     };
-    // end reading
+// end reading
     if(bSuccess) {
-        // delete the searched string
+// delete the searched string
         if(del_stop_str) {
             lpszBuffer[nRecv - stop_str_len] = '\0';
             if(dwLen)
@@ -258,7 +342,7 @@ char* s_get_next_str(SOCKET nSocket, int *dwLen, const char *stop_str, bool del_
         lpszBuffer = realloc(lpszBuffer, *dwLen + 1);
         return lpszBuffer;
     }
-    // in case of an error or missing string
+// in case of an error or missing string
     if(dwLen)
         *dwLen = 0;
     free(lpszBuffer);
@@ -280,13 +364,13 @@ static void* thread_one_client_func(void *args)
     GList *cmd_param_list = NULL;
     while(1)
     {
-        // wait data from client
+// wait data from client
         int is_data = s_poll(newsockfd, timeout);
-        //printf("is data=%d sockfd=%d \n", is_data, newsockfd);
-        // timeout
+//printf("is data=%d sockfd=%d \n", is_data, newsockfd);
+// timeout
         if(!is_data)
             continue;
-        // error (may be socket closed)
+// error (may be socket closed)
         if(is_data < 0)
             break;
 
@@ -296,10 +380,10 @@ static void* thread_one_client_func(void *args)
             //printf("isvalid=%d sockfd=%d \n", is_valid, newsockfd);
             break;
         }
-        // receiving http header
+// receiving http header
         char *str_header = s_get_next_str(newsockfd, &str_len, "\r\n", true, timeout);
-        //printf("str_header='%s' sock=%d\n", str_header, newsockfd);
-        // bad format
+//printf("str_header='%s' sock=%d\n", str_header, newsockfd);
+// bad format
         if(!str_header)
             break;
         if(str_header && strlen(str_header) == 0) {
@@ -307,7 +391,7 @@ static void* thread_one_client_func(void *args)
             if(marker == 1)
                 continue;
         }
-        // filling parameters of command
+// filling parameters of command
         if(marker == 1) {
             cmd_param_list = g_list_append(cmd_param_list, str_header);
             //printf("g_list_append argc=%d command=%s ", argc, str_header);
@@ -360,7 +444,7 @@ static void* thread_one_client_func(void *args)
             break;
         }
     }
-    // close connection
+// close connection
     int cs = closesocket(newsockfd);
     log_it(L_INFO, "close connection=%d sockfd=%d", cs, newsockfd);
     return NULL;
@@ -380,17 +464,17 @@ static void* thread_main_func(void *args)
         pthread_t threadId;
         struct sockaddr_in peer;
         socklen_t size = sizeof(peer);
-        // received a new connection request
+// received a new connection request
         if((newsockfd = accept(sockfd, (struct sockaddr*) &peer, &size)) == (SOCKET) -1) {
             log_it(L_ERROR, "new connection break newsockfd=%d", newsockfd);
             break;
         }
-        // create child thread for a client connection
+// create child thread for a client connection
         pthread_create(&threadId, NULL, thread_one_client_func, (void*) (intptr_t) newsockfd);
-        // in order to thread not remain in state "dead" after completion
+// in order to thread not remain in state "dead" after completion
         pthread_detach(threadId);
     };
-    // close connection
+// close connection
     int cs = closesocket(sockfd);
     log_it(L_INFO, "Exit server thread=%d socket=%d", cs, sockfd);
     return NULL;
@@ -425,7 +509,7 @@ int dap_chain_node_cli_init(dap_config_t * g_config)
     }
 // connecting the address with a socket
     if(bind(sockfd, (const struct sockaddr*) &server, sizeof(struct sockaddr_un)) == SOCKET_ERROR) {
-        // errno = EACCES  13  Permission denied
+// errno = EACCES  13  Permission denied
         if(errno == EACCES) // EACCES=13
             log_it(L_ERROR, "Server can't start(err=%d). Can't create file=%s [Permission denied]", errno,
                     UNIX_SOCKET_FILE);
diff --git a/iputils/ping.c b/iputils/ping.c
index 0c3ec725e8..491a5e4d7f 100644
--- a/iputils/ping.c
+++ b/iputils/ping.c
@@ -455,7 +455,10 @@ static int ping_main(int argc, char **argv)
     optind = 0;
 
     if(!argc)
-        error(1, EDESTADDRREQ, "usage error");
+    {
+        //error(1, EDESTADDRREQ, "usage error");
+        return -EDESTADDRREQ;//    89  Destination address required
+    }
 
     target = argv[argc - 1];
 
@@ -489,7 +492,10 @@ static int ping_main(int argc, char **argv)
 
     status = getaddrinfo(target, NULL, &hints, &result);
     if(status)
-        error(2, 0, "%s: %s", target, gai_strerror(status));
+    {
+        //error(2, 0, "%s: %s", target, gai_strerror(status));
+        return -EADDRNOTAVAIL;//
+    }
 
     for(ai = result; ai; ai = ai->ai_next) {
         switch (ai->ai_family) {
@@ -500,7 +506,10 @@ static int ping_main(int argc, char **argv)
             status = ping6_run(argc, argv, ai, &sock6);
             break;
         default:
-            error(2, 0, "unknown protocol family: %d", ai->ai_family);
+        {
+            //error(2, 0, "unknown protocol family: %d", ai->ai_family);
+            return -EPFNOSUPPORT;
+        }
         }
 
         if(status == 0)
@@ -531,6 +540,7 @@ int ping_util_common(int type, const char *addr, int count)
      Need change range for other users:
      # sysctl net.ipv4.ping_group_range="1 65000"
      */
+    tsum = ntransmitted = nreceived = exiting = 0;
     int argc = 3;
     const char *argv[argc];
     if(type != 4)
@@ -539,11 +549,11 @@ int ping_util_common(int type, const char *addr, int count)
         argv[0] = "ping4";
     argv[1] = g_strdup_printf("-c%d", count);
     argv[2] = addr;
-    ping_main(argc, (char**) argv);
+    int status = ping_main(argc, (char**) argv);
     g_free((char*) argv[1]);
-    if(ntransmitted > 1 && nreceived > 1)
+    if(ntransmitted >= 1 && nreceived >= 1)
         return tsum;
-    return -1;
+    return status;
 }
 
 /**
diff --git a/iputils/ping_common.c b/iputils/ping_common.c
index bf58d31fae..a7d257082e 100755
--- a/iputils/ping_common.c
+++ b/iputils/ping_common.c
@@ -879,6 +879,7 @@ int gather_statistics(uint8_t *icmph, int icmplen,
             else
                 log_printf(" time=%ld.%03ld ms", triptime / 1000,
                         triptime % 1000);
+            log_printf(" tsum=%d ", tsum);
         }
         if(dupflag)
             log_printf(" (DUP!)");
-- 
GitLab