22.2. Получение флагов, IP-адреса получателя и индекса интерфейса

22.2. Получение флагов, IP-адреса получателя и индекса интерфейса

Исторически функции sendmsg и recvmsg использовались только для передачи дескрипторов через доменные сокеты Unix (см. раздел 15.7), но даже это происходило сравнительно редко. Однако в настоящее время популярность этих двух функций растет по двум причинам:

1. Элемент msg_flags, добавленный в структуру msghdr в реализации 4.3BSD Reno, возвращает приложению флаги сообщения. Эти флаги мы перечислили в табл. 14.2.

2. Вспомогательные данные используются для передачи все большего количества информации между приложением и ядром. В главе 27 мы увидим, что IPv6 продолжает эту тенденцию.

В качестве примера использования функции recvmsg мы напишем функцию recvfrom_flags, аналогичную функции recvfrom, но дополнительно позволяющую получить:

? возвращаемое значение msg_flags;

? адрес получателя полученной дейтаграммы (из параметра сокета IP_RECVDSTADDR);

? индекс интерфейса, на котором была получена дейтаграмма (параметр сокета IP_RECVIF).

Чтобы можно было получить два последних элемента, мы определяем в нашем заголовке unp.h следующую структуру:

struct in_pktinfo {

 struct in_addr ipi_addr;    /* IPv4-адрес получателя */

 int            ipi_ifindex; /* индекс интерфейса, на котором была

                                получена дейтаграмма */

};

Мы выбрали имена структуры и ее элементов так, чтобы получить определенное сходство со структурой IPv6 in6_pktinfo, возвращающей те же два элемента для сокета IPv6 (см. раздел 22.8). Наша функция recvfrom_flags будет получать в качестве аргумента указатель на структуру in_pktinfo, и если этот указатель не нулевой, возвращать структуру через указатель.

Проблема построения этой структуры состоит в том, что неясно, что возвращать, если недоступна информация, которая должна быть получена из параметра сокета IP_RECVDSTADDR (то есть реализация не поддерживает данный параметр сокета). Обработать индекс интерфейса легко, поскольку нулевое значение может использоваться как указание на то, что индекс неизвестен. Но для IP-адреса все 32-разрядные значения являются действительными. Мы выбрали такое решение: адрес получателя 0.0.0.0 возвращается в том случае, когда действительное значение недоступно. Хотя это реальный IP-адрес, использовать его в качестве IP-адреса получателя не разрешается (RFC 1122 [10]). Он будет действителен только в качестве IP-адреса отправителя во время начальной загрузки узла, когда узел еще не знает своего IP-адреса.

ПРИМЕЧАНИЕ

К сожалению, Беркли-ядра принимают дейтаграммы, предназначенные для адреса 0.0.0.0 [128, с. 218-219]. Это устаревшие адреса широковещательной передачи, генерируемые ядрами 4.2BSD.

Первая часть нашей функции recvfrom_flags представлена в листинге 22.1[1]. Эта функция предназначена для использования с сокетом UDP.

Листинг 22.1. Функция recvfrom_flags: вызов функции recvmsg

//adviо/recvfromflags.c

 1 #include "unp.h"

 2 #include <sys/param.h> /* макрос ALIGN для макроса CMSG_NXTHDR() */

 3 ssize_t

 4 recvfrom_flags(int fd, void *ptr, size_t nbytes, int *flagsp,

 5  SA *sa, socklen_t *salenptr, struct unp_in_pktinfo *pktp)

 6 {

 7  struct msghdr msg;

 8  struct iovec iov[1];

 9  ssize_t n;

10 #ifdef HAVE_MSGHDR_MSG_CONTROL

11  struct cmsghdr *cmptr;

12  union {

13   struct cmsghdr cm;

14   char control[CMSG_SPACE(sizeof(struct in_addr)) +

15    CMSG_SPACE(sizeof(struct unp_in_pktinfo))];

16  } control_un;

17  msg.msg_control = control_un.control;

18  msg.msg_controllen = sizeof(control_un.control);

19  msg.msg_flags = 0;

20 #else

21  bzero(&msg, sizeof(msg)); /* обнуление msg_accrightslen = 0 */

22 #endif

23  msg.msg_name = sa;

24  msg.msg_namelen = *salenptr;

25  iov[0].iov_base = ptr;

26  iov[0].iov_len = nbytes;

27  msg.msg_iov = iov;

28  msg.msg_iovlen = 1;

29  if ((n = recvmsg(fd, &msg, *flagsp)) < 0)

30   return(n);

31  *salenptr = msg.msg_namelen; /* возвращение результатов */

32  if (pktp)

33   bzero(pktp, sizeof(struct unp_in_pktinfo)); /* 0.0.0.0. интерфейс = 0 */

Подключаемые файлы

1-2 Использование макроопределения CMSG_NXTHDR требует подключения заголовочного файла <sys/param.h>.

Аргументы функции

3-5 Аргументы функции аналогичны аргументам функции recvfrom за исключением того, что четвертый аргумент является указателем на целочисленный флаг (так что мы можем возвратить флаги, возвращаемые функцией recvmsg), а седьмой аргумент новый: это указатель на структуру unp_in_pktinfo, содержащую IPv4-адрес получателя пришедшей дейтаграммы и индекс интерфейса, на котором дейтаграмма была получена.

Различия реализаций

10-22 При работе со структурой msghdr и различными константами MSG_XXX мы встречаемся со множеством различий в реализациях. Одним из вариантов обработки таких различий может быть использование имеющейся в языке С возможности условного подключения (директива #ifdef). Если реализация поддерживает элемент msg_control, то выделяется пространство для хранения значений, возвращаемых параметрами сокета IP_RECVDSTADDR и IP_RECVIF, и соответствующие элементы инициализируются.

Заполнение структуры msghdr и вызов функции recvmsg

23-33 Заполняется структура msghdr и вызывается функция recvmsg. Значения элементов msg_namelen и msg_flags должны быть переданы обратно вызывающему процессу. Они являются аргументами типа «значение-результат». Мы также инициализируем структуру вызывающего процесса unp_in_pktinfo, устанавливая IP-адрес 0.0.0.0 и индекс интерфейса 0.

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

Листинг 22.2. Функция recvfrom_flags: возвращаемые флаги и адрес получателя

//advio/recvfromflags.c

34 #ifndef HAVE_MSGHDR_MSG_CONTROL

35  *flagsp = 0; /* возвращение результатов */

36  return(n);

37 #else

38  *flagsp = msg.msg_flags; /* возвращение результатов */

39  if (msg.msg_controllen < sizeof(struct cmsghdr) ||

40   (msg.msg_flags & MSG_CTRUNC) || pktp == NULL)

41    return(n);

42   for (cmptr = CMSG_FIRSTHDR(&msg); cmptr != NULL;

43    cmptr = CMSG_NXTHDR(&msg, cmptr)) {

44 #ifdef IP_RECVDSTADDR

45    if (cmptr->cmsg_level == IPPROTO_IP &&

46     cmptr->cmsg_type == IP_RECVDSTADDR) {

47     memcpy(&pktp->ipi_addr, CMSG_DATA(cmptr),

48      sizeof(struct in_addr));

49     continue;

50    }

51 #endif

52 #ifdef IP_RECVIF

53    if (cmptr->cmsg_level == IPPROTO_IP && cmptr->cmsg_type == IP_RECVIF) {

54     struct sockaddr_dl *sdl;

55    sdl = (struct sockaddr_dl*)CMSG_DATA(cmptr);

56    pktp->ipi_ifindex = sdl->sdl_index;

57    continue;

58   }

59 #endif

60   err_quit("unknown ancillary data, len = %d, level = %d, type = %d",

61    cmptr->cmsg_len, cmptr->cmsg_level, cmptr->cmsg_type);

62  }

63  return(n);

64 #endif /* HAVE_MSGHDR_MSG_CONTROL */

65 }

34-37 Если реализация не поддерживает элемента msg_control, мы просто обнуляем возвращаемые флаги и завершаем функцию. Оставшаяся часть функции обрабатывает информацию, содержащуюся в структуре msg_control.

Возвращение при отсутствии управляющей информации

38-41 Мы возвращаем значение msg_flags и передаем управление вызывающей функции в том случае, если нет никакой управляющей информации, управляющая информация была обрезана или вызывающий процесс не требует возвращения структуры unp_in_pktinfo.

Обработка вспомогательных данных

42-43 Мы обрабатываем произвольное количество объектов вспомогательных данных с помощью макросов CMSG_FIRSTHDR и CMSG_NEXTHDR.

Обработка параметра сокета IP_RECVDSTADDR

47-54 Если в составе управляющей информации был возвращен IP-адрес получателя (см. рис. 14.2), он возвращается вызывающему процессу.

Обработка параметра сокета IP_RECVIF

55-63 Если в составе управляющей информации был возвращен индекс интерфейса, он возвращается вызывающему процессу. На рис. 22.1 показано содержимое возвращенного объекта вспомогательных данных.

Рис. 22.1. Объект вспомогательных данных, возвращаемый для параметра IP_RECVIF

Вспомните структуру адреса сокета канального уровня (см. листинг 18.1). Данные, возвращаемые в объекте вспомогательных данных, представлены в одной из этих структур, но длины трех элементов являются нулевыми (длина имени, адреса и селектора). Следовательно, нет никакой необходимости указывать эти значения, и таким образом структура имеет размер 8 байт, а не 20, как было в листинге 18.1. Возвращаемая нами информация — это индекс интерфейса.

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

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

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

4.6 НАЗНАЧЕНИЕ ИНДЕКСА НОВОМУ ФАЙЛУ

Из книги Архитектура операционной системы UNIX автора Бах Морис Дж

4.6 НАЗНАЧЕНИЕ ИНДЕКСА НОВОМУ ФАЙЛУ Для выделения известного индекса, то есть индекса, для которого предварительно определен собственный номер (и номер файловой системы), ядро использует алгоритм iget. В алгоритме namei, например, ядро определяет номер индекса, устанавливая


13.1.3 Получение сетевого адреса и установка ПО

Из книги Linux для пользователя автора Костромин Виктор Алексеевич

13.1.3 Получение сетевого адреса и установка ПО Поскольку вы собираетесь устанавливать машину с Linux в уже существующую сеть, то следующим вашим шагом при подключении к сети должно стать обращение к администратору сети за получением сетевого адреса. Точнее, вы должны


Получение индекса компонента в списке родителя

Из книги Советы по Delphi. Версия 1.0.6 автора Озеров Валентин

Получение индекса компонента в списке родителя Мне необходимо найти индекс компонента в родительском списке дочерних элементов управления. Я попытался модифицировать prjexp.dll, но без успеха. У кого-нибудь есть идеи?Есть такая функция. Ищет родителя заданного компонента,


Пополнение индекса

Из книги Windows Vista автора Вавилов Сергей

Пополнение индекса Как говорилось выше, по умолчанию проиндексированными являются только личные папки пользователей. Если попытаться найти файл в неиндексированной папке, появляется всплывающее предложение добавить каталог в список индексируемых. Однако вы можете


6.14.2 Поле Флагов

Из книги TCP/IP Архитектура, протоколы, реализация (включая IP версии 6 и IP Security) автора Фейт Сидни М

6.14.2 Поле Флагов Поле флагов содержит три бита: Бит 0 Бит 1 Бит 2 0=Зарезервировано 0=Можно фрагментировать 1=Нельзя фрагментировать 0=Последний фрагмент (Last) 1=Есть еще фрагменты (More) Бит 0 зарезервирован, но должен иметь значение 0. Отправитель может указать в следующем


16.5 Идентификация получателя и обмен сообщениями

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

16.5 Идентификация получателя и обмен сообщениями В Интернете получатель почтового сообщения идентифицируется по имени с использованием следующего общего формата:локальная_часть@имя_доменаЭтот формат очень гибок. Многие годы в Интернете предпочитали формат с


14.2.1. Разбор флагов в командной строке

Из книги Firebird РУКОВОДСТВО РАЗРАБОТЧИКА БАЗ ДАННЫХ автора Борри Хелен

14.2.1. Разбор флагов в командной строке Для разбора командной строки чаще всего применяется библиотека getoptlong (библиотека getopts.rb, обладающая менее развитой функциональностью, считается устаревшей). Она понимает однобуквенные и длинные флаги и распознает двойной дефис (--)


Изменение индекса

Из книги Искусство программирования на языке сценариев командной оболочки автора Купер Мендель

Изменение индекса Активация/деактивация Оператор ALTER INDEX используется для переключения состояния индекса из активного в неактивное и наоборот. Он может быть применен для отключения индекса перед добавлением или изменением большого пакета строк и устранения при этом


Изменение структуры индекса

Из книги C++ для начинающих автора Липпман Стенли

Изменение структуры индекса В отличие от большинства операторов ALTER синтаксис ALTER INDEX не может быть использован для изменения структуры данного объекта. Для этого необходимо удалить индекс и заново его создать с использованием оператора CREATE


Удаление индекса

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

Удаление индекса Оператор DROP INDEX удаляет созданный пользователем индекс из базы данных.Используйте DROP INDEX также в случае необходимости изменения структуры индекса: добавление, удаление сегментов, изменение порядка сегментов или изменение порядка сортировки. Вначале


Улучшение селективности индекса

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

Улучшение селективности индекса Вообще говоря, селективность (избирательность) индекса - это оценочное количество строк, которые могут быть выбраны при поиске по каждому значению индекса. Уникальный индекс имеет максимально возможную селективность, потому что он не


18.6. Функции имени и индекса интерфейса

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

18.6. Функции имени и индекса интерфейса Документ RFC 3493 [36] определяет четыре функции, обрабатывающие имена и индексы интерфейсов. Эти четыре функции используются во многих случаях, когда необходимо описать интерфейс. Они были предложены в процессе разработки API IPv6 (главы 21


Пример: вывод IP-адреса получателя и флага обрезки дейтаграммы

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

Пример: вывод IP-адреса получателя и флага обрезки дейтаграммы Для проверки нашей функции мы изменим функцию dg_echo (см. листинг 8.2) так, чтобы она вызывала функцию recvfrom_flags вместо функции recvfrom. Новая версия функции dg_echo показана в листинге 22.3.Листинг 22.3. Функция dg_echo,