From: thorinn@diku.dk (Lars Henrik Mathiesen)
Newsgroups: comp.unix.programmer
Subject: Re: Passing file descriptors between processes
Date: 17 Nov 92 15:58:19 GMT
Organization: Department of Computer Science, U of Copenhagen

tml@tik.vtt.fi (Tor Lillqvist) writes:
>I vaguely remember that is is possible (at least in pure BSD) to pass
>open file descriptors between processes.  I think UNIX domain sockets
>had something to do with it.

Indeed they do, as illustrated by the small example program that I
shall append. (It creates a socketpair, forks, opens a file and reads
the first byte, passes the descriptor to the other process and reads
some more --- with some test output to show that it works as claimed.)

>But I can't find anything about it in the HP-UX or SunOS manual
>pages.  Could somebody refresh my memory please?

It does work on SunOS 4.1.1 and HP-UX 8.07. On both systems, the
manual section for recvmsg(2) mentions access rights, but does not
explicitly say that these are file descriptors; while the unix(4F/7P)
sections contain references to the Network Programming document/IPC
programmer's manual, I am not sure that those documents are any more
helpful --- the 4.3 IPC Tutorials certainly are not.

Lars Mathiesen (U of Copenhagen CS Dep) <thorinn@diku.dk> (Humour NOT marked)

-----s-n-i-p-p-e-t-y---s-n-i-p-p-e-t-y---s-n-i-p-p-e-t-y---s-n-i-p-----
#include <sys/file.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/uio.h>
#include <stdio.h>

main(argc, argv)
    char **argv;
{
    char buf[BUFSIZ];
    int sv[2], pid, fd = -1, n;
    struct iovec iov;
    struct msghdr mh;

    if (argc != 2) {
	fprintf(stderr, "Usage: pass_access file\n");
	exit(2);
    }
    /* Set up a message header:
           No send/receive address
	   One buffer in iovec (otherwise recvmsg won't wait for sendmsg)
	   A file descriptor area of length one.
     */
    mh.msg_name = 0;
    mh.msg_namelen = 0;
    iov.iov_base = buf;
    iov.iov_len = BUFSIZ;
    mh.msg_iov = &iov;
    mh.msg_iovlen = 1;
    mh.msg_accrights = (caddr_t)&fd;
    mh.msg_accrightslen = sizeof fd;
    
    /* Create a pair of connected sockets */
    if (socketpair(AF_UNIX, SOCK_DGRAM, 0, sv) < 0) {
	perror("socketpair");
	exit(1);
    }
    if ((pid = fork()) < 0) {
	perror("fork");
	exit(1);
    }
    if (pid == 0) {
	/* Child: close a descriptor to illustrate that
	   access rights are passed in internal form
	 */
	close(sv[0]);
	/* Open a random file */
	if ((fd = open(argv[1], O_RDONLY)) < 0) {
	    fputs(argv[1], stderr);
	    perror(": open");
	    exit(1);
	}
	if ((n = read(fd, buf, 1)) < 0) {
	    perror("child read");
	    exit(1);
	}
	printf("Child: fd = %d, first char '%c'\n", fd, n ? buf[0] : '?');
	fflush(stdout);
	/* Send a null message with access right tacked on */
	iov.iov_len = 0;
	if ((n = sendmsg(sv[1], &mh, 0)) < 0) {
	    perror("sendmsg");
	    exit(1);
	}
	printf("Child: sent %d bytes\n", n);
	fflush(stdout);
	exit(0);
    }
    /* Parent: Close send socket to prevent hang if child never sends */
    close(sv[1]);
    /* Get message and access right */
    if ((n = recvmsg(sv[0], &mh, 0)) < 0) {
	perror("recvmsg");
	exit(1);
    }
    printf("Parent: fd = %d, received %d bytes\n", fd, n);
    fflush(stdout);
    /* Copy contents of (small) file */
    if ((n = read(fd, buf, BUFSIZ)) < 0) {
	perror("read");
	exit(1);
    }
    if ((n = write(1, buf, n)) < 0) {
	perror("write");
	exit(1);
    }
    exit(0);
}
Newsgroups: comp.unix.programmer,comp.lang.c