UNIX: разработка сетевых приложений
Часть 317 из 399 Информация о книге
52 #endif53 } else54 err_quit("unknown address family %d", ai->ai_family);55 pr->sasend = ai->ai_addr; /* содержит адрес получателя */56 pr->sarecv = Calloc(1, ai->ai_addrlen);57 pr->salast = Calloc(1, ai->ai_addrlen);58 pr->sabind = Calloc(1, ai->ai_addrlen);59 pr->salen = ai->ai_addrlen;60 traceloop();61 exit(0);62 }Определение структуры protoОпределяются две структуры2-9, одна для IPv4 и другая для IPv6, хотя указатели на структуры адреса сокета не размещаются в памяти до окончания выполнения данной функции.protoУстановка значений по умолчаниюМаксимальное значение поля TTL или поля предельного количества транзитных узлов, используемое в программе, по умолчанию равно 30. Предусмотрен параметр командной строки10-13, чтобы пользователь мог поменять это значение. Для каждого значения TTL посылается три пробных пакета, но их количество также может быть изменено с помощью параметра командной строки. Изначально используется номер порта получателя 32 768 + 666, и каждый раз, когда посылается новая дейтаграмма UDP, это значение увеличивается на 1. Мы можем надеяться, что порты с такими номерами не используются на узле получателя в тот момент, когда приходит дейтаграмма, однако гарантии здесь нет.-mОбработка аргументов командной строкиПараметр командной строки -v позволяет вывести все остальные ICMP-сообщения.19-37Обработка имени узла или IP-адреса и завершение инициализацииИмя узла получателя или IP-адрес обрабатывается функцией38-58, возвращающей указатель на структуруhost_serv. В зависимости от типа возвращенного адреса (IPv4 или IPv6) заканчивается инициализация структурыaddrinfo, сохраняется указатель в глобальной переменной pr, а также размещается в памяти дополнительная структура адреса сокета соответствующего размера.protoФункция
, приведенная в листинге 28.15, отправляет дейтаграммы и читает вернувшиеся ICMP-сообщения. Это основной цикл программы.traceloopЛистинг 28.15. Функция traceloop: основной цикл обработки
//traceroute/traceloop.c1 #include "trace.h"2 void3 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 IPV612 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 #endif21 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),