Browse Source

Add metrics handler for rcl.

pull/2/head
Vsevolod Stakhov 12 years ago
parent
commit
29c0431542
  1. 192
      src/cfg_rcl.c

192
src/cfg_rcl.c

@ -23,6 +23,7 @@
#include "cfg_rcl.h"
#include "main.h"
#include "settings.h"
/*
* Common section handlers
@ -186,6 +187,192 @@ rspamd_rcl_options_handler (struct config_file *cfg, rspamd_cl_object_t *obj,
return rspamd_rcl_section_parse_defaults (section, cfg, obj, cfg, err);
}
static gint
rspamd_symbols_group_find_func (gconstpointer a, gconstpointer b)
{
const struct symbols_group *gr = a;
const gchar *uv = b;
return g_ascii_strcasecmp (gr->name, uv);
}
/**
* Insert a symbol to the metric
* @param cfg
* @param metric
* @param obj symbol rcl object (either float value or an object)
* @param err
* @return
*/
static gboolean
rspamd_rcl_insert_symbol (struct config_file *cfg, struct metric *metric,
rspamd_cl_object_t *obj, GError **err)
{
const gchar *group = "ungrouped", *description = NULL;
gdouble symbol_score, *score_ptr;
rspamd_cl_object_t *val;
struct symbols_group *sym_group;
struct symbol_def *sym_def;
GList *metric_list, *group_list;
/*
* We allow two type of definitions:
* symbol = weight
* or
* symbol {
* weight = ...;
* description = ...;
* group = ...;
* }
*/
if (rspamd_cl_obj_todouble_safe (obj, &symbol_score)) {
description = NULL;
}
else if (obj->type == RSPAMD_CL_OBJECT) {
HASH_FIND_STR (obj, "score", val);
if (val == NULL || !rspamd_cl_obj_todouble_safe (val, &symbol_score)) {
g_set_error (err, CFG_RCL_ERROR, EINVAL, "invalid symbol score: %s", obj->key);
return FALSE;
}
HASH_FIND_STR (obj, "description", val);
if (val != NULL) {
description = rspamd_cl_obj_tostring (val);
}
HASH_FIND_STR (obj, "group", val);
if (val != NULL) {
rspamd_cl_obj_tostring_safe (val, &group);
}
}
else {
g_set_error (err, CFG_RCL_ERROR, EINVAL, "invalid symbol type: %s", obj->key);
return FALSE;
}
sym_def = memory_pool_alloc (cfg->cfg_pool, sizeof (struct symbol_def));
score_ptr = memory_pool_alloc (cfg->cfg_pool, sizeof (gdouble));
*score_ptr = symbol_score;
sym_def->weight_ptr = score_ptr;
sym_def->name = memory_pool_strdup (cfg->cfg_pool, obj->key);
sym_def->description = (gchar *)description;
g_hash_table_insert (metric->symbols, sym_def->name, score_ptr);
if ((metric_list = g_hash_table_lookup (cfg->metrics_symbols, sym_def->name)) == NULL) {
metric_list = g_list_prepend (NULL, metric);
memory_pool_add_destructor (cfg->cfg_pool, (pool_destruct_func)g_list_free, metric_list);
g_hash_table_insert (cfg->metrics_symbols, sym_def->name, metric_list);
}
else {
/* Slow but keep start element of list in safe */
if (!g_list_find (metric_list, metric)) {
metric_list = g_list_append (metric_list, metric);
}
}
/* Search for symbol group */
group_list = g_list_find_custom (cfg->symbols_groups, group, rspamd_symbols_group_find_func);
if (group_list == NULL) {
/* Create new group */
sym_group = memory_pool_alloc (cfg->cfg_pool, sizeof (struct symbols_group));
sym_group->name = memory_pool_strdup (cfg->cfg_pool, group);
sym_group->symbols = NULL;
cfg->symbols_groups = g_list_prepend (cfg->symbols_groups, sym_group);
}
else {
sym_group = group_list->data;
}
/* Insert symbol */
sym_group->symbols = g_list_prepend (sym_group->symbols, sym_def);
return TRUE;
}
static gboolean
rspamd_rcl_metric_handler (struct config_file *cfg, rspamd_cl_object_t *obj,
gpointer ud, struct rspamd_rcl_section *section, GError **err)
{
rspamd_cl_object_t *val, *lobj, *cur, *tmp;
const gchar *metric_name, *subject_name;
struct metric *metric;
struct metric_action *action;
gdouble action_score, grow_factor;
gint action_value;
gboolean new = TRUE;
lobj = obj->value.ov;
HASH_FIND_STR (lobj, "name", val);
if (val == NULL || !rspamd_cl_obj_tostring_safe (val, &metric_name)) {
metric_name = DEFAULT_METRIC;
}
metric = g_hash_table_lookup (cfg->metrics, metric_name);
if (metric == NULL) {
metric = check_metric_conf (cfg, metric);
}
else {
new = FALSE;
}
/* Handle actions */
HASH_FIND_STR (lobj, "actions", val);
if (val != NULL) {
if (val->type != RSPAMD_CL_OBJECT) {
g_set_error (err, CFG_RCL_ERROR, EINVAL, "actions must be an object");
return FALSE;
}
HASH_ITER (hh, val, cur, tmp) {
if (!check_action_str (cur->key, &action_value) ||
!rspamd_cl_obj_todouble_safe (cur, &action_score)) {
g_set_error (err, CFG_RCL_ERROR, EINVAL, "invalid action definition: %s", cur->key);
return FALSE;
}
action = memory_pool_alloc (cfg->cfg_pool, sizeof (struct metric_action));
action->action = action_value;
action->score = action_score;
metric->actions = g_list_prepend (metric->actions, action);
}
}
else if (new) {
g_set_error (err, CFG_RCL_ERROR, EINVAL, "metric %s has no actions", metric_name);
return FALSE;
}
/* Handle symbols */
HASH_FIND_STR (lobj, "symbols", val);
if (val != NULL) {
if (val->type == RSPAMD_CL_ARRAY) {
val = val->value.ov;
}
if (val->type != RSPAMD_CL_OBJECT) {
g_set_error (err, CFG_RCL_ERROR, EINVAL, "symbols must be an object");
return FALSE;
}
HASH_ITER (hh, val, cur, tmp) {
if (!rspamd_rcl_insert_symbol (cfg, metric, cur, err)) {
return FALSE;
}
}
}
HASH_FIND_STR (lobj, "grow_factor", val);
if (val && rspamd_cl_obj_todouble_safe (val, &grow_factor)) {
metric->grow_factor = grow_factor;
}
HASH_FIND_STR (lobj, "subject", val);
if (val && rspamd_cl_obj_tostring_safe (val, &subject_name)) {
metric->subject = (gchar *)subject_name;
}
/* Insert the resulting metric */
g_hash_table_insert (cfg->metrics, metric->name, metric);
cfg->metrics_list = g_list_prepend (cfg->metrics_list, metric);
return TRUE;
}
/**
* Fake handler to parse default options only, uses struct cfg_file as pointer
* for default handlers
@ -317,6 +504,11 @@ rspamd_rcl_config_init (void)
rspamd_rcl_add_default_handler (sub, "use_mlock", rspamd_rcl_parse_struct_boolean,
G_STRUCT_OFFSET (struct config_file, mlock_statfile_pool), 0);
/**
* Metric section
*/
sub = rspamd_rcl_add_section (new, "metric", rspamd_rcl_metric_handler, RSPAMD_CL_OBJECT,
FALSE, TRUE);
return new;
}

Loading…
Cancel
Save