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

ЖАНРЫ

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

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