Пример: функция mcast_join
Пример: функция 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. Листинг этой тривиальной функции в книге мы не приводим, но исходный код этой функции вы можете скачать вместе со всеми остальными программами.
В листинге 21.2 представлена вторая часть функции mcast_join, обрабатывающая сокеты IPv4.
Листинг 21.2. Присоединение к группе: обработка сокета IPv4
26 switch (grp->sa_family) {
27 case AF_INET: {
28 struct ip_mreq mreq;
29 struct ifreq ifreq;
30 memcpy(&mreq.imr_multiaddr,
31 &((const struct sockaddr_in*)grp)->sin_addr,
32 sizeof(struct in_addr));
33 if (ifindex > 0) {
34 if (if_indextoname(ifindex, ifreq.ifr_name) == NULL) {
35 errno = ENXIO; /* i/f index not found */
36 return(-1);
37 }
38 goto doioctl;
39 } else if (ifname != NULL) {
40 strncpy(ifreq.ifr_name, ifname, IFNAMSIZ);
41 doioctl:
42 if (ioctl(sockfd, SIOCGIFADDR, &ifreq) < 0)
43 return(-1);
44 memcpy(&mreq.imr_interface,
45 &((struct sockaddr_in*)&ifreq.ifr_addr)->sin_addr,
46 sizeof(struct in_addr));
47 } else
48 mreq.imr_interface.s_addr = htonl(INADDR_ANY);
49 return(setsockopt(sockfd, IPPROTO_IP, IP_ADD_MEMBERSHIP,
50 &mreq, sizeof(mreq)));
51 }
Обработка индекса
33-38 Адрес многоадресной передачи IPv4 в структуре адреса сокета копируется в структуру ip_mreq. Если индекс был задан, вызывается функция if_indextoname, сохраняющая имя в нашей структуре ip_mreq. Если это выполняется успешно, мы переходим на точку вызова ioctl.
Обработка имени
39-46 Имя вызывающего процесса копируется в структуру ip_mreq, а вызов SIOCGIFADDR функции ioctl возвращает адрес многоадресной передачи, связанный с этим именем. При успешном выполнении адрес IPv4 копируется в элемент imr_interface структуры ip_mreq.
Значения по умолчанию
47-48 Если ни индекс, ни имя не заданы, используется универсальный адрес, что указывает ядру на необходимость выбрать интерфейс.
49-50 Функция setsockopt выполняет присоединение к группе.
Третья, и последняя, часть функции, обрабатывающая сокеты IPv6, приведена в листинге 21.3.
Листинг 21.3. Присоединение к группе: обработка сокета IPv6
52 #ifdef IPV6
53 case AF_INET6: {
54 struct ipv6_mreq mreq6;
55 memcpy(&mreq6.ipv6mr_multiaddr,
56 &((const struct sockaddr_in6*) grp)->sin6_addr,
57 sizeof(struct in6_addr));
58 if (ifindex > 0) {
59 mreq6.ipv6mr_interface = ifindex;
60 } else if (ifname != NULL) {
61 if ((mreq6.ipv6mr_interface = if_nametoindex(ifname)) == 0) {
62 errno = ENXIO; /* интерфейс не найден */
63 return(-1);
64 }
65 } else
66 mreq6.ipv6mr_interface = 0;
67 return(setsockopt(sockfd, IPPROTO_IPV6, IPV6_JOIN_GROUP,
68 &mreq6, sizeof(mreq6)));
69 }
70 #endif
71 default:
72 errno = EAFNOSUPPORT;
73 return(-1);
74 }
75 #endif
76 }
Копирование адреса
55-57 Сначала адрес IPv6 копируется из структуры адреса сокета в структуру ipv6_mreq.
Обработка индекса или имени интерфейса или выбор интерфейса по умолчанию
58-66 Если был задан индекс, он записывается в элемент ipv6mr_interface. Если индекс не задан, но задано имя, то для получения индекса вызывается функция if_nametoindex. В противном случае для функции setsockopt индекс устанавливается в 0, что указывает ядру на необходимость выбрать интерфейс.
67-68 Выполняется присоединение к группе.
Более 800 000 книг и аудиокниг! 📚
Получи 2 месяца Литрес Подписки в подарок и наслаждайся неограниченным чтением
ПОЛУЧИТЬ ПОДАРОКДанный текст является ознакомительным фрагментом.
Читайте также
Пример: функция приема сообщений в случае сокета
Пример: функция приема сообщений в случае сокета Часто оказывается удобным отправлять и получать сообщения в виде единых блоков. Как было показано в главе 11, каналы позволяют это сделать. Однако в случае сокетов требуется создание заголовка, содержащего размер
Пример: функция str_echo, использующая стандартный ввод-вывод
Пример: функция str_echo, использующая стандартный ввод-вывод Сейчас мы модифицируем наш эхо-сервер TCP (см. листинг 5.2) для использования стандартного ввода-вывода вместо функций readline и writen. В листинге 14.6 представлена версия нашей функции str_echo, использующая стандартный
Пример: функция bind и доменный сокет Unix
Пример: функция bind и доменный сокет Unix Программа, показанная в листинге 15.2, создает доменный сокет Unix, с помощью функции bind связывает с ним полное имя и затем вызывает функцию getsockname и выводит это полное имя.Листинг 15.2. Связывание полного имени с доменным сокетом
21.7. Функция mcast_join и родственные функции
21.7. Функция mcast_join и родственные функции Несмотря на то что параметры сокетов многоадресной передачи для IPv4 аналогичны параметрам сокетов многоадресной передачи для IPv6, есть достаточно много различий, из-за которых не зависящий от протокола код, использующий
Пример: функция mcast_set_loop
Пример: функция mcast_set_loop В листинге 21.4 показана наша функция mcast_set_loop.Поскольку аргументом является дескриптор сокета, а не структура адреса сокета, мы вызываем нашу функцию sockfd_to_family, чтобы получить семейство адресов сокета. Устанавливается соответствующий параметр
Пример: очереди сообщений Posix и функция select
Пример: очереди сообщений Posix и функция select Дескриптор очереди сообщений (переменная типа mqd_t) не является «обычным» дескриптором и не может использоваться с функциями select и poll (глава 6 [24]). Тем не менее их можно использовать вместе с каналом и функцией mq_notify. (Аналогичный
Пример 9-3. Еще один пример ограничения времени ожидания ввода от пользователя
Пример 9-3. Еще один пример ограничения времени ожидания ввода от пользователя #!/bin/bash# timeout.sh# Автор: Stephane Chazelas,# дополнен автором документа.INTERVAL=5 # предел времени ожиданияtimedout_read() { timeout=$1 varname=$2 old_tty_settings=`stty -g` stty -icanon min 0 time ${timeout}0 eval read $varname # или просто read $varname
Пример 10-27. Простой пример сравнения строк
Пример 10-27. Простой пример сравнения строк #!/bin/bash# match-string.sh: простое сравнение строкmatch_string (){ MATCH=0 NOMATCH=90 PARAMS=2 # Функция требует два входных аргумента. BAD_PARAMS=91 [ $# -eq $PARAMS ] || return $BAD_PARAMS case "$1" in "$2") return $MATCH;; * ) return $NOMATCH;; esac}a=oneb=twoc=threed=twomatch_string $a # неверное число
Пример 12-20. Пример форматирования списка файлов в каталоге
Пример 12-20. Пример форматирования списка файлов в каталоге #!/bin/bash# За основу сценария взят пример "man column".(printf "PERMISSIONS LINKS OWNER GROUP SIZE DATE TIME PROG-NAME " ; ls -l | sed 1d) | column -t# Команда "sed 1d" удаляет первую строку, выводимую командой ls,#+ (для локали "С" это строка: "total N",#+ где "N" -- общее
Пример 22-1. Простая функция
Пример 22-1. Простая функция #!/bin/bashfunky (){ echo "Это обычная функция."} # Функция должна быть объявлена раньше, чем ее можно будет использовать. # Вызов функции.funkyexit 0Функция должна быть объявлена раньше, чем ее можно будет использовать. К сожалению, в Bash нет возможности
Пример 22-2. Функция с аргументами
Пример 22-2. Функция с аргументами #!/bin/bash# Функции и аргументыDEFAULT=default # Значение аргумента по-умолчанию.func2 () { if [ -z "$1" ] # Длина аргумента #1 равна нулю? then echo "-Аргумент #1 имеет нулевую длину.-" # Или аргумент не был передан функции. else echo
Пример 24-2. Еще один пример проверки аргументов с помощью "И-списков"
Пример 24-2. Еще один пример проверки аргументов с помощью "И-списков" #!/bin/bashARGS=1 # Ожидаемое число аргументов.E_BADARGS=65 # Код завершения, если число аргументов меньше ожидаемого.test $# -ne $ARGS && echo "Порядок использования: `basename $0` $ARGS аргумент(а)(ов)" && exit $E_BADARGS# Если
Пример 25-8. Пример реализации алгоритма Решето Эратосфена
Пример 25-8. Пример реализации алгоритма Решето Эратосфена #!/bin/bash# sieve.sh# Решето Эратосфена# Очень старый алгоритм поиска простых чисел.# Этот сценарий выполняется во много раз медленнее# чем аналогичная программа на C.LOWER_LIMIT=1 # Начиная с 1.UPPER_LIMIT=1000 # До 1000.# (Вы можете