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:
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.
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.
You cannot send file descriptors over AF_INET. Use a UNIX domain socket.