Passing File Descriptor

Passing File Descriptor

Post by Tsurng-Chen Cher » Sat, 21 Dec 1996 04:00:00



I used to have a program which will fork several
child processes, and then listen on the net waiting
for client's requests. After the program gets a request
it will then pass the file descriptor of the opened socket
to one of the child processes. The program works fine
on Sun OS 4.1.4, Solaris 2.5, and HPUX.

After I got my own Linux box set up, I tried to port the
program using the msghdr, cmsghdr method, however it
seems that the child process has problem getting the
file descriptor from the parent. Don't know what
the problem is, have no idea whether Linux support
this or not. Can anybody help me here?

--
Max Chern, Unix Software Engineer     |  Voice: 213-644-9600
EarthLink Network, Inc.               |  Fax:   213-644-9542

http://www.earthlink.net/             |  Los Angeles, CA 90039

 
 
 

Passing File Descriptor

Post by Eric Gree » Sun, 22 Dec 1996 04:00:00



> I used to have a program which will fork several
> child processes, and then listen on the net waiting
> for client's requests. After the program gets a request
> it will then pass the file descriptor of the opened socket
> to one of the child processes. The program works fine
> on Sun OS 4.1.4, Solaris 2.5, and HPUX.

> After I got my own Linux box set up, I tried to port the
> program using the msghdr, cmsghdr method, however it
> seems that the child process has problem getting the
> file descriptor from the parent. Don't know what
> the problem is, have no idea whether Linux support
> this or not. Can anybody help me here?

Linux does support this.  I got it working from the examples out of
Richard Stevens' "UNIX Network Programming" and "Advanced Programming in
the UNIX Environment," with the following code:

#define CONTROLLEN      (sizeof(struct cmsghdr) + sizeof(int))
#define CMSG_DATA(cmsg) ((u_char *)((cmsg) + 1))

// sockfd is the socket between the processes.
// fd is the new file descriptor to be passed.
int send_fd(int sockfd, int fd)
{
    struct iovec        iov[1];
    char buf[2];
    struct msghdr       msg;
    int                 *ptr;
    static struct cmsghdr       *cmptr = NULL;

    buf[0] = 'w';
    buf[1] = '\0';
    iov[0].iov_base = buf;      // No data to send
    iov[0].iov_len  = 2;

    if (cmptr == NULL &&
        (cmptr = (struct cmsghdr *) malloc(CONTROLLEN)) == NULL)
        return -1;

    cmptr->cmsg_level = SOL_SOCKET;
    cmptr->cmsg_type  = SCM_RIGHTS;
    cmptr->cmsg_len   = CONTROLLEN;
    *(int *)CMSG_DATA(cmptr) = fd;

    msg.msg_iov        = iov;
    msg.msg_iovlen     = 1;
    msg.msg_name       = (caddr_t) 0;
    msg.msg_namelen    = 0;
    msg.msg_control    = (caddr_t) cmptr;
    msg.msg_controllen = CONTROLLEN;

    if (sendmsg(sockfd, &msg, 0) < 0)
        return -1;

    return 0;

Quote:}

// sockfd is the socket used to communicate with the other process
// returns the new file descriptor
int recv_fd(int sockfd)
{
    int fd;
    int *ptr;
    char buf[10];
    struct iovec iov[1];
    struct msghdr msg;
    static struct cmsghdr *cmptr = NULL;

    if (cmptr == NULL &&
        (cmptr = (struct cmsghdr *) malloc(CONTROLLEN)) == NULL)
        return -1;

    iov[0].iov_base = buf;
    iov[0].iov_len = 10;
    msg.msg_iov = iov;
    msg.msg_iovlen = 1;
    msg.msg_name = (caddr_t) 0;
    msg.msg_namelen = 0;
    msg.msg_control = (caddr_t) cmptr;
    msg.msg_controllen = CONTROLLEN;

    if (recvmsg(sockfd, &msg, 0) < 0)
        return -1;

    fd = *(int *)CMSG_DATA(cmptr);

    return(fd);

Quote:}

Eric


 
 
 

Passing File Descriptor

Post by Tsurng-Chen Cher » Tue, 24 Dec 1996 04:00:00


Hi, Eric,

   You are the life saver. I haven't got the chance to
try your code yet. However, as I inspected the code,
I found that the only difference is msg.iov. In my
case I pass iov_base = NULL with length 0. Of ourse,
I got the same idea from the same book. And the program
did work fine on Solaris, HPUX, ...

   Man, I am going to try this tonight. Thanks for
the tip.


> Linux does support this.  I got it working from the examples out of
> Richard Stevens' "UNIX Network Programming" and "Advanced Programming in
> the UNIX Environment," with the following code:

> #define CONTROLLEN      (sizeof(struct cmsghdr) + sizeof(int))
> #define CMSG_DATA(cmsg) ((u_char *)((cmsg) + 1))

> // sockfd is the socket between the processes.
> // fd is the new file descriptor to be passed.
> int send_fd(int sockfd, int fd)
> {
>     struct iovec        iov[1];
>     char buf[2];
>     struct msghdr       msg;
>     int                 *ptr;
>     static struct cmsghdr       *cmptr = NULL;

>     buf[0] = 'w';
>     buf[1] = '\0';
>     iov[0].iov_base = buf;      // No data to send
>     iov[0].iov_len  = 2;

>     if (cmptr == NULL &&
>         (cmptr = (struct cmsghdr *) malloc(CONTROLLEN)) == NULL)
>         return -1;

>     cmptr->cmsg_level = SOL_SOCKET;
>     cmptr->cmsg_type  = SCM_RIGHTS;
>     cmptr->cmsg_len   = CONTROLLEN;
>     *(int *)CMSG_DATA(cmptr) = fd;

>     msg.msg_iov        = iov;
>     msg.msg_iovlen     = 1;
>     msg.msg_name       = (caddr_t) 0;
>     msg.msg_namelen    = 0;
>     msg.msg_control    = (caddr_t) cmptr;
>     msg.msg_controllen = CONTROLLEN;

>     if (sendmsg(sockfd, &msg, 0) < 0)
>         return -1;

>     return 0;
> }

> // sockfd is the socket used to communicate with the other process
> // returns the new file descriptor
> int recv_fd(int sockfd)
> {
>     int fd;
>     int *ptr;
>     char buf[10];
>     struct iovec iov[1];
>     struct msghdr msg;
>     static struct cmsghdr *cmptr = NULL;

>     if (cmptr == NULL &&
>         (cmptr = (struct cmsghdr *) malloc(CONTROLLEN)) == NULL)
>         return -1;

>     iov[0].iov_base = buf;
>     iov[0].iov_len = 10;
>     msg.msg_iov = iov;
>     msg.msg_iovlen = 1;
>     msg.msg_name = (caddr_t) 0;
>     msg.msg_namelen = 0;
>     msg.msg_control = (caddr_t) cmptr;
>     msg.msg_controllen = CONTROLLEN;

>     if (recvmsg(sockfd, &msg, 0) < 0)
>         return -1;

>     fd = *(int *)CMSG_DATA(cmptr);

>     return(fd);
> }

> Eric


--
Max Chern, Unix Software Engineer     |  Voice: 213-644-9600
EarthLink Network, Inc.               |  Fax:   213-644-9542

http://www.earthlink.net/             |  Los Angeles, CA 90039