/* * Send a command (char), data (head), and a file descriptor (sd_send) to a local process * over unix socket sd. Unfortunately, there's no portable way to send file descriptors * to other processes, so this code, as well as its analog (control_message_from_parent below), * is Linux-specific. This function runs in the context of the main process and is used to * send commands, data, and file descriptors to the background process. */ static void port_share_sendmsg (const socket_descriptor_t sd, const char command, const struct buffer *head, const socket_descriptor_t sd_send) { if (socket_defined (sd)) { struct msghdr mesg; struct cmsghdr* h; struct iovec iov[2]; socket_descriptor_t sd_null[2] = { SOCKET_UNDEFINED, SOCKET_UNDEFINED }; char cmd; ssize_t status; dmsg (D_PS_PROXY_DEBUG, "PORT SHARE: sendmsg sd=%d len=%d", (int)sd_send, head ? BLEN(head) : -1); CLEAR (mesg); cmd = command; iov[0].iov_base = &cmd; iov[0].iov_len = sizeof (cmd); mesg.msg_iovlen = 1; if (head) { iov[1].iov_base = BPTR (head); iov[1].iov_len = BLEN (head); mesg.msg_iovlen = 2; } mesg.msg_iov = iov; mesg.msg_controllen = cmsg_size (); mesg.msg_control = (char *) malloc (mesg.msg_controllen); check_malloc_return (mesg.msg_control); mesg.msg_flags = 0; h = CMSG_FIRSTHDR(&mesg); h->cmsg_level = SOL_SOCKET; h->cmsg_type = SCM_RIGHTS; h->cmsg_len = CMSG_LEN(sizeof(socket_descriptor_t)); if (socket_defined (sd_send)) { *((socket_descriptor_t*)CMSG_DATA(h)) = sd_send; } else { socketpair (PF_UNIX, SOCK_DGRAM, 0, sd_null); *((socket_descriptor_t*)CMSG_DATA(h)) = sd_null[0]; } status = sendmsg (sd, &mesg, MSG_NOSIGNAL); if (status == -1) msg (M_WARN, "PORT SHARE: sendmsg failed (unable to communicate with background process)"); close_socket_if_defined (sd_null[0]); close_socket_if_defined (sd_null[1]); free (mesg.msg_control); } }
static inline void close_socket_if_defined (const socket_descriptor_t sd) { if (socket_defined (sd)) openvpn_close_socket (sd); }