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

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

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

38 #else

39  switch (ifr->ifr_addr.sa_family) {

40 #ifdef IPV6

41  case AF_INET6:

42   len = sizeof(struct sockaddr_in6);

43   break;

44 #endif

45  case AF_INET:

46  default:

47   len = sizeof(struct sockaddr);

48   break;

49  }

50 #endif /* HAVE_SOCKADDR_SA_LEN */

51  ptr += sizeof(ifr->ifr_name) + len; /* для следующей строки */


52 #ifdef HAVE_SOCKADDR_DL_STRUCT

53  /* предполагается, что AF_LINK идет перед AF_INET и AF_INET6 */

54  if (ifr->ifr_addr.sa_family == AF_LINK) {

55   struct sockaddr_dl *sdl = (struct sockaddr_dl*)&ifr->ifr_addr;

56   sdlname = ifr->ifr_name;

57   idx = sdl->sdl_index;

58   haddr = sdl->sdl_data + sdl->sdl_nlen;

59   hlen = sdl->sdl_alen;

60  }

61 #endif


62  if (ifr->ifr_addr.sa_family != family)

63   continue; /* игнорируется, если семейство адреса не то */

64  myflags = 0;

65  if ((cptr = strchr(ifr->ifr_name, ':')) != NULL)

66   *cptr = 0; /* замена двоеточия нулем */

67  if (strncmp(lastname, ifr->ifr_name, IFNAMSIZ) == 0) {

68   if (doaliases == 0)

69    continue; /* этот интерфейс уже обработан */

70   myflags = IFI_ALIAS;

71  }

72  memcpy(lastname, ifr->ifr_name, IFNAMSIZ);


73  ifrcopy = *ifr;

74  Ioctl(sockfd, SIOCGIFFLAGS, &ifrcopy);

75  flags = ifrcopy.ifr_flags;

76  if ((flags & IFF_UP) == 0)

77   continue; /* игнорируется, если интерфейс не используется */

Переход к следующей структуре адреса сокета

35-51 При последовательном просмотре всех структур ifreq ifr указывает на текущую структуру, а мы увеличиваем ptr на единицу, чтобы он указывал на следующую. Необходимо предусмотреть особенность более новых систем, предоставляющих поле длины для структур адреса сокета, и вместе с тем учесть, что более старые системы этого поля не предоставляют. Хотя в листинге 17.1 структура адреса сокета, содержащаяся в структуре ifreq, объявляется как общая структура адреса сокета, в новых системах она может относиться к произвольному типу. Действительно, в 4.4BSD структура адреса сокета канального уровня также возвращается для каждого интерфейса [128, с. 118]. Следовательно, если поддерживается элемент длины, то мы должны использовать его значение для переустановки нашего указателя на следующую структуру адреса сокета. В противном случае мы определяем длину, исходя из семейства адресов, используя размер общей структуры адреса сокета (16 байт) в качестве значения по умолчанию.

ПРИМЕЧАНИЕ

В системах, поддерживающих 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] = '';

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));

125    memcpy(ifi->ifi_addr, sin6ptr, sizeof(struct sockaddr_in6));


126 #ifdef SIOCGIFDSTADDR

127    if (flags & IFF_POINTOPOINT) {

128     Ioctl(sockfd, SIOCGIFDSTADDR, &ifrcopy);

129     sin6ptr = (struct sockaddr_in6*)&ifrcopy.ifr_dstaddf;

130     ifi->ifi_dstaddr = Calloc(1, sizeof(struct sockaddr_in6));

131     memcpy(ifi->ifi_dstaddr, sin6ptr,

132     sizeof(struct sockaddr_in6));

133    }

134 #endif

135    break;


136   default:

137    break;

138   }

139  }

140  free(buf);

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

142 }

102-104 Мы копируем IP-адрес, возвращенный из нашего начального вызова SIOCGIFCONF функции ioctl, в структуру, которую мы создаем.

106-119 Если интерфейс поддерживает широковещательную передачу, мы получаем широковещательный адрес с помощью вызова SIOCGIFBRDADDR функции ioctl. Мы выделяем память для структуры адреса сокета, содержащей этот адрес, и добавляем ее к структуре ifi_info, которую мы создаем. Аналогично, если интерфейс является интерфейсом типа «точка-точка», вызов SIOCGIFBRDADDR возвращает IP-адрес другого конца связи.

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