Книга: UNIX: разработка сетевых приложений

21.6. Параметры сокетов многоадресной передачи

21.6. Параметры сокетов многоадресной передачи

Для поддержки многоадресной передачи программным интерфейсом приложений (API) требуется только пять новых параметров сокетов. Поддержка фильтрации отправителей, необходимая для SSM, требует еще четырех параметров. В табл. 21.2 показаны три параметра, не имеющих отношения к членству в группах, а также тип данных аргумента, который предполагается использовать в вызове функций getsockopt или setsockopt для IPv4 и IPv6. В табл. 21.3 представлены оставшиеся шесть параметров сокетов для IPv4, IPv6 и не зависящего от IP-версии API. Во втором столбце показан тип данных переменной, указатель на которую является четвертым аргументом функций getsockopt и setsockopt. Все девять параметров действительны с функцией setsockopt, но шесть предназначенных для входа и выхода из группы не могут быть использованы в вызове функции getsockopt.

Таблица 21.2. Параметры сокетов многоадресной передачи

Параметр Тип данных Описание
IP_MULTICAST_IF struct in_addr Интерфейс по умолчанию для исходящих многоадресных пакетов
IP_MULTICAST_TTL u_char TTL для исходящих многоадресных пакетов
IP_MULTICAST_LOOP u_char Включение и отключение закольцовки для исходящих многоадресных пакетов
IPV6_MULTICAST_IF u_int Интерфейс по умолчанию для исходящих многоадресных пакетов
IPV6_MULTICAST_HOPS int Предел количества прыжков для и сходящих многоадресных пакетов
IPV6_MULTICAST_LOOP u_int Включение и отключение закольцовки для исходящих многоадресных пакетов

Таблица 21.3. Параметры сокета, определяющие членство в группах многоадресной передачи

Параметр Тип данных Описание
IP_ADD_MEMBERSHIP struct ip_mreq Присоединение к группе многоадресной передачи
IP_DROP_MEMBERSHIP struct ip_mreq Отсоединение от группы многоадресной передачи
IP_BLOCK_SOURCE struct ip_mreq_source Блокирование источника из группы, к которой выполнено присоединение
IP_UNBLOCK_SOURCE struct ip_mreq_source Разблокирование ранее заблокированного источника
IP_ADD_SOURCE_MEMBERSHIP struct ip_mreq_source Присоединение к группе источника
IP_DROP_SOURCE_MEMBERSHIP struct ip_mreq_source Отсоединение от группы источника
IPV6_JOIN_GROUP struct ipv6_mreq Присоединение к группе многоадресной передачи
IPV6_LEAVE_GROUP struct ipv6_mreq Отсоединение от группы многоадресной передачи
MCAST_JOIN_GROUP struct group_req Присоединение к группе многоадресной передачи
MCAST_LEAVE_GROUP struct group_req Отсоединение от группы многоадресной передачи
MCAST_BLOCK_SOURCE struct group_source_req Блокирование источника из группы, к которой выполнено присоединение
MCAST_UNBLOCK_SOURCE struct group_source_req Разблокирование ранее заблокированного источника
MCAST_JOIN_SOURCE_GROUP struct group_source_req Присоединение к группе источника
MCAST_LEAVE_SOURCE_GROUP struct group_source_req Отсоединение от группы источника

ПРИМЕЧАНИЕ

Параметры IPv4 TTL и закольцовки получают аргумент типа u_char, в то время как IPv6-параметры предела транзитных узлов и закольцовки получают аргументы соответственно типа int и u_int. Распространенная ошибка программирования с параметрами многоадресной передачи IPv4 — вызов функции setsockopt с аргументом типа int для задания TTL или закольцовки (что не разрешается [128, с. 354–355]), поскольку большинство других параметров сокетов, представленных в табл. 7.1, имеют целочисленные аргументы. Изменения, внесенные в IPv6, должны уменьшить вероятность ошибок.

Теперь мы опишем каждый из девяти параметров сокетов более подробно. Обратите внимание, что эти девять параметров концептуально идентичны в IPv4 и IPv6 — различаются только их названия и типы аргументов.

IP_ADD_MEMBERSHIP, IPV6_JOIN_GROUP, MCAST_JOIN_GROUP. Назначение этих параметров — присоединение к группе на заданном локальном интерфейсе. Мы задаем локальный интерфейс одним из его направленных адресов для IPv4 или индексом интерфейса для IPv6. Следующие три структуры используются при присоединении к группе или при отсоединении от нее:

struct ip_mreq {
 struct in_addr imr_multiaddr; /* IPv4-адрес многоадресной
                                  передачи класса D */
 struct in_addr imr_interface; /* IPv4-адрес локального
                                  интерфейса */
};
struct ipv6_mreq {
 struct in6_addr ipv6mr_multiaddr; /* IPv6-адрес многоадресной
                                      передачи */
 unsigned int ipv6mr_interface;    /* индекс интерфейса или 0 */
};
struct group_req {
 unsigned int gr_interface;        /* индекс интерфейса или 0 */
 struct sockaddr_storage gr_group; /* адрес многоадресной передачи
                                      IPv4 или IPv6 */
};

Если локальный интерфейс задается как универсальный адрес (INADDR_ANY для IPv4) или как нулевой индекс IPv6, то конкретный локальный интерфейс выбирается ядром.

Мы говорим, что узел принадлежит к данной группе на данном интерфейсе, если один или более процессов в настоящий момент принадлежат к этой группе на этом интерфейсе.

Сокет может быть присоединен к нескольким группам, но к каждой группе должен быть присоединен уникальный адрес или уникальный интерфейс. Это свойство можно использовать на узле с несколькими сетевыми интерфейсами: создается один сокет, которому присваивается один адрес многоадресной передачи, но благодаря наличию разных интерфейсов этот сокет может быть присоединен к разным группам.

Вспомните из табл. 21.1, что частью адреса многоадресной передачи IPv6 является поле области действия. Как мы отмечали, адреса многоадресной передачи IPv6, отличающиеся только областью действия, являются различными. Следовательно, если реализация протокола синхронизации времени (network time protocol, NTP) хочет получать все пакеты NTP независимо от их области действия, она должна будет присоединиться к адресу ff01:101 (локальный в пределах узла), ff02:101 (локальный в пределах физической сети), ff05:101 (локальный в пределах сайта), ff08:101 (локальный в пределах организации) и ff0e:101 (глобальный). Все присоединения могут выполняться на одном сокете. Можно установить параметр сокета IPV6_PKTINFO (см. раздел 22.8), чтобы функция recvmsg возвращала адрес получателя каждой дейтаграммы.

Независимый от версии IP параметр сокета (MCAST_JOIN_GROUP) аналогичен соответствующему параметру IPv6 за тем исключением, что он использует структуру sockaddr_storage вместо in6_addr для передачи адреса ядру. Структура sockaddr_storage (см. листинг 3.4) достаточно велика для хранения адреса любой версии, поддерживаемой системой.

ПРИМЕЧАНИЕ

В большинстве реализаций число присоединений, допустимых для одного сокета, ограничено. Предел определяется константой IP_MAX_MEMBERSHIPS (для Беркли-реализаций ее значение равно 20). В некоторых реализациях это ограничение снято, в других оно значительно превышает значение для Беркли-реализаций.

Когда интерфейс, на котором будет происходить присоединение, не задан, Беркли-ядра ищут адрес многоадресной передачи в обычной таблице маршрутизации IP и используют полученный в результате интерфейс [128, с. 357]. Некоторые системы для обработки этой ситуации устанавливают маршрут для всех адресов многоадресной передачи (то есть маршрут с адресом получателя 224.0.0.0/8 для IPv4) в процессе инициализации.

Для IPv6 сделано изменение — при задании интерфейса используется индекс, а не локальный адрес направленной передачи, как было в IPv4. Это позволяет выполнять присоединение на ненумерованных интерфейсах и конечных точках туннелей.

Изначально в API многоадресной передачи IPv6 использовалась константа IPV6_ADD_MEMBERSHIP, а не IPV6_JOIN_GROUP. Во всех остальных отношениях интерфейс программирования не изменился. Описанная далее функция mcast_join скрывает это отличие.

IP_DROP_MEMBERSHIP, IPV6_LEAVE_GROUP и MCAST_LEAVE_GROUP. Назначение этих параметров — выход из группы на заданном локальном интерфейсе. С этими параметрами сокета применяются те же структуры, которые мы только что показали для присоединения к группе. Если локальный интерфейс не задан (то есть его значение равно INADDR_ANY для IPv4 или индекс интерфейса равен нулю для IPv6), удаляется первое совпадающее с искомым вхождение в группу.

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

ПРИМЕЧАНИЕ

Изначально в API многоадресной передачи IPv6 использовалась константа IPV6_DROP_MEMBERSHIP, а не IPV6_LEAVE_GROUP. Во всех остальных отношениях интерфейс программирования не изменился. Описанная далее функция mcast_leave скрывает это отличие.

IP_BLOCK_SOURCE, MCAST_BLOCK_SOURCE. Блокируют получение трафика через данный сокет от конкретного источника для конкретной группы и интерфейса. Если все сокеты, присоединенные к группе, заблокировали один и тот же источник, система может проинформировать маршрутизаторы о нежелательности трафика, что может повлиять на маршрутизацию многоадресного трафика в сети. Локальный интерфейс задается одним из его направленных адресов для IPv4 или индексом для независимого от версии API. Для блокирования и разблокирования источника используются две приведенные ниже структуры:

struct ip_mreq_source {
 struct in_addr imr_multiaddr;  /* IPv4-адрес многоадресной
                                   передачи класса D */
 struct in_addr imr_sourceaddr; /* IPv4-адрес источника */
 struct in_addr imr_interface;  /* IPv4-адрес локального
                                   интерфейса */
};
struct group_source_req {
 unsigned int gsr_interface;         /* индекс интерфейса или 0 */
 struct sockaddr_storage gsr_group;  /* адрес многоадресной
                                        передачи IPv4 или IPv6 */
 struct sockaddr_storage gsr_source; /* адрес источника IPv4
                                        или IPv6 */
};

Если локальный интерфейс задается как универсальный адрес (INADDR_ANY для IPv4) или как нулевой индекс IPv6, то конкретный локальный интерфейс выбирается ядром.

Запрос на блокирование источника действует только для присоединенных групп, то есть таких, которые уже были присоединены к указанному интерфейсу параметром IP_ADD_MEMBERSHIP, IPV6_JOIN_GROUP или MCAST_JOIN_GROUP.

IP_UNBLOCK_SOURCE, MCAST_UNBLOCK_SOURCE. Разблокирование заблокированного ранее источника. Аргументы должны быть в точности те же, что и у предшествовавшего запроса IP_BLOCK_SOURCE или MCAST_BLOCK_SOURCE.

Если локальный интерфейс задается как универсальный адрес (INADDR_ANY для IPv4) или как нулевой индекс IPv6, то конкретный локальный интерфейс выбирается ядром.

IP_ADD_SOURCE_MEMBERSHIР, MCAST_JOIN_SOURCE_GROUP. Присоединение к группе конкретного источника на заданном локальном интерфейсе. С этим параметром используются те же структуры, что и с параметрами блокирования и разблокирования источника. Сокет не должен быть присоединен к той же группе без указания источника (параметры IP_ADD_MEMBERSHIP, IPV6_JOIN_GROUP, MCAST_JOIN_GROUP).

Если локальный интерфейс задается как универсальный адрес (INADDR_ANY для IPv4) или как нулевой индекс IPv6, то конкретный локальный интерфейс выбирается ядром.

IP_DROP_SOURCE_MEMBERSHIP, MCAST_LEAVE_SOURCE_GROUP. Отключение от группы источника конкретного локального интерфейса. Используются те же структуры, что и с предыдущими параметрами сокетов. Если локальный интерфейс не указан (значение INADDR_ANY для IPv4 или 0 для независимого от версии API), отключается первая группа, удовлетворяющая заданным значениям.

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

IP_MULTICAST_IF и IPV6_MULTICAST_IF. Назначение этих параметров - задание интерфейса для исходящих дейтаграмм многоадресной передачи, отправленных на этом сокете. Этот интерфейс задается либо структурой in_addr для IPv4, либо индексом интерфейса для IPv6. Если задано значение INADDR_ANY для IPv4 или нулевой индекс интерфейса для IPv6, то удаляется любой интерфейс, ранее заданный этим параметром сокета, и система будет выбирать интерфейс каждый раз при отправке дейтаграммы.

Будьте внимательны, четко различая локальный интерфейс, заданный (или выбранный), когда процесс присоединяется к группе (интерфейс для получения приходящих дейтаграмм многоадресной передачи), и локальный интерфейс, заданный (или выбранный) для исходящих дейтаграмм.

ПРИМЕЧАНИЕ

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

IP_MULTICAST_TTL и IPV6_MULTICAST_HOPS. Назначение этих параметров - установка значения поля TTL в случае IPv4 или предельного количества транзитных узлов в случае IPv6 для исходящих дейтаграмм многоадресной передачи. По умолчанию значение обоих параметров равно 1, что ограничивает дейтаграмму локальной подсетью.

? IP_MULTICAST_LOOP и IPV6_MULTICAST_LOOP. Назначение этих параметров - включение или отключение локальной закольцовки для дейтаграмм многоадресной передачи. По умолчанию закольцовка включена: копия каждой дейтаграммы многоадресной передачи, посылаемой процессом на узле, будет отправлена обратно на этот узел и обработана им, как любая другая полученная дейтаграмма, если узел принадлежит данной группе на исходящем интерфейсе.

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

ПРИМЕЧАНИЕ

Описываемая здесь закольцовка является внутренней и выполняется на уровне IP или выше. Если интерфейс получает копии своих передач, RFC 1112 [26] требует, чтобы драйвер игнорировал эти копии. В этом документе также утверждается, что параметр закольцовки по умолчанию включен «в целях оптимизации производительности для протоколов верхнего уровня, которые ограничивают членство в группе до одного процесса на узел (например, маршрутизирующих протоколов)».

Первые шесть пар параметров сокетов (ADD_MEMBERSHIP/JOIN_GROUP, DROP_MEMBERSHIP/LEAVE_GROUP, BLOCK_SOURCE, UNBLOCK_SOURCE, ADD_SOURCE_MEMBERSHIP/JOIN_SOURCE_GROUP, DROP_SOURCE_MEMBERSHIP/LEAVE_SOURCE_GROUP) влияют на получение дейтаграмм многоадресной передачи, в то время как последние три пары параметров влияют на отправку дейтаграмм многоадресной передачи (интерфейс для исходящих сообщений, TTL или предел количества транзитных узлов, закольцовка). Ранее мы отмечали, что для отправки дейтаграммы многоадресной передачи ничего особенного не требуется. Если ни один параметр сокетов многоадресной передачи не задан перед отправкой дейтаграммы, интерфейс для исходящей дейтаграммы будет выбран ядром, TTL или предел количества транзитных узлов будут равны 1, а копия отправленной дейтаграммы будет посылаться обратно (то есть будет включена закольцовка).

Чтобы получить дейтаграмму многоадресной передачи, процесс должен присоединиться к группе, а также связать при помощи функции bind сокет UDP с номером порта, который будет использоваться как номер порта получателя для дейтаграмм, отсылаемых данной группе. Это две отдельные операции, и обе они являются обязательными. Присоединение к группе указывает уровню IP узла и канальному уровню, что необходимо получать дейтаграммы многоадресной передачи, отправленные этой группе. Связывая порт, приложение указывает UDP, что требуется получать отправляемые на этот порт дейтаграммы. Некоторые приложения в дополнение к связыванию порта также связывают при помощи функции bind адрес многоадресной передачи с сокетом. Это предотвращает доставку сокету любых других дейтаграмм, которые могли быть получены для этого порта.

ПРИМЕЧАНИЕ

Исторически Беркли-реализации требуют только, чтобы некоторый сокет на узле присоединился к группе — это не обязательно тот сокет, который связывается с портом и затем получает дейтаграммы многоадресной передачи. Однако есть вероятность, что эти реализации могут доставлять дейтаграммы многоадресной передачи приложениям, не знающим о многоадресной передаче. Более новые ядра требуют, чтобы процесс связывался с портом и устанавливал какой-нибудь параметр сокета многоадресной передачи для сокета как указатель того, что приложение знает о многоадресной передаче. Самый обычный параметр сокета многоадресной передачи — признак присоединения к группе. Для Solaris 2.5 характерны некоторые отличия: дейтаграммы многоадресной передачи доставляются только на те сокеты, которые присоединились к группе и связались с портом. В целях переносимости все приложения многоадресной передачи должны присоединиться к группе и связаться с портом.

Более новый интерфейс многоадресного сервиса требует, чтобы уровень IP доставлял многоадресные пакеты сокету только в том случае, если этот сокет присоединился к группе или источнику. Такое требование было введено с IGMPv3 (RFC 3376 [16]), чтобы разрешить фильтрацию источников и многоадресную передачу от источника. Таким образом ужесточается требование на присоединение к группе, но зато ослабляется требование на связывание группового адреса. Однако для наибольшей переносимости со старыми и новыми интерфейсами приложения должны присоединяться к группам и связывать сокеты с групповыми адресами.

Некоторые более старые узлы, имеющие возможность многоадресной передачи, не позволяют связывать адрес многоадресной передачи с сокетом при помощи функции bind. В целях переносимости приложение может игнорировать ошибку функции bind при связывании адреса многоадресной передачи с сокетом и делать повторную попытку с адресом INADDR_ANY или in6addr_any.

Оглавление книги


Генерация: 1.229. Запросов К БД/Cache: 3 / 0
поделиться
Вверх Вниз