Introduced SCM_CREDENTIALS / SCM_CREDS in the socket control msgs.
This commit is contained in:
@@ -59,6 +59,7 @@ $echo >> $NXT_MAKEFILE
|
|||||||
$echo "NXT_LIB_UNIT_OBJS = \\" >> $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_lvlhsh.o \\" >> $NXT_MAKEFILE
|
||||||
$echo " $NXT_BUILD_DIR/src/nxt_murmur_hash.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
|
$echo " $NXT_BUILD_DIR/src/nxt_websocket.o \\" >> $NXT_MAKEFILE
|
||||||
|
|
||||||
for nxt_src in $NXT_LIB_UNIT_SRCS
|
for nxt_src in $NXT_LIB_UNIT_SRCS
|
||||||
|
|||||||
52
auto/sockets
52
auto/sockets
@@ -158,6 +158,58 @@ nxt_feature_test="#include <stdio.h>
|
|||||||
}"
|
}"
|
||||||
. auto/feature
|
. 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="sys/filio.h"
|
||||||
nxt_feature_name=NXT_HAVE_SYS_FILIO_H
|
nxt_feature_name=NXT_HAVE_SYS_FILIO_H
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ NXT_LIB_SRCS=" \
|
|||||||
src/nxt_mem_map.c \
|
src/nxt_mem_map.c \
|
||||||
src/nxt_socket.c \
|
src/nxt_socket.c \
|
||||||
src/nxt_socketpair.c \
|
src/nxt_socketpair.c \
|
||||||
|
src/nxt_socket_msg.c \
|
||||||
src/nxt_credential.c \
|
src/nxt_credential.c \
|
||||||
src/nxt_isolation.c \
|
src/nxt_isolation.c \
|
||||||
src/nxt_process.c \
|
src/nxt_process.c \
|
||||||
|
|||||||
@@ -10,10 +10,10 @@
|
|||||||
#include <nxt_unit_request.h>
|
#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);
|
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,
|
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);
|
||||||
|
|
||||||
int
|
int
|
||||||
nxt_cgo_run(uintptr_t handler)
|
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
|
static ssize_t
|
||||||
nxt_cgo_port_recv(nxt_unit_ctx_t *ctx, nxt_unit_port_t *port,
|
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,
|
return nxt_go_port_recv(port->id.pid, port->id.id,
|
||||||
buf, buf_size, oob, oob_size);
|
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
|
//export nxt_go_port_recv
|
||||||
func nxt_go_port_recv(pid C.int, id C.int, buf unsafe.Pointer, buf_size C.int,
|
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{
|
key := port_key{
|
||||||
pid: int(pid),
|
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),
|
n, oobn, _, _, err := p.rcv.ReadMsgUnix(GoBytes(buf, buf_size),
|
||||||
GoBytes(oob, oob_size))
|
GoBytes(oob, C.int(*oob_size)))
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if nerr, ok := err.(*net.OpError); ok {
|
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)
|
nxt_go_warn("read result %d (%d), %s", n, oobn, err)
|
||||||
|
|
||||||
n = -1
|
n = -1
|
||||||
|
|
||||||
|
} else {
|
||||||
|
*oob_size = C.size_t(oobn)
|
||||||
}
|
}
|
||||||
|
|
||||||
return C.ssize_t(n)
|
return C.ssize_t(n)
|
||||||
|
|||||||
@@ -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,
|
port = nxt_runtime_port_find(task->thread->runtime, msg->port_msg.pid,
|
||||||
msg->port_msg.reply_port);
|
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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1206,10 +1216,23 @@ nxt_cert_store_delete_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg)
|
|||||||
{
|
{
|
||||||
u_char *p;
|
u_char *p;
|
||||||
nxt_str_t name;
|
nxt_str_t name;
|
||||||
|
nxt_port_t *ctl_port;
|
||||||
nxt_runtime_t *rt;
|
nxt_runtime_t *rt;
|
||||||
nxt_file_name_t *path;
|
nxt_file_name_t *path;
|
||||||
|
|
||||||
rt = task->thread->runtime;
|
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)) {
|
if (nxt_slow_path(rt->certs.start == NULL)) {
|
||||||
nxt_alert(task, "no certificates storage directory");
|
nxt_alert(task, "no certificates storage directory");
|
||||||
|
|||||||
@@ -355,6 +355,19 @@ nxt_port_main_start_process_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg)
|
|||||||
|
|
||||||
rt = task->thread->runtime;
|
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);
|
process = nxt_main_process_new(task, rt);
|
||||||
if (nxt_slow_path(process == NULL)) {
|
if (nxt_slow_path(process == NULL)) {
|
||||||
return;
|
return;
|
||||||
@@ -1023,6 +1036,13 @@ nxt_main_port_socket_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg)
|
|||||||
return;
|
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;
|
b = msg->buf;
|
||||||
sa = (nxt_sockaddr_t *) b->mem.pos;
|
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;
|
rt = task->thread->runtime;
|
||||||
|
|
||||||
if (msg->port_msg.pid != rt->port_by_type[NXT_PROCESS_DISCOVERY]->pid) {
|
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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1428,9 +1449,19 @@ nxt_main_port_conf_store_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg)
|
|||||||
void *p;
|
void *p;
|
||||||
size_t n, size;
|
size_t n, size;
|
||||||
nxt_int_t ret;
|
nxt_int_t ret;
|
||||||
|
nxt_port_t *ctl_port;
|
||||||
nxt_runtime_t *rt;
|
nxt_runtime_t *rt;
|
||||||
u_char ver[NXT_INT_T_LEN];
|
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;
|
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);
|
nxt_debug(task, "conf_store_handler(%uz): %*s", size, size, p);
|
||||||
|
|
||||||
rt = task->thread->runtime;
|
|
||||||
|
|
||||||
if (nxt_conf_ver != NXT_VERNUM) {
|
if (nxt_conf_ver != NXT_VERNUM) {
|
||||||
n = nxt_sprintf(ver, ver + NXT_INT_T_LEN, "%d", NXT_VERNUM) - ver;
|
n = nxt_sprintf(ver, ver + NXT_INT_T_LEN, "%d", NXT_VERNUM) - ver;
|
||||||
|
|
||||||
|
|||||||
@@ -153,7 +153,9 @@ typedef enum {
|
|||||||
/* Passed as a first iov chunk. */
|
/* Passed as a first iov chunk. */
|
||||||
typedef struct {
|
typedef struct {
|
||||||
uint32_t stream;
|
uint32_t stream;
|
||||||
nxt_pid_t pid;
|
|
||||||
|
nxt_pid_t pid; /* not used on Linux and FreeBSD */
|
||||||
|
|
||||||
nxt_port_id_t reply_port;
|
nxt_port_id_t reply_port;
|
||||||
|
|
||||||
uint8_t type;
|
uint8_t type;
|
||||||
@@ -186,6 +188,9 @@ typedef struct {
|
|||||||
uint8_t allocated; /* 1 bit */
|
uint8_t allocated; /* 1 bit */
|
||||||
} nxt_port_send_msg_t;
|
} 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 {
|
struct nxt_port_recv_msg_s {
|
||||||
nxt_fd_t fd[2];
|
nxt_fd_t fd[2];
|
||||||
@@ -193,6 +198,9 @@ struct nxt_port_recv_msg_s {
|
|||||||
nxt_port_t *port;
|
nxt_port_t *port;
|
||||||
nxt_port_msg_t port_msg;
|
nxt_port_msg_t port_msg;
|
||||||
size_t size;
|
size_t size;
|
||||||
|
#if (NXT_USE_CMSG_PID)
|
||||||
|
nxt_pid_t cmsg_pid;
|
||||||
|
#endif
|
||||||
nxt_bool_t cancelled;
|
nxt_bool_t cancelled;
|
||||||
union {
|
union {
|
||||||
nxt_port_t *new_port;
|
nxt_port_t *new_port;
|
||||||
@@ -201,6 +209,15 @@ struct nxt_port_recv_msg_s {
|
|||||||
} u;
|
} 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;
|
typedef struct nxt_app_s nxt_app_t;
|
||||||
|
|
||||||
struct nxt_port_s {
|
struct nxt_port_s {
|
||||||
|
|||||||
@@ -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.fd[1] = -1;
|
||||||
msg.buf = &buf;
|
msg.buf = &buf;
|
||||||
msg.port = port;
|
msg.port = port;
|
||||||
|
msg.u.removed_pid = peer;
|
||||||
msg.port_msg.pid = peer;
|
msg.port_msg.pid = nxt_pid;
|
||||||
msg.port_msg.type = _NXT_PORT_MSG_REMOVE_PID;
|
msg.port_msg.type = _NXT_PORT_MSG_REMOVE_PID;
|
||||||
|
|
||||||
peer_link = lhq.value;
|
peer_link = lhq.value;
|
||||||
|
|||||||
@@ -5,6 +5,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include <nxt_main.h>
|
#include <nxt_main.h>
|
||||||
|
#include <nxt_socket_msg.h>
|
||||||
#include <nxt_port_queue.h>
|
#include <nxt_port_queue.h>
|
||||||
#include <nxt_port_memory_int.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 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);
|
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_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,
|
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);
|
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,
|
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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (msg->fd[0] != -1) {
|
nxt_port_close_fds(msg->fd);
|
||||||
nxt_fd_close(msg->fd[0]);
|
}
|
||||||
|
|
||||||
msg->fd[0] = -1;
|
|
||||||
|
nxt_inline void
|
||||||
|
nxt_port_close_fds(nxt_fd_t *fd)
|
||||||
|
{
|
||||||
|
if (fd[0] != -1) {
|
||||||
|
nxt_fd_close(fd[0]);
|
||||||
|
fd[0] = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (msg->fd[1] != -1) {
|
if (fd[1] != -1) {
|
||||||
nxt_fd_close(msg->fd[1]);
|
nxt_fd_close(fd[1]);
|
||||||
|
fd[1] = -1;
|
||||||
msg->fd[1] = -1;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -725,16 +732,17 @@ nxt_port_read_handler(nxt_task_t *task, void *obj, void *data)
|
|||||||
{
|
{
|
||||||
ssize_t n;
|
ssize_t n;
|
||||||
nxt_buf_t *b;
|
nxt_buf_t *b;
|
||||||
|
nxt_int_t ret;
|
||||||
nxt_port_t *port;
|
nxt_port_t *port;
|
||||||
struct iovec iov[2];
|
nxt_recv_oob_t oob;
|
||||||
nxt_port_recv_msg_t msg;
|
nxt_port_recv_msg_t msg;
|
||||||
|
struct iovec iov[2];
|
||||||
|
|
||||||
port = msg.port = nxt_container_of(obj, nxt_port_t, socket);
|
port = msg.port = nxt_container_of(obj, nxt_port_t, socket);
|
||||||
|
|
||||||
nxt_assert(port->engine == task->thread->engine);
|
nxt_assert(port->engine == task->thread->engine);
|
||||||
|
|
||||||
for ( ;; ) {
|
for ( ;; ) {
|
||||||
|
|
||||||
b = nxt_port_buf_alloc(port);
|
b = nxt_port_buf_alloc(port);
|
||||||
|
|
||||||
if (nxt_slow_path(b == NULL)) {
|
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_base = b->mem.pos;
|
||||||
iov[1].iov_len = port->max_size;
|
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) {
|
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.buf = b;
|
||||||
msg.size = n;
|
msg.size = n;
|
||||||
@@ -778,8 +799,8 @@ nxt_port_read_handler(nxt_task_t *task, void *obj, void *data)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* n == 0 || n == NXT_ERROR */
|
fail:
|
||||||
|
/* n == 0 || error */
|
||||||
nxt_work_queue_add(&task->thread->engine->fast_work_queue,
|
nxt_work_queue_add(&task->thread->engine->fast_work_queue,
|
||||||
nxt_port_error_handler, task, &port->socket, NULL);
|
nxt_port_error_handler, task, &port->socket, NULL);
|
||||||
return;
|
return;
|
||||||
@@ -792,8 +813,10 @@ nxt_port_queue_read_handler(nxt_task_t *task, void *obj, void *data)
|
|||||||
{
|
{
|
||||||
ssize_t n;
|
ssize_t n;
|
||||||
nxt_buf_t *b;
|
nxt_buf_t *b;
|
||||||
|
nxt_int_t ret;
|
||||||
nxt_port_t *port;
|
nxt_port_t *port;
|
||||||
struct iovec iov[2];
|
struct iovec iov[2];
|
||||||
|
nxt_recv_oob_t oob;
|
||||||
nxt_port_queue_t *queue;
|
nxt_port_queue_t *queue;
|
||||||
nxt_port_recv_msg_t msg, *smsg;
|
nxt_port_recv_msg_t msg, *smsg;
|
||||||
uint8_t qmsg[NXT_PORT_QUEUE_MSG_SIZE];
|
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_base = b->mem.pos;
|
||||||
iov[1].iov_len = port->max_size;
|
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)
|
if (n == (ssize_t) sizeof(nxt_port_msg_t)
|
||||||
&& msg.port_msg.type == _NXT_PORT_MSG_READ_QUEUE)
|
&& 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",
|
nxt_alert(task, "port %d: too small message:%uz",
|
||||||
port->socket.fd, msg->size);
|
port->socket.fd, msg->size);
|
||||||
|
|
||||||
if (msg->fd[0] != -1) {
|
nxt_port_close_fds(msg->fd);
|
||||||
nxt_fd_close(msg->fd[0]);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (msg->fd[1] != -1) {
|
|
||||||
nxt_fd_close(msg->fd[1]);
|
|
||||||
}
|
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -1225,13 +1258,7 @@ nxt_port_read_msg_process(nxt_task_t *task, nxt_port_t *port,
|
|||||||
b = NULL;
|
b = NULL;
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
if (msg->fd[0] != -1) {
|
nxt_port_close_fds(msg->fd);
|
||||||
nxt_fd_close(msg->fd[0]);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (msg->fd[1] != -1) {
|
|
||||||
nxt_fd_close(msg->fd[1]);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (nxt_fast_path(msg->cancelled == 0)) {
|
if (nxt_fast_path(msg->cancelled == 0)) {
|
||||||
|
|||||||
@@ -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 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_EXPORT ssize_t nxt_socketpair_send(nxt_fd_event_t *ev, nxt_fd_t *fd,
|
||||||
nxt_iobuf_t *iob, nxt_uint_t niob);
|
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_EXPORT ssize_t nxt_socketpair_recv(nxt_fd_event_t *ev,
|
||||||
nxt_iobuf_t *iob, nxt_uint_t niob);
|
nxt_iobuf_t *iob, nxt_uint_t niob, void *oob);
|
||||||
|
|
||||||
|
|
||||||
#define \
|
#define \
|
||||||
|
|||||||
57
src/nxt_socket_msg.c
Normal file
57
src/nxt_socket_msg.c
Normal file
@@ -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;
|
||||||
|
}
|
||||||
220
src/nxt_socket_msg.h
Normal file
220
src/nxt_socket_msg.h
Normal file
@@ -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_ */
|
||||||
@@ -5,7 +5,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include <nxt_main.h>
|
#include <nxt_main.h>
|
||||||
|
#include <nxt_socket_msg.h>
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* SOCK_SEQPACKET protocol is supported for AF_UNIX in Solaris 8 X/Open
|
* SOCK_SEQPACKET protocol is supported for AF_UNIX in Solaris 8 X/Open
|
||||||
@@ -20,12 +20,6 @@
|
|||||||
#endif
|
#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_int_t
|
||||||
nxt_socketpair_create(nxt_task_t *task, nxt_socket_t *pair)
|
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;
|
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;
|
return NXT_OK;
|
||||||
|
|
||||||
fail:
|
fail:
|
||||||
@@ -76,9 +88,12 @@ nxt_socketpair_send(nxt_fd_event_t *ev, nxt_fd_t *fd, nxt_iobuf_t *iob,
|
|||||||
{
|
{
|
||||||
ssize_t n;
|
ssize_t n;
|
||||||
nxt_err_t err;
|
nxt_err_t err;
|
||||||
|
nxt_send_oob_t oob;
|
||||||
|
|
||||||
|
nxt_socket_msg_oob_init(&oob, fd);
|
||||||
|
|
||||||
for ( ;; ) {
|
for ( ;; ) {
|
||||||
n = nxt_sendmsg(ev->fd, fd, iob, niob);
|
n = nxt_sendmsg(ev->fd, iob, niob, &oob);
|
||||||
|
|
||||||
err = (n == -1) ? nxt_socket_errno : 0;
|
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
|
ssize_t
|
||||||
nxt_socketpair_recv(nxt_fd_event_t *ev, nxt_fd_t *fd, nxt_iobuf_t *iob,
|
nxt_socketpair_recv(nxt_fd_event_t *ev, nxt_iobuf_t *iob, nxt_uint_t niob,
|
||||||
nxt_uint_t niob)
|
void *oob)
|
||||||
{
|
{
|
||||||
ssize_t n;
|
ssize_t n;
|
||||||
nxt_err_t err;
|
nxt_err_t err;
|
||||||
|
|
||||||
for ( ;; ) {
|
for ( ;; ) {
|
||||||
n = nxt_recvmsg(ev->fd, fd, iob, niob);
|
n = nxt_recvmsg(ev->fd, iob, niob, oob);
|
||||||
|
|
||||||
err = (n == -1) ? nxt_socket_errno : 0;
|
err = (n == -1) ? nxt_socket_errno : 0;
|
||||||
|
|
||||||
nxt_debug(ev->task, "recvmsg(%d, %FD, %FD, %ui): %z", ev->fd, fd[0],
|
nxt_debug(ev->task, "recvmsg(%d, %ui, %uz): %z",
|
||||||
fd[1], niob, n);
|
ev->fd, niob, ((nxt_recv_oob_t *) oob)->size, n);
|
||||||
|
|
||||||
if (n > 0) {
|
if (n > 0) {
|
||||||
return n;
|
return n;
|
||||||
@@ -163,162 +178,10 @@ nxt_socketpair_recv(nxt_fd_event_t *ev, nxt_fd_t *fd, nxt_iobuf_t *iob,
|
|||||||
continue;
|
continue;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
nxt_alert(ev->task, "recvmsg(%d, %p, %ui) failed %E",
|
nxt_alert(ev->task, "recvmsg(%d, %ui) failed %E",
|
||||||
ev->fd, fd, niob, err);
|
ev->fd, niob, err);
|
||||||
|
|
||||||
return NXT_ERROR;
|
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
|
|
||||||
|
|||||||
212
src/nxt_unit.c
212
src/nxt_unit.c
@@ -3,10 +3,9 @@
|
|||||||
* Copyright (C) NGINX, Inc.
|
* Copyright (C) NGINX, Inc.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <stdlib.h>
|
|
||||||
|
|
||||||
#include "nxt_main.h"
|
#include "nxt_main.h"
|
||||||
#include "nxt_port_memory_int.h"
|
#include "nxt_port_memory_int.h"
|
||||||
|
#include "nxt_socket_msg.h"
|
||||||
#include "nxt_port_queue.h"
|
#include "nxt_port_queue.h"
|
||||||
#include "nxt_app_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 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,
|
static ssize_t nxt_unit_port_send(nxt_unit_ctx_t *ctx,
|
||||||
nxt_unit_port_t *port, const void *buf, size_t buf_size,
|
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,
|
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,
|
static int nxt_unit_ctx_port_recv(nxt_unit_ctx_t *ctx, nxt_unit_port_t *port,
|
||||||
nxt_unit_read_buf_t *rbuf);
|
nxt_unit_read_buf_t *rbuf);
|
||||||
nxt_inline void nxt_unit_rbuf_cpy(nxt_unit_read_buf_t *dst,
|
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_queue_link_t link;
|
||||||
nxt_unit_ctx_impl_t *ctx_impl;
|
nxt_unit_ctx_impl_t *ctx_impl;
|
||||||
ssize_t size;
|
ssize_t size;
|
||||||
|
nxt_recv_oob_t oob;
|
||||||
char buf[16384];
|
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)
|
nxt_unit_ready(nxt_unit_ctx_t *ctx, int ready_fd, uint32_t stream, int queue_fd)
|
||||||
{
|
{
|
||||||
ssize_t res;
|
ssize_t res;
|
||||||
|
nxt_send_oob_t oob;
|
||||||
nxt_port_msg_t msg;
|
nxt_port_msg_t msg;
|
||||||
nxt_unit_impl_t *lib;
|
nxt_unit_impl_t *lib;
|
||||||
|
int fds[2] = {queue_fd, -1};
|
||||||
union {
|
|
||||||
struct cmsghdr cm;
|
|
||||||
char space[CMSG_SPACE(sizeof(int))];
|
|
||||||
} cmsg;
|
|
||||||
|
|
||||||
lib = nxt_container_of(ctx->unit, nxt_unit_impl_t, unit);
|
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.mf = 0;
|
||||||
msg.tracking = 0;
|
msg.tracking = 0;
|
||||||
|
|
||||||
memset(&cmsg, 0, sizeof(cmsg));
|
nxt_socket_msg_oob_init(&oob, fds);
|
||||||
|
|
||||||
cmsg.cm.cmsg_len = CMSG_LEN(sizeof(int));
|
res = nxt_unit_sendmsg(ctx, ready_fd, &msg, sizeof(msg), &oob);
|
||||||
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));
|
|
||||||
|
|
||||||
res = nxt_unit_sendmsg(ctx, ready_fd, &msg, sizeof(msg),
|
|
||||||
&cmsg, sizeof(cmsg));
|
|
||||||
if (res != sizeof(msg)) {
|
if (res != sizeof(msg)) {
|
||||||
return NXT_UNIT_ERROR;
|
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;
|
int rc;
|
||||||
pid_t pid;
|
pid_t pid;
|
||||||
uint8_t quit_param;
|
uint8_t quit_param;
|
||||||
struct cmsghdr *cm;
|
|
||||||
nxt_port_msg_t *port_msg;
|
nxt_port_msg_t *port_msg;
|
||||||
nxt_unit_impl_t *lib;
|
nxt_unit_impl_t *lib;
|
||||||
nxt_unit_recv_msg_t recv_msg;
|
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[0] = -1;
|
||||||
recv_msg.fd[1] = -1;
|
recv_msg.fd[1] = -1;
|
||||||
port_msg = (nxt_port_msg_t *) rbuf->buf;
|
port_msg = (nxt_port_msg_t *) rbuf->buf;
|
||||||
cm = (struct cmsghdr *) rbuf->oob;
|
|
||||||
|
|
||||||
if (cm->cmsg_level == SOL_SOCKET
|
rc = nxt_socket_msg_oob_get_fds(&rbuf->oob, recv_msg.fd);
|
||||||
&& cm->cmsg_type == SCM_RIGHTS)
|
if (nxt_slow_path(rc != NXT_OK)) {
|
||||||
{
|
nxt_unit_alert(ctx, "failed to receive file descriptor over cmsg");
|
||||||
if (cm->cmsg_len == CMSG_LEN(sizeof(int))) {
|
rc = NXT_UNIT_ERROR;
|
||||||
memcpy(recv_msg.fd, CMSG_DATA(cm), sizeof(int));
|
goto done;
|
||||||
}
|
|
||||||
|
|
||||||
if (cm->cmsg_len == CMSG_LEN(sizeof(int) * 2)) {
|
|
||||||
memcpy(recv_msg.fd, CMSG_DATA(cm), sizeof(int) * 2);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
recv_msg.incoming_buf = NULL;
|
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;
|
msg.type = _NXT_PORT_MSG_REQ_HEADERS_ACK;
|
||||||
|
|
||||||
res = nxt_unit_port_send(req->ctx, req->response_port,
|
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))) {
|
if (nxt_slow_path(res != sizeof(msg))) {
|
||||||
return NXT_UNIT_ERROR;
|
return NXT_UNIT_ERROR;
|
||||||
}
|
}
|
||||||
@@ -2673,7 +2646,7 @@ nxt_unit_mmap_buf_send(nxt_unit_request_info_t *req,
|
|||||||
(int) m.mmap_msg.size);
|
(int) m.mmap_msg.size);
|
||||||
|
|
||||||
res = nxt_unit_port_send(req->ctx, req->response_port, &m, sizeof(m),
|
res = nxt_unit_port_send(req->ctx, req->response_port, &m, sizeof(m),
|
||||||
NULL, 0);
|
NULL);
|
||||||
if (nxt_slow_path(res != sizeof(m))) {
|
if (nxt_slow_path(res != sizeof(m))) {
|
||||||
goto free_buf;
|
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,
|
res = nxt_unit_port_send(req->ctx, req->response_port,
|
||||||
buf->start - sizeof(m.msg),
|
buf->start - sizeof(m.msg),
|
||||||
m.mmap_msg.size + sizeof(m.msg),
|
m.mmap_msg.size + sizeof(m.msg), NULL);
|
||||||
NULL, 0);
|
|
||||||
if (nxt_slow_path(res != (ssize_t) (m.mmap_msg.size + sizeof(m.msg)))) {
|
if (nxt_slow_path(res != (ssize_t) (m.mmap_msg.size + sizeof(m.msg)))) {
|
||||||
goto free_buf;
|
goto free_buf;
|
||||||
}
|
}
|
||||||
@@ -2793,7 +2766,7 @@ nxt_unit_read_buf_get(nxt_unit_ctx_t *ctx)
|
|||||||
|
|
||||||
pthread_mutex_unlock(&ctx_impl->mutex);
|
pthread_mutex_unlock(&ctx_impl->mutex);
|
||||||
|
|
||||||
memset(rbuf->oob, 0, sizeof(struct cmsghdr));
|
rbuf->oob.size = 0;
|
||||||
|
|
||||||
return rbuf;
|
return rbuf;
|
||||||
}
|
}
|
||||||
@@ -3312,7 +3285,7 @@ skip_response_send:
|
|||||||
msg.tracking = 0;
|
msg.tracking = 0;
|
||||||
|
|
||||||
(void) nxt_unit_port_send(req->ctx, req->response_port,
|
(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);
|
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.mf = 0;
|
||||||
msg.tracking = 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))) {
|
if (nxt_slow_path(res != sizeof(msg))) {
|
||||||
return NXT_UNIT_ERROR;
|
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)
|
nxt_unit_send_mmap(nxt_unit_ctx_t *ctx, nxt_unit_port_t *port, int fd)
|
||||||
{
|
{
|
||||||
ssize_t res;
|
ssize_t res;
|
||||||
|
nxt_send_oob_t oob;
|
||||||
nxt_port_msg_t msg;
|
nxt_port_msg_t msg;
|
||||||
nxt_unit_impl_t *lib;
|
nxt_unit_impl_t *lib;
|
||||||
union {
|
int fds[2] = {fd, -1};
|
||||||
struct cmsghdr cm;
|
|
||||||
char space[CMSG_SPACE(sizeof(int))];
|
|
||||||
} cmsg;
|
|
||||||
|
|
||||||
lib = nxt_container_of(ctx->unit, nxt_unit_impl_t, unit);
|
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.mf = 0;
|
||||||
msg.tracking = 0;
|
msg.tracking = 0;
|
||||||
|
|
||||||
/*
|
nxt_socket_msg_oob_init(&oob, fds);
|
||||||
* 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));
|
res = nxt_unit_port_send(ctx, port, &msg, sizeof(msg), &oob);
|
||||||
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), &fd, sizeof(int));
|
|
||||||
|
|
||||||
res = nxt_unit_port_send(ctx, port, &msg, sizeof(msg),
|
|
||||||
&cmsg, sizeof(cmsg));
|
|
||||||
if (nxt_slow_path(res != sizeof(msg))) {
|
if (nxt_slow_path(res != sizeof(msg))) {
|
||||||
return NXT_UNIT_ERROR;
|
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;
|
msg.type = _NXT_PORT_MSG_RPC_READY;
|
||||||
|
|
||||||
(void) nxt_unit_port_send(ctx, ctx_impl->read_port,
|
(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);
|
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))) {
|
if (nxt_slow_path(res != sizeof(m))) {
|
||||||
return NXT_UNIT_ERROR;
|
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.mf = 0;
|
||||||
msg.tracking = 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))) {
|
if (nxt_slow_path(res != sizeof(msg))) {
|
||||||
return NXT_UNIT_ERROR;
|
return NXT_UNIT_ERROR;
|
||||||
}
|
}
|
||||||
@@ -4716,7 +4666,7 @@ retry:
|
|||||||
return (err == EAGAIN) ? NXT_UNIT_AGAIN : NXT_UNIT_ERROR;
|
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[0].fd, fds[1].fd, nevents, fds[0].revents,
|
||||||
fds[1].revents);
|
fds[1].revents);
|
||||||
|
|
||||||
@@ -5315,6 +5265,24 @@ nxt_unit_create_port(nxt_unit_ctx_t *ctx)
|
|||||||
return NULL;
|
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",
|
nxt_unit_debug(ctx, "create_port: new socketpair: %d->%d",
|
||||||
port_sockets[0], port_sockets[1]);
|
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)
|
nxt_unit_port_t *port, int queue_fd)
|
||||||
{
|
{
|
||||||
ssize_t res;
|
ssize_t res;
|
||||||
|
nxt_send_oob_t oob;
|
||||||
nxt_unit_impl_t *lib;
|
nxt_unit_impl_t *lib;
|
||||||
int fds[2] = { port->out_fd, queue_fd };
|
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;
|
nxt_port_msg_new_port_t new_port;
|
||||||
} m;
|
} m;
|
||||||
|
|
||||||
union {
|
|
||||||
struct cmsghdr cm;
|
|
||||||
char space[CMSG_SPACE(sizeof(int) * 2)];
|
|
||||||
} cmsg;
|
|
||||||
|
|
||||||
lib = nxt_container_of(ctx->unit, nxt_unit_impl_t, unit);
|
lib = nxt_container_of(ctx->unit, nxt_unit_impl_t, unit);
|
||||||
|
|
||||||
m.msg.stream = 0;
|
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_size = 16 * 1024;
|
||||||
m.new_port.max_share = 64 * 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);
|
res = nxt_unit_port_send(ctx, dst, &m, sizeof(m), &oob);
|
||||||
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));
|
|
||||||
|
|
||||||
return (res == sizeof(m)) ? NXT_UNIT_OK : NXT_UNIT_ERROR;
|
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,
|
(void) nxt_unit_port_send(ctx, ctx_impl->read_port,
|
||||||
&m, sizeof(m), NULL, 0);
|
&m, sizeof(m), NULL);
|
||||||
|
|
||||||
} nxt_queue_loop;
|
} 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,
|
nxt_unit_debug(ctx, "get_port: %d %d", (int) port_id->pid,
|
||||||
(int) port_id->id);
|
(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))) {
|
if (nxt_slow_path(res != sizeof(m))) {
|
||||||
return NXT_UNIT_ERROR;
|
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
|
static ssize_t
|
||||||
nxt_unit_port_send(nxt_unit_ctx_t *ctx, nxt_unit_port_t *port,
|
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;
|
int notify;
|
||||||
ssize_t ret;
|
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);
|
lib = nxt_container_of(ctx->unit, nxt_unit_impl_t, unit);
|
||||||
|
|
||||||
port_impl = nxt_container_of(port, nxt_unit_port_impl_t, port);
|
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)
|
&& buf_size <= NXT_PORT_QUEUE_MSG_SIZE)
|
||||||
{
|
{
|
||||||
rc = nxt_port_queue_send(port_impl->queue, buf, buf_size, ¬ify);
|
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) {
|
if (lib->callbacks.port_send == NULL) {
|
||||||
ret = nxt_unit_sendmsg(ctx, port->out_fd, &msg,
|
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",
|
nxt_unit_debug(ctx, "port{%d,%d} send %d read_queue",
|
||||||
(int) port->id.pid, (int) port->id.id,
|
(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) {
|
if (lib->callbacks.port_send != NULL) {
|
||||||
ret = lib->callbacks.port_send(ctx, port, buf, buf_size,
|
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",
|
nxt_unit_debug(ctx, "port{%d,%d} sendcb %d",
|
||||||
(int) port->id.pid, (int) port->id.id,
|
(int) port->id.pid, (int) port->id.id,
|
||||||
(int) ret);
|
(int) ret);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
ret = nxt_unit_sendmsg(ctx, port->out_fd, buf, buf_size,
|
ret = nxt_unit_sendmsg(ctx, port->out_fd, buf, buf_size, oob);
|
||||||
oob, oob_size);
|
|
||||||
|
|
||||||
nxt_unit_debug(ctx, "port{%d,%d} sendmsg %d",
|
nxt_unit_debug(ctx, "port{%d,%d} sendmsg %d",
|
||||||
(int) port->id.pid, (int) port->id.id,
|
(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
|
static ssize_t
|
||||||
nxt_unit_sendmsg(nxt_unit_ctx_t *ctx, int fd,
|
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;
|
int err;
|
||||||
ssize_t res;
|
ssize_t n;
|
||||||
struct iovec iov[1];
|
struct iovec iov[1];
|
||||||
struct msghdr msg;
|
|
||||||
|
|
||||||
iov[0].iov_base = (void *) buf;
|
iov[0].iov_base = (void *) buf;
|
||||||
iov[0].iov_len = buf_size;
|
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:
|
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;
|
err = errno;
|
||||||
|
|
||||||
if (err == EINTR) {
|
if (err == EINTR) {
|
||||||
@@ -6060,11 +6000,11 @@ retry:
|
|||||||
fd, (int) buf_size, strerror(err), err);
|
fd, (int) buf_size, strerror(err), err);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
nxt_unit_debug(ctx, "sendmsg(%d, %d): %d", fd, (int) buf_size,
|
nxt_unit_debug(ctx, "sendmsg(%d, %d, %d): %d", fd, (int) buf_size,
|
||||||
(int) res);
|
(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);
|
nxt_unit_rbuf_cpy(port_impl->socket_rbuf, rbuf);
|
||||||
|
|
||||||
memset(rbuf->oob, 0, sizeof(struct cmsghdr));
|
rbuf->oob.size = 0;
|
||||||
|
|
||||||
goto retry;
|
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);
|
memcpy(dst->buf, src->buf, src->size);
|
||||||
dst->size = 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)
|
nxt_unit_read_buf_t *rbuf)
|
||||||
{
|
{
|
||||||
int fd, err;
|
int fd, err;
|
||||||
|
size_t oob_size;
|
||||||
struct iovec iov[1];
|
struct iovec iov[1];
|
||||||
struct msghdr msg;
|
|
||||||
nxt_unit_impl_t *lib;
|
nxt_unit_impl_t *lib;
|
||||||
|
|
||||||
lib = nxt_container_of(ctx->unit, nxt_unit_impl_t, unit);
|
lib = nxt_container_of(ctx->unit, nxt_unit_impl_t, unit);
|
||||||
|
|
||||||
if (lib->callbacks.port_recv != NULL) {
|
if (lib->callbacks.port_recv != NULL) {
|
||||||
|
oob_size = sizeof(rbuf->oob.buf);
|
||||||
|
|
||||||
rbuf->size = lib->callbacks.port_recv(ctx, port,
|
rbuf->size = lib->callbacks.port_recv(ctx, port,
|
||||||
rbuf->buf, sizeof(rbuf->buf),
|
rbuf->buf, sizeof(rbuf->buf),
|
||||||
rbuf->oob, sizeof(rbuf->oob));
|
rbuf->oob.buf, &oob_size);
|
||||||
|
|
||||||
nxt_unit_debug(ctx, "port{%d,%d} recvcb %d",
|
nxt_unit_debug(ctx, "port{%d,%d} recvcb %d",
|
||||||
(int) port->id.pid, (int) port->id.id, (int) rbuf->size);
|
(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;
|
return NXT_UNIT_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
rbuf->oob.size = oob_size;
|
||||||
return NXT_UNIT_OK;
|
return NXT_UNIT_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
iov[0].iov_base = rbuf->buf;
|
iov[0].iov_base = rbuf->buf;
|
||||||
iov[0].iov_len = sizeof(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;
|
fd = port->in_fd;
|
||||||
|
|
||||||
retry:
|
retry:
|
||||||
|
|
||||||
rbuf->size = recvmsg(fd, &msg, 0);
|
rbuf->size = nxt_recvmsg(fd, iov, 1, &rbuf->oob);
|
||||||
|
|
||||||
if (nxt_slow_path(rbuf->size == -1)) {
|
if (nxt_slow_path(rbuf->size == -1)) {
|
||||||
err = errno;
|
err = errno;
|
||||||
@@ -6350,7 +6286,7 @@ retry:
|
|||||||
m.quit_param = NXT_QUIT_GRACEFUL;
|
m.quit_param = NXT_QUIT_GRACEFUL;
|
||||||
|
|
||||||
(void) nxt_unit_port_send(ctx, lib->main_ctx.read_port,
|
(void) nxt_unit_port_send(ctx, lib->main_ctx.read_port,
|
||||||
&m, sizeof(m), NULL, 0);
|
&m, sizeof(m), NULL);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -155,7 +155,7 @@ struct nxt_unit_callbacks_s {
|
|||||||
|
|
||||||
/* Receive data on port id. Optional. */
|
/* Receive data on port id. Optional. */
|
||||||
ssize_t (*port_recv)(nxt_unit_ctx_t *, nxt_unit_port_t *port,
|
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 *);
|
int (*ready_handler)(nxt_unit_ctx_t *);
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user