ПРИМЕЧАНИЕ
Пользователи обычно задают имя интерфейса le0 или ether0, а IP-адрес и индекс интерфейса не используются. Например, tcpdump является одной из немногих программ, позволяющих пользователю задавать интерфейс, а ее параметр -i принимает имя интерфейса в качестве аргумента.
Функция
mcast_leave
выводит узел из группы с IP-адресом, содержащимся в структуре адреса сокета, на которую указывает аргумент
grp
.
Функция
mcast_block_source
блокирует получение через конкретный сокет пакетов, относящихся к определенной группе и исходящих от определенного источника. IP-адреса группы и источника хранятся в структурах адреса сокета, на которые указывают аргументы
grp
и
src
соответственно. Длины структур задаются параметрами
srclen
и
grplen
. Для успешного завершения функции необходимо, чтобы до ее вызова уже была вызвана функция
mcast_join
для того же сокета и той же группы.
Функция
mcast_unblock_source
разблокирует получение трафика от источника из заданной группы. Аргументы
src
,
srclen
,
grp
и
grplen
имеют тот же смысл, что и аргументы предыдущей функции, и должны совпадать с ними по значениям.
Функция
mcast_join_source_group
выполняет присоединение к группе источника. Адрес источника и адрес группы содержатся в структурах адреса сокета, на которые указывают аргументы
src
и
grp
. Длины структур задаются параметрами
srclen
и
grplen
. Интерфейс, присоединяемый к группе, может быть задан именем (ненулевой аргумент
ifname
) или индексом (
ifindex
). Если интерфейс не задан явно, ядро выбирает его самостоятельно.
Функция
mcast_leave_source_group
выполняет отсоединение от группы источника. Адреса источника и группы содержатся в структурах адреса сокета, на которые указывают аргументы
src
и
grp
. Длины структур задаются параметрами
srclen
и
grplen
. Подобно
mcast_leave
,
mcast_leave_source_group
не требует указания интерфейса: она всегда отсоединяет от группы первый интерфейс, удовлетворяющий условиям.
Функция
mcast_set_if
устанавливает индекс интерфейса по умолчанию для исходящих дейтаграмм многоадресной передачи. Если аргумент
ifname
непустой, он задает имя интерфейса. Иначе положительное значение аргумента
ifindex
будет задавать индекс интерфейса. В случае IPv6 имя сопоставляется индексу с использованием функции
if_nametoindex
. В случае IPv4 сопоставление имени или индекса IP-адресу направленной передачи интерфейса происходит так же, как для функции
mcast_join
.
Функция
mcast_set_loop
устанавливает параметр закольцовки либо в 0, либо в 1, а функция
mcast_set_ttl
TTL в случае IPv4 или предел количества транзитных узлов в случае IPv6. Функции
mcast_get_XXX
возвращают соответствующие значения.
Пример: функция mcast_join
В листинге 21.1[1] показана первая часть функции
mcast_join
. Эта часть демонстрирует простоту интерфейса программирования, не зависящего от протокола.
Листинг 21.1. Присоединение к группе: сокет IPv4
//lib/mcast_join.c
1 #include "unp.h"
2 #include <net/if.h>
3 int
4 mcast_join(int sockfd, const SA *grp, socklen_t grplen,
5 const char *ifname, u_int ifindex)
6 {
7 #ifdef MCAST_JOIN_GROUP
8 struct group_req req;
9 if (ifindex > 0) {
10 req.gr_interface = ifindex;
11 } else if (ifname != NULL) {
12 if ((req.gr_interface = if_nametoindex(ifname)) == 0) {
13 errno = ENXIO; /* интерфейс не найден */
14 return(-1);
15 }
16 } else
17 req.gr_interface = 0;
18 if (grplen > sizeof(req.gr_group)) {
19 errno = EINVAL;
20 return -1;
21 }
22 memcpy(&req.gr_group, grp, grplen);
23 return (setsockopt(sockfd, family_to_level(grp->sa_family),
24 MCAST_JOIN_GROUP, &req, sizeof(req)));
25 #else
Обработка индекса
9-17
Если при вызове был указан индекс интерфейса, функция использует его непосредственно. В противном случае (при указании имени интерфейса), имя преобразуется в индекс вызовом
if_nametoindex
. Если ни имя, ни индекс не заданы, интерфейс выбирается ядром.
Копирование адреса и вызов setsockopt
18-22
Адрес сокета копируется непосредственно в поле группы. Вспомните, что поле это имеет тип
sockaddr_storage
, а потому достаточно велико для хранения адреса любого типа, поддерживаемого системой. Для предотвращения переполнения буфера (при ошибках в программе) мы проверяем размер
sockaddr
и возвращаем
EINVAL
, если он слишком велик.
23-24
Присоединение к группе выполняется вызовом
setsockopt
. Аргумент
level
определяется на основании семейства группового адреса вызовом нашей собственной функции
family_to_level
. Некоторые системы допускают несоответствие аргумента level семейству адреса сокета, например использование
IPPROTO_IP
с
MCAST_JOIN_GROUP
, даже если сокет относится к семейству
AF_INET6
, но это верно не для всех систем, поэтому мы и должны выполнить преобразование семейства к нужному значению
level
. Листинг этой тривиальной функции в книге мы не приводим, но исходный код этой функции вы можете скачать вместе со всеми остальными программами.