Литмир - Электронная Библиотека
Содержание  
A
A
Переход к следующей структуре адреса сокета

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

21  return (str);

22 }

7-21
 Если длина равна нулю, то подразумевается маска 0.0.0.0. Если длина равна 5, хранится только первый байт 32-разрядной маски, а для оставшихся трех байтов подразумевается нулевое значение. Когда длина равна 8, хранятся все 4 байта маски.

В этом примере мы хотим прочитать ответ ядра, поскольку он содержит информацию, которую мы ищем. Но в общем случае возвращаемое значение нашей функции

write
на маршрутизирующем сокете сообщает нам, успешно ли была выполнена команда. Если это вся необходимая нам информация, мы вызываем функцию
shutdown
со вторым аргументом
SHUT_RD
, чтобы предотвратить отправку ответа. Например, если мы удаляем маршрут, то возвращение нуля функцией
write
означает успешное выполнение, а если удалить маршрут не удалось, возвращается ошибка
ESRCH
[128, с. 608]. Аналогично, когда добавляется маршрут, возвращение ошибки
EEXIST
при выполнении функции
write
означает, что запись уже существует. В нашем примере из листинга 18.3 функция
write
возвращает ошибку
ESRCH
, если записи в таблице маршрутизации не существует (допустим, у нашего узла нет заданного по умолчанию маршрута).

18.4. Операции функции sysctl

Маршрутизирующие сокеты нужны нам главным образом для проверки таблицы маршрутизации и списка интерфейсов при помощи функции

sysctl
. В то время как создание маршрутизирующего сокета (символьного сокета в домене
AF_ROUTE
) требует прав привилегированного пользователя, проверить таблицу маршрутизации и список интерфейсов с помощью функции
sysctl
может любой процесс.

#include <sys/param.h>

#include <sys/sysctl.h>

int sysctl(int *<i>name</i>, u_int <i>namelen</i>, void *<i>oldp</i>, size_t *<i>oldlenp</i>,

 void *<i>newp</i>, size_t <i>Inewlen</i>);

<i>Возвращает: 0 в случае успешного выполнения</i>

Эта функция использует имена, похожие на имена базы управляющей информации (Management Information Base, MIB) простого протокола управления сетью (Simple Network Management Protocol, SNMP). В главе 25 [111] подробно описываются SNMP и его MIB. Эти имена являются иерархическими.

Аргумент

name
— это массив целых чисел, задающий имя, a
namelen
задает число элементов массива. Первый элемент массива определяет, какой подсистеме ядра направлен запрос. Второй элемент определяет некую часть этой подсистемы, и т.д. На рис. 18.3 показана иерархическая организация с некоторыми константами, используемыми на первых трех уровнях.

UNIX: разработка сетевых приложений - img_112.png

Рис. 18.3. Иерархическая организация имен функции sysctl

204
{"b":"225366","o":1}