Литмир - Электронная Библиотека
Содержание  
A
A

Прежде чем вызвать функцию

ioctl
, мы выделяем в памяти место для буфера и для структуры
ifconf
, а затем инициализируем эту структуру. Мы показываем это на рис. 17.1, предполагая, что наш буфер имеет размер 1024 байта. Третий аргумент функции
ioctl
— это указатель на нашу структуру
ifconf
.

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

Рис. 17.1. Инициализация структуры ifconf перед вызовом SIOCGIFCONF

Если мы предположим, что ядро возвращает две структуры

ifreq
, то при завершении функции
ioctl
мы можем получить ситуацию, представленную на рис. 17.2. Затененные области были изменены функцией
ioctl
. Буфер заполняется двумя структурами, и элемент
ifc_len
структуры
ifconf
обновляется, с тем чтобы соответствовать количеству информации, хранимой в буфере. Предполагается, что на этом рисунке каждая структура
ifreq
занимает 32 байта.

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

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

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