Чтение онлайн

ЖАНРЫ

UNIX: разработка сетевых приложений
Шрифт:

43 /* инициализация в зависимости от протокола */

44 if (ai->ai_family == AF_INET) {

45 pr = &proto_v4;

46 #ifdef IPV6

47 } else if (ai->ai_family == AF_INET6) {

48 pr = &proto_v6;

49 if (IN6_IS_ADDR_V4MAPPED

50 (&(((struct sockaddr_in6*)ai->ai_addr)->sin6_addr)))

51 err_quit("cannot traceroute IPv4-mapped IPv6 address");

52 #endif

53 } else

54 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
Определяются две структуры
proto
, одна для IPv4 и другая для IPv6, хотя указатели на структуры адреса сокета не размещаются в памяти до окончания выполнения данной функции.

Установка значений по умолчанию

10-13
Максимальное значение поля TTL или поля предельного количества транзитных узлов, используемое в программе, по умолчанию равно 30. Предусмотрен параметр командной строки
– m
, чтобы пользователь мог поменять это значение. Для каждого значения TTL посылается три пробных пакета, но их количество также может быть изменено с помощью параметра командной строки. Изначально используется номер порта получателя 32 768 + 666, и каждый раз, когда посылается новая дейтаграмма UDP, это значение увеличивается на 1. Мы можем надеяться, что порты с такими номерами не используются на узле получателя в тот момент, когда приходит дейтаграмма, однако гарантии здесь нет.

Обработка аргументов командной строки

19-37
Параметр командной строки -v позволяет вывести все остальные ICMP-сообщения.

Обработка имени узла или IP-адреса и завершение инициализации

38-58
Имя узла получателя или IP-адрес обрабатывается функцией
host_serv
, возвращающей указатель на структуру
addrinfo
. В зависимости от типа возвращенного адреса (IPv4 или IPv6) заканчивается инициализация структуры
proto
, сохраняется указатель в глобальной переменной pr, а также размещается в памяти дополнительная структура адреса сокета соответствующего размера.

Функция

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);

Поделиться с друзьями: