#include #include #include #ifndef NULL #define NULL ((void *) 0) #endif #ifndef MSG_CMSG_CLOEXEC #define MSG_CMSG_CLOEXEC 0 // we explicitly close all file descriptors obtained thought the recv_fd anyway #endif // http://www.thomasstover.com/uds.html int recv_fd(int socket) { int sent_fd; struct msghdr socket_message; struct iovec io_vector[1]; struct cmsghdr *control_message = NULL; char message_buffer[1]; char ancillary_element_buffer[CMSG_SPACE(sizeof(int))]; /* start clean */ memset(&socket_message, 0, sizeof(struct msghdr)); memset(ancillary_element_buffer, 0, CMSG_SPACE(sizeof(int))); /* setup a place to fill in message contents */ io_vector[0].iov_base = message_buffer; io_vector[0].iov_len = 1; socket_message.msg_iov = io_vector; socket_message.msg_iovlen = 1; /* provide space for the ancillary data */ socket_message.msg_control = ancillary_element_buffer; socket_message.msg_controllen = CMSG_SPACE(sizeof(int)); if(recvmsg(socket, &socket_message, MSG_CMSG_CLOEXEC) < 0) return -1; if(message_buffer[0] != 'F') { /* this did not originate from the above function */ return -1; } if((socket_message.msg_flags & MSG_CTRUNC) == MSG_CTRUNC) { /* we did not provide enough space for the ancillary element array */ return -1; } /* iterate ancillary elements */ for(control_message = CMSG_FIRSTHDR(&socket_message); control_message != NULL; control_message = CMSG_NXTHDR(&socket_message, control_message)) { if( (control_message->cmsg_level == SOL_SOCKET) && (control_message->cmsg_type == SCM_RIGHTS) ) { sent_fd = *((int *) CMSG_DATA(control_message)); return sent_fd; } } return -1; }