static gboolean fuzzy_tcp_send_command(struct fuzzy_tcp_connection *conn,
GPtrArray *commands,
struct fuzzy_client_session *session);
+static void fuzzy_tcp_connection_close(struct fuzzy_tcp_connection *conn);
static void fuzzy_tcp_connection_cleanup(struct fuzzy_tcp_connection *conn, const char *reason);
static gboolean fuzzy_check_session_is_completed(struct fuzzy_client_session *session);
if (conn->fd != -1) {
rspamd_ev_watcher_stop(conn->event_loop, &conn->ev);
close(conn->fd);
+ conn->fd = -1;
}
if (conn->write_queue) {
conn->encrypted = FALSE;
}
+ /* Store in connection pool array BEFORE starting event watcher
+ * This prevents race condition where another task might create duplicate connection
+ * Array takes ownership of initial reference */
+ g_ptr_array_add(rule->tcp_connections, conn);
+
/* Initialize event watcher for connection establishment (wait for write) */
rspamd_ev_watcher_init(&conn->ev, fd, EV_WRITE,
fuzzy_tcp_io_handler, conn);
rspamd_ev_watcher_start(conn->event_loop, &conn->ev, rule->tcp_timeout);
- /* Store in connection pool array - array takes ownership of initial reference */
- g_ptr_array_add(rule->tcp_connections, conn);
-
msg_info_task("fuzzy_tcp: initiating connection to %s for rule %s",
rspamd_inet_address_to_string_pretty(addr),
rule->name);
return conn;
}
+/**
+ * Close connection socket and mark as failed
+ * Stops event watcher, closes fd, marks connection as failed
+ * Should be called before fuzzy_tcp_connection_cleanup
+ */
+static void
+fuzzy_tcp_connection_close(struct fuzzy_tcp_connection *conn)
+{
+ if (conn->fd != -1) {
+ rspamd_ev_watcher_stop(conn->event_loop, &conn->ev);
+ close(conn->fd);
+ conn->fd = -1;
+ }
+ conn->failed = TRUE;
+ conn->last_failure = rspamd_get_calendar_ticks();
+ conn->connecting = FALSE;
+ conn->connected = FALSE;
+}
+
/**
* Cleanup pending requests for a failed connection
* Removes all pending commands associated with this connection
elapsed,
conn->connecting,
conn->connected);
- conn->failed = TRUE;
- conn->last_failure = rspamd_get_calendar_ticks();
- conn->connecting = FALSE;
+ fuzzy_tcp_connection_close(conn);
fuzzy_tcp_connection_cleanup(conn, "connection timeout");
- rspamd_ev_watcher_stop(conn->event_loop, &conn->ev);
rspamd_upstream_fail(conn->server, TRUE, "connection timeout");
FUZZY_TCP_RELEASE(conn);
return;
conn->rule->name,
rspamd_upstream_name(conn->server),
strerror(errno));
- conn->failed = TRUE;
- conn->last_failure = rspamd_get_calendar_ticks();
- conn->connecting = FALSE;
+ fuzzy_tcp_connection_close(conn);
fuzzy_tcp_connection_cleanup(conn, "getsockopt failed");
- rspamd_ev_watcher_stop(conn->event_loop, &conn->ev);
rspamd_upstream_fail(conn->server, TRUE, "getsockopt failed");
FUZZY_TCP_RELEASE(conn);
return;
conn->rule->name,
rspamd_upstream_name(conn->server),
strerror(so_error));
- conn->failed = TRUE;
- conn->last_failure = rspamd_get_calendar_ticks();
- conn->connecting = FALSE;
+ fuzzy_tcp_connection_close(conn);
fuzzy_tcp_connection_cleanup(conn, error_buf);
- rspamd_ev_watcher_stop(conn->event_loop, &conn->ev);
rspamd_upstream_fail(conn->server, TRUE, strerror(so_error));
FUZZY_TCP_RELEASE(conn);
return;
conn->rule->name,
rspamd_upstream_name(conn->server),
strerror(errno));
- conn->failed = TRUE;
- conn->last_failure = rspamd_get_calendar_ticks();
+ fuzzy_tcp_connection_close(conn);
fuzzy_tcp_connection_cleanup(conn, error_buf);
- rspamd_ev_watcher_stop(conn->event_loop, &conn->ev);
return;
}
else if (r == 0) {
msg_info("fuzzy_tcp: connection closed by %s for rule %s",
rspamd_upstream_name(conn->server),
conn->rule->name);
- conn->failed = TRUE;
- conn->last_failure = rspamd_get_calendar_ticks();
+ fuzzy_tcp_connection_close(conn);
fuzzy_tcp_connection_cleanup(conn, "connection closed by peer");
- rspamd_ev_watcher_stop(conn->event_loop, &conn->ev);
return;
}
if (available_space == 0) {
msg_err("fuzzy_tcp: read buffer full for rule %s, closing connection",
conn->rule->name);
- conn->failed = TRUE;
- conn->last_failure = rspamd_get_calendar_ticks();
+ fuzzy_tcp_connection_close(conn);
fuzzy_tcp_connection_cleanup(conn, "read buffer overflow");
- rspamd_ev_watcher_stop(conn->event_loop, &conn->ev);
return;
}
rspamd_snprintf(error_buf, sizeof(error_buf), "read error: %s", strerror(errno));
msg_err("fuzzy_tcp: read error for rule %s: %s",
conn->rule->name, strerror(errno));
- conn->failed = TRUE;
- conn->last_failure = rspamd_get_calendar_ticks();
+ fuzzy_tcp_connection_close(conn);
fuzzy_tcp_connection_cleanup(conn, error_buf);
- rspamd_ev_watcher_stop(conn->event_loop, &conn->ev);
return;
}
else if (r == 0) {
msg_info("fuzzy_tcp: connection closed by %s for rule %s",
rspamd_upstream_name(conn->server),
conn->rule->name);
- conn->failed = TRUE;
- conn->last_failure = rspamd_get_calendar_ticks();
+ fuzzy_tcp_connection_close(conn);
fuzzy_tcp_connection_cleanup(conn, "connection closed by peer");
- rspamd_ev_watcher_stop(conn->event_loop, &conn->ev);
return;
}
msg_err("fuzzy_tcp: invalid frame length %d from %s, closing",
(int) frame_len,
rspamd_upstream_name(conn->server));
- conn->failed = TRUE;
- conn->last_failure = rspamd_get_calendar_ticks();
+ fuzzy_tcp_connection_close(conn);
fuzzy_tcp_connection_cleanup(conn, error_buf);
- rspamd_ev_watcher_stop(conn->event_loop, &conn->ev);
return;
}