KnigaRead.com/
KnigaRead.com » Компьютеры и Интернет » Программное обеспечение » Уильям Стивенс - UNIX: разработка сетевых приложений

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

На нашем сайте KnigaRead.com Вы можете абсолютно бесплатно читать книгу онлайн Уильям Стивенс, "UNIX: разработка сетевых приложений" бесплатно, без регистрации.
Перейти на страницу:

Функция if_nameindex возвращает указатель на массив структур if_nameindex:

struct if_nameindex {

 unsigned int if_index; /* 1, 2. ... */

 char *if_name; /* имя, завершаемое нулем: "le0", ... */

};

Последняя запись в этом массиве содержит структуру с нулевым индексом if_index и с пустым указателем ifname. Память для этого массива, а также для имен, на которые указывают элементы массива, выделяется динамически и освобождается при вызове функции if_freenameindex.

Теперь мы представим реализацию этих четырех функций с использованием маршрутизирующих сокетов.

Функция if_nametoindex

В листинге 18.11 показана функция if_nametoindex.

Листинг 18.11. Возвращение индекса интерфейса по его имени

//libroute/if_nametoindex.c

 1 #include "unpifi.h"

 2 #include "unproute.h"


 3 unsigned int

 4 if_nametoindex(const char *name)

 5 {

 6  unsigned int idx, namelen;

 7  char *buf, *next, *lim;

 8  size_t len;

 9  struct if_msghdr *ifm;

10  struct sockadd *sa, *rti_info[RTAX_MAX];

11  struct sockaddr_dl *sdl;


12  if ((buf = net_rt_iflist(0, 0, &len)) == NULL)

13   return(0);


14  namelen = strlen(name);

15  lim = buf + len;

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

17   ifm = (struct if_msghdr*)next;

18   if (ifm->ifm_type == RTM_IFINFO) {

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

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

21    if ((sa = rti_infо[RTAX_IFP]) != NULL) {

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

23      sdl = (struct sockaddr_dl*)sa;

24      if (sdl->sdl_nlen == namelen

25       && strncmp(&sdl->sdl_data[0], name,

26       sdl->sdl_nlen) == 0) {

27       idx = sdl->sdl_index; /* сохранение перед

                                  вызовом free */

28       free(buf);

29       return(idx);

30      }

31     }

32    }


33   }

34  }

35  free(buf);

36  return(0); /* индекс для имени не найден */

37 }

Получение списка интерфейсов

12-13 Наша функция net_rt_iflist возвращает список интерфейсов.

Обработка только сообщений RTM_IFINFO

17-30 Мы обрабатываем сообщения в буфере (см. рис. 18.4) в поисках сообщений типа RTM_IFINFO. Найдя такое сообщение, мы вызываем нашу функцию get_rtaddrs, чтобы установить указатели на структуры адреса сокета, а если присутствует структура имени интерфейса (элемент RTAX_IFP массива rti_info), то имя интерфейса сравнивается с аргументом.

Функция if_indextoname

Следующая функция, if_indextoname, показана в листинге 18.12.

Листинг 18.12. Возвращение имени интерфейса по его индексу

libroute/if_indextoname.c

 1 #include "unpifi.h"

 2 #include "unproute.h"


 3 char*

 4 if_indextoname(unsigned int index, char *name)

 5 {

 6  char *buf, *next, *lim;

 7  size_t len;

 8  struct if_msghdr *ifm;

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

10  struct sockaddr_dl *sdl;


11  if ((buf = net_rt_iflist(0, index, &len)) == NULL)

12   return (NULL);


13  lim = buf + len;

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

15   ifm = (struct if_msghdr*)next;

16   if (ifm->ifm_type == RTM_IFINFO) {

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

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

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

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

21      sdl = (struct sockaddr_dl*)sa;

22      if (sdl->sdl_index == index) {

23       int slen = min(IFNAMSIZ - 1, sdl->sdl_nlen);

24       strncpy(name, sdl->sdl_data, slen);

25       name[slen] = 0; /* завершающий нуль */

26       free(buf);

27       return (name);

28      }

29     }

30    }

31   }

32  }

33  free(buf);

34  return (NULL); /* нет соответствия индексу */

35 }

Эта функция практически идентична предыдущей, но вместо поиска имени интерфейса мы сравниваем индекс интерфейса с аргументом вызывающего процесса. Кроме того, второй аргумент нашей функции net_rt_iflist — это заданный индекс, поэтому результат должен содержать информацию только для определенного интерфейса. Когда обнаруживается совпадение, возвращается имя интерфейса, к которому добавляется завершающий нуль.

Функция if_nameindex

Следующая функция, if_nameindex, возвращает массив структур if_nameindex, содержащих все имена интерфейсов и индексы. Она показана в листинге 18.13.

Листинг 18.13. Возвращение всех имен и индексов интерфейсов

//libroute/if_nameindex.c

 1 #include "unpifi.h"

 2 #include "unproute.h"


 3 struct if_nameindex*

 4 if_nameindex(void)

 5 {

 6  char *buf, *next, *lim;

 7  size_t len;

 8  struct if_msghdr *ifm;

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

10  struct sockaddr_dl *sdl;

11  struct if_nameindex *result, *ifptr;

12  char *namptr;


13  if ((buf = net_it_iflist(0, 0, &len)) == NULL)

14   return (NULL);


15  if ((result = malloc(len)) == NULL) /* завышенная оценка */

16   return (NULL);

17  ifptr = result;

18  namptr = (char*)result + len; /* имена начинаются с конца буфера */


19  lim = buf + len;

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

21   ifm = (struct if_msghdr*)next;

22   if (ifm->ifm_type == RTM_IFINFO) {

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

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

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

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

27      sdl = (struct sockaddr_in*)sa;

28      namptr -= sdl->sdl_nlen + 1;

29      strncpy(namptr, &sdl->sdl_data[0], sdl->sdl_nlen);

30      namptr[sdl->sdl_nlen] = 0; /* завершающий нуль */

31      ifptr->if_name = namptr;

32      ifptr->if_index = sdl->sdl_index;

33      ifptr++;

34     }

35    }

36   }

37  }

38  ifptr->if_name = NULL; /* отмечаем конец массива структур */

39  ifptr->if_index = 0;

40  free(buf);

41  return (result); /* вызывающий процесс должен освободить память

                        с помощью free(), когда все сделано */

43 }

Получение списка интерфейсов, выделение места для результата

13-18 Мы вызываем нашу функцию net_rt_iflist для возвращения списка интерфейсов. Мы также используем возвращаемый размер в качестве размера буфера, который мы размещаем в памяти для записи массива возвращаемых структур if_nameindex. Оценка необходимого размера буфера несколько завышена, но это проще, чем проходить список интерфейсов дважды: один раз для подсчета числа интерфейсов и общего размера имен, а второй — для записи этой информации. Мы создаем массив if_nameindex в начале этого буфера и записываем имена интерфейсов, начиная с конца буфера.

Обработка только сообщений RTM_IFINFO

22-36 Мы обрабатываем все сообщения, ища сообщения RTM_IFINFO и следующие за ними структуры адреса сокета. Имя и индекс интерфейса записываются в создаваемый нами массив.

Завершение массива

38-39 Последняя запись в массиве имеет пустой указатель if_name и нулевой индекс.

Функция if_freenameindex

Последняя функция, показанная в листинге 18.13, освобождает память, которая была выделена для массива структур if_nameindex и хранящихся в нем имен.

Листинг 18.14. Освобождение памяти, выделенной функцией if_nameindex

43 void

44 if_freenameindex(struct if_nameindex *ptr)

45 {

46  free(ptr);

47 }

Эта функция тривиальна, поскольку мы хранили и массив структур, и имена в одном и том же буфере. Если бы мы каждый раз вызывали функцию malloc, то для освобождения памяти нам бы пришлось проходить через весь массив, освобождать память, выделенную для каждого имени, а затем удалять сам массив (используя функцию free).

18.7. Резюме

Последняя из структур адреса сокета, с которой мы встретились в книге, это sockaddr_dl — структура адреса сокета канального уровня, имеющая переменную длину. Ядра Беркли-реализаций связывают их с интерфейсами, возвращая в одной из этих структур индекс интерфейса, его имя и аппаратный адрес.

В маршрутизирующий сокет процессом могут быть записаны 5 типов сообщений, и 12 различных сообщений могут быть асинхронно возвращены ядром через маршрутизирующий сокет. Мы привели пример, когда процесс запрашивает у ядра информацию о записи в таблице маршрутизации и ядро отвечает со всеми подробностями. Ответы ядра могут содержать до восьми структур адреса сокета, поэтому нам приходится анализировать сообщение, чтобы получить все фрагменты информации.

Перейти на страницу:
Прокомментировать
Подтвердите что вы не робот:*