KnigaRead.com/
KnigaRead.com » Компьютеры и Интернет » Программное обеспечение » Уильям Стивенс - UNIX: разработка сетевых приложений

Уильям Стивенс - UNIX: разработка сетевых приложений

На нашем сайте KnigaRead.com Вы можете абсолютно бесплатно читать книгу онлайн Уильям Стивенс, "UNIX: разработка сетевых приложений" бесплатно, без регистрации.
Перейти на страницу:

Рис. 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);

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 *name, u_int namelen, void *oldp, size_t *oldlenp,

 void *newp, size_t Inewlen);

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

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

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

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

Для получения значений используется аргумент oldp. Он указывает на буфер, в котором ядро сохраняет значение. Аргумент oldenp имеет тип «значение-результат»: когда функция вызывается, значение, на которое указывает oldenp, задает размер этого буфера, а по завершении функции значением этого аргумента становится количество данных, сохраненных ядром в буфере. Если размера буфера недостаточно, возвращается ошибка ENOMEM. В специальном случае oldp может быть пустым указателем, a oldenp — непустым указателем, и тогда ядро определяет, сколько данных возвратилось бы при вызове, сообщая это значение через oldenp.

Чтобы установить новое значение, используется аргумент newp, указывающий на буфер размера newlen. Если новое значение не задается, newp должен быть пустым указателем, a newlen должен быть равен нулю.

В руководстве (man) по применению функции sysctl подробно описывается различная системная информация, которую можно получить с помощью этой функции: информация о файловых системах, виртуальной памяти, ограничениях ядра, аппаратных характеристиках и т.д. Нас интересует сетевая подсистема, на которую указывает первый элемент массива name, равный CTL_NET (константы CTL_xxx определяются в заголовочном файле <sys/sysctl.h>). Тогда второй элемент может быть одним из перечисленных ниже.

Перейти на страницу:
Прокомментировать
Подтвердите что вы не робот:*