18.5. Функция get_ifi_info (повтор)

18.5. Функция get_ifi_info (повтор)

Вернемся к примеру из раздела 17.6 — возвращение всех активных интерфейсов в виде связного списка структур ifi_info (см. листинг 17.2). Программа prifinfo остается без изменений (см. листинг 17.3), но теперь мы покажем версию функции get_ifi_info, использующую функцию sysctl вместо вызова SIOCGIFCONF функции ioctl в листинге 17.4.

Сначала в листинге 18.8 мы представим функцию net_rt_iflist. Эта функция вызывает функцию sysctl с командой NET_RT_IFLIST, чтобы возвратить список интерфейсов для заданного семейства адресов.

Листинг 18.8. Вызов функции sysctl для возвращения списка интерфейсов

//libroute/net_rt_iflist.c

 1 #include "unproute.h"

 2 char*

 3 net_rt_iflist(int family, int flags, size_t *lenp)

 4 {

 5  int mib[6];

 6  char *buf;

 7  mib[0] = CTL_NET;

 8  mib[1] = AF_ROUTE;

 9  mib[2] = 0;

10  mib[3] = family; /* только адреса этого семейства */

11  mib[4] = NET_RT_IFLIST;

12  mib[5] = flags; /* индекс интерфейса или 0.*/

13  if (sysctl(mib, 6, NULL, lenp, NULL, 0) < 0)

14   return (NULL);

15  if ((buf = malloc(*lenp)) == NULL)

16   return (NULL);

17  if (sysctl(mib, 6, buf, lenp, NULL, 0) < 0) {

18   free(buf);

19   return (NULL);

20  }

21  return (buf);

22 }

7-14 Инициализируется массив mib, как показано в табл. 18.3, для возвращения списка интерфейсов и всех сконфигурированных адресов заданного семейства. Затем функция sysctl вызывается дважды. В первом вызове функции третий аргумент нулевой, в результате чего в переменной, на которую указывает lenp, возвращается размер буфера, требуемый для хранения всей информации об интерфейсе.

15-21 Затем в памяти выделяется место для буфера, и функция sysctl вызывается снова, на этот раз с ненулевым третьим аргументом. При этом переменная, на которую указывает lenp, содержит при завершении функции число, равное количеству информации, хранимой в буфере, и эта переменная размещается в памяти вызывающим процессом. Указатель на буфер также возвращается вызывающему процессу.

ПРИМЕЧАНИЕ

Поскольку размер таблицы маршрутизации или число интерфейсов может изменяться между двумя вызовами функции sysctl, значение, возвращаемое при первом вызове, содержит поправочный множитель 10% [128, с. 639-640].

В листинге 18.9 показана первая половина функции get_ifi_info.

Листинг 18.9. Функция get_ifi_info, первая половина

//route/get_ifi_info.c

 3 struct ifi_info *

 4 get_ifi_info(int family, int doaliases)

 5 {

 6  int flags;

 7  char *buf, *next, *lim;

 8  size_t len;

 9  struct if_msghdr *ifm;

10  struct ifa_msghdr *ifam;

11  struct sockaddr *sa, *rti_info[RTAX_MAX];

12  struct sockaddr_dl *sdl;

13  struct ifi_info *ifi, *ifisave, *ifihead, **ifipnext;

14  buf = Net_rt_iflist(family, 0, &len);

15  ifihead = NULL;

16  ifipnext = &ifihead;

17  lim = buf + len;

18  for (next = buf; next < lim; next += ifm->ifm_msglen) {

19   ifm = (struct if_msghdr*)next;

20   if (ifm->ifm_type = RTM_IFINFO) {

21    if (((flags = ifm->ifm_flags) & IFF_UP) == 0)

22     continue; /* игнорируем, если интерфейс не активен */

23    sa = (struct sockaddr*)(ifm + 1);

24    get_rtaddrs(ifm->ifm_addrs, sa, rti_info);

25    if ((sa = rti_info[RTAX_IFP]) != NULL) {

26     ifi = Calloc(1, sizeof(struct ifi_info));

27     *ifipnext = ifi; /* предыдущий указатель указывал на эту

                           структуру */

28     ifipnext = &ifi->ifi_next; /* указатель на следующую структуру */

29     ifi->ifi_flags = flags;

30     if (sa->sa_family == AF_LINK) {

31      sdl = (struct sockaddr_dl*)sa;

32      ifi->ifi_index = sdl->sdl_index;

33      if (sdl->sdl_nlen > 0)

34       snprintf(ifi->ifi_name, IFI_NAME, "%*s",

35        sdl->sdl_nlen, &sdl->sdl_data[0]);

36      else

37       snprintf(ifi->ifi_name, IFI_NAME, "index %d",

38        sdl->sdl_index);

39      if ((ifi->ifi_hlen = sdl->sdl_alen) > 0)

40       memcpy(ifi->ifi_haddr, LLADDR(sdl),

41      min(IFI_HADDR, sdl->sdl_alen));

42     }

43    }

6-14 Мы объявляем локальные переменные и затем вызываем нашу функцию net_rt_iflist.

17-19 Цикл for — это цикл по всем сообщениям маршрутизации, попадающим в буфер в результате выполнения функции sysctl. Мы предполагаем, что сообщение — это структура if_msghdr, и рассматриваем поле ifm_type (вспомните, что первые три элемента трех структур идентичны, поэтому все равно, какую из трех структур мы используем для просмотра типа элемента).

Проверка, включен ли интерфейс

20-22 Для каждого интерфейса возвращается структура RTM_IFINFO. Если интерфейс не активен, он игнорируется.

Определение, какие структуры адреса сокета присутствуют

23-24 sa указывает на первую структуру адреса сокета, следующую за структурой if_msghdr. Наша функция get_rtaddrs инициализирует массив rti_info в зависимости от того, какие структуры адреса сокета присутствуют.

Обработка имени интерфейса

25-42 Если присутствует структура адреса сокета с именем интерфейса, в памяти размещается структура ifi_info и хранятся флаги интерфейса. Предполагаемым семейством этой структуры адреса сокета является AF_LINK, что означает структуру адреса сокета канального уровня. Если элемент sdl_nlen ненулевой, имя интерфейса копируется в структуру ifi_info. В противном случае в качестве имени хранится строка, содержащая индекс интерфейса. Если элемент sdl_alen ненулевой, аппаратный адрес (например, адрес Ethernet) копируется в структуру ifi_info, а его длина также возвращается как ifi_hlen.

В листинге 18.10 показана вторая часть нашей функции get_ifi_info, которая возвращает IP-адреса для интерфейса.

Листинг 18.10. Функция get_ifi_info, вторая часть

//route/get_ifi_info.c

44   } else if (ifm->ifm_type == RTM_NEWADDR) {

45    if (ifi->ifi_addr) { /* уже имеется IP-адрес для интерфейса */

46     if (doaliases == 0)

47      continue;

48     /* у нас имеется новый IP-адрес для существующего интерфейса */

49     ifisave = ifi;

50     ifi = Calloc(1, sizeof(struct ifi_info));

51     *ifipnext = ifi; /* предыдущий указатель указывал на эту

                           структуру */

52     ifipnext = &ifi->ifi_next; /* указатель на следующую структуру */

53     ifi->ifi_flags = ifi_save->ifi_flags;

54     ifi->ifi_index = ifisave->ifi_index;

55     ifi->ifi_hlen = ifisave->ifi_hlen;

56     memcpy(ifi->ifi_name, ifisave->ifi_name, IFI_NAME);

57     memcpy(ifi->ifi_haddr, ifisave->ifi_haddr, IFI_HADDR);

58    }

59    ifam = (struct ifa_msghdr*)next;

60    sa = (struct sockaddr*)(ifam + 1);

61    get_rtaddrs(ifam->ifam_addrs, sa, rti_info);

62    if ((sa = rti_infо[RTAX_IFA]) != NULL) {

63     ifi->ifi_addr = Calloc(1, sa->sa_len);

64     memcpy(ifi->ifi_addr, sa, sa->sa_len);

65    }

66    if ((flags & IFF_BROADCAST) && (sa = rti_infо[RTAX_BRD]) |= NULL) {

67     ifi->ifi_brdaddr = Calloc(1, sa->sa_len);

68     memcpy(ifi->ifi_brdaddr, sa, sa->sa_len);

69    }

70    if ((flags & IFF_POINTOPOINT) &&

71     (sa = rti_infо[RTAX_BRD]) != NULL) {

72     ifi->ifi_dstaddr = Calloc(1, sa->sa_len);

73     memcpy(ifi->ifi_dstaddr, sa, sa->sa_len);

74    }

75   } else

76    err_quit("unexpected message type %d", ifm->ifm_type);

77  }

78  /* "ifihead" указывает на первую структуру в связном списке */

79  return (ifihead); /* указатель на первую структуру в связном списке */

80 }

Возвращение IP-адресов

44-65 Сообщение RTM_NEWADDR возвращается функцией sysctl для каждого адреса, связанного с интерфейсом: для первичного адреса и для всех альтернативных имен (псевдонимов). Если мы уже заполнили IP-адрес для этого интерфейса, то мы имеем дело с альтернативным именем. Поэтому если вызывающему процессу нужен адрес псевдонима, мы должны выделить память для другой структуры ifi_info, скопировать заполненные поля и затем заполнить возвращенный адрес.

Возвращение широковещательного адреса и адреса получателя

66-75 Если интерфейс поддерживает широковещательную передачу, возвращается широковещательный адрес, а если интерфейс является интерфейсом типа «точка-точка», возвращается адрес получателя.

Поделитесь на страничке

Следующая глава >

Похожие главы из других книг

Функция SUM

Из книги Обработка баз данных на Visual Basic®.NET автора Мак-Манус Джеффри П

Функция SUM Ваши возможности в подведении итогов не ограничены простым подсчетом записей. Используя функцию SUM, можно генерировать итоговые результаты для всех возвращаемых записей по любым числовым полям. Например, для создания запроса, который генерирует итоги по


Функция uni()

Из книги Fiction Book Designer Краткое руководство автора Автор неизвестен

Функция uni() Поиск/замена символа по его юникодному номеру также может быть сделана при помощи функции uni().Пример функции uni(): Boouni(107,32)Designer найдет слово Book


Функция uni()

Из книги Fiction Book Designer 3.2. Краткое руководство автора Izekbis

Функция uni() Поиск/замена символа по его юникодному номеру также может быть сделана при помощи функции uni().Пример функции uni(): Boouni(107,32)Designer найдет слово Book


Функция pthread_rwlock_rdlock

Из книги UNIX: взаимодействие процессов автора Стивенс Уильям Ричард

Функция pthread_rwlock_rdlock Текст функции pthread_rwlock_rdlock приведен в листинге 8.4.Листинг 8.4. Функция pthread_rwlock_rdlock: получение блокировки на чтение//my_rwlock/pthread_rwlock_rdlock.с1  #include "unpipc.h"2  #include "pthread_rwlock.h"3  int4  pthread_rwlock_rdlock(pthread_rwlock_t *rw)5  {6   int result;7   if (rw->rw_magic != RW_MAGIC)8    return(EINVAL);9   if ((result =


Функция pthread_rwlock_unlock

Из книги Программирование на языке Ruby [Идеология языка, теория и практика применения] автора Фултон Хэл

Функция pthread_rwlock_unlock Последняя функция, pthread_rwlock_unlock, приведена в листинге 8.8.Листинг 8.8. Функция pthread_rwlock_unlock: разблокирование ресурса//my_rwlock/pthread_rwlock_unlock.c1  #include "unpipc.h"2  #include "pthread_rwlock.h"3  int4  pthread_rwlock_unlock(pthread_rwlock_t *rw)5  {6   int result;7   if (rw->rw_magic != RW_MAGIC)8    return(EINVAL);9   if ((result =


2.20. Повтор строк

Из книги Технология XSLT автора Валиков Алексей Николаевич

2.20. Повтор строк В Ruby оператор (или метод) умножения перегружен так, что в применении к строкам выполняет операцию повторения. Если строку умножить на n, то получится строка, состоящая из n конкатенированных копий исходной:etc = "Etc. "*3 # "Etc. Etc. Etc. "ruler = " + " + (". "*4+"5" + "."*4+" + ")*3#


Функция not

Из книги PGP: Кодирование и шифрование информации с открытым ключом. автора Левин Максим


Функция sum

Из книги Macromedia Flash Professional 8. Графика и анимация автора Дронов В. А.


Функция contains

Из книги Fiction Book Designer 3.2. Руководство по созданию книг автора


Функция id

Из книги Введение в криптографию автора Циммерманн Филипп


Функция key

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


Хэш-функция.

Из книги автора

Хэш-функция. Еще одно важное преимущество использования PGP состоит в том, что PGP применяет так называемую «хэш-функцию», которая действует таким образом, что в том случае какого-либо изменения информации, пусть даже на один бит, результат «хэш-функции» будет совершенно


Отмена и повтор выполненных действий

Из книги автора

Отмена и повтор выполненных действий Flash, как и многие другие Windows-приложения, поможет нам исправить случайные ошибки, обязательно возникающие при работе. Мы всегда сможем отменить результат нескольких последних выполненных нами действий, восстановив то, что было до них.


Функция uni()

Из книги автора

Функция uni() Поиск/замена символа по его юникодному номеру также может быть сделана при помощи функции uni().Пример функции uni(): Boouni(107,32)Designer найдет слово Book


Хэш-функция

Из книги автора

Хэш-функция Однако описанная выше схема имеет ряд существенных недостатков. Она крайне медлительна и производит слишком большой объём данных — по меньшей мере вдвое больше объёма исходной информации. Улучшением такой схемы становится введение в процесс преобразования