Send socket descriptors to child processes

From: Jo (JoJoTwilligo_at_hotmail.com)
Date: 09/28/04


Date: 27 Sep 2004 20:45:34 -0700

I'm very confused about all these routines that are supposed to be
able to pass open descriptors to other processes. I've been reading
the man pages on recvmsg, sendmsg, socketpair, cmsg(3) and unix(7),
and this is the best I've come up with:

void SendNewSocket(int desChild, int desNewSocket) {
char test[] = "this message is received; the socket is good";
write(desNewSocket, test, strlen(test)+1);

        struct msghdr msg = {0}; //took this block from man 3 cmsg
        struct cmsghdr *cmsg;
        char buf[CMSG_SPACE(sizeof desNewSocket)]; /* ancillary data buffer
*/
        int *fdptr;

        msg.msg_control = buf;
        msg.msg_controllen = sizeof buf;
        cmsg = CMSG_FIRSTHDR(&msg);
        cmsg->cmsg_level = SOL_SOCKET;
        cmsg->cmsg_type = SCM_RIGHTS;
        cmsg->cmsg_len = CMSG_LEN(sizeof(int));
        /* Initialize the payload: */
        fdptr = (int *)CMSG_DATA(cmsg);
        memcpy(fdptr, &desNewSocket, sizeof(desNewSocket));
        /* Sum of the length of all control messages in the buffer: */
        msg.msg_controllen = cmsg->cmsg_len;
        sendmsg(desChild, &msg, 0);
}
The only time the ancilliary descriptors are used outside of the code
here, is in select and close (which, of course, is not called before
any of this code is called). Sendmsg here always returns 0. This means
the receiving code hasn't been tested yet, but here it is anyway:

int GetNewSocket(int desAncil) {
  struct msghdr msgHdr;
  recvmsg(desAncil, &msgHdr, 0);
  struct cmsghdr *cHdr = (struct cmsghdr *)msgHdr.msg_control;
  char *pFDChar = (char *)CMSG_DATA(cHdr);
  int *pFDInt = (int *)pFDChar;
        
        return *pFDInt;
}

The creation of the ancilliary descriptors is nothing to look at, but
if you want to:

void Fork(int &desAncil) {
  int desAncil[2];
  socketpair(PF_UNIX, SOL_SOCKET, 0, desAncils);
        pid_t nPid = fork();
        switch (nPid) {
                case 0: //child
                        close(desAncils[1]);
                        desAncil = desAncils[0];
                default: { //parent
                        close(desAncils[0]);
                        desAncil = desAncils[1];
        }
}

Is all this correct?