aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/libmime/content_type.c6
-rw-r--r--src/libserver/cfg_file.h2
-rw-r--r--src/libserver/cfg_rcl.c12
-rw-r--r--src/libserver/cfg_utils.c12
-rw-r--r--src/libserver/fuzzy_backend/fuzzy_backend_redis.c35
-rw-r--r--src/libserver/redis_pool.cxx808
-rw-r--r--src/libserver/redis_pool.h12
-rw-r--r--src/libutil/upstream.c17
-rw-r--r--src/libutil/upstream.h12
-rw-r--r--src/plugins/lua/history_redis.lua6
-rw-r--r--src/plugins/lua/mime_types.lua3
-rw-r--r--src/ragel/content_disposition_parser.rl2
12 files changed, 505 insertions, 422 deletions
diff --git a/src/libmime/content_type.c b/src/libmime/content_type.c
index 88102ad2c..40f0fd351 100644
--- a/src/libmime/content_type.c
+++ b/src/libmime/content_type.c
@@ -832,6 +832,12 @@ rspamd_content_disposition_parse (const gchar *in,
struct rspamd_content_disposition *res = NULL, val;
if (rspamd_content_disposition_parser (in, len, &val, pool)) {
+
+ if (val.type == RSPAMD_CT_UNKNOWN) {
+ /* 'Fix' type to attachment as MUA does */
+ val.type = RSPAMD_CT_ATTACHMENT;
+ }
+
res = rspamd_mempool_alloc (pool, sizeof (val));
memcpy (res, &val, sizeof (val));
res->lc_data = rspamd_mempool_alloc (pool, len + 1);
diff --git a/src/libserver/cfg_file.h b/src/libserver/cfg_file.h
index 745f0fb22..2aad328f7 100644
--- a/src/libserver/cfg_file.h
+++ b/src/libserver/cfg_file.h
@@ -363,7 +363,6 @@ struct rspamd_config {
GHashTable *groups; /**< groups of symbols */
struct rspamd_action *actions; /**< all actions of the metric */
- gboolean raw_mode; /**< work in raw mode instead of utf one */
gboolean one_shot_mode; /**< rules add only one symbol */
gboolean check_text_attachements; /**< check text attachements as text */
gboolean check_all_filters; /**< check all filters */
@@ -480,7 +479,6 @@ struct rspamd_config {
guint max_blas_threads; /**< maximum threads for openblas when learning ANN */
guint max_opts_len; /**< maximum length for all options for a symbol */
- GList *classify_headers; /**< list of headers using for statistics */
struct module_s **compiled_modules; /**< list of compiled C modules */
struct worker_s **compiled_workers; /**< list of compiled C modules */
struct rspamd_log_format *log_format; /**< parsed log format */
diff --git a/src/libserver/cfg_rcl.c b/src/libserver/cfg_rcl.c
index e3c69c343..06b7edee2 100644
--- a/src/libserver/cfg_rcl.c
+++ b/src/libserver/cfg_rcl.c
@@ -1760,12 +1760,6 @@ rspamd_rcl_config_init (struct rspamd_config *cfg, GHashTable *skip_sections)
RSPAMD_CL_FLAG_INT_32,
"Maximum DNS requests per task (default: 64)");
rspamd_rcl_add_default_handler (sub,
- "classify_headers",
- rspamd_rcl_parse_struct_string_list,
- G_STRUCT_OFFSET (struct rspamd_config, classify_headers),
- 0,
- "List of headers used for classifiers");
- rspamd_rcl_add_default_handler (sub,
"control_socket",
rspamd_rcl_parse_struct_string,
G_STRUCT_OFFSET (struct rspamd_config, control_socket_path),
@@ -1784,12 +1778,6 @@ rspamd_rcl_config_init (struct rspamd_config *cfg, GHashTable *skip_sections)
0,
"Allow non MIME input for rspamd");
rspamd_rcl_add_default_handler (sub,
- "raw_mode",
- rspamd_rcl_parse_struct_boolean,
- G_STRUCT_OFFSET (struct rspamd_config, raw_mode),
- 0,
- "Don't try to convert all messages to utf8");
- rspamd_rcl_add_default_handler (sub,
"one_shot",
rspamd_rcl_parse_struct_boolean,
G_STRUCT_OFFSET (struct rspamd_config, one_shot_mode),
diff --git a/src/libserver/cfg_utils.c b/src/libserver/cfg_utils.c
index 8344ecc72..98b47efdc 100644
--- a/src/libserver/cfg_utils.c
+++ b/src/libserver/cfg_utils.c
@@ -334,14 +334,8 @@ rspamd_config_free (struct rspamd_config *cfg)
g_hash_table_unref (cfg->trusted_keys);
rspamd_re_cache_unref (cfg->re_cache);
- rspamd_upstreams_library_unref (cfg->ups_ctx);
g_ptr_array_free (cfg->c_modules, TRUE);
- if (cfg->lua_state && cfg->own_lua_state) {
- lua_thread_pool_free (cfg->lua_thread_pool);
- lua_close (cfg->lua_state);
- }
-
#ifdef WITH_HIREDIS
if (cfg->redis_pool) {
rspamd_redis_pool_destroy (cfg->redis_pool);
@@ -352,6 +346,12 @@ rspamd_config_free (struct rspamd_config *cfg)
rspamd_monitored_ctx_destroy (cfg->monitored_ctx);
}
+ if (cfg->lua_state && cfg->own_lua_state) {
+ lua_thread_pool_free (cfg->lua_thread_pool);
+ lua_close (cfg->lua_state);
+ }
+
+ rspamd_upstreams_library_unref (cfg->ups_ctx);
HASH_CLEAR (hh, cfg->actions);
rspamd_mempool_destructors_enforce (cfg->cfg_pool);
diff --git a/src/libserver/fuzzy_backend/fuzzy_backend_redis.c b/src/libserver/fuzzy_backend/fuzzy_backend_redis.c
index f16040d8f..18e049926 100644
--- a/src/libserver/fuzzy_backend/fuzzy_backend_redis.c
+++ b/src/libserver/fuzzy_backend/fuzzy_backend_redis.c
@@ -163,6 +163,7 @@ rspamd_fuzzy_redis_session_dtor (struct rspamd_fuzzy_redis_session *session,
rspamd_fuzzy_redis_session_free_args (session);
REF_RELEASE (session->backend);
+ rspamd_upstream_unref (session->up);
g_free (session);
}
@@ -171,7 +172,7 @@ rspamd_fuzzy_backend_redis_dtor (struct rspamd_fuzzy_backend_redis *backend)
{
lua_State *L = backend->L;
- if (backend->conf_ref) {
+ if (backend->conf_ref != -1) {
luaL_unref (L, LUA_REGISTRYINDEX, backend->conf_ref);
}
@@ -341,7 +342,7 @@ rspamd_fuzzy_redis_shingles_callback (redisAsyncContext *c, gpointer r,
ev_timer_stop (session->event_loop, &session->timeout);
memset (&rep, 0, sizeof (rep));
- if (c->err == 0) {
+ if (c->err == 0 && reply != NULL) {
rspamd_upstream_ok (session->up);
if (reply->type == REDIS_REPLY_ARRAY &&
@@ -462,9 +463,8 @@ rspamd_fuzzy_redis_shingles_callback (redisAsyncContext *c, gpointer r,
if (c->errstr) {
msg_err_redis_session ("error getting shingles: %s", c->errstr);
+ rspamd_upstream_fail (session->up, FALSE, c->errstr);
}
-
- rspamd_upstream_fail (session->up, FALSE, strerror (errno));
}
rspamd_fuzzy_redis_session_dtor (session, FALSE);
@@ -541,7 +541,7 @@ rspamd_fuzzy_redis_check_callback (redisAsyncContext *c, gpointer r,
ev_timer_stop (session->event_loop, &session->timeout);
memset (&rep, 0, sizeof (rep));
- if (c->err == 0) {
+ if (c->err == 0 && reply != NULL) {
rspamd_upstream_ok (session->up);
if (reply->type == REDIS_REPLY_ARRAY && reply->elements >= 2) {
@@ -609,9 +609,8 @@ rspamd_fuzzy_redis_check_callback (redisAsyncContext *c, gpointer r,
msg_err_redis_session ("error getting hashes on %s: %s",
rspamd_inet_address_to_string_pretty (rspamd_upstream_addr_cur (session->up)),
c->errstr);
+ rspamd_upstream_fail (session->up, FALSE, c->errstr);
}
-
- rspamd_upstream_fail (session->up, FALSE, strerror (errno));
}
rspamd_fuzzy_redis_session_dtor (session, FALSE);
@@ -680,7 +679,7 @@ rspamd_fuzzy_backend_check_redis (struct rspamd_fuzzy_backend *bk,
NULL,
0);
- session->up = up;
+ session->up = rspamd_upstream_ref (up);
addr = rspamd_upstream_addr_next (up);
g_assert (addr != NULL);
session->ctx = rspamd_redis_pool_connect (backend->pool,
@@ -730,7 +729,7 @@ rspamd_fuzzy_redis_count_callback (redisAsyncContext *c, gpointer r,
ev_timer_stop (session->event_loop, &session->timeout);
- if (c->err == 0) {
+ if (c->err == 0 && reply != NULL) {
rspamd_upstream_ok (session->up);
if (reply->type == REDIS_REPLY_INTEGER) {
@@ -764,9 +763,9 @@ rspamd_fuzzy_redis_count_callback (redisAsyncContext *c, gpointer r,
msg_err_redis_session ("error getting count on %s: %s",
rspamd_inet_address_to_string_pretty (rspamd_upstream_addr_cur (session->up)),
c->errstr);
+ rspamd_upstream_fail (session->up, FALSE, c->errstr);
}
- rspamd_upstream_fail (session->up, FALSE, strerror (errno));
}
rspamd_fuzzy_redis_session_dtor (session, FALSE);
@@ -820,7 +819,7 @@ rspamd_fuzzy_backend_count_redis (struct rspamd_fuzzy_backend *bk,
NULL,
0);
- session->up = up;
+ session->up = rspamd_upstream_ref (up);
addr = rspamd_upstream_addr_next (up);
g_assert (addr != NULL);
session->ctx = rspamd_redis_pool_connect (backend->pool,
@@ -868,7 +867,7 @@ rspamd_fuzzy_redis_version_callback (redisAsyncContext *c, gpointer r,
ev_timer_stop (session->event_loop, &session->timeout);
- if (c->err == 0) {
+ if (c->err == 0 && reply != NULL) {
rspamd_upstream_ok (session->up);
if (reply->type == REDIS_REPLY_INTEGER) {
@@ -902,9 +901,8 @@ rspamd_fuzzy_redis_version_callback (redisAsyncContext *c, gpointer r,
msg_err_redis_session ("error getting version on %s: %s",
rspamd_inet_address_to_string_pretty (rspamd_upstream_addr_cur (session->up)),
c->errstr);
+ rspamd_upstream_fail (session->up, FALSE, c->errstr);
}
-
- rspamd_upstream_fail (session->up, FALSE, strerror (errno));
}
rspamd_fuzzy_redis_session_dtor (session, FALSE);
@@ -959,7 +957,7 @@ rspamd_fuzzy_backend_version_redis (struct rspamd_fuzzy_backend *bk,
NULL,
0);
- session->up = up;
+ session->up = rspamd_upstream_ref (up);
addr = rspamd_upstream_addr_next (up);
g_assert (addr != NULL);
session->ctx = rspamd_redis_pool_connect (backend->pool,
@@ -1374,7 +1372,7 @@ rspamd_fuzzy_redis_update_callback (redisAsyncContext *c, gpointer r,
ev_timer_stop (session->event_loop, &session->timeout);
- if (c->err == 0) {
+ if (c->err == 0 && reply != NULL) {
rspamd_upstream_ok (session->up);
if (reply->type == REDIS_REPLY_ARRAY) {
@@ -1407,9 +1405,8 @@ rspamd_fuzzy_redis_update_callback (redisAsyncContext *c, gpointer r,
msg_err_redis_session ("error sending update to redis %s: %s",
rspamd_inet_address_to_string_pretty (rspamd_upstream_addr_cur (session->up)),
c->errstr);
+ rspamd_upstream_fail (session->up, FALSE, c->errstr);
}
-
- rspamd_upstream_fail (session->up, FALSE, strerror (errno));
}
rspamd_fuzzy_redis_session_dtor (session, FALSE);
@@ -1534,7 +1531,7 @@ rspamd_fuzzy_backend_update_redis (struct rspamd_fuzzy_backend *bk,
NULL,
0);
- session->up = up;
+ session->up = rspamd_upstream_ref (up);
addr = rspamd_upstream_addr_next (up);
g_assert (addr != NULL);
session->ctx = rspamd_redis_pool_connect (backend->pool,
diff --git a/src/libserver/redis_pool.cxx b/src/libserver/redis_pool.cxx
index a81039d6a..8a460b7fe 100644
--- a/src/libserver/redis_pool.cxx
+++ b/src/libserver/redis_pool.cxx
@@ -24,7 +24,32 @@
#include "cryptobox.h"
#include "logger.h"
-struct rspamd_redis_pool_elt;
+#include <list>
+#include "contrib/robin-hood/robin_hood.h"
+#include "libutil/cxx/local_shared_ptr.hxx"
+
+namespace rspamd {
+class redis_pool_elt;
+class redis_pool;
+
+#define msg_err_rpool(...) rspamd_default_log_function (G_LOG_LEVEL_CRITICAL, \
+ "redis_pool", conn->tag, \
+ __FUNCTION__, \
+ __VA_ARGS__)
+#define msg_warn_rpool(...) rspamd_default_log_function (G_LOG_LEVEL_WARNING, \
+ "redis_pool", conn->tag, \
+ __FUNCTION__, \
+ __VA_ARGS__)
+#define msg_info_rpool(...) rspamd_default_log_function (G_LOG_LEVEL_INFO, \
+ "redis_pool", conn->tag, \
+ __FUNCTION__, \
+ __VA_ARGS__)
+#define msg_debug_rpool(...) rspamd_conditional_debug_fast (NULL, NULL, \
+ rspamd_redis_pool_log_id, "redis_pool", conn->tag, \
+ __FUNCTION__, \
+ __VA_ARGS__)
+
+INIT_LOG_MODULE(redis_pool)
enum rspamd_redis_pool_connection_state {
RSPAMD_REDIS_POOL_CONN_INACTIVE = 0,
@@ -32,158 +57,248 @@ enum rspamd_redis_pool_connection_state {
RSPAMD_REDIS_POOL_CONN_FINALISING
};
-struct rspamd_redis_pool_connection {
+struct redis_pool_connection {
+ using redis_pool_connection_ptr = std::unique_ptr<redis_pool_connection>;
+ using conn_iter_t = std::list<redis_pool_connection_ptr>::iterator;
struct redisAsyncContext *ctx;
- struct rspamd_redis_pool_elt *elt;
- GList *entry;
+ redis_pool_elt *elt;
+ redis_pool *pool;
+ conn_iter_t elt_pos;
ev_timer timeout;
enum rspamd_redis_pool_connection_state state;
gchar tag[MEMPOOL_UID_LEN];
- ref_entry_t ref;
-};
-struct rspamd_redis_pool_elt {
- struct rspamd_redis_pool *pool;
- guint64 key;
- GQueue *active;
- GQueue *inactive;
-};
+ auto schedule_timeout() -> void;
+ ~redis_pool_connection();
-struct rspamd_redis_pool {
- struct ev_loop *event_loop;
- struct rspamd_config *cfg;
- GHashTable *elts_by_key;
- GHashTable *elts_by_ctx;
- gdouble timeout;
- guint max_conns;
+ explicit redis_pool_connection(redis_pool *_pool,
+ redis_pool_elt *_elt,
+ const std::string &db,
+ const std::string &password,
+ struct redisAsyncContext *_ctx);
+
+private:
+ static auto redis_conn_timeout_cb(EV_P_ ev_timer *w, int revents) -> void;
+ static auto redis_quit_cb(redisAsyncContext *c, void *r, void *priv) -> void;
+ static auto redis_on_disconnect(const struct redisAsyncContext *ac, int status) -> auto;
};
-static const gdouble default_timeout = 10.0;
-static const guint default_max_conns = 100;
-#define msg_err_rpool(...) rspamd_default_log_function (G_LOG_LEVEL_CRITICAL, \
- "redis_pool", conn->tag, \
- G_STRFUNC, \
- __VA_ARGS__)
-#define msg_warn_rpool(...) rspamd_default_log_function (G_LOG_LEVEL_WARNING, \
- "redis_pool", conn->tag, \
- G_STRFUNC, \
- __VA_ARGS__)
-#define msg_info_rpool(...) rspamd_default_log_function (G_LOG_LEVEL_INFO, \
- "redis_pool", conn->tag, \
- G_STRFUNC, \
- __VA_ARGS__)
-#define msg_debug_rpool(...) rspamd_conditional_debug_fast (NULL, NULL, \
- rspamd_redis_pool_log_id, "redis_pool", conn->tag, \
- G_STRFUNC, \
- __VA_ARGS__)
-
-INIT_LOG_MODULE(redis_pool)
+using redis_pool_key_t = std::uint64_t;
+class redis_pool;
-static inline guint64
-rspamd_redis_pool_get_key (const gchar *db, const gchar *password,
- const char *ip, int port)
-{
- rspamd_cryptobox_fast_hash_state_t st;
+class redis_pool_elt {
+ using redis_pool_connection_ptr = std::unique_ptr<redis_pool_connection>;
+ redis_pool *pool;
+ /*
+ * These lists owns connections, so if an element is removed from both
+ * lists, it is destructed
+ */
+ std::list<redis_pool_connection_ptr> active;
+ std::list<redis_pool_connection_ptr> inactive;
+ std::list<redis_pool_connection_ptr> terminating;
+ std::string ip;
+ std::string db;
+ std::string password;
+ int port;
+ redis_pool_key_t key;
+ bool is_unix;
+public:
+ explicit redis_pool_elt(redis_pool *_pool,
+ const gchar *_db, const gchar *_password,
+ const char *_ip, int _port)
+ : pool(_pool), ip(_ip), port(_port),
+ key(redis_pool_elt::make_key(_db, _password, _ip, _port))
+ {
+ is_unix = ip[0] == '.' || ip[0] == '/';
+
+ if (_db) {
+ db = _db;
+ }
+ if (_password) {
+ password = _password;
+ }
+ }
- rspamd_cryptobox_fast_hash_init (&st, rspamd_hash_seed ());
+ auto new_connection() -> redisAsyncContext *;
+
+ auto release_connection(const redis_pool_connection *conn) -> void
+ {
+ switch(conn->state) {
+ case RSPAMD_REDIS_POOL_CONN_ACTIVE:
+ active.erase(conn->elt_pos);
+ break;
+ case RSPAMD_REDIS_POOL_CONN_INACTIVE:
+ inactive.erase(conn->elt_pos);
+ break;
+ case RSPAMD_REDIS_POOL_CONN_FINALISING:
+ terminating.erase(conn->elt_pos);
+ break;
+ }
+ }
- if (db) {
- rspamd_cryptobox_fast_hash_update (&st, db, strlen (db));
+ auto move_to_inactive(redis_pool_connection *conn) -> void
+ {
+ inactive.splice(std::end(inactive), active, conn->elt_pos);
+ conn->elt_pos = std::prev(std::end(inactive));
}
- if (password) {
- rspamd_cryptobox_fast_hash_update (&st, password, strlen (password));
+
+ auto move_to_terminating(redis_pool_connection *conn) -> void
+ {
+ terminating.splice(std::end(terminating), terminating, conn->elt_pos);
+ conn->elt_pos = std::prev(std::end(terminating));
}
- rspamd_cryptobox_fast_hash_update (&st, ip, strlen (ip));
- rspamd_cryptobox_fast_hash_update (&st, &port, sizeof (port));
+ inline static auto make_key(const gchar *db, const gchar *password,
+ const char *ip, int port) -> redis_pool_key_t
+ {
+ rspamd_cryptobox_fast_hash_state_t st;
- return rspamd_cryptobox_fast_hash_final (&st);
-}
+ rspamd_cryptobox_fast_hash_init(&st, rspamd_hash_seed());
+ if (db) {
+ rspamd_cryptobox_fast_hash_update(&st, db, strlen(db));
+ }
+ if (password) {
+ rspamd_cryptobox_fast_hash_update(&st, password, strlen(password));
+ }
-static void
-rspamd_redis_pool_conn_dtor (struct rspamd_redis_pool_connection *conn)
-{
- if (conn->state == RSPAMD_REDIS_POOL_CONN_ACTIVE) {
- msg_debug_rpool ("active connection removed");
+ rspamd_cryptobox_fast_hash_update(&st, ip, strlen(ip));
+ rspamd_cryptobox_fast_hash_update(&st, &port, sizeof(port));
- if (conn->ctx) {
- if (!(conn->ctx->c.flags & REDIS_FREEING)) {
- redisAsyncContext *ac = conn->ctx;
+ return rspamd_cryptobox_fast_hash_final(&st);
+ }
- conn->ctx = NULL;
- g_hash_table_remove (conn->elt->pool->elts_by_ctx, ac);
- ac->onDisconnect = NULL;
- redisAsyncFree (ac);
- }
+ auto num_active() const -> auto
+ {
+ return active.size();
+ }
+
+ ~redis_pool_elt() {
+ rspamd_explicit_memzero(password.data(), password.size());
+ }
+
+private:
+ auto redis_async_new() -> redisAsyncContext *
+ {
+ struct redisAsyncContext *ctx;
+
+ if (is_unix) {
+ ctx = redisAsyncConnectUnix(ip.c_str());
+ }
+ else {
+ ctx = redisAsyncConnect(ip.c_str(), port);
}
- if (conn->entry) {
- g_queue_unlink (conn->elt->active, conn->entry);
+ if (ctx && ctx->err != REDIS_OK) {
+ msg_err("cannot connect to redis %s (port %d): %s", ip.c_str(), port,
+ ctx->errstr);
+ redisAsyncFree(ctx);
+
+ return nullptr;
}
+
+ return ctx;
}
- else {
- msg_debug_rpool ("inactive connection removed");
+};
- ev_timer_stop (conn->elt->pool->event_loop, &conn->timeout);
+class redis_pool final {
+ static constexpr const double default_timeout = 10.0;
+ static constexpr const unsigned default_max_conns = 100;
+
+ /* We want to have references integrity */
+ robin_hood::unordered_flat_map<redisAsyncContext *,
+ redis_pool_connection *> conns_by_ctx;
+ robin_hood::unordered_node_map<redis_pool_key_t, redis_pool_elt> elts_by_key;
+ bool wanna_die = false; /* Hiredis is 'clever' so we can call ourselves from destructor */
+public:
+ double timeout = default_timeout;
+ unsigned max_conns = default_max_conns;
+ struct ev_loop *event_loop;
+ struct rspamd_config *cfg;
- if (conn->ctx && !(conn->ctx->c.flags & REDIS_FREEING)) {
- redisAsyncContext *ac = conn->ctx;
+public:
+ explicit redis_pool() : event_loop(nullptr), cfg(nullptr)
+ {
+ conns_by_ctx.reserve(max_conns);
+ }
- /* To prevent on_disconnect here */
- conn->state = RSPAMD_REDIS_POOL_CONN_FINALISING;
- g_hash_table_remove (conn->elt->pool->elts_by_ctx, ac);
- conn->ctx = NULL;
- ac->onDisconnect = NULL;
- redisAsyncFree (ac);
- }
+ /* Legacy stuff */
+ auto do_config(struct ev_loop *_loop, struct rspamd_config *_cfg) -> void
+ {
+ event_loop = _loop;
+ cfg = _cfg;
+ }
- if (conn->entry) {
- g_queue_unlink (conn->elt->inactive, conn->entry);
- }
+ auto new_connection(const gchar *db, const gchar *password,
+ const char *ip, int port) -> redisAsyncContext *;
+
+ auto release_connection(redisAsyncContext *ctx,
+ enum rspamd_redis_pool_release_type how) -> void;
+
+ auto unregister_context(redisAsyncContext *ctx) -> void
+ {
+ conns_by_ctx.erase(ctx);
}
+ auto register_context(redisAsyncContext *ctx, redis_pool_connection *conn)
+ {
+ conns_by_ctx.emplace(ctx, conn);
+ }
- if (conn->entry) {
- g_list_free (conn->entry);
+ ~redis_pool() {
+ /*
+ * XXX: this will prevent hiredis to unregister connections that
+ * are already destroyed during redisAsyncFree...
+ */
+ wanna_die = true;
}
+};
- g_free (conn);
-}
-static void
-rspamd_redis_pool_elt_dtor (gpointer p)
+redis_pool_connection::~redis_pool_connection()
{
- GList *cur;
- struct rspamd_redis_pool_elt *elt = (struct rspamd_redis_pool_elt *)p;
- struct rspamd_redis_pool_connection *c;
-
- for (cur = elt->active->head; cur != NULL; cur = g_list_next (cur)) {
- c = (struct rspamd_redis_pool_connection *)cur->data;
- c->entry = NULL;
- REF_RELEASE (c);
+ const auto *conn = this; /* For debug */
+
+ if (state == RSPAMD_REDIS_POOL_CONN_ACTIVE) {
+ msg_debug_rpool ("active connection destructed");
+
+ if (ctx) {
+ if (!(ctx->c.flags & REDIS_FREEING)) {
+ auto *ac = ctx;
+ ctx = nullptr;
+ pool->unregister_context(ac);
+ ac->onDisconnect = nullptr;
+ redisAsyncFree(ac);
+ }
+ }
}
+ else {
+ msg_debug_rpool("inactive connection destructed");
- for (cur = elt->inactive->head; cur != NULL; cur = g_list_next (cur)) {
- c = (struct rspamd_redis_pool_connection *)cur->data;
- c->entry = NULL;
- REF_RELEASE (c);
- }
+ ev_timer_stop(pool->event_loop, &timeout);
+
+ if (ctx && !(ctx->c.flags & REDIS_FREEING)) {
+ redisAsyncContext *ac = ctx;
- g_queue_free (elt->active);
- g_queue_free (elt->inactive);
- g_free (elt);
+ /* To prevent on_disconnect here */
+ state = RSPAMD_REDIS_POOL_CONN_FINALISING;
+ pool->unregister_context(ac);
+ ctx = nullptr;
+ ac->onDisconnect = nullptr;
+ redisAsyncFree(ac);
+ }
+ }
}
-static void
-rspamd_redis_on_quit (redisAsyncContext *c, gpointer r, gpointer priv)
+auto
+redis_pool_connection::redis_quit_cb(redisAsyncContext *c, void *r, void *priv) -> void
{
- struct rspamd_redis_pool_connection *conn =
- (struct rspamd_redis_pool_connection *)priv;
+ struct redis_pool_connection *conn =
+ (struct redis_pool_connection *) priv;
- msg_debug_rpool ("quit command reply for the connection %p, refcount: %d",
- conn->ctx, conn->ref.refcount);
+ msg_debug_rpool("quit command reply for the connection %p",
+ conn->ctx);
/*
* The connection will be freed by hiredis itself as we are here merely after
* quit command has succeeded and we have timer being set already.
@@ -199,68 +314,40 @@ rspamd_redis_on_quit (redisAsyncContext *c, gpointer r, gpointer priv)
*/
}
-static void
-rspamd_redis_conn_timeout (EV_P_ ev_timer *w, int revents)
+/*
+ * Called for inactive connections that due to be removed
+ */
+auto
+redis_pool_connection::redis_conn_timeout_cb(EV_P_ ev_timer *w, int revents) -> void
{
- struct rspamd_redis_pool_connection *conn =
- (struct rspamd_redis_pool_connection *)w->data;
+ auto *conn = (struct redis_pool_connection *) w->data;
g_assert (conn->state != RSPAMD_REDIS_POOL_CONN_ACTIVE);
if (conn->state == RSPAMD_REDIS_POOL_CONN_INACTIVE) {
- msg_debug_rpool ("scheduled soft removal of connection %p, refcount: %d",
- conn->ctx, conn->ref.refcount);
- /* Prevent reusing */
- if (conn->entry) {
- g_queue_delete_link (conn->elt->inactive, conn->entry);
- conn->entry = NULL;
- }
-
+ msg_debug_rpool("scheduled soft removal of connection %p",
+ conn->ctx);
conn->state = RSPAMD_REDIS_POOL_CONN_FINALISING;
- ev_timer_again (EV_A_ w);
- redisAsyncCommand (conn->ctx, rspamd_redis_on_quit, conn, "QUIT");
+ ev_timer_again(EV_A_ w);
+ redisAsyncCommand(conn->ctx, redis_pool_connection::redis_quit_cb, conn, "QUIT");
+ conn->elt->move_to_terminating(conn);
}
else {
/* Finalising by timeout */
- ev_timer_stop (EV_A_ w);
- msg_debug_rpool ("final removal of connection %p, refcount: %d",
- conn->ctx, conn->ref.refcount);
- REF_RELEASE (conn);
- }
-
-}
-
-static void
-rspamd_redis_pool_schedule_timeout (struct rspamd_redis_pool_connection *conn)
-{
- gdouble real_timeout;
- guint active_elts;
+ ev_timer_stop(EV_A_ w);
+ msg_debug_rpool("final removal of connection %p, refcount: %d",
+ conn->ctx);
- active_elts = g_queue_get_length (conn->elt->active);
-
- if (active_elts > conn->elt->pool->max_conns) {
- real_timeout = conn->elt->pool->timeout / 2.0;
- real_timeout = rspamd_time_jitter (real_timeout, real_timeout / 4.0);
- }
- else {
- real_timeout = conn->elt->pool->timeout;
- real_timeout = rspamd_time_jitter (real_timeout, real_timeout / 2.0);
+ /* Erasure of shared pointer will cause it to be removed */
+ conn->elt->release_connection(conn);
}
- msg_debug_rpool ("scheduled connection %p cleanup in %.1f seconds",
- conn->ctx, real_timeout);
-
- conn->timeout.data = conn;
- ev_timer_init (&conn->timeout,
- rspamd_redis_conn_timeout,
- real_timeout, real_timeout / 2.0);
- ev_timer_start (conn->elt->pool->event_loop, &conn->timeout);
}
-static void
-rspamd_redis_pool_on_disconnect (const struct redisAsyncContext *ac, int status)
+auto
+redis_pool_connection::redis_on_disconnect(const struct redisAsyncContext *ac, int status) -> auto
{
- struct rspamd_redis_pool_connection *conn = (struct rspamd_redis_pool_connection *)ac->data;
+ auto *conn = (struct redis_pool_connection *) ac->data;
/*
* Here, we know that redis itself will free this connection
@@ -269,279 +356,264 @@ rspamd_redis_pool_on_disconnect (const struct redisAsyncContext *ac, int status)
if (conn->state != RSPAMD_REDIS_POOL_CONN_ACTIVE) {
/* Do nothing for active connections as it is already handled somewhere */
if (conn->ctx) {
- msg_debug_rpool ("inactive connection terminated: %s, refs: %d",
- conn->ctx->errstr, conn->ref.refcount);
+ msg_debug_rpool("inactive connection terminated: %s",
+ conn->ctx->errstr);
}
- REF_RELEASE (conn);
+ /* Erasure of shared pointer will cause it to be removed */
+ conn->elt->release_connection(conn);
}
}
-static struct rspamd_redis_pool_connection *
-rspamd_redis_pool_new_connection (struct rspamd_redis_pool *pool,
- struct rspamd_redis_pool_elt *elt,
- const char *db,
- const char *password,
- const char *ip,
- gint port)
+auto
+redis_pool_connection::schedule_timeout() -> void
{
- struct rspamd_redis_pool_connection *conn;
- struct redisAsyncContext *ctx;
+ const auto *conn = this; /* For debug */
+ double real_timeout;
+ auto active_elts = elt->num_active();
- if (*ip == '/' || *ip == '.') {
- ctx = redisAsyncConnectUnix (ip);
+ if (active_elts > pool->max_conns) {
+ real_timeout = pool->timeout / 2.0;
+ real_timeout = rspamd_time_jitter(real_timeout, real_timeout / 4.0);
}
else {
- ctx = redisAsyncConnect (ip, port);
+ real_timeout = pool->timeout;
+ real_timeout = rspamd_time_jitter(real_timeout, real_timeout / 2.0);
}
- if (ctx) {
+ msg_debug_rpool("scheduled connection %p cleanup in %.1f seconds",
+ ctx, real_timeout);
- if (ctx->err != REDIS_OK) {
- msg_err ("cannot connect to redis %s (port %d): %s", ip, port, ctx->errstr);
- redisAsyncFree (ctx);
-
- return NULL;
- }
- else {
- conn = (struct rspamd_redis_pool_connection *)g_malloc0 (sizeof (*conn));
- conn->entry = g_list_prepend (NULL, conn);
- conn->elt = elt;
- conn->state = RSPAMD_REDIS_POOL_CONN_ACTIVE;
-
- g_hash_table_insert (elt->pool->elts_by_ctx, ctx, conn);
- g_queue_push_head_link (elt->active, conn->entry);
- conn->ctx = ctx;
- ctx->data = conn;
- rspamd_random_hex ((guchar *)conn->tag, sizeof (conn->tag));
- REF_INIT_RETAIN (conn, rspamd_redis_pool_conn_dtor);
- msg_debug_rpool ("created new connection to %s:%d: %p", ip, port, ctx);
-
- redisLibevAttach (pool->event_loop, ctx);
- redisAsyncSetDisconnectCallback (ctx, rspamd_redis_pool_on_disconnect);
-
- if (password) {
- redisAsyncCommand (ctx, NULL, NULL,
- "AUTH %s", password);
- }
- if (db) {
- redisAsyncCommand (ctx, NULL, NULL,
- "SELECT %s", db);
- }
- }
-
- return conn;
- }
-
- return NULL;
+ timeout.data = this;
+ ev_timer_init(&timeout,
+ redis_pool_connection::redis_conn_timeout_cb,
+ real_timeout, real_timeout / 2.0);
+ ev_timer_start(pool->event_loop, &timeout);
}
-static struct rspamd_redis_pool_elt *
-rspamd_redis_pool_new_elt (struct rspamd_redis_pool *pool)
-{
- struct rspamd_redis_pool_elt *elt;
-
- elt = (struct rspamd_redis_pool_elt *)g_malloc0 (sizeof (*elt));
- elt->active = g_queue_new ();
- elt->inactive = g_queue_new ();
- elt->pool = pool;
- return elt;
-}
-
-struct rspamd_redis_pool *
-rspamd_redis_pool_init (void)
+redis_pool_connection::redis_pool_connection(redis_pool *_pool,
+ redis_pool_elt *_elt,
+ const std::string &db,
+ const std::string &password,
+ struct redisAsyncContext *_ctx)
+ : ctx(_ctx), elt(_elt), pool(_pool)
{
- struct rspamd_redis_pool *pool;
- pool = (struct rspamd_redis_pool *)g_malloc0 (sizeof (*pool));
- pool->elts_by_key = g_hash_table_new_full (g_int64_hash, g_int64_equal,
- NULL, rspamd_redis_pool_elt_dtor);
- pool->elts_by_ctx = g_hash_table_new (g_direct_hash, g_direct_equal);
+ state = RSPAMD_REDIS_POOL_CONN_ACTIVE;
- return pool;
-}
+ pool->register_context(ctx, this);
+ ctx->data = this;
+ memset(tag, 0, sizeof(tag));
+ rspamd_random_hex((guchar *)tag, sizeof(tag) - 1);
-void
-rspamd_redis_pool_config (struct rspamd_redis_pool *pool,
- struct rspamd_config *cfg,
- struct ev_loop *ev_base)
-{
- g_assert (pool != NULL);
+ redisLibevAttach(pool->event_loop, ctx);
+ redisAsyncSetDisconnectCallback(ctx, redis_pool_connection::redis_on_disconnect);
- pool->event_loop = ev_base;
- pool->cfg = cfg;
- pool->timeout = default_timeout;
- pool->max_conns = default_max_conns;
+ if (!password.empty()) {
+ redisAsyncCommand(ctx, nullptr, nullptr,
+ "AUTH %s", password.c_str());
+ }
+ if (!db.empty()) {
+ redisAsyncCommand(ctx, nullptr, nullptr,
+ "SELECT %s", db.c_str());
+ }
}
-
-struct redisAsyncContext*
-rspamd_redis_pool_connect (struct rspamd_redis_pool *pool,
- const gchar *db, const gchar *password,
- const char *ip, int port)
+auto
+redis_pool_elt::new_connection() -> redisAsyncContext *
{
- guint64 key;
- struct rspamd_redis_pool_elt *elt;
- GList *conn_entry;
- struct rspamd_redis_pool_connection *conn;
-
- g_assert (pool != NULL);
- g_assert (pool->event_loop != NULL);
- g_assert (ip != NULL);
-
- key = rspamd_redis_pool_get_key (db, password, ip, port);
- elt = (struct rspamd_redis_pool_elt *)g_hash_table_lookup (pool->elts_by_key, &key);
-
- if (elt) {
- if (g_queue_get_length (elt->inactive) > 0) {
- conn_entry = g_queue_pop_head_link (elt->inactive);
- conn = (struct rspamd_redis_pool_connection *)conn_entry->data;
- g_assert (conn->state != RSPAMD_REDIS_POOL_CONN_ACTIVE);
-
- if (conn->ctx->err == REDIS_OK) {
- /* Also check SO_ERROR */
- gint err;
- socklen_t len = sizeof (gint);
-
- if (getsockopt (conn->ctx->c.fd, SOL_SOCKET, SO_ERROR,
- (void *) &err, &len) == -1) {
- err = errno;
- }
-
- if (err != 0) {
- g_list_free (conn->entry);
- conn->entry = NULL;
- REF_RELEASE (conn);
- conn = rspamd_redis_pool_new_connection (pool, elt,
- db, password, ip, port);
- }
- else {
+ if (!inactive.empty()) {
+ decltype(inactive)::value_type conn;
+ conn.swap(inactive.back());
+ inactive.pop_back();
+
+ g_assert (conn->state != RSPAMD_REDIS_POOL_CONN_ACTIVE);
+ if (conn->ctx->err == REDIS_OK) {
+ /* Also check SO_ERROR */
+ gint err;
+ socklen_t len = sizeof(gint);
+
+ if (getsockopt(conn->ctx->c.fd, SOL_SOCKET, SO_ERROR,
+ (void *) &err, &len) == -1) {
+ err = errno;
+ }
- ev_timer_stop (elt->pool->event_loop, &conn->timeout);
- conn->state = RSPAMD_REDIS_POOL_CONN_ACTIVE;
- g_queue_push_tail_link (elt->active, conn_entry);
- msg_debug_rpool ("reused existing connection to %s:%d: %p",
- ip, port, conn->ctx);
- }
+ if (err != 0) {
+ /*
+ * We cannot reuse connection, so we just recursively call
+ * this function one more time
+ */
+ return new_connection();
}
else {
- g_list_free (conn->entry);
- conn->entry = NULL;
- REF_RELEASE (conn);
- conn = rspamd_redis_pool_new_connection (pool, elt,
- db, password, ip, port);
+ /* Reuse connection */
+ ev_timer_stop(pool->event_loop, &conn->timeout);
+ conn->state = RSPAMD_REDIS_POOL_CONN_ACTIVE;
+ msg_debug_rpool("reused existing connection to %s:%d: %p",
+ ip.c_str(), port, conn->ctx);
+ active.emplace_front(std::move(conn));
+ active.front()->elt_pos = active.begin();
+
+ return active.front()->ctx;
}
-
}
else {
- /* Need to create connection */
- conn = rspamd_redis_pool_new_connection (pool, elt,
- db, password, ip, port);
+ auto *nctx = redis_async_new();
+ if (nctx) {
+ active.emplace_front(std::make_unique<redis_pool_connection>(pool, this,
+ db.c_str(), password.c_str(), nctx));
+ active.front()->elt_pos = active.begin();
+ }
+
+ return nctx;
}
}
else {
- /* Need to create a pool */
- elt = rspamd_redis_pool_new_elt (pool);
- elt->key = key;
- g_hash_table_insert (pool->elts_by_key, &elt->key, elt);
-
- conn = rspamd_redis_pool_new_connection (pool, elt,
- db, password, ip, port);
- }
+ auto *nctx = redis_async_new();
+ if (nctx) {
+ active.emplace_front(std::make_unique<redis_pool_connection>(pool, this,
+ db.c_str(), password.c_str(), nctx));
+ active.front()->elt_pos = active.begin();
+ }
- if (!conn) {
- return NULL;
+ return nctx;
}
- REF_RETAIN (conn);
-
- return conn->ctx;
+ RSPAMD_UNREACHABLE;
}
-
-void
-rspamd_redis_pool_release_connection (struct rspamd_redis_pool *pool,
- struct redisAsyncContext *ctx, enum rspamd_redis_pool_release_type how)
+auto
+redis_pool::new_connection(const gchar *db, const gchar *password,
+ const char *ip, int port) -> redisAsyncContext *
{
- struct rspamd_redis_pool_connection *conn;
- g_assert (pool != NULL);
- g_assert (ctx != NULL);
+ if (!wanna_die) {
+ auto key = redis_pool_elt::make_key(db, password, ip, port);
+ auto found_elt = elts_by_key.find(key);
- conn = (struct rspamd_redis_pool_connection *)g_hash_table_lookup (pool->elts_by_ctx, ctx);
- if (conn != NULL) {
- g_assert (conn->state == RSPAMD_REDIS_POOL_CONN_ACTIVE);
+ if (found_elt != elts_by_key.end()) {
+ auto &elt = found_elt->second;
- if (ctx->err != REDIS_OK) {
- /* We need to terminate connection forcefully */
- msg_debug_rpool ("closed connection %p due to an error", conn->ctx);
- REF_RELEASE (conn);
+ return elt.new_connection();
}
else {
- if (how == RSPAMD_REDIS_RELEASE_DEFAULT) {
- /* Ensure that there are no callbacks attached to this conn */
- if (ctx->replies.head == NULL) {
- /* Just move it to the inactive queue */
- g_queue_unlink (conn->elt->active, conn->entry);
- g_queue_push_head_link (conn->elt->inactive, conn->entry);
- conn->state = RSPAMD_REDIS_POOL_CONN_INACTIVE;
- rspamd_redis_pool_schedule_timeout (conn);
- msg_debug_rpool ("mark connection %p inactive", conn->ctx);
- }
- else {
- msg_debug_rpool ("closed connection %p due to callbacks left",
- conn->ctx);
- REF_RELEASE (conn);
- }
+ /* Need to create a pool */
+ auto nelt = elts_by_key.emplace(std::piecewise_construct,
+ std::forward_as_tuple(key),
+ std::forward_as_tuple(this, db, password, ip, port));
+
+ return nelt.first->second.new_connection();
+ }
+ }
+
+ return nullptr;
+}
+
+auto redis_pool::release_connection(redisAsyncContext *ctx,
+ enum rspamd_redis_pool_release_type how) -> void
+{
+ if (!wanna_die) {
+ auto conn_it = conns_by_ctx.find(ctx);
+ if (conn_it != conns_by_ctx.end()) {
+ auto *conn = conn_it->second;
+ g_assert (conn->state == RSPAMD_REDIS_POOL_CONN_ACTIVE);
+
+ if (ctx->err != REDIS_OK) {
+ /* We need to terminate connection forcefully */
+ msg_debug_rpool ("closed connection %p due to an error", conn->ctx);
}
else {
- if (how == RSPAMD_REDIS_RELEASE_FATAL) {
- msg_debug_rpool ("closed connection %p due to an fatal termination",
- conn->ctx);
+ if (how == RSPAMD_REDIS_RELEASE_DEFAULT) {
+ /* Ensure that there are no callbacks attached to this conn */
+ if (ctx->replies.head == nullptr) {
+ /* Just move it to the inactive queue */
+ conn->state = RSPAMD_REDIS_POOL_CONN_INACTIVE;
+ conn->elt->move_to_inactive(conn);
+ conn->schedule_timeout();
+ msg_debug_rpool("mark connection %p inactive", conn->ctx);
+
+ return;
+ }
+ else {
+ msg_debug_rpool("closed connection %p due to callbacks left",
+ conn->ctx);
+ }
}
else {
- msg_debug_rpool ("closed connection %p due to explicit termination",
- conn->ctx);
+ if (how == RSPAMD_REDIS_RELEASE_FATAL) {
+ msg_debug_rpool("closed connection %p due to an fatal termination",
+ conn->ctx);
+ }
+ else {
+ msg_debug_rpool("closed connection %p due to explicit termination",
+ conn->ctx);
+ }
}
-
- REF_RELEASE (conn);
}
- }
- REF_RELEASE (conn);
- }
- else {
- g_assert_not_reached ();
+ conn->elt->release_connection(conn);
+ }
+ else {
+ RSPAMD_UNREACHABLE;
+ }
}
}
+}
+
+void *
+rspamd_redis_pool_init(void)
+{
+ return new rspamd::redis_pool{};
+}
void
-rspamd_redis_pool_destroy (struct rspamd_redis_pool *pool)
+rspamd_redis_pool_config(void *p,
+ struct rspamd_config *cfg,
+ struct ev_loop *ev_base)
{
- struct rspamd_redis_pool_elt *elt;
- GHashTableIter it;
- gpointer k, v;
+ g_assert (p != NULL);
+ auto *pool = reinterpret_cast<class rspamd::redis_pool *>(p);
- g_assert (pool != NULL);
+ pool->do_config(ev_base, cfg);
+}
- g_hash_table_iter_init (&it, pool->elts_by_key);
- while (g_hash_table_iter_next (&it, &k, &v)) {
- elt = (struct rspamd_redis_pool_elt *)v;
- rspamd_redis_pool_elt_dtor (elt);
- g_hash_table_iter_steal (&it);
- }
+struct redisAsyncContext *
+rspamd_redis_pool_connect(void *p,
+ const gchar *db, const gchar *password,
+ const char *ip, int port)
+{
+ g_assert (p != NULL);
+ auto *pool = reinterpret_cast<class rspamd::redis_pool *>(p);
+
+ return pool->new_connection(db, password, ip, port);
+}
- g_hash_table_unref (pool->elts_by_ctx);
- g_hash_table_unref (pool->elts_by_key);
- g_free (pool);
+void
+rspamd_redis_pool_release_connection(void *p,
+ struct redisAsyncContext *ctx, enum rspamd_redis_pool_release_type how)
+{
+ g_assert (p != NULL);
+ g_assert (ctx != NULL);
+ auto *pool = reinterpret_cast<class rspamd::redis_pool *>(p);
+
+ pool->release_connection(ctx, how);
+}
+
+
+void
+rspamd_redis_pool_destroy(void *p)
+{
+ auto *pool = reinterpret_cast<class rspamd::redis_pool *>(p);
+
+ delete pool;
}
-const gchar*
-rspamd_redis_type_to_string (int type)
+const gchar *
+rspamd_redis_type_to_string(int type)
{
const gchar *ret = "unknown";
diff --git a/src/libserver/redis_pool.h b/src/libserver/redis_pool.h
index 0df650326..eb3de7194 100644
--- a/src/libserver/redis_pool.h
+++ b/src/libserver/redis_pool.h
@@ -21,8 +21,6 @@
#ifdef __cplusplus
extern "C" {
#endif
-
-struct rspamd_redis_pool;
struct rspamd_config;
struct redisAsyncContext;
struct ev_loop;
@@ -31,14 +29,14 @@ struct ev_loop;
* Creates new redis pool
* @return
*/
-struct rspamd_redis_pool *rspamd_redis_pool_init (void);
+void* rspamd_redis_pool_init (void);
/**
* Configure redis pool and binds it to a specific event base
* @param cfg
* @param ev_base
*/
-void rspamd_redis_pool_config (struct rspamd_redis_pool *pool,
+void rspamd_redis_pool_config (void *pool,
struct rspamd_config *cfg,
struct ev_loop *ev_base);
@@ -53,7 +51,7 @@ void rspamd_redis_pool_config (struct rspamd_redis_pool *pool,
* @return
*/
struct redisAsyncContext *rspamd_redis_pool_connect (
- struct rspamd_redis_pool *pool,
+ void *pool,
const gchar *db, const gchar *password,
const char *ip, int port);
@@ -68,7 +66,7 @@ enum rspamd_redis_pool_release_type {
* @param pool
* @param ctx
*/
-void rspamd_redis_pool_release_connection (struct rspamd_redis_pool *pool,
+void rspamd_redis_pool_release_connection (void *pool,
struct redisAsyncContext *ctx,
enum rspamd_redis_pool_release_type how);
@@ -76,7 +74,7 @@ void rspamd_redis_pool_release_connection (struct rspamd_redis_pool *pool,
* Stops redis pool and destroys it
* @param pool
*/
-void rspamd_redis_pool_destroy (struct rspamd_redis_pool *pool);
+void rspamd_redis_pool_destroy (void *pool);
/**
* Missing in hiredis
diff --git a/src/libutil/upstream.c b/src/libutil/upstream.c
index 889b524ac..8c194eb79 100644
--- a/src/libutil/upstream.c
+++ b/src/libutil/upstream.c
@@ -775,7 +775,7 @@ rspamd_upstream_fail (struct upstream *upstream,
upstream->name,
reason);
- if (upstream->ctx && upstream->active_idx != -1) {
+ if (upstream->ctx && upstream->active_idx != -1 && upstream->ls) {
sec_cur = rspamd_get_ticks (FALSE);
RSPAMD_UPSTREAM_LOCK (upstream);
@@ -885,7 +885,7 @@ rspamd_upstream_ok (struct upstream *upstream)
struct upstream_list_watcher *w;
RSPAMD_UPSTREAM_LOCK (upstream);
- if (upstream->errors > 0 && upstream->active_idx != -1) {
+ if (upstream->errors > 0 && upstream->active_idx != -1 && upstream->ls) {
/* We touch upstream if and only if it is active */
msg_debug_upstream ("reset errors on upstream %s (was %ud)", upstream->name, upstream->errors);
upstream->errors = 0;
@@ -1714,3 +1714,16 @@ void rspamd_upstreams_add_watch_callback (struct upstream_list *ups,
DL_APPEND (ups->watchers, nw);
}
+
+struct upstream*
+rspamd_upstream_ref (struct upstream *up)
+{
+ REF_RETAIN (up);
+ return up;
+}
+
+void
+rspamd_upstream_unref (struct upstream *up)
+{
+ REF_RELEASE (up);
+}
diff --git a/src/libutil/upstream.h b/src/libutil/upstream.h
index 89bcd9b52..72a768892 100644
--- a/src/libutil/upstream.h
+++ b/src/libutil/upstream.h
@@ -299,6 +299,18 @@ struct upstream *rspamd_upstream_get_except (struct upstream_list *ups,
*/
void rspamd_upstream_reresolve (struct upstream_ctx *ctx);
+/**
+ * Share ownership on upstream
+ * @param up
+ * @return
+ */
+struct upstream* rspamd_upstream_ref (struct upstream *up);
+/**
+ * Unshare ownership on upstream
+ * @param up
+ */
+void rspamd_upstream_unref (struct upstream *up);
+
#ifdef __cplusplus
}
#endif
diff --git a/src/plugins/lua/history_redis.lua b/src/plugins/lua/history_redis.lua
index b05df4e5d..c14b8d32a 100644
--- a/src/plugins/lua/history_redis.lua
+++ b/src/plugins/lua/history_redis.lua
@@ -91,7 +91,8 @@ local function normalise_results(tbl, task)
local seconds = task:get_timeval()['tv_sec']
tbl.unix_time = seconds
- tbl.subject = task:get_header('subject') or 'unknown'
+ local subject = task:get_header('subject') or 'unknown'
+ tbl.subject = lua_util.maybe_obfuscate_string(subject, settings, 'subject')
tbl.size = task:get_size()
local ip = task:get_from_ip()
if ip and ip:is_valid() then
@@ -219,9 +220,6 @@ local function handle_history_request(task, conn, from, to, reset)
(rspamd_util:get_ticks() - t1) * 1000.0)
collectgarbage()
t1 = rspamd_util:get_ticks()
- fun.each(function(e)
- e.subject = lua_util.maybe_obfuscate_string(e.subject, settings, 'subject')
- end, data)
reply.rows = data
conn:send_ucl(reply)
lua_util.debugm(N, task, 'process + sending took %s ms',
diff --git a/src/plugins/lua/mime_types.lua b/src/plugins/lua/mime_types.lua
index 2e5dee967..fd1c7e2d5 100644
--- a/src/plugins/lua/mime_types.lua
+++ b/src/plugins/lua/mime_types.lua
@@ -380,7 +380,8 @@ local function check_mime_type(task)
end
if not found then
- task:insert_result(settings['symbol_attachment'], mult, ext)
+ task:insert_result(settings['symbol_attachment'], mult, string.format('%s:%s',
+ ext, ct))
end
end
end
diff --git a/src/ragel/content_disposition_parser.rl b/src/ragel/content_disposition_parser.rl
index cdef4db46..f1b0172b7 100644
--- a/src/ragel/content_disposition_parser.rl
+++ b/src/ragel/content_disposition_parser.rl
@@ -122,5 +122,5 @@ rspamd_content_disposition_parser (const char *data, size_t len, struct rspamd_c
free (st_storage.data);
}
- return cd->type != RSPAMD_CT_UNKNOWN;
+ return cd->attrs != NULL || cd->type != RSPAMD_CT_UNKNOWN;
}