Прежде чем вызвать функцию
ioctl
, мы выделяем в памяти место для буфера и для структуры
ifconf
, а затем инициализируем эту структуру. Мы показываем это на рис. 17.1, предполагая, что наш буфер имеет размер 1024 байта. Третий аргумент функции
ioctl
— это указатель на нашу структуру
ifconf
.
Рис. 17.1. Инициализация структуры ifconf перед вызовом SIOCGIFCONF
Если мы предположим, что ядро возвращает две структуры
ifreq
, то при завершении функции
ioctl
мы можем получить ситуацию, представленную на рис. 17.2. Затененные области были изменены функцией
ioctl
. Буфер заполняется двумя структурами, и элемент
ifc_len
структуры
ifconf
обновляется, с тем чтобы соответствовать количеству информации, хранимой в буфере. Предполагается, что на этом рисунке каждая структура
ifreq
занимает 32 байта.
Рис. 17.2. Значения, возвращаемые в результате вызова SIOCGIFCONF
Указатель на структуру
ifreq
также используется в качестве аргумента оставшихся функций
ioctl
интерфейса, показанных в табл. 17.1, которые мы описываем в разделе 17.7. Отметим, что каждая структура
ifreq
содержит объединение (
union
), а директивы компилятора
#define
позволяют непосредственно обращаться к полям объединения по их именам. Помните о том, что в некоторых системах в объединение
ifr_ifru
добавлено много зависящих от реализации элементов.
17.6. Функция get_ifi_info
Поскольку многим программам нужно знать обо всех интерфейсах системы, мы разработаем нашу собственную функцию
get_ifi_info
, возвращающую связный список структур — по одной для каждого активного в настоящий момент интерфейса. В этом разделе мы покажем, как эта функция реализуется с помощью вызова
SIOCGIFCONF
функции
ioctl
, а в главе 18 мы создадим ее другую версию, использующую маршрутизирующие сокеты.
ПРИМЕЧАНИЕ
BSD/OS предоставляет функцию getifaddrs, имеющую аналогичную функциональность.
Поиск по всему дереву исходного кода BSD/OS 2.1 показывает, что 12 программ выполняют вызов SIOCGIFCONF функции ioctl для определения присутствующих интерфейсов.
Сначала мы определяем структуру
ifi_info
в новом заголовочном файле, который называется
unpifi.h
, показанном в листинге 17.2.
Листинг 17.2. Заголовочный файл unpifi.h
//ioctl/unpifi.h
1 /* Наш собственный заголовочный файл для программ, которым требуется
2 информация о конфигурации интерфейса. Включаем его вместо "unp.h". */
3 #ifndef __unp_ifi_h
4 #define __unp_ifi_h
5 #include "unp.h"
6 #include <net/if.h>
7 #define IFI_NAME 16 /* то же, что и IFNAMSIZ в заголовке <net/if.h> */
8 #define IFI_HADDR 8 /* с учетом 64-битового интерфейса EUI-64 в будущем */
9 struct ifi_info {
10 char ifi_name[IFI_NAME]; /* имя интерфейса, заканчивается
символом конца строки */
11 short ifi_index; /* индекс интерфейса */
12 short ifi_mtu; /* MTU для интерфейса */
13 u_char ifi_haddr[IFI_HADDR]; /* аппаратный адрес */
14 u_short ifi_hlen; /* количество байтов в аппаратном адресе: 0, 6, 8 */
15 short ifi_flags; /* константы IFF_xxx из <net/if.h> */
16 short if_myflags; /* наши флаги IFI_xxx */
17 struct sockaddr *ifi_addr; /* первичный адрес */
18 struct sockaddr *ifi_brdaddr; /* широковещательный адрес */
19 struct sockaddr *ifi_dstaddr; /* адрес получателя */
20 s truct ifi_info *ifi_next; /* следующая из этих структур */
21 };
22 #define IFI_ALIAS 1 /* ifi_addr - это псевдоним */
23 /* прототипы функций */
24 struct ifi_info *get_ifi_info((int, int);
25 struct ifi_info *Get_ifi_info(int, int);
26 void free_ifi_info(struct ifi_info*);
27 #endif /* _unp_ifi_h */
9-21
Связный список этих структур возвращается нашей функцией. Элемент
ifi_next
каждой структуры указывает на следующую структуру. Мы возвращаем в этой структуре информацию, которая может быть востребована в типичном приложении: имя интерфейса, индекс интерфейса, MTU, аппаратный адрес (например, адрес Ethernet), флаги интерфейса (чтобы позволить приложению определить, поддерживает ли приложение широковещательную или многоадресную передачу и относится ли этот интерфейс к типу «точка-точка»), адрес интерфейса, широковещательный адрес, адрес получателя для связи «точка-точка». Вся память, используемая для хранения структур
ifi_info
вместе со структурами адреса сокета, содержащимися в них, выделяется динамически. Следовательно, мы также предоставляем функцию
free_ifi_info
для освобождения всей этой памяти.
Перед тем как представить реализацию нашей функции
ifi_info
, мы покажем простую программу, которая вызывает эту функцию и затем выводит информацию. Эта программа, представленная в листинге 17.3, является уменьшенной версией программы
ifconfig
.
Листинг 17.3. Программа prifinfo, вызывающая нашу функцию ifi_info
//ioctl/prifinfo.c
1 #include "unpifi.h"