Scroll to navigation

CMSG(3) Руководство программиста Linux CMSG(3)

ИМЯ

CMSG_ALIGN, CMSG_SPACE, CMSG_NXTHDR, CMSG_FIRSTHDR - доступ к вспомогательным данным

СИНТАКСИС

#include <sys/socket.h>
struct cmsghdr *CMSG_FIRSTHDR(struct msghdr *msgh);
struct cmsghdr *CMSG_NXTHDR(struct msghdr *msgh,
                            struct cmsghdr *cmsg);
size_t CMSG_ALIGN(size_t length);
size_t CMSG_SPACE(size_t length);
size_t CMSG_LEN(size_t length);
unsigned char *CMSG_DATA(struct cmsghdr *cmsg);

ОПИСАНИЕ

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

Вспомогательные данные представляют собой последовательность структур cmsghdr с присоединёнными к ней данными. Возможные типы управляющих сообщений смотрите в соответствующих страницах протоколов. Максимально возможный размер буфера вспомогательных данных одного сокета можно установить через /proc/sys/net/core/optmem_max; смотрите socket(7).

Структура cmsghdr определена следующим образом:


struct cmsghdr {

size_t cmsg_len; /* счетчик байтов данных с заголовком
(тип — socklen_t в POSIX) */
int cmsg_level; /* начальный протокол */
int cmsg_type; /* тип, зависящий от протокола */ /* после
unsigned char cmsg_data[]; */ };

К последовательности структур cmsghdr нельзя обращаться напрямую. Для этого используйте следующие макросы:

  • Макрос CMSG_FIRSTHDR() возвращает указатель на первый cmsghdr в буфере вспомогательных данных, связанных с переданным cmsghdr. Он возвращает NULL, если в буфере недостаточно места для cmsghdr.
  • Макрос CMSG_NXTHDR() возвращает следующее значение cmsghdr после переданного cmsghdr. Он возвращает NULL, если в буфере недостаточно места.
Для правильной работы CMSG_NXTHDR() при инициализации буфера, который будет содержать набор структур cmsghdr (например, для отправки с помощью sendmsg(2)), его необходимо заполнять нулями.
  • Макрос CMSG_ALIGN() возвращает длину, учитывая необходимое выравнивание. Это постоянное выражение.
  • Макрос CMSG_SPACE() возвращает количество байт, которое занимает вспомогательный элемент с полезной нагрузкой переданных данных. Это постоянное выражение.
  • CMSG_DATA() returns a pointer to the data portion of a cmsghdr. The pointer returned cannot be assumed to be suitably aligned for accessing arbitrary payload data types. Applications should not cast it to a pointer type matching the payload, but should instead use memcpy(3) to copy data to or from a suitably declared object.
  • Макрос CMSG_LEN возвращает значение, хранящееся в поле cmsg_len структуры cmsghdr с учётом необходимого выравнивания. Он принимает значение объёма данных в качестве аргумента. Это постоянное выражение.

Чтобы создать вспомогательные данные, сначала инициализируйте элемент msg_controllen структуры msghdr, указав длину буфера управляющего сообщения. Запустите CMSG_FIRSTHDR() со структурой msghdr для получения первого управляющего сообщения и CMSG_NEXTHDR() для получения последующих. Для каждого управляющего сообщения инициализируйте cmsg_len (с помощью CMSG_LEN()) и другие поля заголовка cmsghdr, а также часть для данных (с помощью CMSG_DATA()). В результате значение поля msg_controllen структуры msghdr будет равно сумме CMSG_SPACE() для длин всех управляющих сообщений в буфере. Дополнительная информация о msghdr находится в recvmsg(2).

СООТВЕТСТВИЕ СТАНДАРТАМ

This ancillary data model conforms to the POSIX.1g draft, 4.4BSD-Lite, the IPv6 advanced API described in RFC 2292 and SUSv2. CMSG_FIRSTHDR(), CMSG_NXTHDR(), and CMSG_DATA() are specified in POSIX.1-2008. CMSG_SPACE() and CMSG_LEN() will be included in the next POSIX release (Issue 8).

CMSG_ALIGN() is a Linux extension.

ЗАМЕЧАНИЯ

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

В Linux CMSG_LEN(), CMSG_DATA() и CMSG_ALIGN() — это постоянные выражения (вне зависимости от переданных аргументов), то есть эти значения можно использовать для объявления размера глобальных переменных. Но это также сделает программу непереносимой на другие платформы.

ПРИМЕРЫ

Данный код ищет параметр IP_TTL в буфере с полученными вспомогательными данными:


struct msghdr msgh;
struct cmsghdr *cmsg;
int received_ttl;
/* приём вспомогательных данных в msgh */
for (cmsg = CMSG_FIRSTHDR(&msgh); cmsg != NULL;

cmsg = CMSG_NXTHDR(&msgh, cmsg)) {
if (cmsg->cmsg_level == IPPROTO_IP
&& cmsg->cmsg_type == IP_TTL) {
memcpy(&receive_ttl, CMSG_DATA(cmsg), sizeof(received_ttl));
break;
} } if (cmsg == NULL) {
/* Ошибка: не включён IP_TTL, мал буфер или ошибка ввода-вывода */ }

Данный код передаёт массив файловых дескрипторов через доменный сокет UNIX, используя SCM_RIGHTS:


struct msghdr msg = { 0 };
struct cmsghdr *cmsg;
int myfds[NUM_FD];  /* содержит дескрипторы файлов для передачи */
char iobuf[1];
struct iovec io = {

.iov_base = iobuf,
.iov_len = sizeof(iobuf) }; union { /* буфер вспомогательных данных, обёрнутый в union,
чтобы точно получить нужное выравнивание */
char buf[CMSG_SPACE(sizeof(myfds))];
struct cmsghdr align; } u; msg.msg_iov = &io; msg.msg_iovlen = 1; msg.msg_control = u.buf; msg.msg_controllen = sizeof(u.buf); cmsg = CMSG_FIRSTHDR(&msg); cmsg->cmsg_level = SOL_SOCKET; cmsg->cmsg_type = SCM_RIGHTS; cmsg->cmsg_len = CMSG_LEN(sizeof(myfds)); memcpy(CMSG_DATA(cmsg), myfds, sizeof(myfds));

СМ. ТАКЖЕ

recvmsg(2), sendmsg(2)

RFC 2292

ЗАМЕЧАНИЯ

Эта страница является частью проекта Linux man-pages версии 5.10. Описание проекта, информацию об ошибках и последнюю версию этой страницы можно найти по адресу https://www.kernel.org/doc/man-pages/.

ПЕРЕВОД

Русский перевод этой страницы руководства был сделан Azamat Hackimov <azamat.hackimov@gmail.com>, Dmitriy S. Seregin <dseregin@59.ru>, Dmitry Bolkhovskikh <d20052005@yandex.ru>, Katrin Kutepova <blackkatelv@gmail.com>, Yuri Kozlov <yuray@komyakino.ru> и Иван Павлов <pavia00@gmail.com>

Этот перевод является бесплатной документацией; прочитайте Стандартную общественную лицензию GNU версии 3 или более позднюю, чтобы узнать об условиях авторского права. Мы не несем НИКАКОЙ ОТВЕТСТВЕННОСТИ.

Если вы обнаружите ошибки в переводе этой страницы руководства, пожалуйста, отправьте электронное письмо на man-pages-ru-talks@lists.sourceforge.net.

1 ноября 2020 г. Linux