From 6dd417bc9fc3abaf4c32033c1a6c8a96e0809d23 Mon Sep 17 00:00:00 2001 From: Vsevolod Stakhov Date: Mon, 22 Apr 2024 18:42:08 +0100 Subject: [PATCH] [Minor] Deal with descriptors in the wait queue --- src/libserver/rspamd_control.c | 41 ++++++++++++++++++++++++++++++++-- 1 file changed, 39 insertions(+), 2 deletions(-) diff --git a/src/libserver/rspamd_control.c b/src/libserver/rspamd_control.c index 7fe1032b4..1bff2ff12 100644 --- a/src/libserver/rspamd_control.c +++ b/src/libserver/rspamd_control.c @@ -361,6 +361,10 @@ void rspamd_pending_control_free(gpointer p) if (rep_elt->sent) { rspamd_ev_watcher_stop(rep_elt->event_loop, &rep_elt->ev); } + else if (rep_elt->attached_fd != -1) { + /* Only for non-sent requests! */ + close(rep_elt->attached_fd); + } g_hash_table_unref(rep_elt->pending_elts); g_free(rep_elt); @@ -439,6 +443,11 @@ rspamd_control_stop_pending(struct rspamd_control_reply_elt *elt) rspamd_ev_watcher_start(cur->event_loop, &cur->ev, worker_io_timeout); cur->sent = true; + if (cur->attached_fd != -1) { + /* Since `sendmsg` performs `dup` for us, we need to remove our own descriptor */ + close(cur->attached_fd); + cur->attached_fd = -1; + } break; /* Exit the outer loop as we have invoked something */ } @@ -501,6 +510,7 @@ rspamd_control_broadcast_cmd(struct rspamd_main *rspamd_main, rep_elt->handler = handler; memcpy(&rep_elt->cmd, cmd, sizeof(*cmd)); rep_elt->sent = false; + rep_elt->attached_fd = -1; if (g_hash_table_size(wrk->control_events_pending) == 0) { /* We can send command */ @@ -545,8 +555,35 @@ rspamd_control_broadcast_cmd(struct rspamd_main *rspamd_main, g_quark_to_string(wrk->type), (int) g_hash_table_size(wrk->control_events_pending)); rep_elt->pending_elts = g_hash_table_ref(wrk->control_events_pending); - g_hash_table_insert(wrk->control_events_pending, rep_elt, rep_elt); - DL_APPEND(res, rep_elt); + /* + * Here are dragons: + * If we have a descriptor to send, the callee expects that we follow + * sendmsg semantics that performs `dup` on it. So we need to clone fd and keep it there. + */ + if (attached_fd != -1) { + rep_elt->attached_fd = dup(attached_fd); + + if (rep_elt->attached_fd == -1) { + /* + * We have a problem: file descriptors limit is reached, so we cannot really deal with this + * request + */ + msg_err_main("cannot duplicate file descriptor to send command to worker %P(%s): %s; failed to send command", + wrk->pid, + g_quark_to_string(wrk->type), + strerror(errno)); + g_hash_table_unref(rep_elt->pending_elts); + g_free(rep_elt); + } + else { + g_hash_table_insert(wrk->control_events_pending, rep_elt, rep_elt); + DL_APPEND(res, rep_elt); + } + } + else { + g_hash_table_insert(wrk->control_events_pending, rep_elt, rep_elt); + DL_APPEND(res, rep_elt); + } } } -- 2.39.5