How to use sendmsg() to send a file-descriptor via sockets between 2 processes?

后端 未结 3 1257
情书的邮戳
情书的邮戳 2020-12-16 05:16

After @cnicutar answers me on this question, I tried to send a file-descriptor from the parent process to its child. Based on this example, I wrote this code:



        
相关标签:
3条回答
  • 2020-12-16 05:38

    The problem is you are passing the file descriptor in a msg_name field. This is an address field, and it is not intended to pass arbitrary data.

    In fact, the file descriptors should be passed in a special way so the kernel could duplicate the file descriptor for the receiving process (and maybe the descriptor will have another value after the duplicating). That's why there is a special ancillary message type (SCM_RIGHTS) to pass file descriptors.

    The following would work (I omitted some of the error handling). In client:

    memset(&child_msg,   0, sizeof(child_msg));
    char cmsgbuf[CMSG_SPACE(sizeof(int))];
    child_msg.msg_control = cmsgbuf; // make place for the ancillary message to be received
    child_msg.msg_controllen = sizeof(cmsgbuf);
    
    printf("Waiting on recvmsg\n");
    rc = recvmsg(worker_sd, &child_msg, 0);
    struct cmsghdr *cmsg = CMSG_FIRSTHDR(&child_msg);
    if (cmsg == NULL || cmsg -> cmsg_type != SCM_RIGHTS) {
         printf("The first control structure contains no file descriptor.\n");
         exit(0);
    }
    memcpy(&pass_sd, CMSG_DATA(cmsg), sizeof(pass_sd));
    printf("Received descriptor = %d\n", pass_sd);
    

    In server:

    memset(&parent_msg, 0, sizeof(parent_msg));
    struct cmsghdr *cmsg;
    char cmsgbuf[CMSG_SPACE(sizeof(accepted_socket_fd))];
    parent_msg.msg_control = cmsgbuf;
    parent_msg.msg_controllen = sizeof(cmsgbuf); // necessary for CMSG_FIRSTHDR to return the correct value
    cmsg = CMSG_FIRSTHDR(&parent_msg);
    cmsg->cmsg_level = SOL_SOCKET;
    cmsg->cmsg_type = SCM_RIGHTS;
    cmsg->cmsg_len = CMSG_LEN(sizeof(accepted_socket_fd));
    memcpy(CMSG_DATA(cmsg), &accepted_socket_fd, sizeof(accepted_socket_fd));
    parent_msg.msg_controllen = cmsg->cmsg_len; // total size of all control blocks
    
    if((sendmsg(server_sd, &parent_msg, 0)) < 0)
    {
        perror("sendmsg()");
        exit(EXIT_FAILURE);
    }
    

    See also man 3 cmsg, there are some examples.

    0 讨论(0)
  • 2020-12-16 05:48

    This is extremely hard to get right. I'd recommend just using a library that does it for you. One of the simplest is libancillary. It gives you two functions, one to send a file descriptor over a UNIX-domain socket and one to receive one. They are absurdly simple to use.

    0 讨论(0)
  • 2020-12-16 05:49

    You cannot send file descriptors over AF_INET. Use a UNIX domain socket.

    0 讨论(0)
提交回复
热议问题