diff options
-rw-r--r-- | auto/make | 1 | ||||
-rw-r--r-- | auto/sockets | 52 | ||||
-rw-r--r-- | auto/sources | 1 | ||||
-rw-r--r-- | go/nxt_cgo_lib.c | 8 | ||||
-rw-r--r-- | go/port.go | 7 | ||||
-rw-r--r-- | src/nxt_cert.c | 25 | ||||
-rw-r--r-- | src/nxt_main_process.c | 33 | ||||
-rw-r--r-- | src/nxt_port.h | 19 | ||||
-rw-r--r-- | src/nxt_port_rpc.c | 4 | ||||
-rw-r--r-- | src/nxt_port_socket.c | 81 | ||||
-rw-r--r-- | src/nxt_socket.h | 4 | ||||
-rw-r--r-- | src/nxt_socket_msg.c | 57 | ||||
-rw-r--r-- | src/nxt_socket_msg.h | 220 | ||||
-rw-r--r-- | src/nxt_socketpair.c | 201 | ||||
-rw-r--r-- | src/nxt_unit.c | 212 | ||||
-rw-r--r-- | src/nxt_unit.h | 2 |
16 files changed, 578 insertions, 349 deletions
@@ -59,6 +59,7 @@ $echo >> $NXT_MAKEFILE $echo "NXT_LIB_UNIT_OBJS = \\" >> $NXT_MAKEFILE $echo " $NXT_BUILD_DIR/src/nxt_lvlhsh.o \\" >> $NXT_MAKEFILE $echo " $NXT_BUILD_DIR/src/nxt_murmur_hash.o \\" >> $NXT_MAKEFILE +$echo " $NXT_BUILD_DIR/src/nxt_socket_msg.o \\" >> $NXT_MAKEFILE $echo " $NXT_BUILD_DIR/src/nxt_websocket.o \\" >> $NXT_MAKEFILE for nxt_src in $NXT_LIB_UNIT_SRCS diff --git a/auto/sockets b/auto/sockets index c8d1173e..1b6b4368 100644 --- a/auto/sockets +++ b/auto/sockets @@ -158,6 +158,58 @@ nxt_feature_test="#include <stdio.h> }" . auto/feature +if [ $nxt_found = no ]; then + $echo + $echo $0: error: no msghdr.msg_control struct member. + $echo + exit 1; +fi + + +nxt_feature="sockopt SO_PASSCRED" +nxt_feature_name=NXT_HAVE_SOCKOPT_SO_PASSCRED +nxt_feature_run= +nxt_feature_incs= +nxt_feature_libs= +nxt_feature_test="#define _GNU_SOURCE + #include <sys/socket.h> + + int main() { + return SO_PASSCRED == 0; + }" +. auto/feature + + +if [ $nxt_found = yes ]; then + nxt_feature="struct ucred" + nxt_feature_name=NXT_HAVE_UCRED + nxt_feature_run= + nxt_feature_incs= + nxt_feature_libs= + nxt_feature_test="#define _GNU_SOURCE + #include <sys/socket.h> + #include <sys/un.h> + + int main() { + return sizeof(struct ucred); + }" + . auto/feature +fi + + +nxt_feature="struct cmsgcred" +nxt_feature_name=NXT_HAVE_MSGHDR_CMSGCRED +nxt_feature_run= +nxt_feature_incs= +nxt_feature_libs= +nxt_feature_test="#define _GNU_SOURCE + #include <sys/socket.h> + + int main() { + return sizeof(struct cmsgcred); + }" +. auto/feature + nxt_feature="sys/filio.h" nxt_feature_name=NXT_HAVE_SYS_FILIO_H diff --git a/auto/sources b/auto/sources index 990f5d11..27a45edc 100644 --- a/auto/sources +++ b/auto/sources @@ -13,6 +13,7 @@ NXT_LIB_SRCS=" \ src/nxt_mem_map.c \ src/nxt_socket.c \ src/nxt_socketpair.c \ + src/nxt_socket_msg.c \ src/nxt_credential.c \ src/nxt_isolation.c \ src/nxt_process.c \ diff --git a/go/nxt_cgo_lib.c b/go/nxt_cgo_lib.c index 3e766b1e..ca9fc3ab 100644 --- a/go/nxt_cgo_lib.c +++ b/go/nxt_cgo_lib.c @@ -10,10 +10,10 @@ #include <nxt_unit_request.h> -static ssize_t nxt_cgo_port_send(nxt_unit_ctx_t *, nxt_unit_port_t *port, +static ssize_t nxt_cgo_port_send(nxt_unit_ctx_t *ctx, nxt_unit_port_t *port, const void *buf, size_t buf_size, const void *oob, size_t oob_size); -static ssize_t nxt_cgo_port_recv(nxt_unit_ctx_t *, nxt_unit_port_t *port, - void *buf, size_t buf_size, void *oob, size_t oob_size); +static ssize_t nxt_cgo_port_recv(nxt_unit_ctx_t *ctx, nxt_unit_port_t *port, + void *buf, size_t buf_size, void *oob, size_t *oob_size); int nxt_cgo_run(uintptr_t handler) @@ -58,7 +58,7 @@ nxt_cgo_port_send(nxt_unit_ctx_t *ctx, nxt_unit_port_t *port, static ssize_t nxt_cgo_port_recv(nxt_unit_ctx_t *ctx, nxt_unit_port_t *port, - void *buf, size_t buf_size, void *oob, size_t oob_size) + void *buf, size_t buf_size, void *oob, size_t *oob_size) { return nxt_go_port_recv(port->id.pid, port->id.id, buf, buf_size, oob, oob_size); @@ -169,7 +169,7 @@ func nxt_go_port_send(pid C.int, id C.int, buf unsafe.Pointer, buf_size C.int, //export nxt_go_port_recv func nxt_go_port_recv(pid C.int, id C.int, buf unsafe.Pointer, buf_size C.int, - oob unsafe.Pointer, oob_size C.int) C.ssize_t { + oob unsafe.Pointer, oob_size *C.size_t) C.ssize_t { key := port_key{ pid: int(pid), @@ -184,7 +184,7 @@ func nxt_go_port_recv(pid C.int, id C.int, buf unsafe.Pointer, buf_size C.int, } n, oobn, _, _, err := p.rcv.ReadMsgUnix(GoBytes(buf, buf_size), - GoBytes(oob, oob_size)) + GoBytes(oob, C.int(*oob_size))) if err != nil { if nerr, ok := err.(*net.OpError); ok { @@ -196,6 +196,9 @@ func nxt_go_port_recv(pid C.int, id C.int, buf unsafe.Pointer, buf_size C.int, nxt_go_warn("read result %d (%d), %s", n, oobn, err) n = -1 + + } else { + *oob_size = C.size_t(oobn) } return C.ssize_t(n) diff --git a/src/nxt_cert.c b/src/nxt_cert.c index 1806bc19..01d413e0 100644 --- a/src/nxt_cert.c +++ b/src/nxt_cert.c @@ -1135,7 +1135,17 @@ nxt_cert_store_get_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg) port = nxt_runtime_port_find(task->thread->runtime, msg->port_msg.pid, msg->port_msg.reply_port); - if (port == NULL) { + if (nxt_slow_path(port == NULL)) { + nxt_alert(task, "process port not found (pid %PI, reply_port %d)", + msg->port_msg.pid, msg->port_msg.reply_port); + return; + } + + if (nxt_slow_path(port->type != NXT_PROCESS_CONTROLLER + && port->type != NXT_PROCESS_ROUTER)) + { + nxt_alert(task, "process %PI cannot store certificates", + msg->port_msg.pid); return; } @@ -1206,10 +1216,23 @@ nxt_cert_store_delete_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg) { u_char *p; nxt_str_t name; + nxt_port_t *ctl_port; nxt_runtime_t *rt; nxt_file_name_t *path; rt = task->thread->runtime; + ctl_port = rt->port_by_type[NXT_PROCESS_CONTROLLER]; + + if (nxt_slow_path(ctl_port == NULL)) { + nxt_alert(task, "controller port not found"); + return; + } + + if (nxt_slow_path(nxt_recv_msg_cmsg_pid(msg) != ctl_port->pid)) { + nxt_alert(task, "process %PI cannot delete certificates", + nxt_recv_msg_cmsg_pid(msg)); + return; + } if (nxt_slow_path(rt->certs.start == NULL)) { nxt_alert(task, "no certificates storage directory"); diff --git a/src/nxt_main_process.c b/src/nxt_main_process.c index fe21aeb5..3ca46202 100644 --- a/src/nxt_main_process.c +++ b/src/nxt_main_process.c @@ -355,6 +355,19 @@ nxt_port_main_start_process_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg) rt = task->thread->runtime; + port = rt->port_by_type[NXT_PROCESS_ROUTER]; + if (nxt_slow_path(port == NULL)) { + nxt_alert(task, "router port not found"); + return; + } + + if (nxt_slow_path(port->pid != nxt_recv_msg_cmsg_pid(msg))) { + nxt_alert(task, "process %PI cannot start processes", + nxt_recv_msg_cmsg_pid(msg)); + + return; + } + process = nxt_main_process_new(task, rt); if (nxt_slow_path(process == NULL)) { return; @@ -1023,6 +1036,13 @@ nxt_main_port_socket_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg) return; } + if (nxt_slow_path(port->type != NXT_PROCESS_ROUTER)) { + nxt_alert(task, "process %PI cannot create listener sockets", + msg->port_msg.pid); + + return; + } + b = msg->buf; sa = (nxt_sockaddr_t *) b->mem.pos; @@ -1266,6 +1286,7 @@ nxt_main_port_modules_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg) rt = task->thread->runtime; if (msg->port_msg.pid != rt->port_by_type[NXT_PROCESS_DISCOVERY]->pid) { + nxt_alert(task, "process %PI cannot send modules", msg->port_msg.pid); return; } @@ -1428,9 +1449,19 @@ nxt_main_port_conf_store_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg) void *p; size_t n, size; nxt_int_t ret; + nxt_port_t *ctl_port; nxt_runtime_t *rt; u_char ver[NXT_INT_T_LEN]; + rt = task->thread->runtime; + + ctl_port = rt->port_by_type[NXT_PROCESS_CONTROLLER]; + + if (nxt_slow_path(msg->port_msg.pid != ctl_port->pid)) { + nxt_alert(task, "process %PI cannot store conf", msg->port_msg.pid); + return; + } + p = MAP_FAILED; /* @@ -1463,8 +1494,6 @@ nxt_main_port_conf_store_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg) nxt_debug(task, "conf_store_handler(%uz): %*s", size, size, p); - rt = task->thread->runtime; - if (nxt_conf_ver != NXT_VERNUM) { n = nxt_sprintf(ver, ver + NXT_INT_T_LEN, "%d", NXT_VERNUM) - ver; diff --git a/src/nxt_port.h b/src/nxt_port.h index c698a49c..d7fc8d73 100644 --- a/src/nxt_port.h +++ b/src/nxt_port.h @@ -153,7 +153,9 @@ typedef enum { /* Passed as a first iov chunk. */ typedef struct { uint32_t stream; - nxt_pid_t pid; + + nxt_pid_t pid; /* not used on Linux and FreeBSD */ + nxt_port_id_t reply_port; uint8_t type; @@ -186,6 +188,9 @@ typedef struct { uint8_t allocated; /* 1 bit */ } nxt_port_send_msg_t; +#if (NXT_HAVE_UCRED) || (NXT_HAVE_MSGHDR_CMSGCRED) +#define NXT_USE_CMSG_PID 1 +#endif struct nxt_port_recv_msg_s { nxt_fd_t fd[2]; @@ -193,6 +198,9 @@ struct nxt_port_recv_msg_s { nxt_port_t *port; nxt_port_msg_t port_msg; size_t size; +#if (NXT_USE_CMSG_PID) + nxt_pid_t cmsg_pid; +#endif nxt_bool_t cancelled; union { nxt_port_t *new_port; @@ -201,6 +209,15 @@ struct nxt_port_recv_msg_s { } u; }; + +#if (NXT_USE_CMSG_PID) +#define nxt_recv_msg_cmsg_pid(msg) ((msg)->cmsg_pid) +#define nxt_recv_msg_cmsg_pid_ref(msg) (&(msg)->cmsg_pid) +#else +#define nxt_recv_msg_cmsg_pid(msg) ((msg)->port_msg.pid) +#define nxt_recv_msg_cmsg_pid_ref(msg) (NULL) +#endif + typedef struct nxt_app_s nxt_app_t; struct nxt_port_s { diff --git a/src/nxt_port_rpc.c b/src/nxt_port_rpc.c index f4008a18..0cac5cbb 100644 --- a/src/nxt_port_rpc.c +++ b/src/nxt_port_rpc.c @@ -393,8 +393,8 @@ nxt_port_rpc_remove_peer(nxt_task_t *task, nxt_port_t *port, nxt_pid_t peer) msg.fd[1] = -1; msg.buf = &buf; msg.port = port; - - msg.port_msg.pid = peer; + msg.u.removed_pid = peer; + msg.port_msg.pid = nxt_pid; msg.port_msg.type = _NXT_PORT_MSG_REMOVE_PID; peer_link = lhq.value; diff --git a/src/nxt_port_socket.c b/src/nxt_port_socket.c index ba1b7081..2a51dfb6 100644 --- a/src/nxt_port_socket.c +++ b/src/nxt_port_socket.c @@ -5,6 +5,7 @@ */ #include <nxt_main.h> +#include <nxt_socket_msg.h> #include <nxt_port_queue.h> #include <nxt_port_memory_int.h> @@ -22,6 +23,7 @@ static nxt_port_send_msg_t *nxt_port_msg_alloc(nxt_port_send_msg_t *m); static void nxt_port_write_handler(nxt_task_t *task, void *obj, void *data); static nxt_port_send_msg_t *nxt_port_msg_first(nxt_port_t *port); nxt_inline void nxt_port_msg_close_fd(nxt_port_send_msg_t *msg); +nxt_inline void nxt_port_close_fds(nxt_fd_t *fd); static nxt_buf_t *nxt_port_buf_completion(nxt_task_t *task, nxt_work_queue_t *wq, nxt_buf_t *b, size_t sent, nxt_bool_t mmap_mode); static nxt_port_send_msg_t *nxt_port_msg_insert_tail(nxt_port_t *port, @@ -593,16 +595,21 @@ nxt_port_msg_close_fd(nxt_port_send_msg_t *msg) return; } - if (msg->fd[0] != -1) { - nxt_fd_close(msg->fd[0]); + nxt_port_close_fds(msg->fd); +} - msg->fd[0] = -1; - } - if (msg->fd[1] != -1) { - nxt_fd_close(msg->fd[1]); +nxt_inline void +nxt_port_close_fds(nxt_fd_t *fd) +{ + if (fd[0] != -1) { + nxt_fd_close(fd[0]); + fd[0] = -1; + } - msg->fd[1] = -1; + if (fd[1] != -1) { + nxt_fd_close(fd[1]); + fd[1] = -1; } } @@ -725,16 +732,17 @@ nxt_port_read_handler(nxt_task_t *task, void *obj, void *data) { ssize_t n; nxt_buf_t *b; + nxt_int_t ret; nxt_port_t *port; - struct iovec iov[2]; + nxt_recv_oob_t oob; nxt_port_recv_msg_t msg; + struct iovec iov[2]; port = msg.port = nxt_container_of(obj, nxt_port_t, socket); nxt_assert(port->engine == task->thread->engine); for ( ;; ) { - b = nxt_port_buf_alloc(port); if (nxt_slow_path(b == NULL)) { @@ -747,9 +755,22 @@ nxt_port_read_handler(nxt_task_t *task, void *obj, void *data) iov[1].iov_base = b->mem.pos; iov[1].iov_len = port->max_size; - n = nxt_socketpair_recv(&port->socket, msg.fd, iov, 2); + n = nxt_socketpair_recv(&port->socket, iov, 2, &oob); if (n > 0) { + msg.fd[0] = -1; + msg.fd[1] = -1; + + ret = nxt_socket_msg_oob_get(&oob, msg.fd, + nxt_recv_msg_cmsg_pid_ref(&msg)); + if (nxt_slow_path(ret != NXT_OK)) { + nxt_alert(task, "failed to get oob data from %d", + port->socket.fd); + + nxt_port_close_fds(msg.fd); + + goto fail; + } msg.buf = b; msg.size = n; @@ -778,8 +799,8 @@ nxt_port_read_handler(nxt_task_t *task, void *obj, void *data) return; } - /* n == 0 || n == NXT_ERROR */ - +fail: + /* n == 0 || error */ nxt_work_queue_add(&task->thread->engine->fast_work_queue, nxt_port_error_handler, task, &port->socket, NULL); return; @@ -792,8 +813,10 @@ nxt_port_queue_read_handler(nxt_task_t *task, void *obj, void *data) { ssize_t n; nxt_buf_t *b; + nxt_int_t ret; nxt_port_t *port; struct iovec iov[2]; + nxt_recv_oob_t oob; nxt_port_queue_t *queue; nxt_port_recv_msg_t msg, *smsg; uint8_t qmsg[NXT_PORT_QUEUE_MSG_SIZE]; @@ -884,7 +907,23 @@ nxt_port_queue_read_handler(nxt_task_t *task, void *obj, void *data) iov[1].iov_base = b->mem.pos; iov[1].iov_len = port->max_size; - n = nxt_socketpair_recv(&port->socket, msg.fd, iov, 2); + n = nxt_socketpair_recv(&port->socket, iov, 2, &oob); + + if (n > 0) { + msg.fd[0] = -1; + msg.fd[1] = -1; + + ret = nxt_socket_msg_oob_get(&oob, msg.fd, + nxt_recv_msg_cmsg_pid_ref(&msg)); + if (nxt_slow_path(ret != NXT_OK)) { + nxt_alert(task, "failed to get oob data from %d", + port->socket.fd); + + nxt_port_close_fds(msg.fd); + + return; + } + } if (n == (ssize_t) sizeof(nxt_port_msg_t) && msg.port_msg.type == _NXT_PORT_MSG_READ_QUEUE) @@ -1139,13 +1178,7 @@ nxt_port_read_msg_process(nxt_task_t *task, nxt_port_t *port, nxt_alert(task, "port %d: too small message:%uz", port->socket.fd, msg->size); - if (msg->fd[0] != -1) { - nxt_fd_close(msg->fd[0]); - } - - if (msg->fd[1] != -1) { - nxt_fd_close(msg->fd[1]); - } + nxt_port_close_fds(msg->fd); return; } @@ -1225,13 +1258,7 @@ nxt_port_read_msg_process(nxt_task_t *task, nxt_port_t *port, b = NULL; } else { - if (msg->fd[0] != -1) { - nxt_fd_close(msg->fd[0]); - } - - if (msg->fd[1] != -1) { - nxt_fd_close(msg->fd[1]); - } + nxt_port_close_fds(msg->fd); } } else { if (nxt_fast_path(msg->cancelled == 0)) { diff --git a/src/nxt_socket.h b/src/nxt_socket.h index 7403de3d..ec21d779 100644 --- a/src/nxt_socket.h +++ b/src/nxt_socket.h @@ -114,8 +114,8 @@ NXT_EXPORT nxt_int_t nxt_socketpair_create(nxt_task_t *task, NXT_EXPORT void nxt_socketpair_close(nxt_task_t *task, nxt_socket_t *pair); NXT_EXPORT ssize_t nxt_socketpair_send(nxt_fd_event_t *ev, nxt_fd_t *fd, nxt_iobuf_t *iob, nxt_uint_t niob); -NXT_EXPORT ssize_t nxt_socketpair_recv(nxt_fd_event_t *ev, nxt_fd_t *fd, - nxt_iobuf_t *iob, nxt_uint_t niob); +NXT_EXPORT ssize_t nxt_socketpair_recv(nxt_fd_event_t *ev, + nxt_iobuf_t *iob, nxt_uint_t niob, void *oob); #define \ diff --git a/src/nxt_socket_msg.c b/src/nxt_socket_msg.c new file mode 100644 index 00000000..3b35ab29 --- /dev/null +++ b/src/nxt_socket_msg.c @@ -0,0 +1,57 @@ +/* + * Copyright (C) Igor Sysoev + * Copyright (C) NGINX, Inc. + */ + +#include <nxt_main.h> +#include <nxt_socket_msg.h> + + +ssize_t +nxt_sendmsg(nxt_socket_t s, nxt_iobuf_t *iob, nxt_uint_t niob, + const nxt_send_oob_t *oob) +{ + struct msghdr msg; + + msg.msg_name = NULL; + msg.msg_namelen = 0; + msg.msg_iov = iob; + msg.msg_iovlen = niob; + /* Flags are cleared just to suppress valgrind warning. */ + msg.msg_flags = 0; + + if (oob != NULL && oob->size != 0) { + msg.msg_control = (void *) oob->buf; + msg.msg_controllen = oob->size; + + } else { + msg.msg_control = NULL; + msg.msg_controllen = 0; + } + + return sendmsg(s, &msg, 0); +} + + +ssize_t +nxt_recvmsg(nxt_socket_t s, nxt_iobuf_t *iob, nxt_uint_t niob, + nxt_recv_oob_t *oob) +{ + ssize_t n; + struct msghdr msg; + + msg.msg_name = NULL; + msg.msg_namelen = 0; + msg.msg_iov = iob; + msg.msg_iovlen = niob; + msg.msg_control = oob->buf; + msg.msg_controllen = sizeof(oob->buf); + + n = recvmsg(s, &msg, 0); + + if (nxt_fast_path(n != -1)) { + oob->size = msg.msg_controllen; + } + + return n; +} diff --git a/src/nxt_socket_msg.h b/src/nxt_socket_msg.h new file mode 100644 index 00000000..04de1761 --- /dev/null +++ b/src/nxt_socket_msg.h @@ -0,0 +1,220 @@ +/* + * Copyright (C) NGINX, Inc. + */ + +#ifndef _NXT_SOCKET_MSG_H_INCLUDED_ +#define _NXT_SOCKET_MSG_H_INCLUDED_ + +#if (NXT_HAVE_UCRED) +#include <sys/un.h> +#endif + + +#if (NXT_HAVE_UCRED) +#define NXT_CRED_USECMSG 1 +#define NXT_CRED_CMSGTYPE SCM_CREDENTIALS +#define NXT_CRED_GETPID(u) (u->pid) + +typedef struct ucred nxt_socket_cred_t; + +#elif (NXT_HAVE_MSGHDR_CMSGCRED) +#define NXT_CRED_USECMSG 1 +#define NXT_CRED_CMSGTYPE SCM_CREDS +#define NXT_CRED_GETPID(u) (u->cmcred_pid) + +typedef struct cmsgcred nxt_socket_cred_t; +#endif + +#if (NXT_CRED_USECMSG) +#define NXT_OOB_RECV_SIZE \ + (CMSG_SPACE(2 * sizeof(int)) + CMSG_SPACE(sizeof(nxt_socket_cred_t))) +#else +#define NXT_OOB_RECV_SIZE \ + CMSG_SPACE(2 * sizeof(int)) +#endif + +#if (NXT_HAVE_MSGHDR_CMSGCRED) +#define NXT_OOB_SEND_SIZE \ + (CMSG_SPACE(2 * sizeof(int)) + CMSG_SPACE(sizeof(nxt_socket_cred_t))) +#else +#define NXT_OOB_SEND_SIZE \ + CMSG_SPACE(2 * sizeof(int)) +#endif + + +typedef struct { + size_t size; + u_char buf[NXT_OOB_RECV_SIZE]; +} nxt_recv_oob_t; + + +typedef struct { + size_t size; + u_char buf[NXT_OOB_SEND_SIZE]; +} nxt_send_oob_t; + + +/** + * The nxt_sendmsg is a wrapper for sendmsg. + * The oob struct must be initialized using nxt_socket_msg_oob_init(). + */ +NXT_EXPORT ssize_t nxt_sendmsg(nxt_socket_t s, nxt_iobuf_t *iob, + nxt_uint_t niob, const nxt_send_oob_t *oob); + +/** + * The nxt_recvmsg is a wrapper for recvmsg. + * The oob buffer must be consumed by using nxt_socket_msg_oob_get(). + */ +NXT_EXPORT ssize_t nxt_recvmsg(nxt_socket_t s, + nxt_iobuf_t *iob, nxt_uint_t niob, nxt_recv_oob_t *oob); + + +nxt_inline void +nxt_socket_msg_oob_init(nxt_send_oob_t *oob, int *fds) +{ + int nfds; + struct cmsghdr *cmsg; + +#if (NXT_HAVE_MSGHDR_CMSGCRED) + cmsg = (struct cmsghdr *) (oob->buf); + /* + * Fill all padding fields with 0. + * Code in Go 1.11 validate cmsghdr using padding field as part of len. + * See Cmsghdr definition and socketControlMessageHeaderAndData function. + */ + nxt_memzero(cmsg, sizeof(struct cmsghdr)); + + cmsg->cmsg_len = CMSG_LEN(sizeof(nxt_socket_cred_t)); + cmsg->cmsg_level = SOL_SOCKET; + cmsg->cmsg_type = NXT_CRED_CMSGTYPE; + + oob->size = CMSG_SPACE(sizeof(nxt_socket_cred_t)); + +#else + oob->size = 0; +#endif + + nfds = (fds[0] != -1 ? 1 : 0) + (fds[1] != -1 ? 1 : 0); + + if (nfds == 0) { + return; + } + + cmsg = (struct cmsghdr *) (oob->buf + oob->size); + + nxt_memzero(cmsg, sizeof(struct cmsghdr)); + + cmsg->cmsg_len = CMSG_LEN(nfds * sizeof(int)); + cmsg->cmsg_level = SOL_SOCKET; + cmsg->cmsg_type = SCM_RIGHTS; + + /* + * nxt_memcpy() is used instead of simple + * *(int *) CMSG_DATA(&cmsg.cm) = fd; + * because GCC 4.4 with -O2/3/s optimization may issue a warning: + * dereferencing type-punned pointer will break strict-aliasing rules + * + * Fortunately, GCC with -O1 compiles this nxt_memcpy() + * in the same simple assignment as in the code above. + */ + nxt_memcpy(CMSG_DATA(cmsg), fds, nfds * sizeof(int)); + + oob->size += CMSG_SPACE(nfds * sizeof(int)); +} + + +nxt_inline nxt_int_t +nxt_socket_msg_oob_get_fds(nxt_recv_oob_t *oob, nxt_fd_t *fd) +{ + size_t size; + struct msghdr msg; + struct cmsghdr *cmsg; + + msg.msg_control = oob->buf; + msg.msg_controllen = oob->size; + + for (cmsg = CMSG_FIRSTHDR(&msg); + cmsg != NULL; + cmsg = CMSG_NXTHDR(&msg, cmsg)) + { + size = cmsg->cmsg_len - CMSG_LEN(0); + + if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_RIGHTS) { + if (nxt_slow_path(size != sizeof(int) && size != 2 * sizeof(int))) { + return NXT_ERROR; + } + + nxt_memcpy(fd, CMSG_DATA(cmsg), size); + + return NXT_OK; + } + } + + return NXT_OK; +} + + +nxt_inline nxt_int_t +nxt_socket_msg_oob_get(nxt_recv_oob_t *oob, nxt_fd_t *fd, nxt_pid_t *pid) +{ + size_t size; + struct msghdr msg; + struct cmsghdr *cmsg; + + if (oob->size == 0) { + return NXT_OK; + } + +#if (NXT_CRED_USECMSG) + *pid = -1; +#endif + + msg.msg_control = oob->buf; + msg.msg_controllen = oob->size; + + for (cmsg = CMSG_FIRSTHDR(&msg); + cmsg != NULL; + cmsg = CMSG_NXTHDR(&msg, cmsg)) + { + size = cmsg->cmsg_len - CMSG_LEN(0); + + if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_RIGHTS) { + if (nxt_slow_path(size != sizeof(int) && size != 2 * sizeof(int))) { + return NXT_ERROR; + } + + nxt_memcpy(fd, CMSG_DATA(cmsg), size); + +#if (!NXT_CRED_USECMSG) + break; +#endif + } + +#if (NXT_CRED_USECMSG) + else if (cmsg->cmsg_level == SOL_SOCKET + && cmsg->cmsg_type == NXT_CRED_CMSGTYPE) + { + nxt_socket_cred_t *creds; + + if (nxt_slow_path(size != sizeof(nxt_socket_cred_t))) { + return NXT_ERROR; + } + + creds = (nxt_socket_cred_t *) CMSG_DATA(cmsg); + *pid = NXT_CRED_GETPID(creds); + } +#endif + } + +#if (NXT_CRED_USECMSG) + /* For platforms supporting credential passing, it's enforced */ + if (nxt_slow_path(*pid == -1)) { + return NXT_ERROR; + } +#endif + + return NXT_OK; +} + + +#endif /* _NXT_SOCKET_MSG_H_INCLUDED_ */ diff --git a/src/nxt_socketpair.c b/src/nxt_socketpair.c index 8b9d12bf..45274b78 100644 --- a/src/nxt_socketpair.c +++ b/src/nxt_socketpair.c @@ -5,7 +5,7 @@ */ #include <nxt_main.h> - +#include <nxt_socket_msg.h> /* * SOCK_SEQPACKET protocol is supported for AF_UNIX in Solaris 8 X/Open @@ -20,12 +20,6 @@ #endif -static ssize_t nxt_sendmsg(nxt_socket_t s, nxt_fd_t *fd, nxt_iobuf_t *iob, - nxt_uint_t niob); -static ssize_t nxt_recvmsg(nxt_socket_t s, nxt_fd_t *fd, nxt_iobuf_t *iob, - nxt_uint_t niob); - - nxt_int_t nxt_socketpair_create(nxt_task_t *task, nxt_socket_t *pair) { @@ -52,6 +46,24 @@ nxt_socketpair_create(nxt_task_t *task, nxt_socket_t *pair) goto fail; } +#if NXT_HAVE_SOCKOPT_SO_PASSCRED + int enable_creds = 1; + + if (nxt_slow_path(setsockopt(pair[0], SOL_SOCKET, SO_PASSCRED, + &enable_creds, sizeof(enable_creds)) == -1)) + { + nxt_alert(task, "failed to set SO_PASSCRED %E", nxt_errno); + goto fail; + } + + if (nxt_slow_path(setsockopt(pair[1], SOL_SOCKET, SO_PASSCRED, + &enable_creds, sizeof(enable_creds)) == -1)) + { + nxt_alert(task, "failed to set SO_PASSCRED %E", nxt_errno); + goto fail; + } +#endif + return NXT_OK; fail: @@ -74,11 +86,14 @@ ssize_t nxt_socketpair_send(nxt_fd_event_t *ev, nxt_fd_t *fd, nxt_iobuf_t *iob, nxt_uint_t niob) { - ssize_t n; - nxt_err_t err; + ssize_t n; + nxt_err_t err; + nxt_send_oob_t oob; + + nxt_socket_msg_oob_init(&oob, fd); for ( ;; ) { - n = nxt_sendmsg(ev->fd, fd, iob, niob); + n = nxt_sendmsg(ev->fd, iob, niob, &oob); err = (n == -1) ? nxt_socket_errno : 0; @@ -123,19 +138,19 @@ nxt_socketpair_send(nxt_fd_event_t *ev, nxt_fd_t *fd, nxt_iobuf_t *iob, ssize_t -nxt_socketpair_recv(nxt_fd_event_t *ev, nxt_fd_t *fd, nxt_iobuf_t *iob, - nxt_uint_t niob) +nxt_socketpair_recv(nxt_fd_event_t *ev, nxt_iobuf_t *iob, nxt_uint_t niob, + void *oob) { ssize_t n; nxt_err_t err; for ( ;; ) { - n = nxt_recvmsg(ev->fd, fd, iob, niob); + n = nxt_recvmsg(ev->fd, iob, niob, oob); err = (n == -1) ? nxt_socket_errno : 0; - nxt_debug(ev->task, "recvmsg(%d, %FD, %FD, %ui): %z", ev->fd, fd[0], - fd[1], niob, n); + nxt_debug(ev->task, "recvmsg(%d, %ui, %uz): %z", + ev->fd, niob, ((nxt_recv_oob_t *) oob)->size, n); if (n > 0) { return n; @@ -163,162 +178,10 @@ nxt_socketpair_recv(nxt_fd_event_t *ev, nxt_fd_t *fd, nxt_iobuf_t *iob, continue; default: - nxt_alert(ev->task, "recvmsg(%d, %p, %ui) failed %E", - ev->fd, fd, niob, err); + nxt_alert(ev->task, "recvmsg(%d, %ui) failed %E", + ev->fd, niob, err); return NXT_ERROR; } } } - - -#if (NXT_HAVE_MSGHDR_MSG_CONTROL) - -/* - * Linux, FreeBSD, Solaris X/Open sockets, - * MacOSX, NetBSD, AIX, HP-UX X/Open sockets. - */ - -static ssize_t -nxt_sendmsg(nxt_socket_t s, nxt_fd_t *fd, nxt_iobuf_t *iob, nxt_uint_t niob) -{ - size_t csize; - struct msghdr msg; - union { - struct cmsghdr cm; - char space[CMSG_SPACE(sizeof(int) * 2)]; - } cmsg; - - msg.msg_name = NULL; - msg.msg_namelen = 0; - msg.msg_iov = iob; - msg.msg_iovlen = niob; - /* Flags are cleared just to suppress valgrind warning. */ - msg.msg_flags = 0; - - if (fd[0] != -1) { - csize = (fd[1] == -1) ? sizeof(int) : sizeof(int) * 2; - - msg.msg_control = (caddr_t) &cmsg; - msg.msg_controllen = CMSG_SPACE(csize); - -#if (NXT_VALGRIND) - nxt_memzero(&cmsg, sizeof(cmsg)); -#endif - - cmsg.cm.cmsg_len = CMSG_LEN(csize); - cmsg.cm.cmsg_level = SOL_SOCKET; - cmsg.cm.cmsg_type = SCM_RIGHTS; - - /* - * nxt_memcpy() is used instead of simple - * *(int *) CMSG_DATA(&cmsg.cm) = fd; - * because GCC 4.4 with -O2/3/s optimization may issue a warning: - * dereferencing type-punned pointer will break strict-aliasing rules - * - * Fortunately, GCC with -O1 compiles this nxt_memcpy() - * in the same simple assignment as in the code above. - */ - nxt_memcpy(CMSG_DATA(&cmsg.cm), fd, csize); - - } else { - msg.msg_control = NULL; - msg.msg_controllen = 0; - } - - return sendmsg(s, &msg, 0); -} - - -static ssize_t -nxt_recvmsg(nxt_socket_t s, nxt_fd_t *fd, nxt_iobuf_t *iob, nxt_uint_t niob) -{ - ssize_t n; - struct msghdr msg; - union { - struct cmsghdr cm; - char space[CMSG_SPACE(sizeof(int) * 2)]; - } cmsg; - - msg.msg_name = NULL; - msg.msg_namelen = 0; - msg.msg_iov = iob; - msg.msg_iovlen = niob; - msg.msg_control = (caddr_t) &cmsg; - msg.msg_controllen = sizeof(cmsg); - - fd[0] = -1; - fd[1] = -1; - -#if (NXT_VALGRIND) - nxt_memzero(&cmsg, sizeof(cmsg)); -#endif - - n = recvmsg(s, &msg, 0); - - if (n > 0 - && cmsg.cm.cmsg_level == SOL_SOCKET - && cmsg.cm.cmsg_type == SCM_RIGHTS) - { - if (cmsg.cm.cmsg_len == CMSG_LEN(sizeof(int))) { - nxt_memcpy(fd, CMSG_DATA(&cmsg.cm), sizeof(int)); - } - - if (cmsg.cm.cmsg_len == CMSG_LEN(sizeof(int) * 2)) { - nxt_memcpy(fd, CMSG_DATA(&cmsg.cm), sizeof(int) * 2); - } - } - - return n; -} - -#else - -/* Solaris 4.3BSD sockets. */ - -static ssize_t -nxt_sendmsg(nxt_socket_t s, nxt_fd_t *fd, nxt_iobuf_t *iob, nxt_uint_t niob) -{ - struct msghdr msg; - - msg.msg_name = NULL; - msg.msg_namelen = 0; - msg.msg_iov = iob; - msg.msg_iovlen = niob; - - if (fd[0] != -1) { - msg.msg_accrights = (caddr_t) fd; - msg.msg_accrightslen = sizeof(int); - - if (fd[1] != -1) { - msg.msg_accrightslen += sizeof(int); - } - - } else { - msg.msg_accrights = NULL; - msg.msg_accrightslen = 0; - } - - return sendmsg(s, &msg, 0); -} - - -static ssize_t -nxt_recvmsg(nxt_socket_t s, nxt_fd_t *fd, nxt_iobuf_t *iob, nxt_uint_t niob) -{ - struct msghdr msg; - - fd[0] = -1; - fd[1] = -1; - - msg.msg_name = NULL; - msg.msg_namelen = 0; - msg.msg_iov = iob; - msg.msg_iovlen = niob; - msg.msg_accrights = (caddr_t) fd; - msg.msg_accrightslen = sizeof(int) * 2; - - return recvmsg(s, &msg, 0); -} - -#endif diff --git a/src/nxt_unit.c b/src/nxt_unit.c index 3a31becd..a29c3fb9 100644 --- a/src/nxt_unit.c +++ b/src/nxt_unit.c @@ -3,10 +3,9 @@ * Copyright (C) NGINX, Inc. */ -#include <stdlib.h> - #include "nxt_main.h" #include "nxt_port_memory_int.h" +#include "nxt_socket_msg.h" #include "nxt_port_queue.h" #include "nxt_app_queue.h" @@ -168,9 +167,9 @@ static void nxt_unit_quit(nxt_unit_ctx_t *ctx, uint8_t quit_param); static int nxt_unit_get_port(nxt_unit_ctx_t *ctx, nxt_unit_port_id_t *port_id); static ssize_t nxt_unit_port_send(nxt_unit_ctx_t *ctx, nxt_unit_port_t *port, const void *buf, size_t buf_size, - const void *oob, size_t oob_size); + const nxt_send_oob_t *oob); static ssize_t nxt_unit_sendmsg(nxt_unit_ctx_t *ctx, int fd, - const void *buf, size_t buf_size, const void *oob, size_t oob_size); + const void *buf, size_t buf_size, const nxt_send_oob_t *oob); static int nxt_unit_ctx_port_recv(nxt_unit_ctx_t *ctx, nxt_unit_port_t *port, nxt_unit_read_buf_t *rbuf); nxt_inline void nxt_unit_rbuf_cpy(nxt_unit_read_buf_t *dst, @@ -278,8 +277,8 @@ struct nxt_unit_read_buf_s { nxt_queue_link_t link; nxt_unit_ctx_impl_t *ctx_impl; ssize_t size; + nxt_recv_oob_t oob; char buf[16384]; - char oob[256]; }; @@ -891,13 +890,10 @@ static int nxt_unit_ready(nxt_unit_ctx_t *ctx, int ready_fd, uint32_t stream, int queue_fd) { ssize_t res; + nxt_send_oob_t oob; nxt_port_msg_t msg; nxt_unit_impl_t *lib; - - union { - struct cmsghdr cm; - char space[CMSG_SPACE(sizeof(int))]; - } cmsg; + int fds[2] = {queue_fd, -1}; lib = nxt_container_of(ctx->unit, nxt_unit_impl_t, unit); @@ -911,25 +907,9 @@ nxt_unit_ready(nxt_unit_ctx_t *ctx, int ready_fd, uint32_t stream, int queue_fd) msg.mf = 0; msg.tracking = 0; - memset(&cmsg, 0, sizeof(cmsg)); - - cmsg.cm.cmsg_len = CMSG_LEN(sizeof(int)); - cmsg.cm.cmsg_level = SOL_SOCKET; - cmsg.cm.cmsg_type = SCM_RIGHTS; - - /* - * memcpy() is used instead of simple - * *(int *) CMSG_DATA(&cmsg.cm) = fd; - * because GCC 4.4 with -O2/3/s optimization may issue a warning: - * dereferencing type-punned pointer will break strict-aliasing rules - * - * Fortunately, GCC with -O1 compiles this nxt_memcpy() - * in the same simple assignment as in the code above. - */ - memcpy(CMSG_DATA(&cmsg.cm), &queue_fd, sizeof(int)); + nxt_socket_msg_oob_init(&oob, fds); - res = nxt_unit_sendmsg(ctx, ready_fd, &msg, sizeof(msg), - &cmsg, sizeof(cmsg)); + res = nxt_unit_sendmsg(ctx, ready_fd, &msg, sizeof(msg), &oob); if (res != sizeof(msg)) { return NXT_UNIT_ERROR; } @@ -945,7 +925,6 @@ nxt_unit_process_msg(nxt_unit_ctx_t *ctx, nxt_unit_read_buf_t *rbuf, int rc; pid_t pid; uint8_t quit_param; - struct cmsghdr *cm; nxt_port_msg_t *port_msg; nxt_unit_impl_t *lib; nxt_unit_recv_msg_t recv_msg; @@ -955,18 +934,12 @@ nxt_unit_process_msg(nxt_unit_ctx_t *ctx, nxt_unit_read_buf_t *rbuf, recv_msg.fd[0] = -1; recv_msg.fd[1] = -1; port_msg = (nxt_port_msg_t *) rbuf->buf; - cm = (struct cmsghdr *) rbuf->oob; - if (cm->cmsg_level == SOL_SOCKET - && cm->cmsg_type == SCM_RIGHTS) - { - if (cm->cmsg_len == CMSG_LEN(sizeof(int))) { - memcpy(recv_msg.fd, CMSG_DATA(cm), sizeof(int)); - } - - if (cm->cmsg_len == CMSG_LEN(sizeof(int) * 2)) { - memcpy(recv_msg.fd, CMSG_DATA(cm), sizeof(int) * 2); - } + rc = nxt_socket_msg_oob_get_fds(&rbuf->oob, recv_msg.fd); + if (nxt_slow_path(rc != NXT_OK)) { + nxt_unit_alert(ctx, "failed to receive file descriptor over cmsg"); + rc = NXT_UNIT_ERROR; + goto done; } recv_msg.incoming_buf = NULL; @@ -1607,7 +1580,7 @@ nxt_unit_send_req_headers_ack(nxt_unit_request_info_t *req) msg.type = _NXT_PORT_MSG_REQ_HEADERS_ACK; res = nxt_unit_port_send(req->ctx, req->response_port, - &msg, sizeof(msg), NULL, 0); + &msg, sizeof(msg), NULL); if (nxt_slow_path(res != sizeof(msg))) { return NXT_UNIT_ERROR; } @@ -2673,7 +2646,7 @@ nxt_unit_mmap_buf_send(nxt_unit_request_info_t *req, (int) m.mmap_msg.size); res = nxt_unit_port_send(req->ctx, req->response_port, &m, sizeof(m), - NULL, 0); + NULL); if (nxt_slow_path(res != sizeof(m))) { goto free_buf; } @@ -2725,8 +2698,8 @@ nxt_unit_mmap_buf_send(nxt_unit_request_info_t *req, res = nxt_unit_port_send(req->ctx, req->response_port, buf->start - sizeof(m.msg), - m.mmap_msg.size + sizeof(m.msg), - NULL, 0); + m.mmap_msg.size + sizeof(m.msg), NULL); + if (nxt_slow_path(res != (ssize_t) (m.mmap_msg.size + sizeof(m.msg)))) { goto free_buf; } @@ -2793,7 +2766,7 @@ nxt_unit_read_buf_get(nxt_unit_ctx_t *ctx) pthread_mutex_unlock(&ctx_impl->mutex); - memset(rbuf->oob, 0, sizeof(struct cmsghdr)); + rbuf->oob.size = 0; return rbuf; } @@ -3312,7 +3285,7 @@ skip_response_send: msg.tracking = 0; (void) nxt_unit_port_send(req->ctx, req->response_port, - &msg, sizeof(msg), NULL, 0); + &msg, sizeof(msg), NULL); nxt_unit_request_info_release(req); } @@ -3634,7 +3607,7 @@ nxt_unit_send_oosm(nxt_unit_ctx_t *ctx, nxt_unit_port_t *port) msg.mf = 0; msg.tracking = 0; - res = nxt_unit_port_send(ctx, lib->router_port, &msg, sizeof(msg), NULL, 0); + res = nxt_unit_port_send(ctx, lib->router_port, &msg, sizeof(msg), NULL); if (nxt_slow_path(res != sizeof(msg))) { return NXT_UNIT_ERROR; } @@ -3903,12 +3876,10 @@ static int nxt_unit_send_mmap(nxt_unit_ctx_t *ctx, nxt_unit_port_t *port, int fd) { ssize_t res; + nxt_send_oob_t oob; nxt_port_msg_t msg; nxt_unit_impl_t *lib; - union { - struct cmsghdr cm; - char space[CMSG_SPACE(sizeof(int))]; - } cmsg; + int fds[2] = {fd, -1}; lib = nxt_container_of(ctx->unit, nxt_unit_impl_t, unit); @@ -3922,30 +3893,9 @@ nxt_unit_send_mmap(nxt_unit_ctx_t *ctx, nxt_unit_port_t *port, int fd) msg.mf = 0; msg.tracking = 0; - /* - * Fill all padding fields with 0. - * Code in Go 1.11 validate cmsghdr using padding field as part of len. - * See Cmsghdr definition and socketControlMessageHeaderAndData function. - */ - memset(&cmsg, 0, sizeof(cmsg)); - - cmsg.cm.cmsg_len = CMSG_LEN(sizeof(int)); - cmsg.cm.cmsg_level = SOL_SOCKET; - cmsg.cm.cmsg_type = SCM_RIGHTS; + nxt_socket_msg_oob_init(&oob, fds); - /* - * memcpy() is used instead of simple - * *(int *) CMSG_DATA(&cmsg.cm) = fd; - * because GCC 4.4 with -O2/3/s optimization may issue a warning: - * dereferencing type-punned pointer will break strict-aliasing rules - * - * Fortunately, GCC with -O1 compiles this nxt_memcpy() - * in the same simple assignment as in the code above. - */ - memcpy(CMSG_DATA(&cmsg.cm), &fd, sizeof(int)); - - res = nxt_unit_port_send(ctx, port, &msg, sizeof(msg), - &cmsg, sizeof(cmsg)); + res = nxt_unit_port_send(ctx, port, &msg, sizeof(msg), &oob); if (nxt_slow_path(res != sizeof(msg))) { return NXT_UNIT_ERROR; } @@ -4135,7 +4085,7 @@ nxt_unit_awake_ctx(nxt_unit_ctx_t *ctx, nxt_unit_ctx_impl_t *ctx_impl) msg.type = _NXT_PORT_MSG_RPC_READY; (void) nxt_unit_port_send(ctx, ctx_impl->read_port, - &msg, sizeof(msg), NULL, 0); + &msg, sizeof(msg), NULL); } @@ -4358,7 +4308,7 @@ nxt_unit_get_mmap(nxt_unit_ctx_t *ctx, pid_t pid, uint32_t id) nxt_unit_debug(ctx, "get_mmap: %d %d", (int) pid, (int) id); - res = nxt_unit_port_send(ctx, lib->router_port, &m, sizeof(m), NULL, 0); + res = nxt_unit_port_send(ctx, lib->router_port, &m, sizeof(m), NULL); if (nxt_slow_path(res != sizeof(m))) { return NXT_UNIT_ERROR; } @@ -4428,7 +4378,7 @@ nxt_unit_send_shm_ack(nxt_unit_ctx_t *ctx, pid_t pid) msg.mf = 0; msg.tracking = 0; - res = nxt_unit_port_send(ctx, lib->router_port, &msg, sizeof(msg), NULL, 0); + res = nxt_unit_port_send(ctx, lib->router_port, &msg, sizeof(msg), NULL); if (nxt_slow_path(res != sizeof(msg))) { return NXT_UNIT_ERROR; } @@ -4716,7 +4666,7 @@ retry: return (err == EAGAIN) ? NXT_UNIT_AGAIN : NXT_UNIT_ERROR; } - nxt_unit_debug(ctx, "poll(%d,%d): %d, revents [%04uXi, %04uXi]", + nxt_unit_debug(ctx, "poll(%d,%d): %d, revents [%04X, %04X]", fds[0].fd, fds[1].fd, nevents, fds[0].revents, fds[1].revents); @@ -5315,6 +5265,24 @@ nxt_unit_create_port(nxt_unit_ctx_t *ctx) return NULL; } +#if (NXT_HAVE_SOCKOPT_SO_PASSCRED) + int enable_creds = 1; + + if (nxt_slow_path(setsockopt(port_sockets[0], SOL_SOCKET, SO_PASSCRED, + &enable_creds, sizeof(enable_creds)) == -1)) + { + nxt_unit_warn(ctx, "failed to set SO_PASSCRED %s", strerror(errno)); + return NULL; + } + + if (nxt_slow_path(setsockopt(port_sockets[1], SOL_SOCKET, SO_PASSCRED, + &enable_creds, sizeof(enable_creds)) == -1)) + { + nxt_unit_warn(ctx, "failed to set SO_PASSCRED %s", strerror(errno)); + return NULL; + } +#endif + nxt_unit_debug(ctx, "create_port: new socketpair: %d->%d", port_sockets[0], port_sockets[1]); @@ -5355,6 +5323,7 @@ nxt_unit_send_port(nxt_unit_ctx_t *ctx, nxt_unit_port_t *dst, nxt_unit_port_t *port, int queue_fd) { ssize_t res; + nxt_send_oob_t oob; nxt_unit_impl_t *lib; int fds[2] = { port->out_fd, queue_fd }; @@ -5363,11 +5332,6 @@ nxt_unit_send_port(nxt_unit_ctx_t *ctx, nxt_unit_port_t *dst, nxt_port_msg_new_port_t new_port; } m; - union { - struct cmsghdr cm; - char space[CMSG_SPACE(sizeof(int) * 2)]; - } cmsg; - lib = nxt_container_of(ctx->unit, nxt_unit_impl_t, unit); m.msg.stream = 0; @@ -5386,24 +5350,9 @@ nxt_unit_send_port(nxt_unit_ctx_t *ctx, nxt_unit_port_t *dst, m.new_port.max_size = 16 * 1024; m.new_port.max_share = 64 * 1024; - memset(&cmsg, 0, sizeof(cmsg)); + nxt_socket_msg_oob_init(&oob, fds); - cmsg.cm.cmsg_len = CMSG_LEN(sizeof(int) * 2); - cmsg.cm.cmsg_level = SOL_SOCKET; - cmsg.cm.cmsg_type = SCM_RIGHTS; - - /* - * memcpy() is used instead of simple - * *(int *) CMSG_DATA(&cmsg.cm) = fd; - * because GCC 4.4 with -O2/3/s optimization may issue a warning: - * dereferencing type-punned pointer will break strict-aliasing rules - * - * Fortunately, GCC with -O1 compiles this nxt_memcpy() - * in the same simple assignment as in the code above. - */ - memcpy(CMSG_DATA(&cmsg.cm), fds, sizeof(int) * 2); - - res = nxt_unit_port_send(ctx, dst, &m, sizeof(m), &cmsg, sizeof(cmsg)); + res = nxt_unit_port_send(ctx, dst, &m, sizeof(m), &oob); return (res == sizeof(m)) ? NXT_UNIT_OK : NXT_UNIT_ERROR; } @@ -5885,7 +5834,7 @@ nxt_unit_quit(nxt_unit_ctx_t *ctx, uint8_t quit_param) } (void) nxt_unit_port_send(ctx, ctx_impl->read_port, - &m, sizeof(m), NULL, 0); + &m, sizeof(m), NULL); } nxt_queue_loop; @@ -5920,7 +5869,7 @@ nxt_unit_get_port(nxt_unit_ctx_t *ctx, nxt_unit_port_id_t *port_id) nxt_unit_debug(ctx, "get_port: %d %d", (int) port_id->pid, (int) port_id->id); - res = nxt_unit_port_send(ctx, lib->router_port, &m, sizeof(m), NULL, 0); + res = nxt_unit_port_send(ctx, lib->router_port, &m, sizeof(m), NULL); if (nxt_slow_path(res != sizeof(m))) { return NXT_UNIT_ERROR; } @@ -5931,7 +5880,7 @@ nxt_unit_get_port(nxt_unit_ctx_t *ctx, nxt_unit_port_id_t *port_id) static ssize_t nxt_unit_port_send(nxt_unit_ctx_t *ctx, nxt_unit_port_t *port, - const void *buf, size_t buf_size, const void *oob, size_t oob_size) + const void *buf, size_t buf_size, const nxt_send_oob_t *oob) { int notify; ssize_t ret; @@ -5943,7 +5892,7 @@ nxt_unit_port_send(nxt_unit_ctx_t *ctx, nxt_unit_port_t *port, lib = nxt_container_of(ctx->unit, nxt_unit_impl_t, unit); port_impl = nxt_container_of(port, nxt_unit_port_impl_t, port); - if (port_impl->queue != NULL && oob_size == 0 + if (port_impl->queue != NULL && (oob == NULL || oob->size == 0) && buf_size <= NXT_PORT_QUEUE_MSG_SIZE) { rc = nxt_port_queue_send(port_impl->queue, buf, buf_size, ¬ify); @@ -5965,7 +5914,7 @@ nxt_unit_port_send(nxt_unit_ctx_t *ctx, nxt_unit_port_t *port, if (lib->callbacks.port_send == NULL) { ret = nxt_unit_sendmsg(ctx, port->out_fd, &msg, - sizeof(nxt_port_msg_t), NULL, 0); + sizeof(nxt_port_msg_t), NULL); nxt_unit_debug(ctx, "port{%d,%d} send %d read_queue", (int) port->id.pid, (int) port->id.id, @@ -6002,15 +5951,15 @@ nxt_unit_port_send(nxt_unit_ctx_t *ctx, nxt_unit_port_t *port, if (lib->callbacks.port_send != NULL) { ret = lib->callbacks.port_send(ctx, port, buf, buf_size, - oob, oob_size); + oob != NULL ? oob->buf : NULL, + oob != NULL ? oob->size : 0); nxt_unit_debug(ctx, "port{%d,%d} sendcb %d", (int) port->id.pid, (int) port->id.id, (int) ret); } else { - ret = nxt_unit_sendmsg(ctx, port->out_fd, buf, buf_size, - oob, oob_size); + ret = nxt_unit_sendmsg(ctx, port->out_fd, buf, buf_size, oob); nxt_unit_debug(ctx, "port{%d,%d} sendmsg %d", (int) port->id.pid, (int) port->id.id, @@ -6023,29 +5972,20 @@ nxt_unit_port_send(nxt_unit_ctx_t *ctx, nxt_unit_port_t *port, static ssize_t nxt_unit_sendmsg(nxt_unit_ctx_t *ctx, int fd, - const void *buf, size_t buf_size, const void *oob, size_t oob_size) + const void *buf, size_t buf_size, const nxt_send_oob_t *oob) { int err; - ssize_t res; + ssize_t n; struct iovec iov[1]; - struct msghdr msg; iov[0].iov_base = (void *) buf; iov[0].iov_len = buf_size; - msg.msg_name = NULL; - msg.msg_namelen = 0; - msg.msg_iov = iov; - msg.msg_iovlen = 1; - msg.msg_flags = 0; - msg.msg_control = (void *) oob; - msg.msg_controllen = oob_size; - retry: - res = sendmsg(fd, &msg, 0); + n = nxt_sendmsg(fd, iov, 1, oob); - if (nxt_slow_path(res == -1)) { + if (nxt_slow_path(n == -1)) { err = errno; if (err == EINTR) { @@ -6060,11 +6000,11 @@ retry: fd, (int) buf_size, strerror(err), err); } else { - nxt_unit_debug(ctx, "sendmsg(%d, %d): %d", fd, (int) buf_size, - (int) res); + nxt_unit_debug(ctx, "sendmsg(%d, %d, %d): %d", fd, (int) buf_size, + (oob != NULL ? (int) oob->size : 0), (int) n); } - return res; + return n; } @@ -6173,7 +6113,7 @@ retry: nxt_unit_rbuf_cpy(port_impl->socket_rbuf, rbuf); - memset(rbuf->oob, 0, sizeof(struct cmsghdr)); + rbuf->oob.size = 0; goto retry; } @@ -6184,7 +6124,8 @@ nxt_unit_rbuf_cpy(nxt_unit_read_buf_t *dst, nxt_unit_read_buf_t *src) { memcpy(dst->buf, src->buf, src->size); dst->size = src->size; - memcpy(dst->oob, src->oob, sizeof(src->oob)); + dst->oob.size = src->oob.size; + memcpy(dst->oob.buf, src->oob.buf, src->oob.size); } @@ -6230,16 +6171,18 @@ nxt_unit_port_recv(nxt_unit_ctx_t *ctx, nxt_unit_port_t *port, nxt_unit_read_buf_t *rbuf) { int fd, err; + size_t oob_size; struct iovec iov[1]; - struct msghdr msg; nxt_unit_impl_t *lib; lib = nxt_container_of(ctx->unit, nxt_unit_impl_t, unit); if (lib->callbacks.port_recv != NULL) { + oob_size = sizeof(rbuf->oob.buf); + rbuf->size = lib->callbacks.port_recv(ctx, port, rbuf->buf, sizeof(rbuf->buf), - rbuf->oob, sizeof(rbuf->oob)); + rbuf->oob.buf, &oob_size); nxt_unit_debug(ctx, "port{%d,%d} recvcb %d", (int) port->id.pid, (int) port->id.id, (int) rbuf->size); @@ -6248,25 +6191,18 @@ nxt_unit_port_recv(nxt_unit_ctx_t *ctx, nxt_unit_port_t *port, return NXT_UNIT_ERROR; } + rbuf->oob.size = oob_size; return NXT_UNIT_OK; } iov[0].iov_base = rbuf->buf; iov[0].iov_len = sizeof(rbuf->buf); - msg.msg_name = NULL; - msg.msg_namelen = 0; - msg.msg_iov = iov; - msg.msg_iovlen = 1; - msg.msg_flags = 0; - msg.msg_control = rbuf->oob; - msg.msg_controllen = sizeof(rbuf->oob); - fd = port->in_fd; retry: - rbuf->size = recvmsg(fd, &msg, 0); + rbuf->size = nxt_recvmsg(fd, iov, 1, &rbuf->oob); if (nxt_slow_path(rbuf->size == -1)) { err = errno; @@ -6350,7 +6286,7 @@ retry: m.quit_param = NXT_QUIT_GRACEFUL; (void) nxt_unit_port_send(ctx, lib->main_ctx.read_port, - &m, sizeof(m), NULL, 0); + &m, sizeof(m), NULL); } } diff --git a/src/nxt_unit.h b/src/nxt_unit.h index 484b7d56..1b5280af 100644 --- a/src/nxt_unit.h +++ b/src/nxt_unit.h @@ -155,7 +155,7 @@ struct nxt_unit_callbacks_s { /* Receive data on port id. Optional. */ ssize_t (*port_recv)(nxt_unit_ctx_t *, nxt_unit_port_t *port, - void *buf, size_t buf_size, void *oob, size_t oob_size); + void *buf, size_t buf_size, void *oob, size_t *oob_size); int (*ready_handler)(nxt_unit_ctx_t *); }; |