Шрифт:
int cmsg_level; /* исходящий протокол */
int cmsg_type; /* тип данных, специфичный для протокола */
/* далее следует массив символов без знака cmsg_data[] */
};
Мы уже видели эту структуру на рис. 14.2, когда она использовалась с параметром сокета
IP_RECVDSTADDR
для возвращения IP-адреса получателя полученной дейтаграммы UDP. Вспомогательные данные, на которые указывает элемент msg_control
, должны быть соответствующим образом выровнены для структуры cmsghdr
. Один из способов выравнивания мы показываем в листинге 15.7. На рис. 14.3 приводится пример двух объектов вспомогательных данных, содержащихся в буфере управляющей информации.
Рис. 14.3. Два объекта вспомогательных данных
Элемент
msg_control
указывает на первый объект вспомогательных данных, а общая длина вспомогательных данных задается элементом msg_controllen
. Каждому объекту предшествует структура cmsghdr
, которая описывает объект. Между элементом cmsg_type
и фактическими данными может существовать заполнение, а также заполнение может быть в конце данных, перед следующим объектом вспомогательных данных. Пять макросов CMSG_xxx
, которые мы описываем далее, учитывают это возможное заполнение. ПРИМЕЧАНИЕ
Не все реализации поддерживают наличие нескольких объектов вспомогательных данных в буфере управляющей информации.
На рис. 14.4 приводится формат структуры
cmsghdr
при ее использовании с доменным сокетом Unix для передачи дескрипторов (см. раздел 15.7) или передачи данных, идентифицирующих пользователя (см. раздел 15.8). Рис. 14.4. Структура cmsghdr при использовании с доменными сокетами Unix
Предполагается, что каждый из трех элементов структуры
cmsghdr
занимает 4 байта и между структурой cmsghdr
и данными нет заполнения. При передаче дескрипторов содержимое массива cmsg_data
— это фактические значения дескрипторов. На этом рисунке мы показываем только один передаваемый дескриптор, но в общем может передаваться и более одного дескриптора (тогда значение элемента cmsg_len
будет равно 12 плюс число дескрипторов, умноженное на 4, если считать, что каждый дескриптор занимает 4 байта). Вспомогательные данные, возвращаемые функцией
recvmsg
, могут содержать любое число объектов вспомогательных данных. Чтобы скрыть возможное заполнение от приложения, для упрощения обработки вспомогательных данных определены следующие пять макросов (что требует включения заголовочного файла <sys/socket.h>
).
#include <sys/socket.h>
#include <sys/param.h> /* для макроса ALIGN во многих реализациях */
struct cmsghdr *CMSG_FIRSTHDR(struct msghdr * mhdrptr);
Возвращает: указатель на первую структуру cmsghdr или NULL, если нет вспомогательных данных
struct cmsghdr *CMSG_NXTHDR(struct msghdr * mhdrptr, struct cmsghdr * cmsgptr);
Возвращает: указатель на структуру cmsghdr или NULL, если нет больше объектов вспомогательных данных
unsigned char *CMSG_DATA(struct cmsghdr * cmsgptr);
Возвращает: указатель на первый байт данных, связанных со структурой cmsghdr
unsigned int CMSG_LEN(unsigned int length);
Возвращает: значение, которое записывается в cmsg_len
unsigned int CMSG_SPACE(unsigned int length);
Возвращает: общий размер объекта вспомогательных данных
ПРИМЕЧАНИЕ
В POSIX определены первые пять макросов, а в [113] определены последние два.
Эти макросы могли бы быть использованы в следующем псевдокоде:
struct msghdr msg;
struct cmsghdr *cmsgptr;
/* заполнение структуры msg */
/* вызов recvmsg */
for (cmsgptr = CMSG_FIRSTHDR(&msg); cmsgptr != NULL;