struct msghdr, passing fds between processes

Jonathan I. Kamens jik at athena.mit.edu
Tue Apr 23 09:43:12 AEST 1991


  (Note Followup-To.  This isn't really related to the TCP/IP protocol.)

In article <1991Apr22.123248.8250 at sserve.cc.adfa.oz.au>, cjsv at 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 <sys/types.h>
#include <sys/socket.h>
#include <sys/file.h>
#include <stdio.h>

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 at Athena.MIT.EDU				Allston, MA  02134
Office: 617-253-8085			      Home: 617-782-0710



More information about the Comp.unix.internals mailing list