UNIX: разработка сетевых приложений
Шрифт:
45 printf("genmask: %s\n", Sock_masktop(sa, sa->sa_len));
46 exit(0);
47 }
34-35
Указатель rtm
указывает на структуру rt_msghdr
, а указатель sa
— на первую следующую за ней структуру адреса сокета.
36
rtm_addrs
— это битовая маска той из возможных восьми структур адреса сокета, которая следует за структурой rt_msghdr
. Наша функция get_rtaddrs
(она показана в следующем листинге), получив
sa
), заполняет массив rti_info
указателями на соответствующие структуры адреса сокета. В предположении, что ядро возвращает все четыре структуры адреса сокета, показанные на рис. 18.1, полученный в результате массив rti_info
будет таким, как показано на рис. 18.2. Рис. 18.2. Структура rti_info, заполненная с помощью нашей функции get_rtaddrs
Затем наша программа проходит массив
rti_info
, делая все, что ей нужно, с непустыми указателями массива.
37-44
Каждый из присутствующих четырех возможных адресов выводится. Мы вызываем нашу функцию sock_ntop_host
для вывода адреса получателя и адреса шлюза, но для вывода двух масок подсети вызываем нашу функцию sock_masktop
. Эту новую функцию мы покажем далее. В листинге 18.5 показана наша функция
get_rtaddrs
, которую мы вызывали в листинге 18.4. Листинг 18.5. Создание массива указателей на структуры адреса сокета в маршрутизирующем сообщении
//libroute/get_rtaddrs.c
1 #include "unproute.h"
2 /*
3 * Округляем 'а' до следующего значения, кратного 'size'
4 */
5 #define ROUNDUP(a, size) (((a) & ((size)-1)) ? (1 + ((a) | ((size)-1))) : (a))
6 /* Переходим к следующей структуре адреса сокета.
7 * Если sa_len равно 0, это значит, что
8 * размер выражен числом типа u_long).
9 */
10 #define NEXT_SA(ap) ар = (SA*) \
11 ((caddr_t)ар + (ap->sa_len ? ROUNDUP(ap->sa_len, sizeof(u_long)) : \
12 sizeof(u_long)))
13 void
14 get_rtaddrs(int addrs, SA *sa, SA **rti_info)
15 {
16 int i;
17 for (i = 0; i < RTAX_MAX; i++) {
18 if (addrs & (1 << i)) {
19 rti_info[i] = sa;
20 NEXT_SA(sa);
21 } else
22 rti_info[1] = NULL;
23 }
24 }
Цикл по восьми возможным указателям
Значение
RTAX_MAX
— максимальное число структур адреса сокета, возвращаемых от ядра в сообщении через маршрутизирующий сокет — равно 8. В цикле функции ведется поиск по каждой из восьми констант битовой маски RTA_xxx
(см. табл. 18.2), которые могут быть присвоены элементам rtm_addrs
, ifm_addrs
и ifam_addrs
структур,
показанных в листинге 18.2. Если бит установлен, соответствующий элемент в массиве rti_info
становится указателем на структуру адреса сокета; иначе элемент массива становится пустым указателем. Переход к следующей структуре адреса сокета
2-12
Структуры адреса сокета имеют переменную длину, но в этом коде считается, что у каждой из них имеется поле sa_len
, задающее длину структуры. Есть две сложности, с которыми придется столкнуться. Во-первых, маска подсети и маска клонирования могут возвращаться в структуре адреса сокета с нулевым значением поля sa_len
, но на самом деле они занимают размер, представленный числом типа unsigned long
(В главе 19 [128] обсуждается свойство клонирования таблицы маршрутизации 4.4BSD.) Это значение соответствует маске, состоящей только из нулевых битов, что мы видели в одном из приведенных выше примеров, когда для заданного по умолчанию маршрута маска подсети имела вид 0.0.0.0. Во-вторых, каждая структура адреса сокета может быть заполнена в конце таким образом, что следующая начнется на определенной границе, которая в данном случае соответствует значению типа unsigned long
(например, 4-байтовая граница для 32-разрядной архитектуры). Хотя структуры sockaddr
_in занимают 16 байт и не требуют заполнения, маски часто имеют в конце заполнение. Последняя функция, которую мы покажем в примере нашей программы, — это функция
sock_masktop
, представленная в листинге 18.6, возвращающая строку для одного из двух возможных значений масок. Маски хранятся в структурах адреса сокета. Элемент sa_family
не задан, но имеется элемент sa_len
, принимающий значения 0, 5, 6, 7 или 8 для 32-битовых масок IPv4. Когда длина больше нуля, действительная маска начинается с того же смещения от начала структуры, что и адрес IPv4 в структуре sockaddr_in
: 4 байта от начала структуры (как показано на рис. 18.21 [128]), что соответствует элементу sa_data[2]
общей структуры адреса сокета. Листинг 18.6. Преобразование значения маски к формату представления
//libroute/sock_masktop.c
1 #include "unproute.h"
2 const char*
3 sock_masktop(SA *sa, socklen_t salen)
4 {
5 static char str[INET6_ADDRSTRLEN];
6 unsigned char *ptr = &sa->sa_data[2];
7 if (sa->sa_len == 0)
8 return ("0.0.0.0");
9 else if (sa->sa_len == 5)
10 snprintf(str, sizeof(str), '"%d.0.0.0", *ptr);
11 else if (sa->sa_len == 6)
12 snprintf(str, sizeof(str), "%d.%d.0.0", *ptr, *(ptr + 1));
13 else if (sa->sa_len == 7)
14 snprintf(str, sizeof(str), "%d.%d.%d.0", *ptr, *(ptr + 1), *(ptr + 2));
15 else if (sa->sa_len == 8)
16 snprintf(str, sizeof(str), "%d.%d.%d.%d",
17 *ptr, *(ptr + 1), *(ptr + 2), *(ptr + 3));
18 else
19 snprintf(str, sizeof(str), "(unknown mask, len = %d, family = %d)",
20 sa->sa_len, sa->sa_family);
Поделиться с друзьями: