首先是一些上下文:有一个主程序(一个web服务器),它分叉一堆工人,并等待传入的连接。当它接受一个时,它通过sendmsg()原语将套接字描述符发送给其中一个工作者。
这是发送描述符的代码:
int send_msg (worker_t * l, struct message_t * m)
{
#ifdef __WIN32__
#else
struct msghdr msg;
struct cmsghdr * cmsg;
char anc [CMSG_SPACE (sizeof(int))];
int * fd_ptr;
int buf [1] = {m->msg};
struct iovec vec;
vec.iov_base = buf;
vec.iov_len = sizeof (int);
msg.msg_iov = &vec;
msg.msg_iovlen = 1;
msg.msg_control = NULL;
msg.msg_controllen = 0;
if (m->msg == GC_SOCKET) {
msg.msg_control = anc;
msg.msg_controllen = sizeof anc;
cmsg = CMSG_FIRSTHDR (&msg);
cmsg->cmsg_level = SOL_SOCKET;
cmsg->cmsg_type = SCM_RIGHTS;
cmsg->cmsg_len = CMSG_LEN (sizeof (int));
fd_ptr = (int *) CMSG_DATA (cmsg);
*fd_ptr = m->sockfd;
msg.msg_controllen = cmsg->cmsg_len;
}
msg.msg_flags = 0;
if (sendmsg (l->channel.chan, &msg, 0) == -1) {
i_log (1, "Unable to send message to listener.");
return -1;
}
else {
if (m->msg == GC_SOCKET && m->sockfd)
close (m->sockfd);
return 1;
}
#endif
}
在上面的代码中,
l->channel.chan
是AF_UNIX
套接字,struct message_t
是:struct message_t {
int msg;
int sockfd;
};
其中
msg
可以得到GC_SOCKET
或GC_CLOSE
的值。在前一种情况下,字段sockfd包含传递的套接字的描述符,在后一种情况下,不发送辅助数据(工人应该自杀)。现在,这些东西不起作用了。这就是strace所说的,当主程序向一个工人发送gc_时:
...
[pid 6229] sendmsg(5, {msg_name(6229)={...}, msg_iov(1)=[{"\1\0\0\0", 4}],
msg_controllen=0, msg_flags=0}, 0) = -1 EINVAL (Invalid argument)
...
任何帮助都是非常感谢的。
最佳答案
我认为您没有初始化msg.msg_name
和msg.msg_namelen
。如果你这样做会更安全:
struct msghdr msg = {}
这相当于调用memset(0)或bzero(),但更简洁。不管怎么说,现在看来你是通过未初始化谁知道什么,这可能很容易导致英瓦尔。
另外,现在和将来,试着在valgrind下运行程序——它可以帮助捕捉这样的错误。
关于c - sendmsg()无效参数(??),我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/9370479/