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. Возвращаемая нами информация — это индекс интерфейса.
Пример: вывод IP-адреса получателя и флага обрезки дейтаграммы
Для проверки нашей функции мы изменим функцию
dg_echo
(см. листинг 8.2) так, чтобы она вызывала функцию
recvfrom_flags
вместо функции recvfrom. Новая версия функции
dg_echo
показана в листинге 22.3.
Листинг 22.3. Функция dg_echo, вызывающая нашу функцию recvfrom_flags
//advio/dgechoaddr.c
1 #include "unpifi.h"
2 #undef MAXLINE
3 #define MAXLINE 20 /* устанавливаем новое значение, чтобы
пронаблюдать обрезку дейтаграмм */
4 void
5 dg_echo(int sockfd, SA *pcliaddr, socklen_t clilen)
6 {
7 int flags;
8 const int on = 1;
9 socklen_t len;
10 ssize_t n;
11 char
mesg[MAXLINE], str[INET6_ADDRSTRLEN], ifname[IFNAMSIZ];
12 struct in_addr in_zero;
13 struct in_pktinfo pktinfo;
14 #ifdef IP_RECVDSTADDR
15 if (setsockopt(sockfd, IPPROTO_IP, IP_RECVDSTADDR, &on, sizeof(on)) < 0)
16 err_ret("setsockopt of IP_RECVDSTADDR");
17 #endif
18 #ifdef IP_RECVIF
19 if (setsockopt(sockfd, IPPROTO_IP, IP_RECVIF, &on, sizeof(on)) < 0)
20 err_ret("setsockopt of IP_RECVIF");
21 #endif
22 bzero(&in_zero, sizeof(struct in_addr)); /* IPv4-адрес, состоящий
из одних нулей */
23 for (;;) {
24 len = clilen;
25 flags = 0;
26 n = Recvfrom_flags(sockfd, mesg, MAXLINE, &flags,
27 pcliaddr, &len, &pktinfo);
28 printf("%d-byte datagram from %s", n, Sock_ntop(pcliaddr, len));
29 if (memcmp(&pktinfo.ipi_addr, &in_zero, sizeof(in_zero)) != 0)
30 printf(", to %s", Inet_ntop(AF_INET, &pktinfo.ipi_addr,
31 str, sizeof(str)));
32 if (pktinfo.ipi_ifindex > 0)
33 printf(", recv i/f = %s",
34 If_indextoname(pktinfо.ipi_ifindex, ifname));
35 #ifdef MSG_TRUNC
36 if (flags & MSG_TRUNC)
37 printf(" (datagram truncated)");
38 #endif
39 #ifdef MSG_CTRUNC
40 if (flags & MSG_CTRUNC)
41 printf(" (control info truncated)");
42 #endif
43 #ifdef MSG_BCAST
44 if (flags & MSG_BCAST)
45 printf(" (broadcast)");
46 #endif
47 #ifdef MSG_MCAST
48 if (flags & MSG_MCAST)
49 printf(" (multicast)");
50 #endif
51 printf("\n");