gpt4 book ai didi

linux - CMSG_NXTHDR() 返回 NULL 即使有更多的 cmsghdr 对象

转载 作者:太空狗 更新时间:2023-10-29 11:13:45 41 4
gpt4 key购买 nike

我需要通过 Unix 域套接字发送一些辅助数据,但我在创建 msghdr 时遇到了问题。我似乎只能访问 msghdr.msg_control 中的第一个 cmsghdrCMSG_NXTHDR() 无论我将 msghdr.msg_control 设为多大都返回 NULL。

我正在运行带有 eglibc 2.19 的 64 位 Linux 3.13.0,如果这很重要的话。下面是一些演示问题的示例代码。我用 gcc -std=c99 -Wall -Werror -Wpedantic test.c 编译了它。我知道我可以在同一条消息中发送两个文件描述符——这只是一个测试。

#include <stdio.h>
#include <string.h>
#include <sys/socket.h>
#include <unistd.h>


int main()
{
int data1 = STDIN_FILENO;
int data2 = STDOUT_FILENO;

char control[CMSG_SPACE(sizeof(data1)) + CMSG_SPACE(sizeof(data2))];
struct msghdr mh = {
.msg_namelen = 0,
.msg_iovlen = 0,
.msg_control = control,
.msg_controllen = sizeof(control),
.msg_flags = 0
};

struct cmsghdr *cmh = CMSG_FIRSTHDR(&mh);
if (cmh == NULL) {
puts("Can't get first cmsg");
return 1;
}
cmh->cmsg_len = CMSG_LEN(sizeof(data1));
cmh->cmsg_level = SOL_SOCKET;
cmh->cmsg_type = SCM_RIGHTS;
memcpy(CMSG_DATA(cmh), &data1, sizeof(data1));

cmh = CMSG_NXTHDR(&mh, cmh);
if (cmh == NULL) {
puts("Can't get second cmsg");
return 1;
}
cmh->cmsg_len = CMSG_LEN(sizeof(data2));
cmh->cmsg_level = SOL_SOCKET;
cmh->cmsg_type = SCM_RIGHTS;
memcpy(CMSG_DATA(cmh), &data2, sizeof(data2));
}

当我构建并运行该程序时,它会打印“无法获取第二个 cmsg”。即使我将 control 的大小增加数百个字节也是如此。显然 CMSG_NXTHDR() 认为 .msg_control 中没有第二个 cmsghdr。我怎样才能说服它有两个,而不是一个?

最佳答案

我在这个问题上浪费了几个小时,所以想把我发现的东西记录下来。这是未初始化的控制缓冲区的情况。手册页没有具体说明这一点,但如果您查看头文件/usr/include/bits/socket.h,代码如下所示

_EXTERN_INLINE struct cmsghdr *
__NTH (__cmsg_nxthdr (struct msghdr *__mhdr, struct cmsghdr *__cmsg))
{
if ((size_t) __cmsg->cmsg_len < sizeof (struct cmsghdr))
/* The kernel header does this so there may be a reason. */
return (struct cmsghdr *) 0;

__cmsg = (struct cmsghdr *) ((unsigned char *) __cmsg
+ CMSG_ALIGN (__cmsg->cmsg_len));

if ((unsigned char *) (__cmsg + 1) > ((unsigned char *) __mhdr->msg_control
+ __mhdr->msg_controllen)
|| ((unsigned char *) __cmsg + CMSG_ALIGN (__cmsg->cmsg_len)
> ((unsigned char *) __mhdr->msg_control + __mhdr->msg_controllen)))
/* No more entries. */
return (struct cmsghdr *) 0;

return __cmsg;
}

第一次检查后,__cmsg 指向一个地址,该地址被视为下一个 header 。随后,第二个 if 语句的 rhs 表达式使用 __cmsg->cmsg_len 的值,如果您没有首先初始化控制缓冲区,它可能是垃圾。根据垃圾值,您可能有此检查失败的可能性,因此无论您将控制缓冲区的大小增加多少,都会导致空值。

解决方案可以像(从您的代码)一样简单

char control[CMSG_SPACE(sizeof(data1)) + CMSG_SPACE(sizeof(data2))] = {};

这对我有用。

关于linux - CMSG_NXTHDR() 返回 NULL 即使有更多的 cmsghdr 对象,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27601849/

41 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com