Xref: utzoo comp.protocols.tcp-ip:15770 comp.unix.internals:2594 Path: utzoo!utgpu!news-server.csri.toronto.edu!cs.utexas.edu!sdd.hp.com!think.com!mintaka!bloom-picayune.mit.edu!athena.mit.edu!jik From: jik@athena.mit.edu (Jonathan I. Kamens) Newsgroups: comp.protocols.tcp-ip,comp.unix.internals Subject: Re: struct msghdr, passing fds between processes Keywords: access rights, UNIX domain sockets, open fds, BSD Message-ID: <1991Apr22.234312.15732@athena.mit.edu> Date: 22 Apr 91 23:43:12 GMT References: <1991Apr22.123248.8250@sserve.cc.adfa.oz.au> Sender: news@athena.mit.edu (News system) Followup-To: comp.unix.internals Organization: Massachusetts Institute of Technology Lines: 76 (Note Followup-To. This isn't really related to the TCP/IP protocol.) In article <1991Apr22.123248.8250@sserve.cc.adfa.oz.au>, cjsv@sserve.cc.adfa.oz.au (Christopher JS Vance) writes: |> I note that a BSD struct msghdr (used with sendmsg and recvmsg) allows the |> passing of `access rights'. I seem to remember someone indicating that this |> meant open file descriptors, sort of like a call on dup, except to a different |> process. Yes. |> Could someone who knows please point me to some documentation of this feature, |> or at least let me know what kinds of stream these can be passed over. I assume |> that the numbers change on the wire and come out as open fds at the other end. The only documentation about it that I know of is the recvmsg(2) man page (or, at least, that's the only place I've seen it mentioned; it may be mentioned in other man pages as well). According to that man page, fd's can only be passed over sockets (although I suspect that it'll work with pipes too, since pipes are implemented on top of sockets). The way you pass a descriptor is by assigning the address of an int containing the descriptor number to the msg_accrights member of the msghdr structure and sizeof(int) to the msg_accrightslen member of the structure, and then sending a message over a socket to another process using sendmsg(). The other process receives the mssage using recvmsg(), and the integer found in the msg_accrights member will be the number of the open file descriptor that was passed (as you point out, it may be a different number than what it was at the originating end). I'm not sure what happens if you send a descriptor from a process to itself; I suspect it's just like a dup(). Here's a really simple program, with absolutely no error checking, that demonstrates how this works. It works for me, but I make no guarantees :-). #include #include #include #include main() { int pair[2]; struct msghdr msg; int fd; char buf[BUFSIZ]; int c; socketpair(AF_UNIX, SOCK_STREAM, 0, pair); msg.msg_name = 0; msg.msg_namelen = 0; msg.msg_iov = 0; msg.msg_iovlen = 0; msg.msg_accrights = (char *) &fd; msg.msg_accrightslen = sizeof(fd); if (fork()) { /* Parent */ close(pair[1]); fd = open("/etc/passwd", O_RDONLY, 0); sendmsg(pair[0], &msg, 0); } else { /* Child */ close(pair[0]); recvmsg(pair[1], &msg, 0); while ((c = read(fd, buf, sizeof(buf))) > 0) write(1, buf, c); } } -- Jonathan Kamens USnail: MIT Project Athena 11 Ashford Terrace jik@Athena.MIT.EDU Allston, MA 02134 Office: 617-253-8085 Home: 617-782-0710