From e3a2901370743795851ada2d0b3f79cf8c974bec Mon Sep 17 00:00:00 2001 From: tomoron Date: Fri, 2 May 2025 01:17:18 +0200 Subject: [PATCH] show ping response lines and stats lines --- Makefile | 14 +++-- srcs/ft_ping.c | 131 +++++++++------------------------------- srcs/icmp.c | 44 +++++++++++++- srcs/includes/ft_ping.h | 32 +++++++++- srcs/main.c | 11 +++- srcs/stats.c | 41 +++++++++++++ srcs/utils.c | 14 ++++- srcs/waitlist_utils.c | 63 +++++++++++++++++++ 8 files changed, 233 insertions(+), 117 deletions(-) create mode 100644 srcs/stats.c create mode 100644 srcs/waitlist_utils.c diff --git a/Makefile b/Makefile index 083b3bc..387145e 100644 --- a/Makefile +++ b/Makefile @@ -1,15 +1,17 @@ NAME = ft_ping CC=cc -FLAGS=-Werror -Wextra -Wall -g -Wno-unused-result +FLAGS=-Werror -Wextra -Wall -g -Wno-unused-result -lm SRCS_DIR = srcs OBJS_DIR = .objs -SRCS = main.c\ - icmp.c\ - parsing.c\ - utils.c\ - ft_ping.c +SRCS = main.c\ + icmp.c\ + parsing.c\ + utils.c\ + ft_ping.c\ + stats.c\ + waitlist_utils.c OBJS = $(addprefix $(OBJS_DIR)/,$(SRCS:.c=.o)) diff --git a/srcs/ft_ping.c b/srcs/ft_ping.c index ea78c7b..e72b255 100644 --- a/srcs/ft_ping.c +++ b/srcs/ft_ping.c @@ -6,7 +6,7 @@ /* By: tomoron +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2025/04/26 19:54:25 by tomoron #+# #+# */ -/* Updated: 2025/04/30 17:59:21 by tomoron ### ########.fr */ +/* Updated: 2025/05/02 01:04:29 by tomoron ### ########.fr */ /* */ /* ************************************************************************** */ @@ -38,131 +38,54 @@ struct addrinfo *resolve_ip(char *host, t_settings *settings) return(ret); } -double timediff(struct timeval *from) +void ping_start_print(t_settings *set, char *host) { - struct timeval now; - float diff; - - gettimeofday(&now, 0); - diff = ((double)now.tv_sec - from->tv_sec); - diff += (((double)now.tv_usec / 1000000) - ((double)from->tv_usec / 1000000)); - return(diff); + printf("PING %s (%s): 56 data bytes\n", host, set->current_ip); } -t_waitlist *send_icmp(t_settings *set, struct addrinfo *host, uint16_t *seq, struct timeval *last) +void ping_end_print(t_settings *set, char *host, t_stats *stats) { - t_icmp_echo packet; - t_waitlist *ret; - - if(timediff(last) < set->interval) - return (0); - packet = prepare_icmp_echo(*seq, set->id); - sendto(set->socket, &packet, sizeof(t_icmp_echo), 0, host->ai_addr, host->ai_addrlen); - gettimeofday(last, 0); - (*seq)++; - ret = malloc(sizeof(t_waitlist)); - if(!ret) - return(0); - ret->time = *last; - ret->seq = *seq; - ret->next = 0; - return(ret); -} + int percent; + double stddev; -void waitlist_add(t_waitlist **waitlist, t_waitlist *elem) -{ - t_waitlist *cur; - - cur = *waitlist; - - while(cur && cur->next) - cur = cur->next; - if(cur) - cur->next = elem; - else - *waitlist = elem; -} - -void waitlist_free(t_waitlist *lst) -{ - t_waitlist *tmp; - - while(lst) - { - tmp = lst->next; - free(lst); - lst = tmp; - } -} - -void waitlist_remove(t_waitlist **lst, uint16_t seq) -{ - t_waitlist *cur; - t_waitlist *prev; - - if(!*lst) - return ; - cur = *lst; - prev = 0; - while(cur && cur->seq != seq) - { - prev = cur; - cur = cur->next; - } - if(!prev) - return ; - if(!prev && *lst) - *lst = (*lst)->next; - if(cur) - prev->next = cur->next; - free(cur); -} - -void receive_icmp(t_settings *set, struct addrinfo *info, t_waitlist **wl) -{ - size_t len; - char buf[256]; - t_icmp_echo *res; - uint16_t checksum; - - len = recvfrom(set->socket, buf, sizeof(t_icmp_echo) + 20, 0, info->ai_addr, &info->ai_addrlen); - res = (void*)(buf + 20); - if(len == (size_t)-1 || !len) - return; - if(res->type != 0 && res->identifier != set->id) - return ; - checksum = res->checksum; - res->checksum = 0; - if(calc_checksum(res, sizeof(t_icmp_echo)) != checksum) - return ; - waitlist_remove(wl, res->sequence); + (void)set; + stddev = sqrt(stats->sqr_diff / (stats->received - 1)); + printf("--- %s ping statistics ---\n", host); + percent = ((double)stats->sent / 100) * stats->received; + printf("%lu packets transmitted, %lu packets received, %d%% packet loss\n", stats->sent, stats->received, percent); + printf("round-trip min/avg/max/stddev = %.3f/%.3f/%.3f/%.3f ms\n", stats->min, stats->avg, stats->max, stddev); } int ping_host(t_settings *set, char *host) { uint16_t seq; - struct addrinfo *info; - struct timeval last_sent; - t_waitlist *wl; - t_waitlist *tmp; + struct addrinfo *info; + struct timeval last_sent; + t_waitlist *wl; + t_waitlist *tmp; + t_stats stats; seq = 0; + memset(&stats, 0, sizeof(t_stats)); info = resolve_ip(host, set); if(!info) return(0); last_sent.tv_sec = 0; last_sent.tv_usec = 0; wl = 0; - while(seq < set->count || set->count == -1) + inet_ntop(info->ai_family, (void *)&((struct sockaddr_in *)(info->ai_addr))->sin_addr, set->current_ip, sizeof(set->current_ip)); + ping_start_print(set, host); + while((seq < set->count || set->count == -1) && !g_stop) { - tmp = send_icmp(set, info, &seq, &last_sent); + tmp = send_icmp(set, info, &seq, &last_sent, &stats); if(tmp) waitlist_add(&wl, tmp); - usleep(1000); - receive_icmp(set, info, &wl); + usleep(100); + receive_icmp(set, info, &wl, &stats); } - while(wl) - receive_icmp(set, info, &wl); + while(wl && !g_stop) + receive_icmp(set, info, &wl, &stats); + ping_end_print(set, host, &stats); freeaddrinfo(info); waitlist_free(wl); return(1); diff --git a/srcs/icmp.c b/srcs/icmp.c index 430f568..ca8b5a3 100644 --- a/srcs/icmp.c +++ b/srcs/icmp.c @@ -6,7 +6,7 @@ /* By: tomoron +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2025/04/24 22:49:22 by tomoron #+# #+# */ -/* Updated: 2025/04/30 17:53:19 by tomoron ### ########.fr */ +/* Updated: 2025/05/01 20:19:41 by tomoron ### ########.fr */ /* */ /* ************************************************************************** */ #include "includes/ft_ping.h" @@ -62,3 +62,45 @@ t_icmp_echo prepare_icmp_echo(uint16_t sequence, uint16_t identifier) return(packet); } + +t_waitlist *send_icmp(t_settings *set, struct addrinfo *host, uint16_t *seq, struct timeval *last, t_stats *stats) +{ + t_icmp_echo packet; + t_waitlist *ret; + + if(timediff(last) < set->interval) + return (0); + packet = prepare_icmp_echo(*seq, set->id); + sendto(set->socket, &packet, sizeof(t_icmp_echo), 0, host->ai_addr, host->ai_addrlen); + gettimeofday(last, 0); + ret = malloc(sizeof(t_waitlist)); + if(!ret) + return(0); + ret->time = *last; + ret->seq = *seq; + ret->next = 0; + stats->sent++; + (*seq)++; + return(ret); +} + +void receive_icmp(t_settings *set, struct addrinfo *info, t_waitlist **wl, t_stats *stats) +{ + size_t len; + char buf[256]; + t_icmp_echo *res; + uint16_t checksum; + + len = recvfrom(set->socket, buf, sizeof(t_icmp_echo) + 20, 0, info->ai_addr, &info->ai_addrlen); + res = (void*)(buf + 20); + if(len == (size_t)-1 || len < 84) + return; + if(res->type != 0 && res->identifier != set->id) + return ; + checksum = res->checksum; + res->checksum = 0; + if(calc_checksum(res, sizeof(t_icmp_echo)) != checksum) + return ; + res->sequence = htons(res->sequence); + waitlist_remove(wl, res->sequence, set, stats); +} diff --git a/srcs/includes/ft_ping.h b/srcs/includes/ft_ping.h index 0ce672d..95fbaf1 100644 --- a/srcs/includes/ft_ping.h +++ b/srcs/includes/ft_ping.h @@ -13,6 +13,8 @@ #include #include #include +#include +#include #include @@ -21,14 +23,16 @@ #define HELP_MESSAGE " [OPTION...] HOST ...\n\ Send ICMP ECHO_REQUEST packets to network hosts.\n\ \n\ - -c, --count=NUMBER stop after sending NUMBER packets\n\ - -n, --numeric do not resolve host addresses\n\ + -c, --count=N stop after sending NUMBER packets\n\ --ttl=N specify N as time-to-live\n\ -w, --timeout=N stop after N seconds\n\ + -i, --interval=N wait N seconds between sending each packet\n\ + -W, --linger=N number of seconds to wait for response\n\ \n\ - -f, --flood flood ping (root only)\n\ -?, --help give this help list\n" +extern int g_stop; + typedef struct s_waitlist { struct timeval time; @@ -57,6 +61,8 @@ typedef struct s_settings short stop; short err; char *name; + + char current_ip[INET_ADDRSTRLEN]; } t_settings; @@ -72,6 +78,19 @@ typedef struct s_icmp_echo uint8_t data[40]; } t_icmp_echo; +typedef struct s_stats +{ + size_t sent; + size_t received; + + double min; + double avg; + double max; + + double sqr_diff; + double prev; +} t_stats; + t_icmp_echo prepare_icmp_echo(uint16_t sequence, uint16_t identifier); int add_host(t_settings *res, char *host); void free_hosts(t_host_list *list); @@ -79,5 +98,12 @@ t_settings parse_args(int argc, char **argv); void show_help(t_settings *set, char *name); void send_pings(t_settings *set); uint16_t calc_checksum(void *ptr, size_t len); +double timediff(struct timeval *from); +void waitlist_remove(t_waitlist **lst, uint16_t seq, t_settings *set, t_stats *stats); +void show_ping_res_line(t_waitlist *cur, t_settings *set, uint16_t seq, t_stats *stats); +void waitlist_free(t_waitlist *lst); +t_waitlist *send_icmp(t_settings *set, struct addrinfo *host, uint16_t *seq, struct timeval *last, t_stats *stats); +void waitlist_add(t_waitlist **waitlist, t_waitlist *elem); +void receive_icmp(t_settings *set, struct addrinfo *info, t_waitlist **wl, t_stats *stats); #endif diff --git a/srcs/main.c b/srcs/main.c index 40a5d09..825df14 100644 --- a/srcs/main.c +++ b/srcs/main.c @@ -6,12 +6,14 @@ /* By: tomoron +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2025/04/24 00:03:56 by tomoron #+# #+# */ -/* Updated: 2025/04/30 16:48:45 by tomoron ### ########.fr */ +/* Updated: 2025/05/02 00:51:39 by tomoron ### ########.fr */ /* */ /* ************************************************************************** */ #include "includes/ft_ping.h" +int g_stop = 0; + void show_help(t_settings *set, char *name) { set->stop = 1; @@ -47,6 +49,12 @@ uint16_t get_id(void) } +void signal_handler(int signum) +{ + (void)signum; + g_stop = 1; +} + int main(int argc, char **argv) { t_settings settings; @@ -55,6 +63,7 @@ int main(int argc, char **argv) settings.socket = init_socket(argv[0]); settings.id = get_id(); settings.name = argv[0]; + signal(SIGINT, signal_handler); if(settings.stop || settings.err || settings.socket == -1) { free_hosts(settings.hosts); diff --git a/srcs/stats.c b/srcs/stats.c new file mode 100644 index 0000000..ac4e47e --- /dev/null +++ b/srcs/stats.c @@ -0,0 +1,41 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* stats.c :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: tomoron +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2025/05/01 17:41:42 by tomoron #+# #+# */ +/* Updated: 2025/05/02 01:03:15 by tomoron ### ########.fr */ +/* */ +/* ************************************************************************** */ + +#include "includes/ft_ping.h" + +void update_stats(t_stats *stats, double time) +{ + double tmp; + + stats->received++; + tmp = 0; + if(stats->prev) + tmp = time - stats->avg; + stats->min = MIN(stats->min, time); + if(stats->min == 0) + stats->min = time; + stats->max = MAX(stats->max, time); + stats->avg += (time - stats->avg) / stats->received; + if(stats->prev) + stats->sqr_diff += tmp * stats->avg; + stats->prev = time; +} + +void show_ping_res_line(t_waitlist *cur, t_settings *set, uint16_t seq, t_stats *stats) +{ + double diff; + + diff = timediff(&cur->time) * 1000; + update_stats(stats, diff); + printf("%d bytes from %s: icmp_seq=%d ttl=??? time=%.3f ms\n", 64, set->current_ip, seq, diff); +} + diff --git a/srcs/utils.c b/srcs/utils.c index 28b0320..b6e6a74 100644 --- a/srcs/utils.c +++ b/srcs/utils.c @@ -6,7 +6,7 @@ /* By: tomoron +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2025/04/26 17:03:11 by tomoron #+# #+# */ -/* Updated: 2025/04/26 17:08:08 by tomoron ### ########.fr */ +/* Updated: 2025/05/02 01:07:37 by tomoron ### ########.fr */ /* */ /* ************************************************************************** */ #include "includes/ft_ping.h" @@ -37,9 +37,19 @@ void free_hosts(t_host_list *list) while(list) { - printf("free : %s\n", list->host); tmp = list->next; free(list); list = tmp; } } + +double timediff(struct timeval *from) +{ + struct timeval now; + float diff; + + gettimeofday(&now, 0); + diff = ((double)now.tv_sec - from->tv_sec); + diff += (((double)now.tv_usec / 1000000) - ((double)from->tv_usec / 1000000)); + return(diff); +} diff --git a/srcs/waitlist_utils.c b/srcs/waitlist_utils.c new file mode 100644 index 0000000..034d327 --- /dev/null +++ b/srcs/waitlist_utils.c @@ -0,0 +1,63 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* waitlist_utils.c :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: tomoron +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2025/05/01 17:38:58 by tomoron #+# #+# */ +/* Updated: 2025/05/02 01:06:21 by tomoron ### ########.fr */ +/* */ +/* ************************************************************************** */ + +#include "includes/ft_ping.h" + +void waitlist_add(t_waitlist **waitlist, t_waitlist *elem) +{ + t_waitlist *cur; + + cur = *waitlist; + + while(cur && cur->next) + cur = cur->next; + if(cur) + cur->next = elem; + else + *waitlist = elem; +} + +void waitlist_free(t_waitlist *lst) +{ + t_waitlist *tmp; + + while(lst) + { + tmp = lst->next; + free(lst); + lst = tmp; + } +} + +void waitlist_remove(t_waitlist **lst, uint16_t seq, t_settings *set, t_stats *stats) +{ + t_waitlist *prev; + t_waitlist *cur; + + prev = 0; + cur = *lst; + while(cur && cur->seq != seq) + { + printf("%d, %d\n", cur->seq, seq); + prev = cur; + cur = cur->next; + } + if(!cur) + return ; + if(!prev) + *lst = cur->next; + else + prev->next = cur->next; + show_ping_res_line(cur, set, seq, stats); + free(cur); +} +