static void rspamd_fuzzy_redis_count_callback (redisAsyncContext *c, gpointer r, gpointer priv) { struct rspamd_fuzzy_redis_session *session = priv; redisReply *reply = r; event_del (&session->timeout); if (c->err == 0) { rspamd_upstream_ok (session->up); if (reply->type == REDIS_REPLY_INTEGER) { if (session->callback.cb_count) { session->callback.cb_count (reply->integer, session->cbdata); } } else { if (session->callback.cb_count) { session->callback.cb_count (0, session->cbdata); } } } else { if (session->callback.cb_count) { session->callback.cb_count (0, session->cbdata); } rspamd_upstream_fail (session->up); } rspamd_fuzzy_redis_session_dtor (session); }
/* Called when we have checked the specified message id */ static void rspamd_stat_cache_redis_get (redisAsyncContext *c, gpointer r, gpointer priv) { struct rspamd_redis_cache_runtime *rt = priv; redisReply *reply = r; struct rspamd_task *task; glong val = 0; task = rt->task; if (c->err == 0) { if (reply) { if (G_LIKELY (reply->type == REDIS_REPLY_INTEGER)) { val = reply->integer; } else if (reply->type == REDIS_REPLY_STRING) { rspamd_strtol (reply->str, reply->len, &val); } else { if (reply->type != REDIS_REPLY_NIL) { msg_err_task ("bad learned type for %s: %d", rt->ctx->stcf->symbol, reply->type); } val = 0; } } if ((val > 0 && (task->flags & RSPAMD_TASK_FLAG_LEARN_SPAM)) || (val < 0 && (task->flags & RSPAMD_TASK_FLAG_LEARN_HAM))) { /* Already learned */ g_set_error (&task->err, rspamd_stat_quark (), 404, "<%s> has been already " "learned as %s, ignore it", task->message_id, (task->flags & RSPAMD_TASK_FLAG_LEARN_SPAM) ? "spam" : "ham"); task->flags |= RSPAMD_TASK_FLAG_ALREADY_LEARNED; } else if (val != 0) { /* Unlearn flag */ task->flags |= RSPAMD_TASK_FLAG_UNLEARN; } rspamd_upstream_ok (rt->selected); } else { rspamd_upstream_fail (rt->selected); } if (rt->has_event) { rspamd_session_remove_event (task->s, rspamd_redis_cache_fin, rt); } }
/* Called when we have connected to the redis server and got stats */ static void rspamd_redis_connected (redisAsyncContext *c, gpointer r, gpointer priv) { struct redis_stat_runtime *rt = REDIS_RUNTIME (priv); redisReply *reply = r; struct rspamd_task *task; glong val = 0; task = rt->task; if (c->err == 0) { if (r != NULL) { if (G_UNLIKELY (reply->type == REDIS_REPLY_INTEGER)) { val = reply->integer; } else if (reply->type == REDIS_REPLY_STRING) { rspamd_strtol (reply->str, reply->len, &val); } else { if (reply->type != REDIS_REPLY_NIL) { msg_err_task ("bad learned type for %s: %d", rt->stcf->symbol, reply->type); } val = 0; } if (val < 0) { msg_warn_task ("invalid number of learns for %s: %L", rt->stcf->symbol, val); val = 0; } rt->learned = val; msg_debug_task ("connected to redis server, tokens learned for %s: %uL", rt->redis_object_expanded, rt->learned); rspamd_upstream_ok (rt->selected); } } else { msg_err_task ("error getting reply from redis server %s: %s", rspamd_upstream_name (rt->selected), c->errstr); rspamd_upstream_fail (rt->selected); } }
/* Called when we have learned the specified message id */ static void rspamd_stat_cache_redis_set (redisAsyncContext *c, gpointer r, gpointer priv) { struct rspamd_redis_cache_runtime *rt = priv; struct rspamd_task *task; task = rt->task; if (c->err == 0) { /* XXX: we ignore results here */ rspamd_upstream_ok (rt->selected); } else { rspamd_upstream_fail (rt->selected); } if (rt->has_event) { rspamd_session_remove_event (task->s, rspamd_redis_cache_fin, rt); } }
/* Called when we have set tokens during learning */ static void rspamd_redis_learned (redisAsyncContext *c, gpointer r, gpointer priv) { struct redis_stat_runtime *rt = REDIS_RUNTIME (priv); struct rspamd_task *task; task = rt->task; if (c->err == 0) { rspamd_upstream_ok (rt->selected); } else { msg_err_task_check ("error getting reply from redis server %s: %s", rspamd_upstream_name (rt->selected), c->errstr); if (rt->redis) { rspamd_upstream_fail (rt->selected); } } if (rt->has_event) { rspamd_session_remove_event (task->s, rspamd_redis_fin_learn, rt); } }
/* Called when we have received tokens values from redis */ static void rspamd_redis_processed (redisAsyncContext *c, gpointer r, gpointer priv) { struct redis_stat_runtime *rt = REDIS_RUNTIME (priv); redisReply *reply = r, *elt; struct rspamd_task *task; rspamd_token_t *tok; guint i, processed = 0, found = 0; gulong val; gdouble float_val; task = rt->task; if (c->err == 0) { if (r != NULL) { if (reply->type == REDIS_REPLY_ARRAY) { if (reply->elements == task->tokens->len) { for (i = 0; i < reply->elements; i ++) { tok = g_ptr_array_index (task->tokens, i); elt = reply->element[i]; if (G_UNLIKELY (elt->type == REDIS_REPLY_INTEGER)) { tok->values[rt->id] = elt->integer; found ++; } else if (elt->type == REDIS_REPLY_STRING) { if (rt->stcf->clcf->flags & RSPAMD_FLAG_CLASSIFIER_INTEGER) { rspamd_strtoul (elt->str, elt->len, &val); tok->values[rt->id] = val; } else { float_val = strtod (elt->str, NULL); tok->values[rt->id] = float_val; } found ++; } else { tok->values[rt->id] = 0; } processed ++; } if (rt->stcf->is_spam) { task->flags |= RSPAMD_TASK_FLAG_HAS_SPAM_TOKENS; } else { task->flags |= RSPAMD_TASK_FLAG_HAS_HAM_TOKENS; } } else { msg_err_task_check ("got invalid length of reply vector from redis: " "%d, expected: %d", (gint)reply->elements, (gint)task->tokens->len); } } else { msg_err_task_check ("got invalid reply from redis: %d", reply->type); } msg_debug_task_check ("received tokens for %s: %d processed, %d found", rt->redis_object_expanded, processed, found); rspamd_upstream_ok (rt->selected); } } else { msg_err_task ("error getting reply from redis server %s: %s", rspamd_upstream_name (rt->selected), c->errstr); if (rt->redis) { rspamd_upstream_fail (rt->selected); } } if (rt->has_event) { rspamd_session_remove_event (task->s, rspamd_redis_fin, rt); } }
/* Called when we have connected to the redis server and got keys to check */ static void rspamd_redis_stat_keys (redisAsyncContext *c, gpointer r, gpointer priv) { struct rspamd_redis_stat_cbdata *cbdata = priv; redisReply *reply = r, *elt; gchar **pk, *k; guint i, processed = 0; if (cbdata->wanna_die) { return; } cbdata->inflight --; if (c->err == 0 && r != NULL) { if (reply->type == REDIS_REPLY_ARRAY) { g_ptr_array_set_size (cbdata->cur_keys, reply->elements); for (i = 0; i < reply->elements; i ++) { elt = reply->element[i]; if (elt->type == REDIS_REPLY_STRING) { pk = (gchar **)&g_ptr_array_index (cbdata->cur_keys, i); *pk = g_malloc (elt->len + 1); rspamd_strlcpy (*pk, elt->str, elt->len + 1); processed ++; } } if (processed) { for (i = 0; i < cbdata->cur_keys->len; i ++) { k = (gchar *)g_ptr_array_index (cbdata->cur_keys, i); if (k) { redisAsyncCommand (cbdata->redis, rspamd_redis_stat_key, cbdata, "HLEN %s", k); redisAsyncCommand (cbdata->redis, rspamd_redis_stat_learns, cbdata, "HGET %s learns", k); cbdata->inflight += 2; } } } } /* Set up the required keys */ ucl_object_insert_key (cbdata->cur, ucl_object_typed_new (UCL_INT), "revision", 0, false); ucl_object_insert_key (cbdata->cur, ucl_object_typed_new (UCL_INT), "used", 0, false); ucl_object_insert_key (cbdata->cur, ucl_object_typed_new (UCL_INT), "total", 0, false); ucl_object_insert_key (cbdata->cur, ucl_object_typed_new (UCL_INT), "size", 0, false); ucl_object_insert_key (cbdata->cur, ucl_object_fromstring (cbdata->elt->ctx->stcf->symbol), "symbol", 0, false); ucl_object_insert_key (cbdata->cur, ucl_object_fromstring ("redis"), "type", 0, false); ucl_object_insert_key (cbdata->cur, ucl_object_fromint (0), "languages", 0, false); ucl_object_insert_key (cbdata->cur, ucl_object_fromint (processed), "users", 0, false); rspamd_upstream_ok (cbdata->selected); } else { if (c->errstr) { msg_err ("cannot get keys to gather stat: %s", c->errstr); } else { msg_err ("cannot get keys to gather stat: unknown error"); } rspamd_upstream_fail (cbdata->selected); rspamd_redis_async_cbdata_cleanup (cbdata); } if (cbdata->inflight == 0) { rspamd_redis_async_cbdata_cleanup (cbdata); } }