Шрифт:
Рис. 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
для освобождения всей этой памяти.