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);
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 */
}
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 */
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);
+ }
}
}