UNIX: разработка сетевых приложений
Переход к следующей структуре адреса сокетаСтруктуры адреса сокета имеют переменную длину, но в этом коде считается, что у каждой из них имеется поле2-12, задающее длину структуры. Есть две сложности, с которыми придется столкнуться. Во-первых, маска подсети и маска клонирования могут возвращаться в структуре адреса сокета с нулевым значением поляsa_len, но на самом деле они занимают размер, представленный числом типаsa_len(В главе 19 [128] обсуждается свойство клонирования таблицы маршрутизации 4.4BSD.) Это значение соответствует маске, состоящей только из нулевых битов, что мы видели в одном из приведенных выше примеров, когда для заданного по умолчанию маршрута маска подсети имела вид 0.0.0.0. Во-вторых, каждая структура адреса сокета может быть заполнена в конце таким образом, что следующая начнется на определенной границе, которая в данном случае соответствует значению типаunsigned long(например, 4-байтовая граница для 32-разрядной архитектуры). Хотя структурыunsigned long_in занимают 16 байт и не требуют заполнения, маски часто имеют в конце заполнение.sockaddrПоследняя функция, которую мы покажем в примере нашей программы, — это функция
, представленная в листинге 18.6, возвращающая строку для одного из двух возможных значений масок. Маски хранятся в структурах адреса сокета. Элементsock_masktopне задан, но имеется элементsa_family, принимающий значения 0, 5, 6, 7 или 8 для 32-битовых масок IPv4. Когда длина больше нуля, действительная маска начинается с того же смещения от начала структуры, что и адрес IPv4 в структуреsa_len: 4 байта от начала структуры (как показано на рис. 18.21 [128]), что соответствует элементуsockaddr_inобщей структуры адреса сокета.sa_data[2]Листинг 18.6. Преобразование значения маски к формату представления
//libroute/sock_masktop.c1 #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 else19 snprintf(str, sizeof(str), "(unknown mask, len = %d, family = %d)",20 sa->sa_len, sa->sa_family);21 return (str);22 }Если длина равна нулю, то подразумевается маска 0.0.0.0. Если длина равна 5, хранится только первый байт 32-разрядной маски, а для оставшихся трех байтов подразумевается нулевое значение. Когда длина равна 8, хранятся все 4 байта маски.7-21В этом примере мы хотим прочитать ответ ядра, поскольку он содержит информацию, которую мы ищем. Но в общем случае возвращаемое значение нашей функции
на маршрутизирующем сокете сообщает нам, успешно ли была выполнена команда. Если это вся необходимая нам информация, мы вызываем функциюwriteсо вторым аргументомshutdown, чтобы предотвратить отправку ответа. Например, если мы удаляем маршрут, то возвращение нуля функциейSHUT_RDозначает успешное выполнение, а если удалить маршрут не удалось, возвращается ошибкаwrite[128, с. 608]. Аналогично, когда добавляется маршрут, возвращение ошибкиESRCHпри выполнении функцииEEXISTозначает, что запись уже существует. В нашем примере из листинга 18.3 функцияwriteвозвращает ошибкуwrite, если записи в таблице маршрутизации не существует (допустим, у нашего узла нет заданного по умолчанию маршрута).ESRCH18.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. Эти имена являются иерархическими.
Аргумент
— это массив целых чисел, задающий имя, anameзадает число элементов массива. Первый элемент массива определяет, какой подсистеме ядра направлен запрос. Второй элемент определяет некую часть этой подсистемы, и т.д. На рис. 18.3 показана иерархическая организация с некоторыми константами, используемыми на первых трех уровнях.namelenРис. 18.3. Иерархическая организация имен функции sysctl
