sendmsg() 无效参数 (??)
首先是一些上下文:有一个主程序(一个网络服务器),它分叉了一群工作人员,并等待传入的连接。当它接受一个时,它通过 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< /code> 是:
struct message_t {
int msg;
int sockfd;
};
其中 msg
可以获取值 GC_SOCKET
或 GC_CLOSE
。在前一种情况下,字段 sockfd 包含所传递的套接字的描述符,而在后一种情况下,不会发送任何辅助数据(并且工作人员应该自杀)。
现在,这个东西不起作用了。当主程序向工作线程发送 GC_CLOSE 时,strace 是这么说的:
...
[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)
...
任何帮助都非常感谢。
Some context first: there is the main program (a web server) which forks a bunch of workers, and waits for incoming connections. When it accepts one, it send the socket descriptor to one of the workers via the sendmsg() primitive.
This is the code that is supposed to send the descriptor:
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
}
In the code above, l->channel.chan
is the AF_UNIX
socket, and struct message_t
is:
struct message_t {
int msg;
int sockfd;
};
where msg
can get values GC_SOCKET
or GC_CLOSE
. In the former case the field sockfd contains the descriptor of the socket passed, and in the latter no ancillary data is sent (and the worker is supposed to kill himself).
Now, this stuff doesn't work. This is what strace says about it, when the main program sends GC_CLOSE to a worker:
...
[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)
...
Any help is really appreciated.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
我认为您没有初始化
msg.msg_name
和msg.msg_namelen
。如果这样做会更安全:这相当于调用 memset(0) 或 bzero(),但更简洁。不管怎样,现在看起来你正在传递未初始化的谁知道什么,这很容易导致 EINVAL。
另外,现在和将来,尝试在 valgrind 下运行你的程序——它可以帮助捕获这样的错误。
I think you are not initializing
msg.msg_name
andmsg.msg_namelen
. It would be safer if you did this:This is equivalent to calling memset(0) or bzero(), but more concise. Anyway right now it looks like you're passing uninitialized who-knows-what, which could easily result in EINVAL.
Also, now and in the future, try running your program under valgrind--it can help catch errors like this.