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

ЖАНРЫ

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

После отправки сообщения ядру мы с помощью функции

read
читаем ответ, формат которого показан на рис. 18.1 справа: структура
rt_msghdr
, за которой следует до четырех структур адреса сокета. Какая из четырех структур адреса сокета возвращается, зависит от записи в таблице маршрутизации. Мы сможем идентифицировать возвращаемую структуру адреса сокета по значению элемента
rtm_addrs
возвращаемой структуры
rt_msghdr
. Семейство каждой структуры адреса сокета указано в элементе
ss_family
, и как мы видели в наших предыдущих примерах,
первый раз сообщение
RST_GET
содержало информацию о том, что адрес шлюза является структурой адреса сокета IPv4, а второй раз это была структура адреса сокета канального уровня.

В листинге 18.3 показана первая часть нашей программы.

Листинг 18.3. Первая часть программы, запускающая команду RTM_GET на маршрутизирующем сокете

//route/getrt.c

1 #include "unproute.h"

2 #define BUFLEN (sizeof(struct rt_msghdr) + 512)

3 /* sizeof(struct sockaddr_in6) * 8 = 192 */

4 #define SEQ 9999

5 int

6 main(int argc, char **argv)

7 {

8 int sockfd;

9 char *buf;

10 pid_t pid;

11 ssize_t n;

12 struct rt_msghdr *rtm;

13 struct sockaddr *sa, *rti_info[RTAX_MAX];

14 struct sockaddr_in *sin;

15 if (argc != 2)

16 err_quit("usage: getrt <Ipaddress>");

17 sockfd = Socket(AF_ROUTE, SOCK_RAW, 0); /* необходимы права

привилегированного пользователя */

18 buf = Calloc(1, BUFLEN); /* инициализируется нулем */

19 rtm = (struct rt_msghdr*)buf;

20 rtm->rtm_msglen = sizeof(struct rt_msghdr) + sizeof(struct sockaddr_in);

21 rtm->rtm_version = RTM_VERSION;

22 rtm->rtm_type = RTM_GET;

23 rtm->rtm_addrs = RTA_DST;

24 rtm->rtm_pid = pid = getpid;

25 rtm->rtm_seq = SEQ;

26 sin = (struct sockaddr_in*)(rtm + 1);

27 sin->sin_len = sizeof(struct sockaddr_in);

28 sin->sin_family = AF_INET;

29 Inet_pton(AF_INET, argv[1], &sin->sin_addr);

30 Write(sockfd, rtm, rtm->rtm_msglen);

31 do {

32 n = Read(sockfd, rtm, BUFLEN);

33 } while (rtm->rtm_type != RTM_GET || rtm->rtm_seq != SEQ ||

34 rtm->rtm_pid != pid);

1-3
Наш заголовочный файл
unproute.h
подключает некоторые необходимые файлы, а затем включает наш файл
unp.h
. Константа
BUFLEN
— это размер буфера, который мы размещаем в памяти для хранения нашего сообщения ядру вместе с ответом ядра. Нам необходимо место для одной структуры
rt_msghdr
и, возможно, восьми структур адреса сокета (максимальное число, которое может возвратиться через маршрутизирующий сокет). Поскольку структура адреса сокета IPv6 имеет размер 28 байт, то значения 512 нам более чем достаточно.

Создание маршрутизирующего сокета

17
Мы создаем символьный сокет в домене
AF_ROUTE
, что, как мы отмечали ранее, может потребовать прав привилегированного пользователя. Буфер размещается в памяти и инициализируется нулем.

Заполнение структуры rt_msghdr

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

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