-
Notifications
You must be signed in to change notification settings - Fork 0
/
icmp_receive.c
125 lines (104 loc) · 3.21 KB
/
icmp_receive.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
#include "icmp_receive.h"
#include <netinet/ip.h>
#include <netinet/ip_icmp.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <time.h>
#include <stdbool.h>
#include <sys/time.h>
bool is_other_ip_occured(char ips_str[][20], int index) {
for (int i = index - 1; i >= 0; --i) {
if (strcmp(ips_str[index], ips_str[i]) != 0)
return true;
}
return false;
}
void print_avg_time(struct timeval* times, int n) {
double res = 0;
for (int i = 0; i < n; ++i) {
res += times[i].tv_usec + times[i].tv_sec * 1000000.0;
}
res /= 1000.0;
res /= n;
printf("%.2f ms\n", res);
}
int receive_packets_from_socket(int pid, int sockfd, int timeout, int ttl,
int num_of_packets, struct timeval* start_time, int* line_number) {
fd_set descriptors;
FD_ZERO(&descriptors);
FD_SET(sockfd, &descriptors);
struct timeval tv = {timeout, 0}, current_time;
int packets = 0;
char sender_ip_str[num_of_packets][20];
bool is_more_than_one_router = false;
bool got_echo_reply = false;
struct timeval times[num_of_packets];
for (int i = 0; i < num_of_packets; ++i) {
times[i].tv_sec = 0;
times[i].tv_usec = 0;
}
while ((tv.tv_sec != 0 || tv.tv_usec != 0) && packets < num_of_packets) {
int ready = select(sockfd + 1, &descriptors, NULL, NULL, &tv);
if (ready < 0)
return ready;
for (int i = 0; i < ready; ++i) {
struct sockaddr_in sender;
socklen_t sender_len = sizeof(sender);
u_int8_t buffer[IP_MAXPACKET];
ssize_t packet_len = recvfrom(sockfd, buffer, IP_MAXPACKET, MSG_DONTWAIT, (struct sockaddr*) &sender, &sender_len);
if (packet_len < 0) {
return -1;
}
if (inet_ntop(AF_INET, &(sender.sin_addr), sender_ip_str[packets], sizeof(sender_ip_str[packets])) == NULL) {
return -1;
}
struct ip* ip_header = (struct ip*) buffer;
u_int8_t* icmp_packet = buffer + 4 * ip_header->ip_hl;
struct icmp* icmp_header = (struct icmp*) icmp_packet;
int type = icmp_header->icmp_type;
if (type != ICMP_TIME_EXCEEDED && type != ICMP_ECHOREPLY)
continue;
struct icmp* original_icmphdr = icmp_header;
if (type == ICMP_TIME_EXCEEDED) {
struct ip* original_iphdr = (void *) icmp_header + 8;
original_icmphdr = (void *) original_iphdr + 4 * original_iphdr->ip_hl;
}
if (original_icmphdr->icmp_hun.ih_idseq.icd_seq != ttl && original_icmphdr->icmp_hun.ih_idseq.icd_id != pid)
continue;
if (!is_more_than_one_router)
is_more_than_one_router = is_other_ip_occured(sender_ip_str, packets);
gettimeofday(¤t_time, NULL);
timersub(¤t_time, start_time, ×[packets]);
++packets;
if (type == ICMP_ECHOREPLY) {
got_echo_reply = true;
tv.tv_sec = 0;
tv.tv_usec = 0;
break;
}
}
}
printf("%d ", *line_number);
*line_number = *line_number + 1;
if (packets == 0) {
printf("*\n");
} else if (!is_more_than_one_router) {
printf("%s ", sender_ip_str[0]);
if (packets == num_of_packets || got_echo_reply)
print_avg_time(times, packets);
else
printf("???\n");
} else {
for (int i = 0; i < packets; ++i) {
printf("%s ", sender_ip_str[i]);
}
if (packets == num_of_packets)
print_avg_time(times, packets);
else
printf("???\n");
}
return got_echo_reply ? 1 : 0;
}