Passing file descriptors across processes

Passing file descriptors across processes

Post by Arvind Srivat » Fri, 07 Mar 1997 04:00:00



I was reading this example from Stevens book about using socketpair to send
the fd of a file opened by a child back to its parent.

This program called openfile is execed by the function myopen and is passed
a socket fd (opened using socketpair) which openfile then uses to send the
fd to the parent process.  My question is - are stream pipes assigned
global numbers valid across all processes?  Otherwise how is a
process (instance of openfile) able to use a socket fd opened by another?

I'd be grateful if someone could clarify this.

Arvind

-------------------

/*
 * Open a file, returning a file descriptor.
 *
 * This function is similar to the UNIX open() system call,
 * however here we invoke another program to do the actual
 * open(), to illustrate the passing of open files
 * between processes.
 */

int
my_open(filename, mode)
char    *filename;
int     mode;
{
        int             fd, childpid, sfd[2], status;
        char            argsfd[10], argmode[10];
        extern int      errno;

        if (s_pipe(sfd) < 0)         /* create an unnamed stream pipe */
                return(-1);             /* errno will be set */

        if ( (childpid = fork()) < 0)
                err_sys("can't fork");

        else if (childpid == 0) {       /* child process */
                close(sfd[0]);          /* close the end we don't use */
                sprintf(argsfd, "%d", sfd[1]);
                sprintf(argmode, "%d", mode);
                if (execl("./openfile", "openfile", argsfd, filename,
                          argmode, (char *) 0) < 0)
                                err_sys("can't execl");
        }

        /* parent process - wait for the child's execl() to complete */

        close(sfd[1]);                  /* close the end we don't use */
        if (wait(&status) != childpid)
                err_dump("wait error");
        if ((status & 255) != 0)
                err_dump("child did not exit");
        status = (status >> 8) & 255;         /* child's exit() argument */
        if (status == 0) {
                fd = recvfile(sfd[0]);          /* all OK, receive fd */
        } else {
                errno = status; /* error, set errno value from child's errno */
                fd = -1;
        }

        close(sfd[0]);          /* close the stream pipe */
        return(fd);

Quote:}

/*
 *      openfile  <socket-descriptor-number>  <filename>  <mode>
 *
 * Open the specified file using the specified mode.
 * Return the open file descriptor on the specified socket descriptor
 * (which the invoker has to set up before exec'ing us).
 * We exit() with a value of 0 if all is OK, otherwise we pass back the
 * errno value as our exit status.
 */

main(argc, argv)
int     argc;
char    *argv[];
{
        int             fd;
        extern int      errno;
        extern char     *pname;

        pname = argv[0];

        if (argc != 4)
                err_quit("openfile <sockfd#> <filename> <mode>");

        /*
         * Open the file.
         */

        if ( (fd = open(argv[2], atoi(argv[3]))) < 0)
                exit( (errno > 0) ? errno : 255 );

        /*
         * And pass the descriptor back to caller.
         */

        exit( sendfile(atoi(argv[1]), fd) );

Quote:}

 
 
 

Passing file descriptors across processes

Post by Andrew Giert » Sat, 08 Mar 1997 04:00:00


 Arvind> I was reading this example from Stevens book about using
 Arvind> socketpair to send the fd of a file opened by a child back to
 Arvind> its parent.

 Arvind> This program called openfile is execed by the function myopen
 Arvind> and is passed a socket fd (opened using socketpair) which
 Arvind> openfile then uses to send the fd to the parent process.  My
 Arvind> question is - are stream pipes assigned global numbers valid
 Arvind> across all processes?  Otherwise how is a process (instance
 Arvind> of openfile) able to use a socket fd opened by another?

What actually happens is that when a process writes a file descriptor
to a STREAMS pipe or Unix-domain socket, the kernel converts the file
descriptor (which is meaningful only to the process sending it) into a
pointer to a kernel file table entry (which is global to all processes).
Then, when the receiving process reads the file table pointer from the
pipe or socket, the kernel creates a new file descriptor in the
receiving process, pointing to the specified file table entry.

This isn't restricted to sockets; any open file descriptor can be passed
between processes this way.

--
Andrew.