You cannot transfer a socket (or any other file descriptor) from one process to another through shared memory. A file descriptor is just a small integer. Placing this integer in shared memory and accessing it from another process does not automatically make the same integer in a valid file descriptor from the point of view of another process.
The correct way to send a file descriptor from one process to another is to send it as SCM_RIGHTS auxiliary data using sendmsg() through an existing socket communication channel between the two processes.
First create your socketpair() communication channel before fork() . Now, in the parent, close one end of the socket pair, and in the child case, close the other end. Now you can sendmsg() from the parent at one end of this socket and get recvmsg() to get the child using the other end.
Sending a message using SCM_RIGHTS looks something like this:
struct msghdr m; struct cmsghdr *cm; struct iovec iov; char buf[CMSG_SPACE(sizeof(int))]; char dummy[2]; memset(&m, 0, sizeof(m)); m.msg_controllen = CMSG_SPACE(sizeof(int)); m.msg_control = &buf; memset(m.msg_control, 0, m.msg_controllen); cm = CMSG_FIRSTHDR(&m); cm->cmsg_level = SOL_SOCKET; cm->cmsg_type = SCM_RIGHTS; cm->cmsg_len = CMSG_LEN(sizeof(int)); *((int *)CMSG_DATA(cm)) = your_file_descriptor_to_send; m.msg_iov = &iov; m.msg_iovlen = 1; iov.iov_base = dummy; iov.iov_len = 1; dummy[0] = 0; sendmsg(fd, &m, 0);
Receiving a message with SCM_RIGHTS in it happens like this:
struct msghdr m; struct cmsghdr *cm; struct iovec iov; struct dummy[100]; char buf[CMSG_SPACE(sizeof(int))]; ssize_t readlen; int *fdlist; iov.iov_base = dummy; iov.iov_len = sizeof(dummy); memset(&m, 0, sizeof(m)); m.msg_iov = &iov; m.msg_iovlen = 1; m.msg_controllen = CMSG_SPACE(sizeof(int)); m.msg_control = buf; readlen = recvmsg(fd, &m, 0); received_file_descriptor = -1; for (cm = CMSG_FIRSTHDR(&m); cm; cm = CMSG_NXTHDR(&m, cm)) { if (cm->cmsg_level == SOL_SOCKET && cm->cmsg_type == SCM_RIGHTS) { nfds = (cm->cmsg_len - CMSG_LEN(0)) / sizeof(int); fdlist = (int *)CMSG_DATA(cm); received_file_descriptor = *fdlist; break; } }
Celada
source share