CMSG - Linux手册页

时间:2019-08-20 18:00:03  来源:igfitidea点击:

Linux程序员手册 第3部分
更新日期: 2020-06-09

名称

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

说明

这些宏用于创建和访问不属于套接字有效负载的控制消息(也称为辅助数据)。此控制信息可能包括接收数据包的接口,各种很少使用的头字段,扩展的错误描述,一组文件描述符或UNIX凭据。例如,控制消息可用于发送其他报头字段,例如IP选项。通过调用sendmsg(2)发送辅助数据,并通过调用recvmsg(2)接收辅助数据。有关更多信息,请参见其手册页。

辅助数据是带有附加数据的一系列cmsghdr结构。有关可用的控制消息类型,请参见特定的协议手册页。可以使用/ proc / sys / net / core / optmem_max设置每个套接字允许的最大辅助缓冲区大小;参见套接字(7)。

cmsghdr结构定义如下:

struct cmsghdr {
    size_t cmsg_len;    /* Data byte count, including header
                           (type is socklen_t in POSIX) */
    int    cmsg_level;  /* Originating protocol */
    int    cmsg_type;   /* Protocol-specific type */
/* followed by
   unsigned char cmsg_data[]; */
};

cmsghdr结构的序列绝不能直接访问。而是,仅使用以下宏:

*
CMSG_FIRSTHDR()返回一个指针,该指针指向与传递的msghdr关联的辅助数据缓冲区中的第一个cmsghdr。如果缓冲区中没有足够的空间可容纳cmsghdr,则返回NULL。
*
CMSG_NXTHDR()返回传递的cmsghdr之后的下一个有效cmsghdr。当缓冲区中没有足够的空间时,它将返回NULL。
初始化将包含一系列cmsghdr结构的缓冲区时(例如,将通过sendmsg(2)发送),该缓冲区应首先初始化为零以确保CMSG_NXTHDR()的正确操作。
*
给定长度,CMSG_ALIGN()将返回它,包括所需的对齐方式。这是一个常量表达式。
*
CMSG_SPACE()返回带有已传递数据长度的有效负载的辅助元素的字节数。这是一个常量表达式。
*
CMSG_DATA()返回一个指向cmsghdr的数据部分的指针。返回的指针不能被假定为适当对齐以访问任意有效载荷数据类型。应用程序不应将其强制转换为与有效负载匹配的指针类型,而应使用memcpy(3)将数据复制到适当声明的对象或从适当声明的对象复制数据。
*
CMSG_LEN()返回值,该值将存储在cmsghdr结构的cmsg_len成员中,同时考虑到任何必要的对齐方式。它以数据长度为参数。这是一个常量表达式。

若要创建辅助数据,请首先使用控制消息缓冲区的长度初始化msghdr的msg_controllen成员。使用msghdr上的CMSG_FIRSTHDR()获取第一个控制消息,并使用CMSG_NXTHDR()获取所有后续消息。在每个控制消息中,使用CMSG_DATA()初始化CMSG_LEN(使用CMSG_LEN()),其他cmsghdr标头字段和数据部分。最后,应将msghdr的msg_controllen字段设置为缓冲区中所有控制消息的长度的CMSG_SPACE()的总和。有关msghdr的更多信息,请参见recvmsg(2)。

遵循规范

此辅助数据模型符合POSIX.1g草案4.4BSD-Lite,RFC2292和SUSv2中描述的IPv6高级API。在POSIX.1-2008中指定了CMSG_FIRSTHDR(),CMSG_NXTHDR()和CMSG_DATA()。 CMSG_SPACE()和CMSG_LEN()将包含在下一个POSIX版本中(问题8)。

CMSG_ALIGN()是Linux扩展。

备注

为了便于移植,应仅使用此处描述的宏访问辅助数据。 CMSG_ALIGN()是Linux扩展,不应在可移植程序中使用。

在Linux中,CMSG_LEN(),CMSG_DATA()和CMSG_ALIGN()是常量表达式(假设它们的参数为常量),这意味着这些值可用于声明全局变量的大小。但是,这可能不是便携式的。

示例

此代码在收到的辅助缓冲区中查找IP_TTL选项:

struct msghdr msgh;
struct cmsghdr *cmsg;
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) {
        memcpy(&receive_ttl, CMSG_DATA(cmsg), sizeof(int));
        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 iobuf[1];
struct iovec io = {
    .iov_base = iobuf,
    .iov_len = sizeof(iobuf)
};
union {         /* Ancillary data buffer, wrapped in a union
                   in order to ensure it is suitably aligned */
    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(int) * NUM_FD);
memcpy(CMSG_DATA(cmsg), myfds, NUM_FD * sizeof(int));

另外参见

recvmsg(2),sendmsg(2)

RFC 2229

出版信息

这个页面是Linux手册页项目5.08版的一部分。有关项目的说明、有关报告错误的信息以及此页面的最新版本,请访问https://www.kernel.org/doc/man-pages/