This commit is contained in:
Jack Halford 2017-11-13 15:33:42 +01:00
parent 728fc5b296
commit c90606706b
2 changed files with 75 additions and 58 deletions

View file

@ -27,6 +27,27 @@
# define PACKETSIZE 64 # define PACKETSIZE 64
typedef struct s_ping t_ping;
struct s_ping
{
pid_t pid;
t_rs rs;
int pkt_sent;
int pkt_recv;
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;
struct s_packet struct s_packet
{ {
struct icmp hdr; struct icmp hdr;

View file

@ -15,86 +15,78 @@
#define TIME_END 1 #define TIME_END 1
#define TIME_TRIPTIME 2 #define TIME_TRIPTIME 2
int g_pid = -1; t_ping g_ping =
int g_pkt_rec = 0; {
char g_domain[256]; .pid = -1,
struct s_stats g_rs; .pkt_sent = -1,
.pkt_recv = 0,
};
void display(void *buf, int bytes, struct sockaddr_in *addr) void display(void *buf, int bytes, struct sockaddr_in *addr)
{ {
struct ip *ip; struct ip *ip;
struct icmp *icmp; struct icmp *icmp;
struct s_packet *pkt; struct s_packet *pkt;
int hlen; int hlen;
double triptime; double triptime;
char strbuf[INET_ADDRSTRLEN];
ip = buf; ip = buf;
(void)bytes; (void)bytes;
hlen = ip->ip_hl << 2; hlen = ip->ip_hl << 2;
pkt = (struct s_packet*)(buf + hlen); pkt = (struct s_packet*)(buf + hlen);
icmp = &pkt->hdr; icmp = &pkt->hdr;
if (icmp->icmp_id != g_pid) if (icmp->icmp_id != g_ping.pid)
return ; return ;
triptime = time_milli() - *(double*)&pkt->msg; triptime = time_milli() - *(double*)&pkt->msg;
rs_push(triptime); rs_push(&g_ping.rs, triptime);
g_pkt_rec++; g_ping.pkt_recv++;
printf("%d bytes from %s: icmp_seq=%d ttl=%i time=%.3f ms\n", printf("%d bytes from %s: icmp_seq=%d ttl=%i time=%.3f ms\n",
ip->ip_len, ip->ip_len,
inet_ntop(AF_INET, &(addr->sin_addr), g_domain, INET_ADDRSTRLEN), inet_ntop(AF_INET, &(addr->sin_addr), strbuf, INET_ADDRSTRLEN),
icmp->icmp_seq, ip->ip_ttl, triptime); icmp->icmp_seq, ip->ip_ttl, triptime);
} }
void ping(struct sockaddr_in *addr) void ping(int signo)
{ {
int sd;
int cnt;
struct s_packet pkt; struct s_packet pkt;
double epoch; double epoch;
if ((sd = socket(PF_INET, SOCK_RAW, IPPROTO_ICMP)) < 0) (void)signo;
return (perror("sender socket")); bzero(&pkt, sizeof(pkt));
if (setsockopt(sd, 0, IP_TTL, (int[]){255, 0}, sizeof(int)) != 0) pkt.hdr.icmp_type = ICMP_ECHO;
perror("set TTL option"); pkt.hdr.icmp_id = g_ping.pid;
cnt = 0; pkt.hdr.icmp_seq = ++g_ping.pkt_sent;
while (1) epoch = time_milli();
{ ft_memcpy(pkt.msg, (void*)&epoch, sizeof(epoch));
bzero(&pkt, sizeof(pkt)); pkt.hdr.icmp_cksum = cksum(&pkt, sizeof(pkt));
pkt.hdr.icmp_type = ICMP_ECHO; sendto(g_ping.sock, &pkt, sizeof(pkt), 0, g_ping.sa->ai_addr,
pkt.hdr.icmp_id = g_pid; sizeof(struct sockaddr));
pkt.hdr.icmp_seq = cnt++;
epoch = time_milli();
ft_memcpy(pkt.msg, (void*)&epoch, sizeof(epoch));
pkt.hdr.icmp_cksum = cksum(&pkt, sizeof(pkt));
if (sendto(sd, &pkt, sizeof(pkt), 0,
(struct sockaddr*)addr, sizeof(*addr)) <= 0)
return (perror("sendto"));
sleep(1);
}
} }
void stats_recap(int signo) void stats_recap(int signo)
{ {
double loss; double loss;
(void)signo; (void)signo;
rs_calcmore(); rs_final(&g_ping.rs);
loss = FT_PCT(g_pkt_rec, g_rs.count); loss = FT_PCT(g_ping.pkt_recv, g_ping.pkt_sent);
printf("\n--- %s ping statistics ---", g_domain); printf("\n--- %s ping statistics ---", g_ping.ip4);
printf("\n%d packets transmitted, %d packets received, %0.1f%% packet loss", printf("\n%d packets transmitted, %d packets received, %0.1f%% packet loss",
g_rs.count, g_pkt_rec, loss); g_ping.rs.count, g_ping.pkt_recv, loss);
printf("\nround-trip min/avg/max/stddev = %.3f/%.3f/%.3f/%.3f ms", printf("\nround-trip min/avg/max/stddev = %.3f/%.3f/%.3f/%.3f ms",
g_rs.min, g_rs.avg, g_rs.max, g_rs.stdev); g_ping.rs.min, g_ping.rs.avg, g_ping.rs.max, g_ping.rs.stdev);
freeaddrinfo(g_ping.sa);
exit(0); exit(0);
} }
struct addrinfo *resolve_host(char *hostname) int resolve_host(char *hostname, t_ping *ping)
{ {
struct addrinfo *result; struct addrinfo *result;
struct addrinfo hints; struct addrinfo hints;
struct sockaddr_in *addr;
memset(&hints, 0, sizeof(hints)); memset(&hints, 0, sizeof(hints));
hints.ai_family = PF_UNSPEC; hints.ai_family = PF_INET;
hints.ai_socktype = SOCK_STREAM; hints.ai_socktype = SOCK_STREAM;
hints.ai_flags |= AI_CANONNAME; hints.ai_flags |= AI_CANONNAME;
if (getaddrinfo(hostname, NULL, &hints, &result) != 0) if (getaddrinfo(hostname, NULL, &hints, &result) != 0)
@ -102,35 +94,39 @@ struct addrinfo *resolve_host(char *hostname)
perror("getaddrinfo"); perror("getaddrinfo");
exit(1); exit(1);
} }
addr = (struct sockaddr_in*)result->ai_addr; ping->sa = result;
inet_ntop(AF_INET, &(addr->sin_addr), g_domain, INET_ADDRSTRLEN); inet_ntop(AF_INET, &(((struct sockaddr_in*)ping->sa->ai_addr)->sin_addr), ping->ip4, INET_ADDRSTRLEN);
if (result->ai_canonname) return (0);
ft_strcpy(g_domain, result->ai_canonname);
return (result);
} }
int main(int ac, char **av) int main(int ac, char **av)
{ {
struct addrinfo *result;
if (ac != 2) if (ac != 2)
{ {
ft_usage("%s <addr>\n", av[0]); ft_usage("%s <addr>\n", av[0]);
exit(1); exit(1);
} }
g_pid = getpid(); resolve_host(av[1], &g_ping);
result = resolve_host(av[1]); if (g_ping.sa->ai_canonname)
if (result->ai_canonname)
printf("PING %s (%s): %i data bytes\n", printf("PING %s (%s): %i data bytes\n",
result->ai_canonname, g_domain, PACKETSIZE); g_ping.sa->ai_canonname, g_ping.ip4, PACKETSIZE);
else else
printf("PING %s: %i data bytes\n", g_domain, PACKETSIZE); printf("PING %s: %i data bytes\n", g_ping.ip4, PACKETSIZE);
if (fork() == 0) if ((g_ping.sock = socket(PF_INET, SOCK_RAW, IPPROTO_ICMP)) < 0)
{ {
signal(SIGINT, stats_recap); ft_dprintf(2, "socket(2) error\n");
rs_clear(); exit(1);
listener(PF_INET, SOCK_RAW, IPPROTO_ICMP, &display);
} }
ping((struct sockaddr_in*)result->ai_addr); if (setsockopt(g_ping.sock, 0, IP_TTL, (int[]){255, 0}, sizeof(int)) != 0)
{
ft_dprintf(2, "setsockopt(2) error\n");
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); return (0);
} }