return TRUE;
}
+static ucl_object_t *
+rspamd_fuzzy_storage_stat_key (struct fuzzy_key_stat *key_stat)
+{
+ ucl_object_t *res;
+
+ res = ucl_object_typed_new (UCL_OBJECT);
+
+ ucl_object_insert_key (res, ucl_object_fromint (key_stat->checked),
+ "checked", 0, false);
+ ucl_object_insert_key (res, ucl_object_fromint (key_stat->matched),
+ "matched", 0, false);
+ ucl_object_insert_key (res, ucl_object_fromint (key_stat->added),
+ "added", 0, false);
+ ucl_object_insert_key (res, ucl_object_fromint (key_stat->deleted),
+ "deleted", 0, false);
+ ucl_object_insert_key (res, ucl_object_fromint (key_stat->errors),
+ "errors", 0, false);
+
+ return res;
+}
+
+static gboolean
+rspamd_fuzzy_storage_stat (struct rspamd_main *rspamd_main,
+ struct rspamd_worker *worker, gint fd,
+ struct rspamd_control_command *cmd,
+ gpointer ud)
+{
+ struct rspamd_fuzzy_storage_ctx *ctx = ud;
+ struct rspamd_control_reply rep;
+ GHashTableIter it, ip_it;
+ GHashTable *ip_hash;
+ struct fuzzy_key_stat *key_stat;
+ struct rspamd_http_keypair *kp;
+ ucl_object_t *obj, *elt, *ip_elt, *ip_cur;
+ struct ucl_emitter_functions *emit_subr;
+ guchar fdspace[CMSG_SPACE(sizeof (int))];
+ struct iovec iov;
+ struct msghdr msg;
+ struct cmsghdr *cmsg;
+ gpointer k, v;
+ gint outfd = -1;
+ gchar tmppath[PATH_MAX], keyname[17];
+
+ memset (&rep, 0, sizeof (rep));
+ rep.type = RSPAMD_CONTROL_RELOAD;
+
+ rspamd_snprintf (tmppath, sizeof (tmppath), "%s%c%s-XXXXXXXXXX",
+ rspamd_main->cfg->temp_dir, G_DIR_SEPARATOR, "fuzzy-stat");
+
+ if ((outfd = mkstemp (tmppath)) == -1) {
+ rep.reply.fuzzy_stat.status = errno;
+ msg_info_main ("cannot make temporary stat file for fuzzy stat: %s",
+ strerror (errno));
+ }
+ else {
+ rep.reply.fuzzy_stat.status = 0;
+
+ /* Iterate over all keys */
+ obj = ucl_object_typed_new (UCL_OBJECT);
+ g_hash_table_iter_init (&it, ctx->keys);
+
+ while (g_hash_table_iter_next (&it, &k, &v)) {
+ kp = v;
+ key_stat = g_hash_table_lookup (ctx->keys_stats, kp->pk);
+
+ if (key_stat) {
+ rspamd_snprintf (keyname, sizeof (keyname), "%8xs", k);
+
+ elt = rspamd_fuzzy_storage_stat_key (key_stat);
+
+ if (key_stat->last_ips) {
+ ip_hash = rspamd_lru_hash_get_htable (key_stat->last_ips);
+
+ if (ip_hash) {
+ g_hash_table_iter_init (&ip_it, ip_hash);
+ ip_elt = ucl_object_typed_new (UCL_OBJECT);
+
+ while (g_hash_table_iter_next (&ip_it, &k, &v)) {
+ ip_cur = rspamd_fuzzy_storage_stat_key (v);
+ ucl_object_insert_key (ip_elt, ip_cur,
+ rspamd_inet_address_to_string (k), 0, true);
+ }
+
+ ucl_object_insert_key (elt, ip_elt, "ips", 0, false);
+ }
+ }
+
+ ucl_object_insert_key (obj, elt, keyname, 0, true);
+ }
+ }
+
+ emit_subr = ucl_object_emit_fd_funcs (outfd);
+ ucl_object_emit_full (obj, UCL_EMIT_JSON_COMPACT, emit_subr);
+ ucl_object_emit_funcs_free (emit_subr);
+ ucl_object_unref (obj);
+ }
+
+ /* Now we can send outfd and status message */
+ memset (&msg, 0, sizeof (msg));
+
+ /* Attach fd to the message */
+ if (outfd != -1) {
+ memset (fdspace, 0, sizeof (fdspace));
+ msg.msg_control = fdspace;
+ msg.msg_controllen = sizeof (fdspace);
+ cmsg = CMSG_FIRSTHDR (&msg);
+ cmsg->cmsg_level = SOL_SOCKET;
+ cmsg->cmsg_type = SCM_RIGHTS;
+ cmsg->cmsg_len = CMSG_LEN (sizeof (int));
+ memcpy (CMSG_DATA (cmsg), &outfd, sizeof (int));
+ }
+
+ iov.iov_base = &rep;
+ iov.iov_len = sizeof (rep);
+ msg.msg_iov = &iov;
+ msg.msg_iovlen = 1;
+
+ if (sendmsg (fd, &msg, 0) == -1) {
+ msg_err_main ("cannot send fuzzy stat: %s", strerror (errno));
+ }
+
+ if (outfd != -1) {
+ close (outfd);
+ }
+
+ return TRUE;
+}
+
static gboolean
fuzzy_parse_keypair (rspamd_mempool_t *pool,
const ucl_object_t *obj,
rspamd_fuzzy_backend_sync (ctx->backend, ctx->expire, TRUE);
}
- /* Register custom reload command for the control socket */
+ /* Register custom reload and stat commands for the control socket */
rspamd_control_worker_add_cmd_handler (worker, RSPAMD_CONTROL_RELOAD,
rspamd_fuzzy_storage_reload, ctx);
+ rspamd_control_worker_add_cmd_handler (worker, RSPAMD_CONTROL_FUZZY_STAT,
+ rspamd_fuzzy_storage_stat, ctx);
/* Create radix tree */
if (ctx->update_map != NULL) {
if (!rspamd_map_add (worker->srv->cfg, ctx->update_map,