Чтение онлайн

ЖАНРЫ

UNIX: разработка сетевых приложений
Шрифт:
ПРИМЕЧАНИЕ

В системах, поддерживающих IPv6, не оговаривается, возвращается ли адрес IPv6 вызовом SIOCGIFCONF. Для более новых систем мы вводим оператор case, в котором предусмотрена возможность возвращения адресов IPv6. Проблема состоит в том, что объединение в структуре ifreq определяет возвращаемые адреса как общие 16-байтовые структуры sockaddr, подходящие для 16-байтовых структур sockaddr_in IPv4, но для 24-байтовых структур sockaddr_in6 IPv6 они слишком малы. В случае возвращения адресов IPv6 возможно некорректное поведение существующего кода, созданного в предположении, что в каждой структуре ifreq содержится структура sockaddr фиксированного

размера. В системах, где структура sockaddr имеет поле sa_len, никаких проблем не возникает, потому что такие системы легко могут указывать размер структур sockaddr.

52-60
Если система возвращает структуры
sockaddr
семейства
AF_LINK
в
SIOCGIFCONF
, мы копируем индекс интерфейса и данные об аппаратном адресе из таких структур.

62-63
Мы игнорируем все адреса из семейств, отличных от указанного вызывающим процессом в аргументе функции
get_ini_info
.

Обработка альтернативных имен

64-72
Нам нужно обнаружить все альтернативные имена (псевдонимы), которые могут существовать для интерфейса, то есть присвоенные этому интерфейсу дополнительные адреса. Обратите внимание в наших примерах, следующих за листингом 17.3, что в Solaris псевдоним содержит двоеточие, в то время как в 4.4BSD имя интерфейса в псевдониме не изменяется. Чтобы обработать оба случая, мы сохраняем последнее имя интерфейса в
lastname
и сравниваем его только до двоеточия, если оно присутствует. Если двоеточия нет, мы игнорируем этот интерфейс в том случае, когда имя эквивалентно последнему обработанному интерфейсу.

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

73-77
Мы выполняем вызов
SIOCGIFFLAGS
функции
ioctl
(см. раздел 16.5), чтобы получить флаги интерфейса. Третий аргумент функции
ioctl
— это указатель на структуру
ifreq
, содержащую имя интерфейса, для которого мы хотим получить флаги. Мы создаем копию структуры
ifreq
, перед тем как запустить функцию ioctl, поскольку в противном случае этот вызов перезаписал бы IP-адрес интерфейса, потому что оба они являются элементами одного и того же объединения из листинга 17.1. Если интерфейс не активен, мы игнорируем его.

В листинге 17.6 представлена третья часть нашей функции.

Листинг 17.6. Получение и возвращение адресов интерфейса

//ioctl/get_ifi_infо.c

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

79 *ifipnext = ifi; /* prev указывает на новую структуру */

80 ifipnext = &ifi->ifi_next; /* сюда указывает указатель на

следующую структуру */

81 ifi->ifi_flags = flags; /* значения IFF_xxx */

82 ifi->ifi_myflags = myflags; /* значения IFI_xxx */

83 #if defined(SIOCGIFMTU) && defined(HAVE_STRUCT_IFREQ_IFR_MTU)

84 Ioctl(sockfd, SIOCGIFMTU, &ifrcopy);

85 ifi->ifi_mtu = ifrcopy.ifr_mtu;

86 #else

87 ifi->ifi_mtu = 0;

88 #endif

89 memcpy(ifi->ifi_name, ifr->ifr_name, IFI_NAME);

90 ifi->ifi_name[IFI_NAME-1] = '\0';

91 /*
если sockaddr_dl относится к другому интерфейсу, он игнорируется */

92 if (sdlname == NULL || strcmp(sdlname, ifr->ifr_name) != 0)

93 idx = hlen = 0;

94 ifi->ifi_index = idx;

95 ifi->ifi_hlen = hlen;

96 if (ifi->ifi_hlen > IFI_HADDR)

97 ifi->ifi_hlen = IFI_HADDR;

98 if (hlen)

99 memcpy(ifi->ifi_haddr, haddr, ifi->ifi_hlen);

Выделение памяти и инициализация структуры ifi_info

78-99
На этом этапе мы знаем, что возвратим данный интерфейс вызывающему процессу. Мы выделяем память для нашей структуры
ifi_info
и добавляем ее в конец связного списка, который мы создаем. Мы копируем флаги и имя интерфейса в эту структуру. Далее мы проверяем, заканчивается ли имя интерфейса нулем, и поскольку функция
callос
инициализирует выделенную в памяти область нулями, мы знаем, что
ifi_hlen
инициализируется нулем, a
ifi_next
— пустым указателем.

В листинге 17.7 представлена последняя часть нашей функции.

Листинг 17.7. Получение и возврат адреса интерфейса

100 switch (ifr->ifr_addr.sa_family) {

101 case AF_INET:

102 sinptr = (struct sockaddr_in*)&ifr->ifr_addr;

103 ifi->ifi_addr = Calloc(1, sizeof(struct sockaddr_in));

104 memcpy(ifi->ifi_addr, sinptr, sizeof(struct sockaddr_in));

105 #ifdef SIOCGIFBRDADDR

106 if (flags & IFF_BROADCAST) {

107 Ioctl(sockfd, SIOCGIFBRDADDR, &ifrcopy);

108 sinptr = (struct sockaddr_in*) &ifrcopy.ifr_broadaddr;

109 ifi->ifi_brdaddr = Calloc(1, sizeof(struct sockaddr_in));

110 memcpy(ifi->ifi_brdaddr, sinptr, sizeof(struct sockaddr_in));

111 }

112 #endif

113 #ifdef SIOCGIFDSTADDR

114 if (flags & IFF_POINTOPOINT) {

115 Ioctl(sockfd, SIOCGIFDSTADDR, &ifrcopy);

116 sinptr = (struct sockaddr_in*) &ifrcopy.ifr_dstaddr;

117 ifi->ifi_dstaddr = Calloc(1, sizeof(struct sockaddr_in));

118 memcpy(ifi->ifi_dstaddr, sinptr, sizeof(struct sockaddr_in));

119 }

120 #endif

121 break;

122 case AF_INET6:

123 sin6ptr = (struct sockaddr_in6*)&ifr->ifr_addr;

124 ifi->ifi_addr = Calloc(1, sizeof(struct sockaddr_in6));

Поделиться с друзьями: