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);

struct cmsghdr {
	socklen_t 	cmsg_len;	/* счетчик байтов данных с заголовком */
	int	cmsg_level;	/* создаваемый протокол передачи */
	int	cmsg_type;	/* тип, зависящий от протокола */
/* с последующей переменной без знака	cmsg_data[]; */
};

ОПИСАНИЕ
Эти макросы используются для создания управляющих сообщений (также называемых служебными данными), которые не являются частью полезной "нагрузки" пакета; а также доступа к ним. Эта управляющая информация может быть об интерфейсе, с которого переслан пакет, о редко используемых полях заголовков; она может содержать описание ошибок, наборы описателей файлов или сертификатов Unix. В том числе, служебные сообщения могут быть использованы для пересылки дополнительных полей заголовков, таких, как параметры IP. Служебные данные посылаются с помощью вызова sendmsg(2) и получаются посредством вызова recvmsg(2). Более полная информация приведена на соответствующих страницах руководства.

Служебные данные являются последовательностью структур struct cmsghdr с присоединенными к ней данными. Доступ к этой последовательности может быть осуществлен только с помощью макросов, описанных в данном руководстве. Смотрите также соответствующие страницы руководства, описывающие протоколы для получения полной информации о доступных типах управляюший сообщений. Максимально возможный размер буфера в одном пакете можно установить, используя системный вызов (sysctl) net.core.optmem_max; см. также socket(7).

CMSG_FIRSTHDR возвращает указатель на первый cmsghdr в буфере служебных данных, связанных с переданным msghdr.

CMSG_NXTHDR возвращает следующее значение cmsghdr после переданного cmsghdr. Он возвращает NULL, если в буфере недостаточно места.

CMSG_ALIGN возвращает длину и необходимые выравнивания. Это постоянное выражение.

CMSG_SPACE возвращает объем в байтах, который занимают управляющие элементы и полезная "нагрузка" переданных данных. Это постоянное выражение.

CMSG_DATA возвращает указатель на часть данных в cmsghdr.

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).

Если буфер управляющих сообщений слишком мал для сохранения всех сообщений, то флаг MSG_CTRUNC в поле msg_flags структуры msghdr присваивает значение, равное единице.

ПРИМЕРЫ ИСПОЛЬЗОВАНИЯ
Эта часть программы просматривает входящие служебные данные в поисках опции IP_TTL:

    struct msghdr msgh;
    struct cmsghdr *cmsg;
    int *ttlptr;
    int received_ttl;
    /* Принять служебные данные в msgh */
    for (cmsg = CMSG_FIRSTHDR(&msgh);
         cmsg != NULL;
         cmsg = CMSG_NXTHDR(&msgh,cmsg) {
    	if (cmsg->cmsg_level == SOL_IP
    	  && cmsg->cmsg_type == IP_TTL) {
    		ttlptr = (int *) CMSG_DATA(cmsg);
    		received_ttl = *ttlptr;
    		break;
    	}
    }
    if (cmsg == NULL) {
    	/* Ошибка: IP_TTL не разрешен, недостаточно размера буфера,
    	 * или произошла ошибка ввода-вывода.
    	 */
    }

Эта часть программы передает массив файловых описателей через сокет Unix, используя SCM_RIGHTS:

    struct msghdr msg = {0};
    struct cmsghdr *cmsg;
    int myfds[NUM_FD]; /* Содержит описатели файлов для передачи. */
    char buf[CMSG_SPACE(sizeof myfds)];  /* буфер служебных данных */
    int *fdptr;
    msg.msg_control = buf;
    msg.msg_controllen = sizeof buf;
    cmsg = CMSG_FIRSTHDR(&msg);
    cmsg->cmsg_level = SOL_SOCKET;
    cmsg->cmsg_type = SCM_RIGHTS;
    cmsg->cmsg_len = CMSG_LEN(sizeof(int) * NUM_FD);
    /* Инициализация полезных данных: */
    fdptr = (int *)CMSG_DATA(cmsg);
    memcpy(fdptr, myfds, NUM_FD * sizeof(int));
    /* Сумма длин всех управляющих сообщений в буфере: */
    msg.msg_controllen = cmsg->cmsg_len;

ЗАМЕЧАНИЯ
В целях переносимости служебные данные могут быть доступны только с помощью макросов, описанных в данном руководстве. CMSG_ALIGN Это расширение Linux, поэтому оно не должно быть использовано в программах предназначенных для переноса на другую платформу.

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

СООТВЕТСТВИЕ СТАНДАРТАМ
Эта модель служебных данных соответствует черновому варианту POSIX.1003.1g, 4.4BSD-Lite (расширение IPv6 API описано в RFC2292 и Single Unix specification v2). CMSG_ALIGN - это расширение для Linux.

СМ. ТАКЖЕ
sendmsg(2), recvmsg(2)

RFC 2292