Major refactor
This commit is contained in:
0
.editorconfig
Normal file
0
.editorconfig
Normal file
21
ft_ping.h
21
ft_ping.h
@@ -1,9 +1,12 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <math.h>
|
||||||
|
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <sys/socket.h>
|
#include <sys/socket.h>
|
||||||
@@ -13,6 +16,8 @@
|
|||||||
#include <arpa/inet.h>
|
#include <arpa/inet.h>
|
||||||
#include <netdb.h>
|
#include <netdb.h>
|
||||||
|
|
||||||
|
#define PACKET_SIZE 64
|
||||||
|
|
||||||
struct icmp_header
|
struct icmp_header
|
||||||
{
|
{
|
||||||
uint8_t type;
|
uint8_t type;
|
||||||
@@ -21,3 +26,19 @@ struct icmp_header
|
|||||||
uint16_t id;
|
uint16_t id;
|
||||||
uint16_t seq;
|
uint16_t seq;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct packet_stats
|
||||||
|
{
|
||||||
|
uint16_t n_packet_sent;
|
||||||
|
uint16_t n_packet_recv;
|
||||||
|
double timestamp_array[65536];
|
||||||
|
};
|
||||||
|
|
||||||
|
uint16_t calculate_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);
|
||||||
|
|||||||
149
main.c
149
main.c
@@ -1,42 +1,14 @@
|
|||||||
#include "ft_ping.h"
|
#include "ft_ping.h"
|
||||||
|
|
||||||
int n_packet_sent = 0;
|
struct packet_stats stats;
|
||||||
int n_packet_recv = 0;
|
bool loop = true;
|
||||||
char *ip;
|
|
||||||
char loop = 1;
|
|
||||||
|
|
||||||
uint16_t calculate_checksum(uint16_t *data, int len)
|
int ft_ping(int sock, uint16_t seq, struct sockaddr_in *dst)
|
||||||
{
|
|
||||||
uint32_t checksum = 0;
|
|
||||||
|
|
||||||
while (len > 1)
|
|
||||||
{
|
|
||||||
checksum += *data++;
|
|
||||||
len -= 2;
|
|
||||||
}
|
|
||||||
if (len == 1)
|
|
||||||
checksum += *(uint8_t *)data;
|
|
||||||
|
|
||||||
while (checksum >> 16)
|
|
||||||
checksum = (checksum & 0xFFFF) + (checksum >> 16);
|
|
||||||
return (~checksum);
|
|
||||||
}
|
|
||||||
|
|
||||||
double get_timestamp()
|
|
||||||
{
|
|
||||||
struct timeval timestamp;
|
|
||||||
|
|
||||||
gettimeofday(×tamp, NULL);
|
|
||||||
return (timestamp.tv_sec + (double)timestamp.tv_usec / 1000000);
|
|
||||||
}
|
|
||||||
|
|
||||||
int ft_ping(int sock, int seq, struct sockaddr_in dst)
|
|
||||||
{
|
{
|
||||||
unsigned char data[64];
|
unsigned char data[64];
|
||||||
struct icmp_header *icmp_hdr = (struct icmp_header *)data;
|
struct icmp_header *icmp_hdr = (struct icmp_header *)data;
|
||||||
|
|
||||||
memset(data, 0, sizeof(data));
|
memset(data, 0, sizeof(data));
|
||||||
memset(icmp_hdr, 0, sizeof(*icmp_hdr));
|
|
||||||
|
|
||||||
icmp_hdr->type = ICMP_ECHO;
|
icmp_hdr->type = ICMP_ECHO;
|
||||||
icmp_hdr->code = 0;
|
icmp_hdr->code = 0;
|
||||||
@@ -44,16 +16,16 @@ int ft_ping(int sock, int seq, struct sockaddr_in dst)
|
|||||||
icmp_hdr->seq = seq;
|
icmp_hdr->seq = seq;
|
||||||
icmp_hdr->checksum = calculate_checksum((uint16_t *)icmp_hdr, sizeof(icmp_hdr));
|
icmp_hdr->checksum = calculate_checksum((uint16_t *)icmp_hdr, sizeof(icmp_hdr));
|
||||||
|
|
||||||
if (sendto(sock, data, sizeof(data), 0, (struct sockaddr *)&dst, sizeof(dst)) == -1)
|
if (sendto(sock, data, sizeof(data), 0, (struct sockaddr *)dst, sizeof(struct sockaddr_in)) == -1)
|
||||||
{
|
{
|
||||||
fprintf(stderr, "ERROR : sendto() failed\n");
|
fprintf(stderr, "ERROR : Network is unreachable\n");
|
||||||
return (0);
|
return (0);
|
||||||
}
|
}
|
||||||
n_packet_sent++;
|
stats.n_packet_sent++;
|
||||||
return (1);
|
return (1);
|
||||||
}
|
}
|
||||||
|
|
||||||
int ft_recv(int sock, int seq, char *ip, double start)
|
void ft_recv(int sock, uint16_t seq, char *ip, double start)
|
||||||
{
|
{
|
||||||
unsigned char data[64];
|
unsigned char data[64];
|
||||||
struct icmp_header *icmp_hdr = (struct icmp_header *)(data + 20);
|
struct icmp_header *icmp_hdr = (struct icmp_header *)(data + 20);
|
||||||
@@ -61,26 +33,21 @@ int ft_recv(int sock, int seq, char *ip, double start)
|
|||||||
struct sockaddr_in addr;
|
struct sockaddr_in addr;
|
||||||
int len = sizeof(addr);
|
int len = sizeof(addr);
|
||||||
double time;
|
double time;
|
||||||
|
uint16_t checksum;
|
||||||
|
|
||||||
|
memset(data, 0, sizeof(data));
|
||||||
n_bytes = recvfrom(sock, data, sizeof(data), 0, (struct sockaddr *)&addr, (socklen_t *)&len);
|
n_bytes = recvfrom(sock, data, sizeof(data), 0, (struct sockaddr *)&addr, (socklen_t *)&len);
|
||||||
while (icmp_hdr->type != 0 && n_bytes > 0)
|
if (n_bytes < 1)
|
||||||
n_bytes = recvfrom(sock, data, sizeof(data), 0, (struct sockaddr *)&addr, (socklen_t *)&len);
|
return;
|
||||||
time = (get_timestamp() - start) * 1000000;
|
time = (get_timestamp() - start) * 1000;
|
||||||
if (icmp_hdr->seq != seq || calculate_checksum((uint16_t *)data, sizeof(data)))
|
checksum = icmp_hdr->checksum;
|
||||||
return (-1);
|
icmp_hdr->checksum = 0;
|
||||||
n_packet_recv++;
|
if (icmp_hdr->seq != seq || calculate_checksum((uint16_t *)icmp_hdr, sizeof(*icmp_hdr)) != checksum)
|
||||||
printf("%d bytes from %s: icmp_seq:%d time:%5.3fms\n", n_bytes, ip, icmp_hdr->seq, time);
|
return;
|
||||||
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, ip, icmp_hdr->seq, (uint8_t)data[8], time);
|
||||||
char *get_ip_by_hostname(char *hostname)
|
return;
|
||||||
{
|
|
||||||
struct hostent *he;
|
|
||||||
struct in_addr **addr_list;
|
|
||||||
|
|
||||||
he = gethostbyname(hostname);
|
|
||||||
addr_list = (struct in_addr **)he->h_addr_list;
|
|
||||||
return (inet_ntoa(*addr_list[0]));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void handler(int code)
|
void handler(int code)
|
||||||
@@ -94,43 +61,83 @@ void init_signal()
|
|||||||
signal(SIGINT, handler);
|
signal(SIGINT, handler);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool init_socket(int *sock, struct sockaddr_in *dst, char *host)
|
||||||
|
{
|
||||||
|
struct timeval timeout;
|
||||||
|
|
||||||
|
memset(dst, 0, sizeof(*dst));
|
||||||
|
memset(&stats.timestamp_array, 0, sizeof(stats.timestamp_array));
|
||||||
|
|
||||||
|
dst->sin_family = AF_INET;
|
||||||
|
dst->sin_port = 0;
|
||||||
|
if (gethostbyname(host) == NULL && inet_aton(host, &dst->sin_addr) == 0)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "ERROR : %s is an unknown host\n", host);
|
||||||
|
return (false);
|
||||||
|
}
|
||||||
|
dst->sin_addr = get_addr_by_hostname(host);
|
||||||
|
if ((*sock = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP)) < 0) // create a RAW socket for issuing ICMP Requests
|
||||||
|
{
|
||||||
|
fprintf(stderr, "ERROR : socket() failed, are you sudo ?\n"); // creating a RAW socket will fail if we are not superuser
|
||||||
|
return (false);
|
||||||
|
}
|
||||||
|
timeout.tv_sec = 1;
|
||||||
|
timeout.tv_usec = 0;
|
||||||
|
setsockopt(*sock, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout)); // use the timeval struct to set a timeout to our socket
|
||||||
|
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)(100 - (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 main(int argc, char **argv)
|
||||||
{
|
{
|
||||||
int sock;
|
int sock;
|
||||||
struct sockaddr_in dst;
|
struct sockaddr_in dst;
|
||||||
int seq = 1;
|
char *ip;
|
||||||
|
uint16_t seq = 1;
|
||||||
double start;
|
double start;
|
||||||
|
int flags;
|
||||||
|
bool verbose = false;
|
||||||
|
|
||||||
if (argc != 2 || argv[1] == NULL || argv[1][0] == 0)
|
while ((flags = getopt(argc, argv, "v?")) != -1)
|
||||||
{
|
{
|
||||||
fprintf(stderr, "ERROR : usage : ping {-v?} [ADRESS]\n");
|
switch (flags)
|
||||||
return (0);
|
{
|
||||||
|
case 'v':
|
||||||
|
verbose = true;
|
||||||
|
break;
|
||||||
|
case '?':
|
||||||
|
fprintf(stdout, "usage : %s {-v?} [ADRESS]\n", argv[0]);
|
||||||
|
return (1);
|
||||||
}
|
}
|
||||||
if (inet_aton(argv[1], (struct in_addr *)&dst.sin_addr.s_addr) == 0 && gethostbyname(argv[1]) == NULL)
|
}
|
||||||
|
if (argc < 2 || argv[optind] == NULL || argv[optind][0] == 0)
|
||||||
{
|
{
|
||||||
fprintf(stderr, "ERROR : %s is an invalid adress\n", argv[1]);
|
fprintf(stderr, "ERROR : usage : %s {-v?} [ADRESS]\n", argv[0]);
|
||||||
return (0);
|
return (0);
|
||||||
}
|
}
|
||||||
init_signal();
|
init_signal();
|
||||||
dst.sin_family = AF_INET;
|
if (!init_socket(&sock, &dst, argv[optind]))
|
||||||
dst.sin_port = 0;
|
return (-1);
|
||||||
sock = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
|
ip = inet_ntoa(get_addr_by_hostname(argv[optind]));
|
||||||
ip = get_ip_by_hostname(argv[1]);
|
if (verbose)
|
||||||
if (sock < 0)
|
fprintf(stdout, "PING %s (%s) : %d data bytes, id 0x%04x = %d\n", argv[optind], ip, PACKET_SIZE, getpid(), getpid());
|
||||||
{
|
else
|
||||||
fprintf(stderr, "ERROR : socket() failed\n");
|
fprintf(stdout, "PING %s (%s) : %d data bytes\n", argv[optind], ip, PACKET_SIZE);
|
||||||
return (0);
|
|
||||||
}
|
|
||||||
while (loop)
|
while (loop)
|
||||||
{
|
{
|
||||||
start = get_timestamp();
|
start = get_timestamp();
|
||||||
ft_ping(sock, seq, dst);
|
if (ft_ping(sock, seq, &dst) == 0)
|
||||||
|
break;
|
||||||
ft_recv(sock, seq, ip, start);
|
ft_recv(sock, seq, ip, start);
|
||||||
seq++;
|
seq++;
|
||||||
sleep(1);
|
sleep(1);
|
||||||
}
|
}
|
||||||
printf("--- %s ping statistics ---\n", ip);
|
print_recap(argv[optind]);
|
||||||
printf("%d packed transmitted, %d received, %2.1f%% packet loss\n", n_packet_sent, n_packet_recv, (double)((n_packet_sent / n_packet_sent) - 1) * 100);
|
|
||||||
close(sock);
|
close(sock);
|
||||||
return (0);
|
return (0);
|
||||||
}
|
}
|
||||||
|
|||||||
91
utils.c
Normal file
91
utils.c
Normal file
@@ -0,0 +1,91 @@
|
|||||||
|
#include "ft_ping.h"
|
||||||
|
|
||||||
|
uint16_t calculate_checksum(uint16_t *data, int len)
|
||||||
|
{
|
||||||
|
uint32_t checksum = 0;
|
||||||
|
int i = 0;
|
||||||
|
|
||||||
|
while (len > 1)
|
||||||
|
{
|
||||||
|
checksum += data[i++];
|
||||||
|
len -= 2;
|
||||||
|
}
|
||||||
|
if (len == 1)
|
||||||
|
checksum += ((uint8_t *)data)[i];
|
||||||
|
|
||||||
|
while (checksum >> 16)
|
||||||
|
checksum = (checksum & 0xFFFF) + (checksum >> 16);
|
||||||
|
return (~checksum);
|
||||||
|
}
|
||||||
|
|
||||||
|
double get_timestamp()
|
||||||
|
{
|
||||||
|
struct timeval timestamp;
|
||||||
|
|
||||||
|
gettimeofday(×tamp, NULL);
|
||||||
|
return (timestamp.tv_sec + (double)timestamp.tv_usec / 1000000);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct in_addr get_addr_by_hostname(char *hostname)
|
||||||
|
{
|
||||||
|
struct hostent *he;
|
||||||
|
struct in_addr **addr_list;
|
||||||
|
|
||||||
|
he = gethostbyname(hostname);
|
||||||
|
addr_list = (struct in_addr **)he->h_addr_list;
|
||||||
|
return (*addr_list[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
void fill_timestamp_array(struct packet_stats *stats, double time)
|
||||||
|
{
|
||||||
|
stats->timestamp_array[stats->n_packet_recv] = time;
|
||||||
|
}
|
||||||
|
|
||||||
|
double get_min(double *timestamp_array)
|
||||||
|
{
|
||||||
|
double min = timestamp_array[0];
|
||||||
|
for (int i = 1; timestamp_array[i]; i++)
|
||||||
|
{
|
||||||
|
if (min > timestamp_array[i])
|
||||||
|
min = timestamp_array[i];
|
||||||
|
}
|
||||||
|
return (min);
|
||||||
|
}
|
||||||
|
|
||||||
|
double get_max(double *timestamp_array)
|
||||||
|
{
|
||||||
|
double max = timestamp_array[0];
|
||||||
|
for (int i = 1; timestamp_array[i]; i++)
|
||||||
|
{
|
||||||
|
if (max < timestamp_array[i])
|
||||||
|
max = timestamp_array[i];
|
||||||
|
}
|
||||||
|
return (max);
|
||||||
|
}
|
||||||
|
|
||||||
|
double get_avg(double *timestamp_array)
|
||||||
|
{
|
||||||
|
double avg = 0;
|
||||||
|
int i = 0;
|
||||||
|
|
||||||
|
while (timestamp_array[i])
|
||||||
|
{
|
||||||
|
avg += timestamp_array[i];
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
return (avg /= i);
|
||||||
|
}
|
||||||
|
|
||||||
|
double get_stddev(double *timestamp_array)
|
||||||
|
{
|
||||||
|
float avg = get_avg(timestamp_array);
|
||||||
|
float variance = 0;
|
||||||
|
float variance_tmp;
|
||||||
|
|
||||||
|
for (int i = 0; timestamp_array[i]; i++)
|
||||||
|
{
|
||||||
|
variance_tmp = timestamp_array[i] - avg;
|
||||||
|
variance += variance_tmp * variance_tmp;
|
||||||
|
}
|
||||||
|
return (sqrt(variance));
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user