[comp.unix.questions] How to transfer file descriptors with UNIX domain sockets?

rgm@lightning.Berkeley.EDU (Rob Menke) (06/28/90)

I have seen references in various IPC tutorials and manuals that it is
possible to transfer file descriptors between processes via UNIX domain
sockets using sendmsg(2) and recvmsg(2).  Unfortunately, none of these
documents contain anything more than a tantalizing aside.

I'm hoping that someone out there might be able to provide a detailed
description of how this is done, or better yet, some clear code that could be
used as an example.

Please e-mail as I will be going on vacation shortly and our news server will
cheerfully overwrite any posted replies.

							Thanks.

>GIVE COIN TO CHARON			|  Wabewalker
"So educated," giggles the voice in	|    rgm@OCF.berkeley.edu
your ear...				|    Robert.Menke@bmug.fidonet.org

nystrom@enea.se (Lars Nystr|m) (06/29/90)

In article <37317@ucbvax.BERKELEY.EDU> rgm@OCF.Berkeley.EDU (Rob Menke) writes:
>
>I have seen references in various IPC tutorials and manuals that it is
>possible to transfer file descriptors between processes via UNIX domain
>sockets using sendmsg(2) and recvmsg(2).  Unfortunately, none of these
>documents contain anything more than a tantalizing aside.

There is a book that explains how to do this.

UNIX Network Programming
W. Richard Stevens
Prentice-Hall 1990
ISBN 0-13-949876-1

An example will be E-mailed to you.

net@tub.UUCP (Oliver Laumann) (06/29/90)

In article <37317@ucbvax.BERKELEY.EDU> rgm@OCF.Berkeley.EDU (Rob Menke) writes:
> 
> I have seen references in various IPC tutorials and manuals that it is
> possible to transfer file descriptors between processes via UNIX domain
> sockets using sendmsg(2) and recvmsg(2).
> 
> I'm hoping that someone out there might be able to provide a detailed
> description of how this is done, or better yet, some clear code that could be
> used as an example.

The following two trivial programs demonstrate this functionality.

The first of them accepts a connection on a UNIX domain socket, opens
/etc/passwd, sends the file descriptor to the peer process, and then exits.

The other program establishes a connection, receives the file descriptor,
reads a buffer full of data from it, and writes it to standard output.

Yes, I know, the programs are written in a sloppy style (no exit codes,
arguments not properly casted, no man-page and "imake" file :-)

Regards,
--
Oliver Laumann     net@TUB.BITNET     net@tub.cs.tu-berlin.de     net@tub.UUCP


--------------------------------------------------------------------------
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <sys/uio.h>

main () {
    int s, fd;
    struct sockaddr_un a;
    static struct msghdr msg;
    static struct iovec iov;
    char *name = "foo";

    unlink (name);
    if ((s = socket (AF_UNIX, SOCK_STREAM, 0)) == -1) {
	perror ("socket"); return;
    }
    a.sun_family = AF_UNIX;
    strcpy (a.sun_path, name);
    if (bind (s, (struct sockaddr *)&a, strlen (name)+2) == -1) {
	perror ("bind"); return;
    }
    listen (s, 1);
    s = accept (s, (struct sockaddr *)0, (int *)0);
    if ((fd = open ("/etc/passwd", 0)) == -1) {
	perror ("passwd"); return;
    }
    msg.msg_accrights = (caddr_t)&fd;
    msg.msg_accrightslen = sizeof (fd);
    msg.msg_iov = &iov;
    if (sendmsg (s, &msg, 0) == -1)
	perror ("sendmsg");
}
--------------------------------------------------------------------------
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <sys/uio.h>

main () {
    int s, n, fd;
    struct sockaddr_un a;
    static struct msghdr msg;
    static struct iovec iov;
    char *name = "foo";
    char buf[512];

    if ((s = socket (AF_UNIX, SOCK_STREAM, 0)) == -1) {
	perror ("socket"); return;
    }
    a.sun_family = AF_UNIX;
    strcpy (a.sun_path, name);
    if (connect (s, (struct sockaddr *)&a, strlen (name)+2) == -1) {
	perror ("connect"); return;
    }
    msg.msg_accrights = (caddr_t)&fd;
    msg.msg_accrightslen = sizeof(fd);
    msg.msg_iov = &iov;
    if ((n = recvmsg (s, &msg, 0)) == -1) {
	perror ("recvmsg"); return;
    }
    if ((n = read (fd, buf, 512)) == -1) {
	perror ("read"); return;
    }
    write (1, buf, n);
}
--------------------------------------------------------------------------

gt0178a@prism.gatech.EDU (BURNS,JIM) (07/01/90)

in article <1421@tub.UUCP>, net@tub.UUCP (Oliver Laumann) says:
> In article <37317@ucbvax.BERKELEY.EDU> rgm@OCF.Berkeley.EDU (Rob Menke) writes:
>> possible to transfer file descriptors between processes via UNIX domain
>> sockets using sendmsg(2) and recvmsg(2).
> The following two trivial programs demonstrate this functionality.
> The first of them accepts a connection on a UNIX domain socket, opens
> /etc/passwd, sends the file descriptor to the peer process, and then exits.

I don't understand the concept here - if the program exits, its files are
closed, and the file descriptor is no longer valid. I know that child procs
can refer to parent fds even after the parent exits, but merely sending an
fd in a message - so what? How does the system know that the message
contains an fd that must remain valid after the program that opened it
exits?

-- 
BURNS,JIM
Georgia Institute of Technology, Box 30178, Atlanta Georgia, 30332
uucp:	  ...!{decvax,hplabs,ncar,purdue,rutgers}!gatech!prism!gt0178a
Internet: gt0178a@prism.gatech.edu

cpcahil@virtech.uucp (Conor P. Cahill) (07/01/90)

In article <10970@hydra.gatech.EDU> gt0178a@prism.gatech.EDU (BURNS,JIM) writes:
>in article <1421@tub.UUCP>, net@tub.UUCP (Oliver Laumann) says:
>> In article <37317@ucbvax.BERKELEY.EDU> rgm@OCF.Berkeley.EDU (Rob Menke) writes:
>>> possible to transfer file descriptors between processes via UNIX domain
>>> sockets using sendmsg(2) and recvmsg(2).
>> The following two trivial programs demonstrate this functionality.
>> The first of them accepts a connection on a UNIX domain socket, opens
>> /etc/passwd, sends the file descriptor to the peer process, and then exits.
>
>I don't understand the concept here - if the program exits, its files are
>closed, and the file descriptor is no longer valid. I know that child procs
>can refer to parent fds even after the parent exits, but merely sending an
>fd in a message - so what? How does the system know that the message
>contains an fd that must remain valid after the program that opened it
>exits?

The system knows because the person, or persons, that added that capability
to the sockets code ensured that the file descriptor that was passed became
a valid file descriptor in the process that received it.

This is not that hard to do since the kernel has control of both processes 
and thier file descriptor tables.

The same capability exists in SVR3 streams although I'm not sure if it has
equal functionality.
-- 
Conor P. Cahill            (703)430-9247        Virtual Technologies, Inc.,
uunet!virtech!cpcahil                           46030 Manekin Plaza, Suite 160
                                                Sterling, VA 22170 

gt0178a@prism.gatech.EDU (BURNS,JIM) (07/02/90)

in article <1990Jul01.130157.3627@virtech.uucp>, cpcahil@virtech.uucp (Conor P. Cahill) says:
>>in article <1421@tub.UUCP>, net@tub.UUCP (Oliver Laumann) says:
	[code deleted]
> The system knows because the person, or persons, that added that capability
> to the sockets code ensured that the file descriptor that was passed became
> a valid file descriptor in the process that received it.

I'm sure that it *can* be done - my question is what was it in Oliver
Laumann's code that informed the kernel that what was in the message was a
file descriptor?
-- 
BURNS,JIM
Georgia Institute of Technology, Box 30178, Atlanta Georgia, 30332
uucp:	  ...!{decvax,hplabs,ncar,purdue,rutgers}!gatech!prism!gt0178a
Internet: gt0178a@prism.gatech.edu

cpcahil@virtech.uucp (Conor P. Cahill) (07/02/90)

In article <10981@hydra.gatech.EDU> gt0178a@prism.gatech.EDU (BURNS,JIM) writes:
>in article <1990Jul01.130157.3627@virtech.uucp>, cpcahil@virtech.uucp (Conor P. Cahill) says:
>>>in article <1421@tub.UUCP>, net@tub.UUCP (Oliver Laumann) says:
>	[code deleted]
>> The system knows because the person, or persons, that added that capability
>> to the sockets code ensured that the file descriptor that was passed became
>> a valid file descriptor in the process that received it.
>
>I'm sure that it *can* be done - my question is what was it in Oliver
>Laumann's code that informed the kernel that what was in the message was a
>file descriptor?

Essentially it is the portion of the that supports the passing of "access
rights".  The access rights to the file descriptor are passed using a
send/recvmsg().  For more info, you could look at section 6.10 "Passing
file descriptors" in UNIX Network Programming (by W. Richard Stevens).

-- 
Conor P. Cahill            (703)430-9247        Virtual Technologies, Inc.,
uunet!virtech!cpcahil                           46030 Manekin Plaza, Suite 160
                                                Sterling, VA 22170 

guy@auspex.auspex.com (Guy Harris) (07/03/90)

>I'm sure that it *can* be done - my question is what was it in Oliver
>Laumann's code that informed the kernel that what was in the message was a
>file descriptor?

It was

    msg.msg_accrights = (caddr_t)&fd;
    msg.msg_accrightslen = sizeof (fd);

I.e., the "access rights" in a message sent down a UNIX-domain socket
are, by definition, file descriptors....

stevens@hsi.UUCP (Richard Stevens) (07/03/90)

In article <1990Jul01.130157.3627@virtech.uucp> cpcahil@virtech.UUCP (Conor P. Cahill) writes:
>
>The same capability exists in SVR3 streams although I'm not sure if it has
>equal functionality.

It provides the same functionality plus the SVR3 routines provide the
receiver with the effective UID and effective GID of the sender.

	Richard Stevens
	3M Health Information Systems, Wallingford, CT
	   stevens@hsi.com