1 /* $NetBSD: unix_recv_fd.c,v 1.1.1.1 2009/06/23 10:09:01 tron Exp $ */
7 /* receive file descriptor
9 /* #include <iostuff.h>
11 /* int unix_recv_fd(fd)
14 /* unix_recv_fd() receives a file descriptor via the specified
15 /* UNIX-domain socket. The result value is the received descriptor.
21 /* unix_recv_fd() returns -1 upon failure.
25 /* The Secure Mailer license must be distributed with this software.
28 /* IBM T.J. Watson Research
30 /* Yorktown Heights, NY 10598, USA
35 #include <sys_defs.h> /* includes <sys/types.h> */
36 #include <sys/socket.h>
40 /* Utility library. */
45 /* unix_recv_fd - receive file descriptor */
47 int unix_recv_fd(int fd
)
49 const char *myname
= "unix_recv_fd";
52 * This code does not work with version <2.2 Linux kernels, and it does
53 * not compile with version <2 Linux libraries.
55 #ifdef CANT_USE_SEND_RECV_MSG
56 msg_warn("%s: your system has no support for file descriptor passing",
66 * Adapted from: W. Richard Stevens, UNIX Network Programming, Volume 1,
67 * Second edition. Except that we use CMSG_LEN instead of CMSG_SPACE, for
68 * portability to LP64 environments.
70 #if defined(CMSG_SPACE) && !defined(NO_MSGHDR_MSG_CONTROL)
72 struct cmsghdr just_for_alignment
;
73 char control
[CMSG_SPACE(sizeof(newfd
))];
75 struct cmsghdr
*cmptr
;
77 memset((char *) &msg
, 0, sizeof(msg
)); /* Fix 200512 */
78 msg
.msg_control
= control_un
.control
;
79 msg
.msg_controllen
= sizeof(control_un
.control
); /* Fix 200506 */
81 msg
.msg_accrights
= (char *) &newfd
;
82 msg
.msg_accrightslen
= sizeof(newfd
);
89 * XXX We don't want to pass any data, just a file descriptor. However,
90 * setting msg.msg_iov = 0 and msg.msg_iovlen = 0 causes trouble: we need
91 * to read_wait() before we can receive the descriptor, and the code
92 * fails after the first descriptor when we attempt to receive a sequence
96 iov
->iov_len
= sizeof(buf
);
100 if (recvmsg(fd
, &msg
, 0) < 0)
103 #if defined(CMSG_SPACE) && !defined(NO_MSGHDR_MSG_CONTROL)
104 if ((cmptr
= CMSG_FIRSTHDR(&msg
)) != 0
105 && cmptr
->cmsg_len
== CMSG_LEN(sizeof(newfd
))) {
106 if (cmptr
->cmsg_level
!= SOL_SOCKET
)
107 msg_fatal("%s: control level %d != SOL_SOCKET",
108 myname
, cmptr
->cmsg_level
);
109 if (cmptr
->cmsg_type
!= SCM_RIGHTS
)
110 msg_fatal("%s: control type %d != SCM_RIGHTS",
111 myname
, cmptr
->cmsg_type
);
112 return (*(int *) CMSG_DATA(cmptr
));
116 if (msg
.msg_accrightslen
== sizeof(newfd
))
127 * Proof-of-concept program. Receive a descriptor (presumably from the
128 * unix_send_fd test program) and copy its content until EOF.
133 #include <split_at.h>
136 int main(int argc
, char **argv
)
147 || (endpoint
= split_at(transport
= argv
[1], ':')) == 0
148 || *endpoint
== 0 || *transport
== 0)
149 msg_fatal("usage: %s transport:endpoint", argv
[0]);
151 if (strcmp(transport
, "unix") == 0) {
152 listen_sock
= unix_listen(endpoint
, 10, BLOCKING
);
154 msg_fatal("invalid transport name: %s", transport
);
157 msg_fatal("listen %s:%s: %m", transport
, endpoint
);
159 client_sock
= accept(listen_sock
, (struct sockaddr
*) 0, (SOCKADDR_SIZE
) 0);
161 msg_fatal("accept: %m");
163 while ((client_fd
= unix_recv_fd(client_sock
)) >= 0) {
164 msg_info("client_fd = %d", client_fd
);
165 while ((read_count
= read(client_fd
, buf
, sizeof(buf
))) > 0)
166 write(1, buf
, read_count
);
168 msg_fatal("read: %m");