diff --git a/.editorconfig b/.editorconfig deleted file mode 100644 index e69de29..0000000 diff --git a/Makefile b/Makefile index 4549d0c..08880dd 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,8 @@ NAME = ./ft_ping SRCS = src/main.c \ - src/utils.c + src/utils.c \ + src/flags.c OBJ_DIR = objs diff --git a/compile_commands.json b/compile_commands.json deleted file mode 100644 index 963e993..0000000 --- a/compile_commands.json +++ /dev/null @@ -1,12 +0,0 @@ -[ - { - "directory": "/nfs/homes/vvaas/42/ft_ping", - "command": "clang++ -std=c++20 -I includes -c /nfs/homes/vvaas/42/ft_ping/src/main.c -o /nfs/homes/vvaas/42/ft_ping/objs/ma.o", - "file": "/nfs/homes/vvaas/42/ft_ping/src/main.c" - }, - { - "directory": "/nfs/homes/vvaas/42/ft_ping", - "command": "clang++ -std=c++20 -I includes -c /nfs/homes/vvaas/42/ft_ping/src/utils.c -o /nfs/homes/vvaas/42/ft_ping/objs/uti.o", - "file": "/nfs/homes/vvaas/42/ft_ping/src/utils.c" - } -] \ No newline at end of file diff --git a/includes/ft_ping.h b/includes/ft_ping.h index b34f7c8..61364a1 100644 --- a/includes/ft_ping.h +++ b/includes/ft_ping.h @@ -1,12 +1,12 @@ #pragma once - #include #include #include #include #include #include +#include #include #include @@ -17,7 +17,7 @@ #include #include -#define PACKET_SIZE 56 +#define PACKET_SIZE 64 struct icmp_header { @@ -35,11 +35,32 @@ struct packet_stats double timestamp_array[65536]; }; -uint16_t make_checksum(uint16_t *data, int len); -double get_timestamp(); -struct in_addr get_addr_by_hostname(char *hostname); -double get_stddev(double *timestamp_array); -void fill_timestamp_array(struct packet_stats *sockstats, double time); -double get_avg(double *timestamp_array); -double get_min(double *timestamp_array); -double get_max(double *timestamp_array); +struct flags +{ + bool verbose; + bool quiet; + bool flood; + double interval; + int preload_count; + int count; +}; + +// PACKET UTILS +uint16_t make_checksum(uint16_t *data, int len); +struct in_addr get_addr_by_hostname(char *hostname); + +// MATH +double get_stddev(const double *timestamp_array); +double get_avg(const double *timestamp_array); +double get_min(const double *timestamp_array); +double get_max(const double *timestamp_array); +long ft_atoi(const char *nptr); + +// VERBOSE +void print_help(void); +bool parse_opt(int argc, char **argv, struct flags *flags); + +// STATS +void print_recap(char *ip, const struct packet_stats stats); +void fill_timestamp_array(struct packet_stats *sockstats, double time); +double get_timestamp(); \ No newline at end of file diff --git a/src/flags.c b/src/flags.c new file mode 100644 index 0000000..157118a --- /dev/null +++ b/src/flags.c @@ -0,0 +1,91 @@ +#include "ft_ping.h" + +const char *flag_list[] = +{ + "usage : ping [OPTIONS ...] [ADDRESS]", + " -c [COUNT] stop after COUNT packets have been sent", + " -f flood mode", + " -i [NUMBER] send a ping at NUMBER seconds intervals", + " -l [NUMBER] send NUMBER ping as fast as possible then continue in normal mode", + " -q quiet mode", + " -v, verbose output", + " -?, print this help page", + +}; + +void print_help(void) +{ + for (int i = 0; flag_list[i]; i++) + printf("%s\n", flag_list[i]); +} + +bool parse_opt(int argc, char **argv, struct flags *flags) +{ + int flag; + while ((flag = getopt(argc, argv, "c:fi:l:qv?")) != -1) + { + switch (flag) + { + case 'v': + flags->verbose = true; + break; + + case 'q': + flags->quiet = true; + break; + + case '?': + print_help(); + return (false); + + case 'i': + if (flags->flood) + { + fprintf(stderr, "%s: -f and -i flags are incompatible\n%s\n", argv[0], flag_list[0]); + return (false); + } + if (atof(optarg) <= 0) + { + fprintf(stderr, "%s: invalid value '%s'\n%s\n", argv[0], optarg, flag_list[0]); + return (false); + } + flags->interval = atof(optarg); + break; + + case 'c': + if (ft_atoi(optarg) == -1) + { + fprintf(stderr, "%s: invalid value '%s'\n%s\n", argv[0], optarg, flag_list[0]); + return (false); + } + flags->count = ft_atoi(optarg); + break; + + case 'f': + if (flags->interval != -1) + { + fprintf(stderr, "%s: -f and -i flags are incompatible\n%s\n", argv[0], flag_list[0]); + return (false); + } + flags->flood = true; + flags->quiet = true; + flags->interval = 0; + break; + + case 'l': + if (ft_atoi(optarg) == -1) + { + fprintf(stderr, "%s: invalid value '%s'\n%s\n", argv[0], optarg, flag_list[0]); + return (false); + } + flags->preload_count = ft_atoi(optarg); + break; + } + } + if (argc < 2 || argv[optind] == NULL || argv[optind][0] == 0) // optind is a value given by getopt() that's equal to the first argument that isn't a flag + { + fprintf(stderr, "ERROR : usage : %s [OPTIONS ...] [ADDRESS]\n", argv[0]); + return (false); + } + return (true); +} \ No newline at end of file diff --git a/src/main.c b/src/main.c index a0ce149..e9deb7f 100644 --- a/src/main.c +++ b/src/main.c @@ -3,7 +3,7 @@ struct packet_stats stats; bool loop = true; -int ft_ping(int sock, uint16_t seq, struct sockaddr_in *dst) +static int ft_ping(const int sock, const uint16_t seq, const struct sockaddr_in *dst) { unsigned char data[PACKET_SIZE]; struct icmp_header *icmp_hdr = (struct icmp_header *)data; @@ -25,7 +25,7 @@ int ft_ping(int sock, uint16_t seq, struct sockaddr_in *dst) return (1); } -int ft_recv(int sock, uint16_t seq, double start) +static int ft_recv(const int sock, const uint16_t seq, const double start, const bool quiet) { unsigned char data[PACKET_SIZE]; struct icmp_header *icmp_hdr = (struct icmp_header *)(data + 20); @@ -46,22 +46,23 @@ int ft_recv(int sock, uint16_t seq, double start) return (0); fill_timestamp_array(&stats, time); stats.n_packet_recv++; - printf("%d bytes from %s: icmp_seq=%d ttl=%d time=%5.3fms\n", n_bytes, inet_ntoa(addr.sin_addr), icmp_hdr->seq, (uint8_t)data[8], time); + if (!quiet) + printf("%d bytes from %s: icmp_seq=%d ttl=%d time=%5.3fms\n", n_bytes, inet_ntoa(addr.sin_addr), icmp_hdr->seq, (uint8_t)data[8], time); return (1); } -void handler(int code) +static void signal_handler(int code) { (void)code; - loop = 0; + loop = false; } -void init_signal() +static void init_signal() { - signal(SIGINT, handler); + signal(SIGINT, signal_handler); } -bool init_socket(int *sock, struct sockaddr_in *dst, char *host) +static bool init_socket(int *sock, struct sockaddr_in *dst, char *host) { struct timeval timeout; @@ -87,58 +88,42 @@ bool init_socket(int *sock, struct sockaddr_in *dst, char *host) return (true); } -void print_recap(char *ip) -{ - printf("--- %s ping statistics ---\n", ip); - printf("%d packed transmitted, %d received, %0.0f%% packet loss\n", stats.n_packet_sent, stats.n_packet_recv, (double)(stats.n_packet_sent - stats.n_packet_recv) / stats.n_packet_sent * 100); - printf("round-trip min/avg/max/stddev = %5.3f/%5.3f/%5.3f/%5.3f ms\n", get_min(stats.timestamp_array), get_avg(stats.timestamp_array), get_max(stats.timestamp_array), get_stddev(stats.timestamp_array)); -} - int main(int argc, char **argv) { - int sock; - struct sockaddr_in dst; + int socket_fd; + struct sockaddr_in dst_addr; char *ip; uint16_t seq = 1; double start; - int flags; - bool verbose = false; + struct flags flags = {false, false, false, 1, -1, -1}; - while ((flags = getopt(argc, argv, "v?")) != -1) - { - switch (flags) - { - case 'v': - verbose = true; - break; - case '?': - fprintf(stdout, "usage : %s {-v?} [ADRESS]\n", argv[0]); - return (1); - } - } - if (argc < 2 || argv[optind] == NULL || argv[optind][0] == 0) // optind is a value given by getopt() that's equal to the first argument that isn't a flag - { - fprintf(stderr, "ERROR : usage : %s {-v?} [ADRESS]\n", argv[0]); + if (parse_opt(argc, argv, &flags) == false) return (0); - } init_signal(); - if (!init_socket(&sock, &dst, argv[optind])) + if (!init_socket(&socket_fd, &dst_addr, argv[optind])) return (-1); ip = inet_ntoa(get_addr_by_hostname(argv[optind])); - if (verbose) - fprintf(stdout, "PING %s (%s) : %d data bytes, id 0x%04x = %d\n", argv[optind], ip, PACKET_SIZE, getpid(), getpid()); + if (flags.verbose) + printf("PING %s (%s) : %d data bytes, id 0x%04x = %d\n", argv[optind], ip, (PACKET_SIZE - 8), getpid(), getpid()); else - fprintf(stdout, "PING %s (%s) : %d data bytes\n", argv[optind], ip, PACKET_SIZE); + printf("PING %s (%s) : %d data bytes\n", argv[optind], ip, (PACKET_SIZE - 8)); while (loop) { start = get_timestamp(); - if (ft_ping(sock, seq, &dst) == 0) + if (ft_ping(socket_fd, seq, &dst_addr) == 0) break; - while (!ft_recv(sock, seq, start)); + while (!ft_recv(socket_fd, seq, start, flags.quiet)); seq++; - sleep(1); + if (flags.count != -1) + flags.count--; + if (flags.count == 0) + break; + if (flags.preload_count <= 0) + usleep(flags.interval * 1000000); + else + flags.preload_count--; } - print_recap(argv[optind]); - close(sock); + print_recap(argv[optind], stats); + close(socket_fd); return (0); } diff --git a/src/utils.c b/src/utils.c index 38cf756..7ef04fd 100644 --- a/src/utils.c +++ b/src/utils.c @@ -42,7 +42,31 @@ void fill_timestamp_array(struct packet_stats *stats, double time) stats->timestamp_array[stats->n_packet_recv] = time; } -double get_min(double *timestamp_array) +bool ft_isdigit(const char n) +{ + return (n >= '0' && n <= '9'); +} + +long ft_atoi(const char *nptr) +{ + unsigned long i = 0; + + if (nptr == NULL) + return (-1); + for (int j = 0; nptr[j]; j++) + { + if (!ft_isdigit(nptr[j])) + return (-1); + } + while (*nptr) + { + i = i * 10 + *nptr - '0'; + nptr++; + } + return (i); +} + +double get_min(const double *timestamp_array) { // get the smallest element of the timestamp_array double min = timestamp_array[0]; @@ -54,7 +78,7 @@ double get_min(double *timestamp_array) return (min); } -double get_max(double *timestamp_array) +double get_max(const double *timestamp_array) { // get the biggest element of the timestamp_array double max = timestamp_array[0]; @@ -66,7 +90,7 @@ double get_max(double *timestamp_array) return (max); } -double get_avg(double *timestamp_array) +double get_avg(const double *timestamp_array) { // get the average of elements in timestamp_array double avg = 0; @@ -82,7 +106,7 @@ double get_avg(double *timestamp_array) return (avg /= i); } -double get_stddev(double *timestamp_array) +double get_stddev(const double *timestamp_array) { // get the standard deviation of elements in timestamp_array float avg = get_avg(timestamp_array); @@ -96,3 +120,10 @@ double get_stddev(double *timestamp_array) } return (sqrt(variance)); } + +void print_recap(char *ip, const struct packet_stats stats) +{ + printf("--- %s ping statistics ---\n", ip); + printf("%d packed transmitted, %d received, %0.0f%% packet loss\n", stats.n_packet_sent, stats.n_packet_recv, (double)(stats.n_packet_sent - stats.n_packet_recv) / stats.n_packet_sent * 100); + printf("round-trip min/avg/max/stddev = %5.3f/%5.3f/%5.3f/%5.3f ms\n", get_min(stats.timestamp_array), get_avg(stats.timestamp_array), get_max(stats.timestamp_array), get_stddev(stats.timestamp_array)); +} \ No newline at end of file