]> source.dussan.org Git - rspamd.git/commitdiff
[Minor] Deal with descriptors in the wait queue 4937/head
authorVsevolod Stakhov <vsevolod@rspamd.com>
Mon, 22 Apr 2024 17:42:08 +0000 (18:42 +0100)
committerVsevolod Stakhov <vsevolod@rspamd.com>
Mon, 22 Apr 2024 17:42:08 +0000 (18:42 +0100)
src/libserver/rspamd_control.c

index 7fe1032b4398afab427286d9c894d4bbf6309824..1bff2ff12bf6b84bd02aa336135b98d69a6263d7 100644 (file)
@@ -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);
+                       }
                }
        }