diff --git a/ping/Makefile b/ping/Makefile index 11b6c1c0..e6031de4 100644 --- a/ping/Makefile +++ b/ping/Makefile @@ -17,7 +17,7 @@ NAME = ft_ping CC = gcc RM = rm -rf 2>&- W_FLAGS = -Wall -Wextra -Werror -D_FLAGS = +D_FLAGS = -D _GNU_SOURCE FLAGS = $(W_FLAGS) $(D_FLAGS) LEN_NAME = `printf "%s" $(NAME) |wc -c` @@ -30,9 +30,11 @@ OBJ_DIR = objs/ SRC_BASE = \ ping.c\ create_client.c\ -epoch.c\ cksum.c\ rs.c\ +epoch.c\ +cliopts.c\ +error.c\ SRCS = $(addprefix $(SRC_DIR), $(SRC_BASE)) OBJS = $(addprefix $(OBJ_DIR), $(SRC_BASE:.c=.o)) @@ -43,10 +45,7 @@ all : @make -j $(NAME) $(NAME): $(OBJ_DIR) $(OBJS) $(CLIENT_OBJ) - $(CC) $(OBJS) -o $@ \ - -I $(INC_DIR) \ - $(CLIENT_OBJ) $(FLAGS) \ - -lm + $(CC) $(OBJS) -o $@ -I $(INC_DIR) $(CLIENT_OBJ) $(FLAGS) -lm # sudo setcap cap_net_raw+ep $@ 2>&- $(OBJ_DIR) : diff --git a/ping/cliopts.c b/ping/cliopts.c new file mode 100644 index 00000000..5a7bd001 --- /dev/null +++ b/ping/cliopts.c @@ -0,0 +1,132 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* cliopts_get.c :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: jhalford +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2017/03/14 20:04:04 by jhalford #+# #+# */ +/* Updated: 2017/04/02 20:45:11 by jhalford ### ########.fr */ +/* */ +/* ************************************************************************** */ + +/* +** void *data must be a structure starting with `int flag` +** to do polymorphism with t_data_template ! +*/ + +#include "cliopts.h" + +t_cliopts *cliopts_getmap_long(t_cliopts opt_map[], char *arg) +{ + int i; + + i = -1; + while (opt_map[++i].c) + if (!strcmp(opt_map[i].str, arg)) + return (&opt_map[i]); + return (NULL); +} + +t_cliopts *cliopts_getmap_short(t_cliopts opt_map[], char arg) +{ + int i; + + i = -1; + while (opt_map[++i].c) + if (opt_map[i].c == arg) + return (&opt_map[i]); + return (NULL); +} + +static char *check_required(char ***av, char *arg) +{ + char *ret; + + if (!av || !*av) + return (NULL); + if (!arg || !*arg || !*(arg + 1)) + return (*++(*av)); + ret = arg + 1; + return (ret); +} + +static int cliopts_parse_short( + char ***av, t_cliopts opt_map[], void *data) +{ + t_cliopts *map; + char *arg; + int i; + char *tmp; + + arg = **av + 1; + i = -1; + while (arg[++i] && !(tmp = NULL)) + { + if (!(map = cliopts_getmap_short(opt_map, arg[i]))) + return (ERR_SET(E_CO_INV, arg[i])); + ((t_data_template*)data)->flag |= map->flag_on; + ((t_data_template*)data)->flag &= ~map->flag_off; + if (map->get) + { + if (map->arg_required && !(tmp = check_required(av, arg + i))) + return (ERR_SET(E_CO_MISS, *arg)); + tmp = tmp ? tmp : **av; + if ((map->get)(tmp, data)) + return (ERR_SET(E_CO_MISS, *arg)); + if (map->arg_required) + break ; + } + } + return (++(*av) ? 0 : 0); +} + +static int cliopts_parse_long( + char ***av, t_cliopts opt_map[], void *data) +{ + t_cliopts *map; + char *arg; + char *tmp; + + arg = **av + 2; + tmp = NULL; + if (!(map = cliopts_getmap_long(opt_map, arg))) + return (ERR_SET(E_CO_INVL, arg)); + ((t_data_template*)data)->flag |= map->flag_on; + ((t_data_template*)data)->flag &= ~map->flag_off; + if (map->get) + { + if (map->arg_required && !(tmp = check_required(av, NULL))) + return (ERR_SET(E_CO_MISS, *arg)); + if ((map->get)(tmp, data)) + return (ERR_SET(E_CO_MISSL, arg)); + } + ++(*av); + return (0); +} + +int cliopts_get(char **av, t_cliopts opt_map[], void *data) +{ + if (!av) + return (1); + av++; + while (av && *av) + { + if (strcmp(*av, "-") == 0 || (strcmp(*av, "--") == 0 && av++)) + break ; + else if ((*av)[0] == '-' && (*av)[1] == '-') + { + if (cliopts_parse_long(&av, opt_map, data)) + return (1); + } + else if ((*av)[0] == '-') + { + if (cliopts_parse_short(&av, opt_map, data)) + return (1); + } + else + break ; + } + ((t_data_template*)data)->av_data = av; + return (0); +} diff --git a/ping/cliopts.h b/ping/cliopts.h new file mode 100644 index 00000000..cb12f929 --- /dev/null +++ b/ping/cliopts.h @@ -0,0 +1,40 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* cliopts.h :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: jhalford +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2017/03/14 20:22:56 by jhalford #+# #+# */ +/* Updated: 2017/10/07 18:04:53 by jhalford ### ########.fr */ +/* */ +/* ************************************************************************** */ + +#pragma once + +# include "error.h" +# include + +typedef struct s_cliopts t_cliopts; +typedef struct s_data_template t_data_template; +typedef long long t_flag; + +struct s_cliopts +{ + char c; + char *str; + t_flag flag_on; + t_flag flag_off; + int (*get)(); // (char *arg, void *data) + int arg_required:1; +}; + +struct s_data_template +{ + t_flag flag; + char **av_data; +}; + +int cliopts_get(char **av, t_cliopts opt_map[], void *data); +t_cliopts *cliopts_getmap_long(t_cliopts opt_map[], char *arg); +t_cliopts *cliopts_getmap_short(t_cliopts opt_map[], char arg); diff --git a/ping/error.c b/ping/error.c new file mode 100644 index 00000000..cbc459dc --- /dev/null +++ b/ping/error.c @@ -0,0 +1,68 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* error.c :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: jhalford +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2017/03/14 16:47:00 by jhalford #+# #+# */ +/* Updated: 2017/03/25 01:53:25 by jhalford ### ########.fr */ +/* */ +/* ************************************************************************** */ + +#include "error.h" + +char g_error_msglist[E_MAX][ERRMSG_MAX_SIZE] = +{ + "unknown error 0", + "invalid option -%c", + "invalid option --%s", + "option '%c' awaits argument(s): please don't combine", + "option '%c': missing argument", + "option '%s': missing argument", + "%s: no such file or directory", + "%s: Is a directory", + "%s: Permission denied", +}; + +int g_errnum = 0; +char *g_errmsg = NULL; +char **g_argv; + +int error_set(int n, ...) +{ + va_list ap; + + g_errnum = n; + va_start(ap, n); + if (g_errmsg) + { + free(g_errmsg); + g_errmsg = NULL; + } + vasprintf(&g_errmsg, g_error_msglist[n], ap); + return (g_errnum); +} + +int ft_perror(char *utility) +{ + utility = utility ? utility : g_argv[0]; + ERR_MSG(utility, g_errmsg); + return (g_errnum); +} + +void ft_usage(char *format, ...) +{ + va_list ap; + char *usage; + + va_start(ap, format); + usage = NULL; + vasprintf(&usage, format, ap); + dprintf(2, "usage: %s\n", usage); + if (usage) + { + free(usage); + usage = NULL; + } +} diff --git a/ping/error.h b/ping/error.h new file mode 100644 index 00000000..4ff21d9c --- /dev/null +++ b/ping/error.h @@ -0,0 +1,64 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* error.h :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: jhalford +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2017/03/14 15:34:21 by jhalford #+# #+# */ +/* Updated: 2017/05/15 17:37:29 by ariard ### ########.fr */ +/* */ +/* ************************************************************************** */ + +#ifndef ERROR_H +# define ERROR_H + +# include +# include +# include + +/* +** DEBUG with malloc +*/ +# define DG_MSG "{inv}{ran}%5i{yel}%21s {bol}{blu}%-3d{eoc}" +# define DG_ARGS getpid(), getpid(), ft_path_notdir(__FILE__), __LINE__ +# define DG(s, ...) dprintf(STDBUG,DG_MSG s "{eoc}\n",DG_ARGS,##__VA_ARGS__) + +/* +** DEBUG with no malloc +*/ +# define DG2 ft_putstr(__FILE__"\t");ft_putnbr(__LINE__) +# define DGW(d) DG2;d;ft_putchar('\n') +# define DGS(s) DGW(ft_putstr(": "s"=")) +# define DGSN(s, n) DGW(ft_putstr(": "s"=");ft_putnbr(n)) +# define DGSH(s, n) DGW(ft_putstr(": "s"=");ft_putnbr_hex(n)) + +# define ERR_PROTO(u, m) "%s: %s\n", u, m +# define ERR_MSG(u, m) dprintf(2, ERR_PROTO(u, m)) +# define ERR_SET(n, ...) error_set(n, ##__VA_ARGS__) +# define ERRMSG_MAX_SIZE 150 + +enum e_errors +{ + E_NOERR, + E_CO_INV, + E_CO_INVL, + E_CO_MULT, + E_CO_MISS, + E_CO_MISSL, + E_SYS_NOFILE, + E_SYS_ISDIR, + E_SYS_NOPERM, + E_MAX, +}; + +extern char g_error_msg[E_MAX][ERRMSG_MAX_SIZE]; +extern char *g_errmsg; +extern int g_errnum; +extern char **g_argv; + +int error_set(int n, ...); +int ft_perror(char *utility); +void ft_usage(char *format, ...); + +#endif diff --git a/ping/ping.c b/ping/ping.c index 504fc963..0ec0e764 100644 --- a/ping/ping.c +++ b/ping/ping.c @@ -12,12 +12,27 @@ #include "ping.h" +#define PING_USAGE "%s [-hv] [-t ttl] destination" + t_ping g_ping = { .pid = -1, .pkt_size = 56, .pkt_sent = -1, .pkt_recv = 0, + .ttl = 255, +}; + +int get_ttl(char *arg, t_ping *data); + +t_cliopts opts[] = +{ +#define FLAG_HELP (1 << 0) +#define FLAG_VERBOSE (1 << 1) +#define FLAG_TTL (1 << 2) + {'h', NULL, FLAG_HELP, 0, NULL, 0}, + {'v', NULL, FLAG_VERBOSE, 0, NULL, 0}, + {'t', NULL, FLAG_TTL, 0, get_ttl, 1}, }; int resolve_host(char *node, t_ping *ping) @@ -126,14 +141,33 @@ void stats_recap(int signo) exit(0); } +int get_interval(char *arg, t_ping *data) +{ + data->interval = atof(arg); + return (0); +} + +int get_ttl(char *arg, t_ping *data) +{ + data->ttl = atoi(arg); + return (0); +} + int main(int ac, char **av) { - if (ac != 2) + (void)ac; + if (cliopts_get(av, opts, &g_ping)) { - dprintf(2, "%s \n", av[0]); + ft_perror(av[0]); + ft_usage(PING_USAGE, av[0]); exit(1); } - resolve_host(av[1], &g_ping); + if (g_ping.flag & FLAG_HELP || !g_ping.av_data[0]) + { + ft_usage(PING_USAGE, av[0]); + exit(!(g_ping.flag & FLAG_HELP)); + } + resolve_host(g_ping.av_data[0], &g_ping); if (g_ping.sa->ai_canonname) printf("PING %s (%s): %zu(%zu) data bytes\n", g_ping.sa->ai_canonname, g_ping.ip4, @@ -146,7 +180,7 @@ int main(int ac, char **av) perror("socket"); exit(1); } - if (setsockopt(g_ping.sock, 0, IP_TTL, (int[]){255}, sizeof(int)) != 0) + if (setsockopt(g_ping.sock, 0, IP_TTL, &g_ping.ttl, sizeof(g_ping.ttl)) != 0) { perror("setsockopt"); exit(1); diff --git a/ping/ping.h b/ping/ping.h index 2f9a039d..26773ba8 100644 --- a/ping/ping.h +++ b/ping/ping.h @@ -10,27 +10,27 @@ /* */ /* ************************************************************************** */ -#ifndef FT_PING_H -# define FT_PING_H +#pragma once # include "rs.h" +# include "cliopts.h" # include # include # include # include +# include +# include +# include # include # include -# include # include # include -# include # include # include # include # include -# include # define FT_PCT(a, t) (t ? 100 * (float)(t - a)/(float)t : 0) @@ -38,11 +38,15 @@ typedef struct s_ping t_ping; struct s_ping { + t_flag flag; + char **av_data; size_t pkt_size; pid_t pid; t_rs rs; int pkt_sent; int pkt_recv; + int ttl; + float interval; int sock; struct addrinfo *sa; union @@ -60,5 +64,3 @@ unsigned short cksum(void *b, int len); double time_milli(void); void listener(int domain, int sock, int proto, void (*handler)(void *buf, int bytes, struct sockaddr *addr)); - -#endif diff --git a/ping/rs.h b/ping/rs.h index 40bf6fc1..3aa6bd6b 100644 --- a/ping/rs.h +++ b/ping/rs.h @@ -10,8 +10,7 @@ /* */ /* ************************************************************************** */ -#ifndef LIBFT_RS_H -# define LIBFT_RS_H +#pragma once # include # include @@ -33,5 +32,3 @@ struct s_rs { void rs_init(t_rs *rs); void rs_push(t_rs *rs, double n); void rs_final(t_rs *rs); - -#endif