即使有更多cmsghdr对象,CMSG_NXTHDR()也会返回NULL [英] CMSG_NXTHDR() returns NULL even though there are more cmsghdr objects

查看:124
本文介绍了即使有更多cmsghdr对象,CMSG_NXTHDR()也会返回NULL的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I need to send some ancillary data over a Unix domain socket, but I'm having problems creating a msghdr. I can only seem to access the first cmsghdr in msghdr.msg_control. CMSG_NXTHDR() returns NULL no matter how large I make msghdr.msg_control.

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

I'm running 64-bit Linux 3.13.0 with eglibc 2.19, if that matters. Here is some sample code that demonstrates the problem. I compiled it with gcc -std=c99 -Wall -Werror -Wpedantic test.c. I'm aware that I could send both file descriptors in the same message—this is just a test.

#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 .我怎么能说服他们有两个,而不仅仅是一个?

When I build and run this program, it prints "Can't get second cmsg". This is true even if I increase the size of control by hundreds of bytes. Apparently CMSG_NXTHDR() doesn't think there is a second cmsghdr in .msg_control. How can I convince it that there are two of them, not just one?

推荐答案

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

I had couple of hours wasted on this issue, so thought document what I found. It is a case of uninitialised control buffer. The man pages does not instruct about this specifically but if you look in the header file /usr/include/bits/socket.h, the code reads as

_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指向一个地址,该地址被视为下一个标头.随后,第二个if语句上的rhs表达式使用__cmsg-> cmsg_len的值,如果您尚未首先初始化控制缓冲区,则该值可能是垃圾.根据垃圾值的不同,您可能有可能导致此检查失败,从而导致无论您增加多少控制缓冲区大小,都将导致空值.

After the first check, the __cmsg is made to point to an address which is treated as the next header. Subsequently, the rhs expression on second if statements, uses the value of __cmsg->cmsg_len which could be a garbage if you have not initialised the control buffer first. Depending on the garbage value, you could have the possibility of this check failing and thus resulting in a null value no matter how much you pump up the size of control buffer.

解决方案可能很简单(根据您的代码)

Solution could be as simple as(from your code)

字符控制[CMSG_SPACE(sizeof(data1))+ CMSG_SPACE(sizeof(data2))] = {};

为我做到了.

这篇关于即使有更多cmsghdr对象,CMSG_NXTHDR()也会返回NULL的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆