From: Vsevolod Stakhov Date: Mon, 22 Apr 2024 17:42:08 +0000 (+0100) Subject: [Minor] Deal with descriptors in the wait queue X-Git-Tag: 3.9.0~59^2 X-Git-Url: https://source.dussan.org/?a=commitdiff_plain;h=refs%2Fpull%2F4937%2Fhead;p=rspamd.git [Minor] Deal with descriptors in the wait queue --- 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); + } } }