CMSG(3)
NAME
CMSG_ALIGN, CMSG_SPACE, CMSG_NXTHDR, CMSG_FIRSTHDR —— 访问辅助数据
SYNOPSIS
#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; /* data byte count, including header */
int cmsg_level; /* originating protocol */
int cmsg_type; /* protocol-specific type */
/* followed by unsigned char cmsg_data[]; */
};
DESCRIPTION
这些宏用于创建和访问控制消息(又称辅助数据),它们并不是套接字负载的一部分。这些控制消息可能包含接收数据包的接口,很少使用的各种报头字段,额外的错误描述,一组文件描述符和Unix凭据。举例来说,控制消息可以用于发送额外的报头字段,诸如IP选项。辅助数据通过调用sendmsg(2)发送,通过调用recvmsg(2)接收。参见它们的手册页了解更多信息。
辅助数据是一组struct cmsghdr结构的序列。这个序列只应该使用手册页上描述的宏访问,而不是直接操作。参见特定协议的手册页了解可用的控制消息类型。每个套接字所允许的辅助消息缓冲的上限值可以在/proc/sys/net/core/optmem_max设置,参见socket(7)。
CMSG_FIRSTHDR()返回msghdr关联的辅助数据中的第一个cmsghdr的指针。
CMSG_NXTHDR()返回参数指代的cmsghdr之后的下一个有效的cmsghdr。遍历过后返回NULL。
CMSG_ALIGN(),给定一个长度,返回它所必须的对齐边界。这是一个常量表达式。
CMSG_SPACE()返回一个辅助数据所占用的字节数。这是一个常量表达式。
CMSG_DATA()返回cmsghdr的数据部分指针。
CMSG_LEN()返回cmsghdr结构的cmsg_len成员的值,考虑到任何必要的对齐。它取出参数的长度。这是一个常量表达式。
为了创建辅助数据,首先用控制消息缓冲的长度初始化msghdr结构的msg_controllen成员。接着,用CMSG_FIRSTHDR()在msghdr中取出第一个控制消息,用CMSG_NEXTHDR()获取接下来的所有元素。对于每个控制消息,用CMSG_LEN()初始化其cmsg_len,其余的cmsghdr头字段和数据部分用CMSG_DATA()填充。最终,msghdr的msg_controllen字段应该被设置为缓冲区中所有控制消息的CMSG_SPACE()之和。有关msghdr的更多信息,参见recvmsg(2)。
当控制消息缓冲太短而无法存下所有消息,MSG_CTRUNC标记将被设置到msghdr的msg_flags成员中。
CONFORMING TO
这个辅助数据模型符合POSIX.1g草案,4.4BSD-Lite,RFC 2292和SUSv2中描述的IPv6高级API。CMSG_ALIGN()是Linux扩展。
NOTES
出于移植性考虑,辅助数据应该只用这里的宏访问。CMSG_ALIGN是Linux扩展而可能不能用于移植程序。
Linux下,CMSG_LEN(),CMSG_DATA(),CMSG_ALIGN()都是常量表达式(假设它们的参数是常量);它们可以用于声明全局变量的尺寸,但这是不可移植的。
EXAMPLE
这段代码在收到的辅助缓冲中寻找IP_TTL选项:
struct msghdr msgh;
struct cmsghdr *cmsg;
int *ttlptr;
int received_ttl;
/* Receive auxiliary data in msgh */
for (cmsg = CMSG_FIRSTHDR(&msgh); cmsg != NULL;
cmsg = CMSG_NXTHDR(&msgh,cmsg)) {
if (cmsg->cmsg_level == IPPROTO_IP
&& cmsg->cmsg_type == IP_TTL) {
ttlptr = (int *) CMSG_DATA(cmsg);
received_ttl = *ttlptr;
break;
}
}
if (cmsg == NULL) {
/*
* Error: IP_TTL not enabled or small buffer
* or I/O error.
*/
}
下面的代码用SCM_RIGHTS在Unix套接字上传递一组文件描述符:
struct msghdr msg = { 0 };
struct cmsghdr *cmsg;
int myfds[NUM_FD]; /* Contains the file descriptors to pass. */
char buf[CMSG_SPACE(sizeof myfds)]; /* ancillary data buffer */
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);
/* Initialize the payload: */
fdptr = (int *) CMSG_DATA(cmsg);
memcpy(fdptr, myfds, NUM_FD * sizeof(int));
/* Sum of the length of all control messages in the buffer: */
msg.msg_controllen = cmsg->cmsg_len;
SEE ALSO
recvmsg(2), sendmsg(2)
RFC 2292
COLOPHON
This page is part of release 3.23 of the Linux man-pages project. A
description of the project, and information about reporting bugs, can
be found at http://www.kernel.org/doc/man-pages/.