日期:2014-05-16  浏览次数:20647 次

进程间传递文件描述符 - UNIX
先来两个函数: unix_send_fd 和 unix_recv_fd
int unix_send_fd(int fd, int sendfd)
{
struct msghdr msg;
struct iovec iov[1];

/*
* Adapted from: W. Richard Stevens, UNIX Network Programming, Volume 1,
* Second edition. Except that we use CMSG_LEN instead of CMSG_SPACE; the
* latter breaks on LP64 systems.
*/
#if defined(CMSG_SPACE) && !defined(NO_MSGHDR_MSG_CONTROL)
union {
struct cmsghdr just_for_alignment;
char control[CMSG_SPACE(sizeof(sendfd))];
} control_un;
struct cmsghdr *cmptr;

memset((char *) &msg, 0, sizeof(msg)); /* Fix 200512 */
msg.msg_control = control_un.control;
msg.msg_controllen = CMSG_LEN(sizeof(sendfd)); /* Fix 200506 */

cmptr = CMSG_FIRSTHDR(&msg);
cmptr->cmsg_len = CMSG_LEN(sizeof(sendfd));
cmptr->cmsg_level = SOL_SOCKET;
cmptr->cmsg_type = SCM_RIGHTS;
*(int *) CMSG_DATA(cmptr) = sendfd;
#else
msg.msg_accrights = (char *) &sendfd;
msg.msg_accrightslen = sizeof(sendfd);
#endif

msg.msg_name = 0;
msg.msg_namelen = 0;

/*
* XXX We don't want to pass any data, just a file descriptor. However,
* setting msg.msg_iov = 0 and msg.msg_iovlen = 0 causes trouble. See the
* comments in the unix_recv_fd() routine.
*/
iov->iov_base = (void *)"";
iov->iov_len = 1;
msg.msg_iov = iov;
msg.msg_iovlen = 1;

return (sendmsg(fd, &msg, 0));
}

/* unix_recv_fd - receive file descriptor */
int unix_recv_fd(int fd)
{
const char *myname = "unix_recv_fd";

struct msghdr msg;
int newfd;
struct iovec iov[1];
char buf[1];

/*
* Adapted from: W. Richard Stevens, UNIX Network Programming, Volume 1,
* Second edition. Except that we use CMSG_LEN instead of CMSG_SPACE, for
* portability to LP64 environments.
*/
#if defined(CMSG_SPACE) && !defined(NO_MSGHDR_MSG_CONTROL)
union {
struct cmsghdr just_for_alignment;
char control[CMSG_SPACE(sizeof(newfd))];
} control_un;
struct cmsghdr *cmptr;

memset((char *) &msg, 0, sizeof(msg)); /* Fix 200512 */
msg.msg_control = control_un.control;
msg.msg_controllen = CMSG_LEN(sizeof(newfd)); /* Fix 200506 */
#else
msg.msg_accrights = (char *) &newfd;
msg.msg_accrightslen = sizeof(newfd);
#endif

msg.msg_name = 0;
msg.msg_namelen = 0;

/*
* XXX We don't want to pass any data, just a file descriptor. However,
* setting msg.msg_iov = 0 and msg.msg_iovlen = 0 causes trouble: we need
* to read_wait() before we can receive the descriptor, and the code
* fails after the first descriptor when we attempt to receive a sequence
* of descriptors.
*/
iov->iov_base = buf;
iov->iov_len = sizeof(buf);
msg.msg_iov = iov;
msg.msg_iovlen = 1;

if (recvmsg(fd, &msg, 0) cmsg_len == CMSG_LEN(sizeof(newfd))) {
if (cmptr->cmsg_level != SOL_SOCKET)
printf("%s: control level %d != SOL_SOCKET",
myname, cmptr->cmsg_level);
if (cmptr->cmsg_type != SCM_RIGHTS)
printf("%s: control type %d != SCM_RIGHTS",
myname, cmptr->cmsg_type);
return (*(int *) CMSG_DATA(cmptr));
} else
return (-1);
#else
if (msg.msg_accrightslen == sizeof(newfd))
return (newfd);
else
return (-1);
#endif
}

这两个函数来自 postfix。其中NO_MSGHDR_MSG_CONTROL应该是针对Tru64平台特有的定义。