17 Мы создаем символьный сокет в домене AF_ROUTE, что, как мы отмечали ранее, может потребовать прав привилегированного пользователя. Буфер размещается в памяти и инициализируется нулем.
Заполнение структуры rt_msghdr18-25 Мы заполняем структуру rt_msghdr данными нашего запроса. В этой структуре хранится идентификатор процесса и порядковый номер, который мы выбираем. Мы сравним эти значения, когда будем искать правильный ответ.
Заполнение структуры адреса сокета адресом получателя26-29 Следом за структурой rt_msghdr мы создаем структуру sockaddr_in, содержащую IPv4-адрес получателя, поиск которого будет проведен ядром в таблице маршрутизации. Все, что мы задаем — это длина адреса, семейство адреса и адрес.
Запись сообщения ядру (функция write) и чтение ответа (функция read)30-34 Мы передаем сообщение ядру с помощью функции write, и с помощью функции read читаем ответ. Поскольку у других процессов могут быть открытые маршрутизирующие сокеты, а ядро передает копию всех маршрутизирующих сообщений всем маршрутизирующим сокетам, мы должны проверить тип сообщения, порядковый номер и идентификатор процесса, чтобы узнать, что полученное сообщение — это ожидаемое нами сообщение.
Вторая часть этой программы показана в листинге 18.4. Она обрабатывает ответ.
Листинг 18.4. Вторая часть программы, запускающая команду RTM_GET на маршрутизирующем сокете
//route/getrt.c
35 rtm = (struct rt_msghdr*)buf;
36 sa = (struct sockaddr*)(rtm + 1);
37 get_rtaddrs(rtm->rtm_addrs, sa, rti_info);
38 if ((sa = rti_infо[RTAX_DST]) != NULL)
39 printf("dest: %s\n", Sock_ntop_host(sa, sa->sa_len));
40 if ((sa = rti_infо[RTAX_GATEWAY]) != NULL)
41 printf("gateway: %s\n", Sock_ntop_host(sa, sa->sa_len));
42 if ((sa = rti_info[RTAX_NETMASK]) != NULL)
43 printf("netmask: %s\n", Sock_masktop(sa, sa->sa_len));
44 if ((sa = rti_info[RTAX_GENMASK]) != NULL)
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 становится указателем на структуру адреса сокета; иначе элемент массива становится пустым указателем.