Уильям Стивенс - UNIX: разработка сетевых приложений
- Название:UNIX: разработка сетевых приложений
- Автор:
- Жанр:
- Издательство:Питер
- Год:2007
- Город:Санкт-Петербург
- ISBN:5-94723-991-4
- Рейтинг:
- Избранное:Добавить в избранное
-
Отзывы:
-
Ваша оценка:
Уильям Стивенс - UNIX: разработка сетевых приложений краткое содержание
Новое издание книги, посвященной созданию веб-серверов, клиент-серверных приложений или любого другого сетевого программного обеспечения в операционной системе UNIX, — классическое руководство по сетевым программным интерфейсам, в частности сокетам. Оно основано на трудах Уильяма Стивенса и полностью переработано и обновлено двумя ведущими экспертами по сетевому программированию. В книгу включено описание ключевых современных стандартов, реализаций и методов, она содержит большое количество иллюстрирующих примеров и может использоваться как учебник по программированию в сетях, так и в качестве справочника для опытных программистов.
UNIX: разработка сетевых приложений - читать онлайн бесплатно ознакомительный отрывок
Интервал:
Закладка:
Вернемся к примеру из раздела 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)
14 return (NULL);
15 if ((buf = malloc(*lenp)) == NULL)
16 return (NULL);
17 if (sysctl(mib, 6, buf, lenp, NULL, 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 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
Интервал:
Закладка: