From c69ec94d13dfec24d55345af462dd1c4a7f0fa47 Mon Sep 17 00:00:00 2001 From: xuewenliang Date: Mon, 14 Mar 2022 16:12:11 +0800 Subject: [PATCH] Modifying the ping command MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1、Round trip times in the ping command range from millisecond to subtle 2、Add statistics on RTT related min/avg/Max/mdev in ping program 3、The ping command supports ctrl+c interruption operations Signed-off-by: xuewenliang --- include/netutils/icmp_ping.h | 2 +- include/netutils/icmpv6_ping.h | 2 +- netutils/ping/icmp_ping.c | 41 ++++++++++++++----- netutils/ping/icmpv6_ping.c | 41 ++++++++++++++----- system/ping/ping.c | 72 ++++++++++++++++++++++++++------- system/ping6/ping6.c | 74 ++++++++++++++++++++++++++-------- 6 files changed, 179 insertions(+), 53 deletions(-) diff --git a/include/netutils/icmp_ping.h b/include/netutils/icmp_ping.h index 93652c883..02979929b 100644 --- a/include/netutils/icmp_ping.h +++ b/include/netutils/icmp_ping.h @@ -79,7 +79,7 @@ struct ping_info_s struct ping_result_s { int code; /* Notice code ICMP_I/E/W_XXX */ - int extra; /* Extra information for code */ + long extra; /* Extra information for code */ struct in_addr dest; /* Target address to ping */ uint16_t nrequests; /* Number of ICMP ECHO requests sent */ uint16_t nreplies; /* Number of matching ICMP ECHO replies received */ diff --git a/include/netutils/icmpv6_ping.h b/include/netutils/icmpv6_ping.h index e3014d8bb..e7ff07c11 100644 --- a/include/netutils/icmpv6_ping.h +++ b/include/netutils/icmpv6_ping.h @@ -79,7 +79,7 @@ struct ping6_info_s struct ping6_result_s { int code; /* Notice code ICMPv6_I/E/W_XXX */ - int extra; /* Extra information for code */ + long extra; /* Extra information for code */ struct in6_addr dest; /* Target address to ping */ uint16_t nrequests; /* Number of ICMP ECHO requests sent */ uint16_t nreplies; /* Number of matching ICMP ECHO replies received */ diff --git a/netutils/ping/icmp_ping.c b/netutils/ping/icmp_ping.c index e915f7fb2..f158ce808 100644 --- a/netutils/ping/icmp_ping.c +++ b/netutils/ping/icmp_ping.c @@ -32,6 +32,8 @@ #include #include #include +#include +#include #ifdef CONFIG_LIBC_NETDB # include @@ -58,12 +60,22 @@ * separate instance of g_pingid in every process space. */ -static uint16_t g_pingid = 0; +static uint16_t g_pingid; +static volatile bool g_exiting; /**************************************************************************** * Private Functions ****************************************************************************/ +/**************************************************************************** + * Name: sigexit + ****************************************************************************/ + +static void sigexit(int signo) +{ + g_exiting = true; +} + /**************************************************************************** * Name: ping_newid ****************************************************************************/ @@ -136,7 +148,7 @@ static int ping_gethostip(FAR const char *hostname, FAR struct in_addr *dest) ****************************************************************************/ static void icmp_callback(FAR struct ping_result_s *result, - int code, int extra) + int code, long extra) { result->code = code; result->extra = extra; @@ -161,7 +173,7 @@ void icmp_ping(FAR const struct ping_info_s *info) struct pollfd recvfd; FAR uint8_t *iobuffer; FAR uint8_t *ptr; - int32_t elapsed; + long elapsed; clock_t kickoff; clock_t start; socklen_t addrlen; @@ -173,6 +185,9 @@ void icmp_ping(FAR const struct ping_info_s *info) int ch; int i; + g_exiting = false; + signal(SIGINT, sigexit); + /* Initialize result structure */ memset(&result, 0, sizeof(result)); @@ -218,6 +233,11 @@ void icmp_ping(FAR const struct ping_info_s *info) while (result.nrequests < info->count) { + if (g_exiting) + { + break; + } + /* Copy the ICMP header into the I/O buffer */ memcpy(iobuffer, &outhdr, sizeof(struct icmp_hdr_s)); @@ -262,7 +282,7 @@ void icmp_ping(FAR const struct ping_info_s *info) recvfd.events = POLLIN; recvfd.revents = 0; - ret = poll(&recvfd, 1, info->timeout - elapsed); + ret = poll(&recvfd, 1, info->timeout - elapsed / USEC_PER_MSEC); if (ret < 0) { icmp_callback(&result, ICMP_E_POLL, errno); @@ -290,7 +310,7 @@ void icmp_ping(FAR const struct ping_info_s *info) goto done; } - elapsed = (unsigned int)TICK2MSEC(clock() - start); + elapsed = TICK2USEC(clock() - start); inhdr = (FAR struct icmp_hdr_s *)iobuffer; if (inhdr->type == ICMP_ECHO_REPLY) @@ -309,13 +329,13 @@ void icmp_ping(FAR const struct ping_info_s *info) else { bool verified = true; - int32_t pktdelay = elapsed; + long pktdelay = elapsed; if (ntohs(inhdr->seqno) < result.seqno) { icmp_callback(&result, ICMP_W_SEQNOSMALL, ntohs(inhdr->seqno)); - pktdelay += info->delay; + pktdelay += info->delay * USEC_PER_MSEC; retry = true; } @@ -362,11 +382,12 @@ void icmp_ping(FAR const struct ping_info_s *info) icmp_callback(&result, ICMP_W_TYPE, inhdr->type); } } - while (retry && info->delay > elapsed && info->timeout > elapsed); + while (retry && info->delay > elapsed / USEC_PER_MSEC && + info->timeout > elapsed / USEC_PER_MSEC); /* Wait if necessary to preserved the requested ping rate */ - elapsed = (unsigned int)TICK2MSEC(clock() - start); + elapsed = TICK2MSEC(clock() - start); if (elapsed < info->delay) { struct timespec rqt; @@ -388,7 +409,7 @@ void icmp_ping(FAR const struct ping_info_s *info) } done: - icmp_callback(&result, ICMP_I_FINISH, TICK2MSEC(clock() - kickoff)); + icmp_callback(&result, ICMP_I_FINISH, TICK2USEC(clock() - kickoff)); close(sockfd); free(iobuffer); } diff --git a/netutils/ping/icmpv6_ping.c b/netutils/ping/icmpv6_ping.c index e2aeebf2c..793de1796 100644 --- a/netutils/ping/icmpv6_ping.c +++ b/netutils/ping/icmpv6_ping.c @@ -32,6 +32,8 @@ #include #include #include +#include +#include #ifdef CONFIG_LIBC_NETDB # include @@ -57,12 +59,22 @@ * separate instance of g_ping6_id in every process space. */ -static uint16_t g_ping6_id = 0; +static uint16_t g_ping6_id; +static volatile bool g_exiting6; /**************************************************************************** * Private Functions ****************************************************************************/ +/**************************************************************************** + * Name: sigexit + ****************************************************************************/ + +static void sigexit(int signo) +{ + g_exiting6 = true; +} + /**************************************************************************** * Name: ping6_newid ****************************************************************************/ @@ -135,7 +147,7 @@ static int ping6_gethostip(FAR const char *hostname, ****************************************************************************/ static void icmp6_callback(FAR struct ping6_result_s *result, - int code, int extra) + int code, long extra) { result->code = code; result->extra = extra; @@ -160,7 +172,7 @@ void icmp6_ping(FAR const struct ping6_info_s *info) struct pollfd recvfd; FAR uint8_t *iobuffer; FAR uint8_t *ptr; - int32_t elapsed; + long elapsed; clock_t kickoff; clock_t start; socklen_t addrlen; @@ -172,6 +184,9 @@ void icmp6_ping(FAR const struct ping6_info_s *info) int ch; int i; + g_exiting6 = false; + signal(SIGINT, sigexit); + /* Initialize result structure */ memset(&result, 0, sizeof(result)); @@ -217,6 +232,11 @@ void icmp6_ping(FAR const struct ping6_info_s *info) while (result.nrequests < info->count) { + if (g_exiting6) + { + break; + } + /* Copy the ICMP header into the I/O buffer */ memcpy(iobuffer, &outhdr, SIZEOF_ICMPV6_ECHO_REQUEST_S(0)); @@ -261,7 +281,7 @@ void icmp6_ping(FAR const struct ping6_info_s *info) recvfd.events = POLLIN; recvfd.revents = 0; - ret = poll(&recvfd, 1, info->timeout - elapsed); + ret = poll(&recvfd, 1, info->timeout - elapsed / USEC_PER_MSEC); if (ret < 0) { icmp6_callback(&result, ICMPv6_E_POLL, errno); @@ -289,7 +309,7 @@ void icmp6_ping(FAR const struct ping6_info_s *info) goto done; } - elapsed = (unsigned int)TICK2MSEC(clock() - start); + elapsed = TICK2USEC(clock() - start); inhdr = (FAR struct icmpv6_echo_reply_s *)iobuffer; if (inhdr->type == ICMPv6_ECHO_REPLY) @@ -308,13 +328,13 @@ void icmp6_ping(FAR const struct ping6_info_s *info) else { bool verified = true; - int32_t pktdelay = elapsed; + long pktdelay = elapsed; if (ntohs(inhdr->seqno) < result.seqno) { icmp6_callback(&result, ICMPv6_W_SEQNOSMALL, ntohs(inhdr->seqno)); - pktdelay += info->delay; + pktdelay += info->delay * USEC_PER_MSEC; retry = true; } @@ -361,11 +381,12 @@ void icmp6_ping(FAR const struct ping6_info_s *info) icmp6_callback(&result, ICMPv6_W_TYPE, inhdr->type); } } - while (retry && info->delay > elapsed && info->timeout > elapsed); + while (retry && info->delay > elapsed / USEC_PER_MSEC && + info->timeout > elapsed / USEC_PER_MSEC); /* Wait if necessary to preserved the requested ping rate */ - elapsed = (unsigned int)TICK2MSEC(clock() - start); + elapsed = TICK2MSEC(clock() - start); if (elapsed < info->delay) { struct timespec rqt; @@ -387,7 +408,7 @@ void icmp6_ping(FAR const struct ping6_info_s *info) } done: - icmp6_callback(&result, ICMPv6_I_FINISH, TICK2MSEC(clock() - kickoff)); + icmp6_callback(&result, ICMPv6_I_FINISH, TICK2USEC(clock() - kickoff)); close(sockfd); free(iobuffer); } diff --git a/system/ping/ping.c b/system/ping/ping.c index e259fd9c8..f03aa609b 100644 --- a/system/ping/ping.c +++ b/system/ping/ping.c @@ -23,12 +23,16 @@ ****************************************************************************/ #include +#include #include #include #include #include #include +#include +#include +#include #include "netutils/icmp_ping.h" @@ -48,6 +52,10 @@ struct ping_priv_s { int code; /* Notice code ICMP_I/E/W_XXX */ + long tmin; /* Minimum round trip time */ + long tmax; /* Maximum round trip time */ + long long tsum; /* Sum of all times, for doing average */ + long long tsum2; /* Sum2 is the sum of the squares of sum ,for doing mean deviation */ }; /**************************************************************************** @@ -118,7 +126,7 @@ static void ping_result(FAR const struct ping_result_s *result) break; case ICMP_E_SOCKET: - fprintf(stderr, "ERROR: socket() failed: %d\n", result->extra); + fprintf(stderr, "ERROR: socket() failed: %ld\n", result->extra); break; case ICMP_I_BEGIN: @@ -131,21 +139,21 @@ static void ping_result(FAR const struct ping_result_s *result) break; case ICMP_E_SENDTO: - fprintf(stderr, "ERROR: sendto failed at seqno %u: %d\n", + fprintf(stderr, "ERROR: sendto failed at seqno %u: %ld\n", result->seqno, result->extra); break; case ICMP_E_SENDSMALL: - fprintf(stderr, "ERROR: sendto returned %d, expected %u\n", + fprintf(stderr, "ERROR: sendto returned %ld, expected %u\n", result->extra, result->outsize); break; case ICMP_E_POLL: - fprintf(stderr, "ERROR: poll failed: %d\n", result->extra); + fprintf(stderr, "ERROR: poll failed: %ld\n", result->extra); break; case ICMP_W_TIMEOUT: - printf("No response from %u.%u.%u.%u: icmp_seq=%u time=%d ms\n", + printf("No response from %u.%u.%u.%u: icmp_seq=%u time=%ld ms\n", (unsigned int)(result->dest.s_addr) & 0xff, (unsigned int)(result->dest.s_addr >> 8) & 0xff, (unsigned int)(result->dest.s_addr >> 16) & 0xff, @@ -154,23 +162,23 @@ static void ping_result(FAR const struct ping_result_s *result) break; case ICMP_E_RECVFROM: - fprintf(stderr, "ERROR: recvfrom failed: %d\n", result->extra); + fprintf(stderr, "ERROR: recvfrom failed: %ld\n", result->extra); break; case ICMP_E_RECVSMALL: - fprintf(stderr, "ERROR: short ICMP packet: %d\n", result->extra); + fprintf(stderr, "ERROR: short ICMP packet: %ld\n", result->extra); break; case ICMP_W_IDDIFF: fprintf(stderr, - "WARNING: Ignoring ICMP reply with ID %d. " + "WARNING: Ignoring ICMP reply with ID %ld. " "Expected %u\n", result->extra, result->id); break; case ICMP_W_SEQNOBIG: fprintf(stderr, - "WARNING: Ignoring ICMP reply to sequence %d. " + "WARNING: Ignoring ICMP reply to sequence %ld. " "Expected <= %u\n", result->extra, result->seqno); break; @@ -180,19 +188,32 @@ static void ping_result(FAR const struct ping_result_s *result) break; case ICMP_I_ROUNDTRIP: - printf("%u bytes from %u.%u.%u.%u: icmp_seq=%u time=%d ms\n", + priv->tsum += result->extra; + priv->tsum2 += (long long)result->extra * result->extra; + if (result->extra < priv->tmin) + { + priv->tmin = result->extra; + } + + if (result->extra > priv->tmax) + { + priv->tmax = result->extra; + } + + printf("%u bytes from %u.%u.%u.%u: icmp_seq=%u time=%ld.%ld ms\n", result->info->datalen, (unsigned int)(result->dest.s_addr) & 0xff, (unsigned int)(result->dest.s_addr >> 8) & 0xff, (unsigned int)(result->dest.s_addr >> 16) & 0xff, (unsigned int)(result->dest.s_addr >> 24) & 0xff, - result->seqno, result->extra); + result->seqno, result->extra / USEC_PER_MSEC, + result->extra % USEC_PER_MSEC / MSEC_PER_DSEC); break; case ICMP_W_RECVBIG: fprintf(stderr, "WARNING: Ignoring ICMP reply with different payload " - "size: %d vs %u\n", + "size: %ld vs %u\n", result->extra, result->outsize); break; @@ -201,7 +222,7 @@ static void ping_result(FAR const struct ping_result_s *result) break; case ICMP_W_TYPE: - fprintf(stderr, "WARNING: ICMP packet with unknown type: %d\n", + fprintf(stderr, "WARNING: ICMP packet with unknown type: %ld\n", result->extra); break; @@ -217,8 +238,25 @@ static void ping_result(FAR const struct ping_result_s *result) result->nrequests; printf("%u packets transmitted, %u received, %u%% packet loss, " - "time %d ms\n", - result->nrequests, result->nreplies, tmp, result->extra); + "time %ld ms\n", + result->nrequests, result->nreplies, tmp, + result->extra / USEC_PER_MSEC); + if (result->nreplies > 0) + { + long avg = priv->tsum / result->nreplies; + long long tempnum = priv->tsum2 / result->nreplies - + (long long)avg * avg; + long tmdev = ub16toi(ub32sqrtub16(uitoub32(tempnum))); + + printf("rtt min/avg/max/mdev = %ld.%03ld/%ld.%03ld/" + "%ld.%03ld/%ld.%03ld ms\n", + priv->tmin / USEC_PER_MSEC, + priv->tmin % USEC_PER_MSEC, + avg / USEC_PER_MSEC, avg % USEC_PER_MSEC, + priv->tmax / USEC_PER_MSEC, + priv->tmax % USEC_PER_MSEC, + tmdev / USEC_PER_MSEC, tmdev % USEC_PER_MSEC); + } } break; } @@ -243,6 +281,10 @@ int main(int argc, FAR char *argv[]) info.callback = ping_result; info.priv = &priv; priv.code = ICMP_I_OK; + priv.tmin = LONG_MAX; + priv.tmax = 0; + priv.tsum = 0; + priv.tsum2 = 0; /* Parse command line options */ diff --git a/system/ping6/ping6.c b/system/ping6/ping6.c index 5fb6c1a72..d039ced0a 100644 --- a/system/ping6/ping6.c +++ b/system/ping6/ping6.c @@ -23,12 +23,16 @@ ****************************************************************************/ #include +#include #include #include #include #include #include +#include +#include +#include #include @@ -50,6 +54,10 @@ struct ping6_priv_s { int code; /* Notice code ICMP_I/E/W_XXX */ + long tmin; /* Minimum round trip time */ + long tmax; /* Maximum round trip time */ + long long tsum; /* Sum of all times, for doing average */ + long long tsum2; /* Sum2 is the sum of the squares of sum ,for doing mean deviation */ }; /**************************************************************************** @@ -121,7 +129,7 @@ static void ping6_result(FAR const struct ping6_result_s *result) break; case ICMPv6_E_SOCKET: - fprintf(stderr, "ERROR: socket() failed: %d\n", result->extra); + fprintf(stderr, "ERROR: socket() failed: %ld\n", result->extra); break; case ICMPv6_I_BEGIN: @@ -132,44 +140,44 @@ static void ping6_result(FAR const struct ping6_result_s *result) break; case ICMPv6_E_SENDTO: - fprintf(stderr, "ERROR: sendto failed at seqno %u: %d\n", + fprintf(stderr, "ERROR: sendto failed at seqno %u: %ld\n", result->seqno, result->extra); break; case ICMPv6_E_SENDSMALL: - fprintf(stderr, "ERROR: sendto returned %d, expected %u\n", + fprintf(stderr, "ERROR: sendto returned %ld, expected %u\n", result->extra, result->outsize); break; case ICMPv6_E_POLL: - fprintf(stderr, "ERROR: poll failed: %d\n", result->extra); + fprintf(stderr, "ERROR: poll failed: %ld\n", result->extra); break; case ICMPv6_W_TIMEOUT: inet_ntop(AF_INET6, result->dest.s6_addr16, strbuffer, INET6_ADDRSTRLEN); - printf("No response from %s: icmp_seq=%u time=%d ms\n", + printf("No response from %s: icmp_seq=%u time=%ld ms\n", strbuffer, result->seqno, result->extra); break; case ICMPv6_E_RECVFROM: - fprintf(stderr, "ERROR: recvfrom failed: %d\n", result->extra); + fprintf(stderr, "ERROR: recvfrom failed: %ld\n", result->extra); break; case ICMPv6_E_RECVSMALL: - fprintf(stderr, "ERROR: short ICMP packet: %d\n", result->extra); + fprintf(stderr, "ERROR: short ICMP packet: %ld\n", result->extra); break; case ICMPv6_W_IDDIFF: fprintf(stderr, - "WARNING: Ignoring ICMP reply with ID %d. " + "WARNING: Ignoring ICMP reply with ID %ld. " "Expected %u\n", result->extra, result->id); break; case ICMPv6_W_SEQNOBIG: fprintf(stderr, - "WARNING: Ignoring ICMP reply to sequence %d. " + "WARNING: Ignoring ICMP reply to sequence %ld. " "Expected <= %u\n", result->extra, result->seqno); break; @@ -179,17 +187,30 @@ static void ping6_result(FAR const struct ping6_result_s *result) break; case ICMPv6_I_ROUNDTRIP: + priv->tsum += result->extra; + priv->tsum2 += (long long)result->extra * result->extra; + if (result->extra < priv->tmin) + { + priv->tmin = result->extra; + } + + if (result->extra > priv->tmax) + { + priv->tmax = result->extra; + } + inet_ntop(AF_INET6, result->dest.s6_addr16, strbuffer, INET6_ADDRSTRLEN); - printf("%u bytes from %s icmp_seq=%u time=%u ms\n", + printf("%u bytes from %s icmp_seq=%u time=%ld.%ld ms\n", result->info->datalen, strbuffer, result->seqno, - result->extra); + result->extra / USEC_PER_MSEC, + result->extra % USEC_PER_MSEC / MSEC_PER_DSEC); break; case ICMPv6_W_RECVBIG: fprintf(stderr, "WARNING: Ignoring ICMP reply with different payload " - "size: %d vs %u\n", + "size: %ld vs %u\n", result->extra, result->outsize); break; @@ -198,7 +219,7 @@ static void ping6_result(FAR const struct ping6_result_s *result) break; case ICMPv6_W_TYPE: - fprintf(stderr, "WARNING: ICMP packet with unknown type: %d\n", + fprintf(stderr, "WARNING: ICMP packet with unknown type: %ld\n", result->extra); break; @@ -213,9 +234,26 @@ static void ping6_result(FAR const struct ping6_result_s *result) (result->nrequests >> 1)) / result->nrequests; - printf("%u packets transmitted, %u received, " - "%u%% packet loss, time %d ms\n", - result->nrequests, result->nreplies, tmp, result->extra); + printf("%u packets transmitted, %u received, %u%% packet loss," + "time %ld ms\n", + result->nrequests, result->nreplies, tmp, + result->extra / USEC_PER_MSEC); + if (result->nreplies > 0) + { + long avg = priv->tsum / result->nreplies; + long long tempnum = priv->tsum2 / result->nreplies - + (long long)avg * avg; + long tmdev = ub16toi(ub32sqrtub16(uitoub32(tempnum))); + + printf("rtt min/avg/max/mdev = %ld.%03ld/%ld.%03ld/" + "%ld.%03ld/%ld.%03ld ms\n", + priv->tmin / USEC_PER_MSEC, + priv->tmin % USEC_PER_MSEC, + avg / USEC_PER_MSEC, avg % USEC_PER_MSEC, + priv->tmax / USEC_PER_MSEC, + priv->tmax % USEC_PER_MSEC, + tmdev / USEC_PER_MSEC, tmdev % USEC_PER_MSEC); + } } break; } @@ -240,6 +278,10 @@ int main(int argc, FAR char *argv[]) info.callback = ping6_result; info.priv = &priv; priv.code = ICMPv6_I_OK; + priv.tmin = LONG_MAX; + priv.tmax = 0; + priv.tsum = 0; + priv.tsum2 = 0; /* Parse command line options */