Функция
traceloop
, приведенная в листинге 28.15, отправляет дейтаграммы и читает вернувшиеся ICMP-сообщения. Это основной цикл программы.
Листинг 28.15. Функция traceloop: основной цикл обработки
//traceroute/traceloop.c
1 #include "trace.h"
2 void
3 traceloop(void)
4 {
5 int seq, code, done;
6 double rtt;
7 struct rec *rec;
8 struct timeval tvrecv;
9 recvfd = Socket(pr-sasend-sa_family, SOCK_RAW, pr-icmpproto);
10 setuid(getuid); /* права привилегированного пользователя больше
не нужны */
11 #ifdef IPV6
12 if (pr-sasend-sa_family == AF_INET6 verbose == 0) {
13 struct icmp6_filter myfilt;
14 ICMP6_FILTER_SETBLOCKALL(myfilt);
15 ICMP6_FILTER_SETPASS(ICMP6_TIME_EXCEEDED, myfilt);
16 ICMP6_FILTER_SETPASS(ICMP6_DST_UNREACH, myfilt);
17 setsockopt(recvfd, IPPROTO_IPV6, ICMP6_FILTER,
18 myfilt, sizeof(myfilt));
19 }
20 #endif
21 sendfd = Socket(pr-sasend-sa_family, SOCK_DGRAM, 0);
22 pr-sabind-sa_family = pr-sasend-sa_family;
23 sport = (getpid 0xffff) | 0x8000; /* UDP-порт отправителя # */
24 sock_set_port(pr-sabind, pr-salen, htons(sport));
25 Bind(sendfd, pr-sabind, pr-salen);
26 sig_alrm(SIGALRM);
27 seq = 0;
28 done = 0;
29 for (ttl = 1; ttl = max_ttl done == 0; ttl++) {
30 Setsockopt(sendfd, pr-ttllevel, pr-ttloptname, ttl, sizeof(int));
31 bzero(pr-salast, pr-salen);
32 printf("%2d ", ttl);
33 fflush(stdout);
34 for (probe = 0; probe nprobes; probe++) {
35 rec = (struct rec*)sendbuf;
36 rec-rec_seq = ++seq;
37 rec-rec_ttl = ttl;
38 Gettimeofday(rec-rec_tv, NULL);
39 sock_set_port(pr-sasend, pr-salen, htons(dport + seq));
40 Sendto(sendfd, sendbuf, datalen, 0, pr-sasend, pr-salen);
41 if ((code = (*pr-recv)(seq, tvrecv)) == -3)
42 printf(" *"); /* тайм-аут, ответа нет */
43 else {
44 char str[NI_MAXHOST];
45 if (sock_cmp_addr(pr-sarecv, pr-salast, pr-salen) != 0) {
46 if (getnameinfo(pr-sarecv, pr-salen, str, sizeof(str),
47 NULL, 0, 0) == 0)
48 printf(" %s (%s)", str,
49 Sock_ntop_host(pr-sarecv, pr-salen));
50 else
51 printf(" %s", Sock_ntop_host(pr-sarecv, pr-salen));
52 memcpy(pr-salast, pr-sarecv, pr-salen);
53 }
54 tv_sub(tvrecv, rec-rec_tv);
55 rtt = tvrecv.tv_sec * 1000.0 + tvrecv.tv_usec / 1000.0;
56 printf(" %.3f ms", rtt);
57 if (code == -1) /* порт получателя недоступен */
58 done++;
59 else if (code = 0)
60 printf(" (ICMP %s)", (*pr-icmpcode)(code));
61 }
62 fflush(stdout);
63 }
64 printf("\n");
65 }
66 }