Merge ping with full history
This commit is contained in:
commit
4320bc5460
13 changed files with 849 additions and 0 deletions
1
ping/.gitignore
vendored
Normal file
1
ping/.gitignore
vendored
Normal file
|
|
@ -0,0 +1 @@
|
|||
ft_ping
|
||||
67
ping/Makefile
Normal file
67
ping/Makefile
Normal file
|
|
@ -0,0 +1,67 @@
|
|||
# **************************************************************************** #
|
||||
# #
|
||||
# ::: :::::::: #
|
||||
# Makefile :+: :+: :+: #
|
||||
# +:+ +:+ +:+ #
|
||||
# By: wescande <wescande@student.42.fr> +#+ +:+ +#+ #
|
||||
# +#+#+#+#+#+ +#+ #
|
||||
# Created: 2016/08/29 21:32:58 by wescande #+# #+# #
|
||||
# Updated: 2017/10/08 14:36:33 by jhalford ### ########.fr #
|
||||
# #
|
||||
# **************************************************************************** #
|
||||
|
||||
SHELL := bash
|
||||
|
||||
NAME = ft_ping
|
||||
|
||||
CC = gcc
|
||||
RM = rm -rf 2>&-
|
||||
W_FLAGS = -Wall -Wextra -Werror
|
||||
D_FLAGS = -D _GNU_SOURCE
|
||||
FLAGS = $(W_FLAGS) $(D_FLAGS)
|
||||
|
||||
LEN_NAME = `printf "%s" $(NAME) |wc -c`
|
||||
DELTA = $$(echo "$$(tput cols)-31-$(LEN_NAME)"|bc)
|
||||
|
||||
SRC_DIR = ./
|
||||
INC_DIR = ./
|
||||
OBJ_DIR = objs/
|
||||
|
||||
SRC_BASE = \
|
||||
ping.c\
|
||||
create_client.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))
|
||||
NB = $(words $(SRC_BASE))
|
||||
INDEX = 0
|
||||
|
||||
all :
|
||||
@make -j $(NAME)
|
||||
|
||||
$(NAME): $(OBJ_DIR) $(OBJS) $(CLIENT_OBJ)
|
||||
$(CC) $(OBJS) -o $@ -I $(INC_DIR) $(CLIENT_OBJ) $(FLAGS) -lm
|
||||
# sudo setcap cap_net_raw+ep $@ 2>&-
|
||||
|
||||
$(OBJ_DIR) :
|
||||
@mkdir -p $(OBJ_DIR)
|
||||
|
||||
$(OBJ_DIR)%.o : $(SRC_DIR)%.c | $(OBJ_DIR)
|
||||
$(CC) $(FLAGS) $(OBJ_FLAG) -MMD -c $< -o $@ -I $(INC_DIR)
|
||||
|
||||
clean:
|
||||
$(RM) $(OBJ_DIR)
|
||||
|
||||
re: fclean all
|
||||
|
||||
fclean: clean
|
||||
$(RM) $(NAME)
|
||||
|
||||
.PHONY : fclean clean re
|
||||
|
||||
-include $(OBJS:.o=.d)
|
||||
31
ping/cksum.c
Normal file
31
ping/cksum.c
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
/* ************************************************************************** */
|
||||
/* */
|
||||
/* ::: :::::::: */
|
||||
/* cksum.c :+: :+: :+: */
|
||||
/* +:+ +:+ +:+ */
|
||||
/* By: jhalford <jack@crans.org> +#+ +:+ +#+ */
|
||||
/* +#+#+#+#+#+ +#+ */
|
||||
/* Created: 2017/10/08 12:45:43 by jhalford #+# #+# */
|
||||
/* Updated: 2017/10/08 12:48:41 by jhalford ### ########.fr */
|
||||
/* */
|
||||
/* ************************************************************************** */
|
||||
|
||||
#include "ping.h"
|
||||
|
||||
unsigned short cksum(void *b, int len)
|
||||
{
|
||||
unsigned short *buf;
|
||||
unsigned int sum;
|
||||
|
||||
buf = b;
|
||||
sum = 0;
|
||||
while (len > 1)
|
||||
{
|
||||
sum += *((unsigned short*)buf++);
|
||||
len -= 2;
|
||||
}
|
||||
if (len == 1)
|
||||
sum += *(unsigned char*)buf;
|
||||
sum = (sum >> 16) + (sum & 0xFFFF);
|
||||
return (~(sum + (sum >> 16)));
|
||||
}
|
||||
132
ping/cliopts.c
Normal file
132
ping/cliopts.c
Normal file
|
|
@ -0,0 +1,132 @@
|
|||
/* ************************************************************************** */
|
||||
/* */
|
||||
/* ::: :::::::: */
|
||||
/* cliopts_get.c :+: :+: :+: */
|
||||
/* +:+ +:+ +:+ */
|
||||
/* By: jhalford <jack@crans.org> +#+ +:+ +#+ */
|
||||
/* +#+#+#+#+#+ +#+ */
|
||||
/* 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);
|
||||
}
|
||||
40
ping/cliopts.h
Normal file
40
ping/cliopts.h
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
/* ************************************************************************** */
|
||||
/* */
|
||||
/* ::: :::::::: */
|
||||
/* cliopts.h :+: :+: :+: */
|
||||
/* +:+ +:+ +:+ */
|
||||
/* By: jhalford <jack@crans.org> +#+ +:+ +#+ */
|
||||
/* +#+#+#+#+#+ +#+ */
|
||||
/* 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 <string.h>
|
||||
|
||||
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);
|
||||
59
ping/create_client.c
Normal file
59
ping/create_client.c
Normal file
|
|
@ -0,0 +1,59 @@
|
|||
/* ************************************************************************** */
|
||||
/* */
|
||||
/* ::: :::::::: */
|
||||
/* create_client.c :+: :+: :+: */
|
||||
/* +:+ +:+ +:+ */
|
||||
/* By: jhalford <jack@crans.org> +#+ +:+ +#+ */
|
||||
/* +#+#+#+#+#+ +#+ */
|
||||
/* Created: 2017/10/07 17:59:28 by jhalford #+# #+# */
|
||||
/* Updated: 2017/10/08 13:33:51 by jhalford ### ########.fr */
|
||||
/* */
|
||||
/* ************************************************************************** */
|
||||
|
||||
#include "ping.h"
|
||||
|
||||
int create_client(char *addr, int port, char *protoname)
|
||||
{
|
||||
int sock;
|
||||
struct protoent *proto;
|
||||
struct sockaddr_in sin;
|
||||
|
||||
if (!(proto = getprotobyname(protoname)))
|
||||
return (-1);
|
||||
sock = socket(PF_INET, SOCK_STREAM, proto->p_proto);
|
||||
sin.sin_family = AF_INET;
|
||||
sin.sin_port = htons(port);
|
||||
sin.sin_addr.s_addr = inet_addr(addr);
|
||||
if (connect(sock, (const struct sockaddr *)&sin, sizeof(sin)) < 0)
|
||||
return (-1);
|
||||
return (sock);
|
||||
}
|
||||
|
||||
void listener(int domain, int sock, int proto,
|
||||
void (*handler)(void *buf, int bytes, struct sockaddr *addr))
|
||||
{
|
||||
int sd;
|
||||
struct sockaddr addr;
|
||||
unsigned char buf[1024];
|
||||
int bytes;
|
||||
socklen_t len;
|
||||
|
||||
len = sizeof(addr);
|
||||
sd = socket(domain, sock, proto);
|
||||
if (sd < 0)
|
||||
{
|
||||
perror("listener socket");
|
||||
exit(0);
|
||||
}
|
||||
while (1)
|
||||
{
|
||||
bzero(buf, sizeof(buf));
|
||||
bytes = recvfrom(sd, buf, sizeof(buf), 0,
|
||||
&addr, &len);
|
||||
if (bytes > 0 && handler)
|
||||
handler(buf, bytes, &addr);
|
||||
else
|
||||
perror("recvfrom");
|
||||
}
|
||||
exit(0);
|
||||
}
|
||||
31
ping/epoch.c
Normal file
31
ping/epoch.c
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
/* ************************************************************************** */
|
||||
/* */
|
||||
/* ::: :::::::: */
|
||||
/* epoch.c :+: :+: :+: */
|
||||
/* +:+ +:+ +:+ */
|
||||
/* By: jhalford <jack@crans.org> +#+ +:+ +#+ */
|
||||
/* +#+#+#+#+#+ +#+ */
|
||||
/* Created: 2017/10/07 17:58:42 by jhalford #+# #+# */
|
||||
/* Updated: 2017/10/08 13:15:50 by jhalford ### ########.fr */
|
||||
/* */
|
||||
/* ************************************************************************** */
|
||||
|
||||
#include "ping.h"
|
||||
|
||||
uint64_t epoch_micro(void)
|
||||
{
|
||||
struct timeval tv;
|
||||
|
||||
if (gettimeofday(&tv, NULL))
|
||||
return (0);
|
||||
return (tv.tv_sec * 1000000 + tv.tv_usec);
|
||||
}
|
||||
|
||||
double time_milli(void)
|
||||
{
|
||||
struct timeval tv;
|
||||
|
||||
if (gettimeofday(&tv, NULL))
|
||||
return (0);
|
||||
return ((double)(tv.tv_sec * 1000. + (double)tv.tv_usec / 1000.));
|
||||
}
|
||||
68
ping/error.c
Normal file
68
ping/error.c
Normal file
|
|
@ -0,0 +1,68 @@
|
|||
/* ************************************************************************** */
|
||||
/* */
|
||||
/* ::: :::::::: */
|
||||
/* error.c :+: :+: :+: */
|
||||
/* +:+ +:+ +:+ */
|
||||
/* By: jhalford <jhalford@student.42.fr> +#+ +:+ +#+ */
|
||||
/* +#+#+#+#+#+ +#+ */
|
||||
/* 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;
|
||||
}
|
||||
}
|
||||
64
ping/error.h
Normal file
64
ping/error.h
Normal file
|
|
@ -0,0 +1,64 @@
|
|||
/* ************************************************************************** */
|
||||
/* */
|
||||
/* ::: :::::::: */
|
||||
/* error.h :+: :+: :+: */
|
||||
/* +:+ +:+ +:+ */
|
||||
/* By: jhalford <jack@crans.org> +#+ +:+ +#+ */
|
||||
/* +#+#+#+#+#+ +#+ */
|
||||
/* 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 <stdarg.h>
|
||||
# include <stdlib.h>
|
||||
# include <stdio.h>
|
||||
|
||||
/*
|
||||
** 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
|
||||
195
ping/ping.c
Normal file
195
ping/ping.c
Normal file
|
|
@ -0,0 +1,195 @@
|
|||
/* ************************************************************************** */
|
||||
/* */
|
||||
/* ::: :::::::: */
|
||||
/* main.c :+: :+: :+: */
|
||||
/* +:+ +:+ +:+ */
|
||||
/* By: jhalford <jack@crans.org> +#+ +:+ +#+ */
|
||||
/* +#+#+#+#+#+ +#+ */
|
||||
/* Created: 2017/04/22 14:10:24 by jhalford #+# #+# */
|
||||
/* Updated: 2017/10/08 14:35:02 by jhalford ### ########.fr */
|
||||
/* */
|
||||
/* ************************************************************************** */
|
||||
|
||||
#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)
|
||||
{
|
||||
struct addrinfo *result;
|
||||
struct addrinfo hints;
|
||||
|
||||
memset(&hints, 0, sizeof(hints));
|
||||
hints.ai_family = PF_INET;
|
||||
hints.ai_socktype = SOCK_STREAM;
|
||||
hints.ai_flags |= AI_CANONNAME;
|
||||
if (getaddrinfo(node, NULL, &hints, &result) != 0)
|
||||
{
|
||||
perror("getaddrinfo");
|
||||
exit(1);
|
||||
}
|
||||
ping->sa = result;
|
||||
inet_ntop(AF_INET, &(((struct sockaddr_in*)ping->sa->ai_addr)->sin_addr),
|
||||
ping->ip4, INET_ADDRSTRLEN);
|
||||
return (0);
|
||||
}
|
||||
|
||||
void display_time_exceeded(struct sockaddr *addr, struct icmp *icmp)
|
||||
{
|
||||
char ipbuf[INET_ADDRSTRLEN];
|
||||
|
||||
bzero(ipbuf, INET_ADDRSTRLEN);
|
||||
getnameinfo(addr, sizeof(struct sockaddr_in), ipbuf, INET_ADDRSTRLEN,
|
||||
NULL, 0, NI_NUMERICHOST);
|
||||
printf("From %s icmp_seq=%d Time to live exceeded\n",
|
||||
ipbuf, icmp->icmp_id);
|
||||
}
|
||||
|
||||
void display(void *buf, int bytes, struct sockaddr *addr)
|
||||
{
|
||||
struct ip *ip;
|
||||
struct icmp *icmp;
|
||||
int hlen;
|
||||
double triptime;
|
||||
char hbuf[NI_MAXHOST];
|
||||
char ipbuf[INET_ADDRSTRLEN];
|
||||
|
||||
ip = buf;
|
||||
(void)bytes;
|
||||
hlen = ip->ip_hl << 2;
|
||||
icmp = (struct icmp*)(buf + hlen);
|
||||
if (icmp->icmp_type == ICMP_TIME_EXCEEDED)
|
||||
return (display_time_exceeded(addr, icmp));
|
||||
else if (icmp->icmp_id != g_ping.pid)
|
||||
{
|
||||
dprintf(2, "id = %i\n", icmp->icmp_id);
|
||||
return ;
|
||||
}
|
||||
triptime = time_milli() - *(double*)(icmp + 1);
|
||||
rs_push(&g_ping.rs, triptime);
|
||||
g_ping.pkt_recv++;
|
||||
|
||||
bzero(hbuf, NI_MAXHOST);
|
||||
bzero(ipbuf, INET_ADDRSTRLEN);
|
||||
getnameinfo(addr, sizeof(struct sockaddr_in), ipbuf, INET_ADDRSTRLEN,
|
||||
NULL, 0, NI_NUMERICHOST);
|
||||
if (getnameinfo(addr, sizeof(struct sockaddr_in), hbuf, NI_MAXHOST, NULL, 0, 0) == 0)
|
||||
printf("%zu bytes from %s (%s): icmp_seq=%d ttl=%i time=%.1f ms\n",
|
||||
bytes - hlen - sizeof(struct icmphdr), hbuf, ipbuf, icmp->icmp_seq, ip->ip_ttl, triptime);
|
||||
else
|
||||
printf("%zu bytes from %s: icmp_seq=%d ttl=%i time=%.1f ms\n",
|
||||
bytes - hlen - sizeof(struct icmphdr), ipbuf, icmp->icmp_seq, ip->ip_ttl, triptime);
|
||||
|
||||
}
|
||||
|
||||
void ping(int signo)
|
||||
{
|
||||
char pkt[g_ping.pkt_size + sizeof(struct icmp)];
|
||||
double *msg;
|
||||
struct icmp *hdr;
|
||||
double epoch;
|
||||
|
||||
(void)signo;
|
||||
hdr = (struct icmp*)&pkt;
|
||||
bzero(&pkt, sizeof(pkt));
|
||||
hdr->icmp_type = ICMP_ECHO;
|
||||
hdr->icmp_id = g_ping.pid;
|
||||
hdr->icmp_seq = ++g_ping.pkt_sent;
|
||||
msg = (double*)(pkt + sizeof(struct icmp));
|
||||
epoch = time_milli();
|
||||
memcpy(msg, (void*)&epoch, sizeof(double));
|
||||
hdr->icmp_cksum = cksum(&pkt, sizeof(pkt));
|
||||
sendto(g_ping.sock, &pkt, sizeof(pkt), 0, g_ping.sa->ai_addr,
|
||||
sizeof(struct sockaddr));
|
||||
alarm(1);
|
||||
}
|
||||
|
||||
void stats_recap(int signo)
|
||||
{
|
||||
double loss;
|
||||
|
||||
(void)signo;
|
||||
rs_final(&g_ping.rs);
|
||||
loss = FT_PCT(g_ping.pkt_recv, g_ping.pkt_sent);
|
||||
printf("\n--- %s ping statistics ---", g_ping.sa->ai_canonname);
|
||||
printf("\n%d packets transmitted, %d packets received, %0.1f%% packet loss",
|
||||
g_ping.pkt_sent, g_ping.pkt_recv, loss);
|
||||
printf("\nrtt min/avg/max/stddev = %.3f/%.3f/%.3f/%.3f ms\n",
|
||||
g_ping.rs.min, g_ping.rs.avg, g_ping.rs.max, g_ping.rs.stdev);
|
||||
freeaddrinfo(g_ping.sa);
|
||||
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)
|
||||
{
|
||||
(void)ac;
|
||||
if (cliopts_get(av, opts, &g_ping))
|
||||
{
|
||||
ft_perror(av[0]);
|
||||
ft_usage(PING_USAGE, av[0]);
|
||||
exit(1);
|
||||
}
|
||||
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,
|
||||
g_ping.pkt_size, g_ping.pkt_size + sizeof(struct icmp));
|
||||
else
|
||||
printf("PING %s: %zu(%zu) data bytes\n", g_ping.ip4,
|
||||
g_ping.pkt_size, g_ping.pkt_size + sizeof(struct icmp));
|
||||
if ((g_ping.sock = socket(PF_INET, SOCK_RAW, IPPROTO_ICMP)) < 0)
|
||||
{
|
||||
perror("socket");
|
||||
exit(1);
|
||||
}
|
||||
if (setsockopt(g_ping.sock, 0, IP_TTL, &g_ping.ttl, sizeof(g_ping.ttl)) != 0)
|
||||
{
|
||||
perror("setsockopt");
|
||||
exit(1);
|
||||
}
|
||||
g_ping.pid = getpid();
|
||||
rs_init(&g_ping.rs);
|
||||
signal(SIGINT, stats_recap);
|
||||
signal(SIGALRM, ping);
|
||||
alarm(1);
|
||||
listener(PF_INET, SOCK_RAW, IPPROTO_ICMP, &display);
|
||||
return (0);
|
||||
}
|
||||
66
ping/ping.h
Normal file
66
ping/ping.h
Normal file
|
|
@ -0,0 +1,66 @@
|
|||
/* ************************************************************************** */
|
||||
/* */
|
||||
/* ::: :::::::: */
|
||||
/* ft_ping.h :+: :+: :+: */
|
||||
/* +:+ +:+ +:+ */
|
||||
/* By: jhalford <jack@crans.org> +#+ +:+ +#+ */
|
||||
/* +#+#+#+#+#+ +#+ */
|
||||
/* Created: 2017/04/22 14:10:24 by jhalford #+# #+# */
|
||||
/* Updated: 2017/10/08 14:36:37 by jhalford ### ########.fr */
|
||||
/* */
|
||||
/* ************************************************************************** */
|
||||
|
||||
#pragma once
|
||||
|
||||
# include "rs.h"
|
||||
# include "cliopts.h"
|
||||
|
||||
# include <stdlib.h>
|
||||
# include <string.h>
|
||||
# include <unistd.h>
|
||||
# include <sys/types.h>
|
||||
# include <sys/time.h>
|
||||
# include <sys/socket.h>
|
||||
# include <sys/wait.h>
|
||||
|
||||
# include <fcntl.h>
|
||||
# include <errno.h>
|
||||
# include <resolv.h>
|
||||
# include <netdb.h>
|
||||
# include <arpa/inet.h>
|
||||
# include <netinet/in.h>
|
||||
# include <netinet/ip.h>
|
||||
# include <netinet/ip_icmp.h>
|
||||
|
||||
# define FT_PCT(a, t) (t ? 100 * (float)(t - a)/(float)t : 0)
|
||||
|
||||
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
|
||||
{
|
||||
char ip4[INET_ADDRSTRLEN];
|
||||
char ip6[INET6_ADDRSTRLEN];
|
||||
} ip;
|
||||
#define ip4 ip.ip4
|
||||
#define ip6 ip.ip6
|
||||
};
|
||||
|
||||
extern t_ping g_ping;
|
||||
|
||||
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));
|
||||
61
ping/rs.c
Normal file
61
ping/rs.c
Normal file
|
|
@ -0,0 +1,61 @@
|
|||
/* ************************************************************************** */
|
||||
/* */
|
||||
/* ::: :::::::: */
|
||||
/* rs.c :+: :+: :+: */
|
||||
/* +:+ +:+ +:+ */
|
||||
/* By: jhalford <jack@crans.org> +#+ +:+ +#+ */
|
||||
/* +#+#+#+#+#+ +#+ */
|
||||
/* Created: 2017/10/07 17:57:54 by jhalford #+# #+# */
|
||||
/* Updated: 2017/10/07 18:19:47 by jhalford ### ########.fr */
|
||||
/* */
|
||||
/* ************************************************************************** */
|
||||
|
||||
#include "rs.h"
|
||||
#include <math.h>
|
||||
|
||||
double sqrt(double x);
|
||||
|
||||
void rs_init(t_rs *rs)
|
||||
{
|
||||
bzero(rs, sizeof(t_rs));
|
||||
rs->count = 0;
|
||||
rs->min = DBL_MAX;
|
||||
rs->max = -DBL_MAX;
|
||||
}
|
||||
|
||||
void rs_push(t_rs *rs, double n)
|
||||
{
|
||||
double delta;
|
||||
|
||||
rs->count++;
|
||||
n < rs->min ? rs->min = n : (0);
|
||||
n > rs->max ? rs->max = n : (0);
|
||||
if (rs->count == 1)
|
||||
{
|
||||
rs->avg = n;
|
||||
rs->m = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
delta = n - rs->avg;
|
||||
rs->avg += delta / rs->count;
|
||||
rs->m += delta * (n - rs->avg);
|
||||
}
|
||||
}
|
||||
|
||||
void rs_final(t_rs *rs)
|
||||
{
|
||||
if (rs->count == 0)
|
||||
{
|
||||
rs->min = 0;
|
||||
rs->max = 0;
|
||||
}
|
||||
if (rs->count < 2)
|
||||
{
|
||||
rs->var = 0;
|
||||
rs->stdev = 0;
|
||||
return ;
|
||||
}
|
||||
rs->var = rs->m / (rs->count - 1);
|
||||
rs->stdev = sqrt(rs->var);
|
||||
}
|
||||
34
ping/rs.h
Normal file
34
ping/rs.h
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
/* ************************************************************************** */
|
||||
/* */
|
||||
/* ::: :::::::: */
|
||||
/* rs.h :+: :+: :+: */
|
||||
/* +:+ +:+ +:+ */
|
||||
/* By: jhalford <jack@crans.org> +#+ +:+ +#+ */
|
||||
/* +#+#+#+#+#+ +#+ */
|
||||
/* Created: 2017/10/07 18:05:30 by jhalford #+# #+# */
|
||||
/* Updated: 2017/10/08 15:59:58 by jhalford ### ########.fr */
|
||||
/* */
|
||||
/* ************************************************************************** */
|
||||
|
||||
#pragma once
|
||||
|
||||
# include <strings.h>
|
||||
# include <float.h>
|
||||
# include <dlfcn.h>
|
||||
# include <math.h>
|
||||
|
||||
typedef struct s_rs t_rs;
|
||||
|
||||
struct s_rs {
|
||||
int count;
|
||||
double min;
|
||||
double max;
|
||||
double avg;
|
||||
double m;
|
||||
double stdev;
|
||||
double var;
|
||||
};
|
||||
|
||||
void rs_init(t_rs *rs);
|
||||
void rs_push(t_rs *rs, double n);
|
||||
void rs_final(t_rs *rs);
|
||||
Loading…
Reference in a new issue