ПРИМЕЧАНИЕ
Формат, приведенный на рис. 27.2, определен в заголовочном файле в виде следующей структуры:
#define MAX_IPOPTLEN 40
struct ipoption {
struct in_addr ipopt_dst; /* адрес первого получателя */
char ipopt_list[MAX_IPOPTLEN]; /* соответствующие параметры */
};
В листинге 27.3 мы анализируем эти данные, не используя указанную структуру.
Возвращаемый формат отличается от того, который был передан функции setsockopt
. Если нам было бы нужно преобразовать формат, показанный на рис. 27.2, к формату, показанному на рис. 27.1, нам следовало бы поменять местами первые и вторые 4 байта и изменить значение поля len
, добавив к имеющемуся значению 4. К счастью, нам не нужно этого делать, так как Беркли-реализации автоматически используют обращенный маршрут от получателя для сокета TCP. Иными словами, данные, возвращаемые функцией getsockopt
(представленные на рис. 27.2), носят чисто информативный характер. Нам не нужно вызывать функцию setsockopt
, чтобы указать ядру на необходимость использования данного маршрута для дейтаграмм IP, отсылаемых по соединению TCP, — ядро сделает это само. Подобный пример с нашим сервером TCP мы вскоре увидим.
Следующей из рассматриваемых нами функций, связанных с параметром маршрутизации, полученный маршрут от отправителя передается в формате, показанном на рис. 27.2. Затем она выводит соответствующую информацию. Эту функцию inet_srtcrt_print
мы показываем в листинге 27.3.
Листинг 27.3. Функция inet_srtcrt_print: вывод полученного маршрута от отправителя
//ipopts/sourceroute.c
37 void
38 inet_srcrt_print(u_char *ptr, int len)
39 {
40 u_char c;
41 char str[INET_ADDRSTRLEN];
42 struct in_addr hop1;
43 memcpy(&hop1, ptr, sizeof(struct in_addr));
44 ptr += sizeof(struct in_addr);
45 while ((c = *ptr++) == IPOPT_NOP); /* пропуск параметров NOP */
46 if (с == IPOPT_LSRR)
47 printf("received LSRR: ");
48 else if (c == IPOPT_SSRR)
49 printf("received SSRR: ");
50 else {
51 printf("received option type %d\n", c);
52 return;
53 }
54 printf("%s ", Inet_ntop(AF_INET, &hop1, str, sizeof(str)));
55 len = *ptr++ - sizeof(struct in_addr); /* вычитаем адрес получателя */
56 ptr++; /* пропуск указателя */
57 while (len > 0) {
58 printf("%s ", Inet_ntop(AF_INET, ptr, str, sizeof(str)));
59 ptr += sizeof(struct in_addr);
60 len -= sizeof(struct in_addr);
61 }
62 printf("\n");
63 }
Сохраняем первый адрес IP, пропускаем все параметры NOP
43-45
Первый IP-адрес в буфере сохраняется, а все следующие за ним параметры NOP мы пропускаем.
Проверяем параметр маршрута от отправителя
46-62
Мы выводим информацию о маршруте и проверяем значение поля code
, содержащегося в 3-байтовом заголовке, получаем значение поля len
и пропускаем указатель ptr
. Затем мы выводим все IP-адреса, следующие за 3-байтовым заголовком, кроме IP-адреса получателя.
Теперь мы модифицируем наш эхо-сервер TCP таким образом, чтобы выводить полученный маршрут от отправителя, а эхо-клиент TCP — так, чтобы маршрут от отправителя можно было задавать. В листинге 27.4 показан код эхо-клиента TCP.
Листинг 27.4. Эхо-клиент TCP, задающий маршрут от отправителя
//ipopts/tcpcli01.c
1 #include "unp.h"
2 int
3 main(int argc, char **argv)
4 {
5 int c, sockfd, len = 0;
6 u_char *ptr = NULL;
7 struct addrinfo *ai;
8 if (argc
9 err_quit("usage: tcpcli01 [ -[gG] ... ] ");
10 opterr = 0; /* отключаем запись сообщений getopt() в stderr */
11 while ((с = getopt(argc, argv, "gG")) != -1) {
12 switch (c) {
13 case 'g': /* свободный маршрут от отправителя */
14 if (ptr)
15 err_quit("can't use both -g and -G");
16 ptr = inet_srcrt_init(0);
17 break;
18 case 'G': /* жесткий маршрут от отправителя */
19 if (ptr)
20 err_qint("can't use both -g and -G");
21 ptr = inet_srcrt_init(1);
22 break;
23 case '?':
24 err_quit("unrecognized option: %c", c);
25 }
26 }
27 if (ptr)
28 while (optind
29 len = inet_srcrt_add(argv[optind++]);
30 else if (optind
31 err_quit("need -g or -G to specify route");
32 if (optind != argc-1)
33 err_quit("missing ");
34 ai = Host_serv(argv[optind], SERV_PORT_STR, AF_INET, SOCK_STREAM);
35 sockfd = Socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
36 if (ptr) {
37 len = inet_srcrt_add(argv[optind]); /* получатель в конце */
38 Setsockopt(sockfd, IPPROTO_IP, IP_OPTIONS, ptr, len);
39 free(ptr);
40 }
41 Connect(sockfd, ai->ai_addr, ai->ai_addrlen);
42 str_cli(stdin, sockfd); /* вызов рабочей функции */
43 exit(0);
44 }
Обработка аргументов командной строки
12-26
Мы вызываем нашу функцию inet_srcrt_init
, чтобы инициализировать маршрут от отправителя. Тип маршрутизации указывается при помощи параметра -g
(свободная) или -G
(жесткая).
Читать дальше
Конец ознакомительного отрывка
Купить книгу