From: cebka@cebka-laptop Date: Tue, 14 Oct 2008 15:10:21 +0000 (+0400) Subject: * Implement composite symbols X-Git-Tag: 0.2.7~359 X-Git-Url: https://source.dussan.org/?a=commitdiff_plain;h=cd9b528a22e190c11d47c452b6d83fd1fbd4550c;p=rspamd.git * Implement composite symbols --- diff --git a/cfg_file.h b/cfg_file.h index 21c8b26fa..9632a70e7 100644 --- a/cfg_file.h +++ b/cfg_file.h @@ -47,6 +47,7 @@ fprintf (stderr, fmt, ##__VA_ARGS__); \ fprintf (stderr, "\n") +struct expression; enum { VAL_UNDEF=0, VAL_TRUE, VAL_FALSE }; @@ -119,6 +120,7 @@ struct config_file { GHashTable* metrics; GHashTable* factors; GHashTable* c_modules; + GHashTable* composite_symbols; }; int add_memcached_server (struct config_file *cf, char *str); @@ -132,6 +134,7 @@ char parse_flag (const char *str); char* substitute_variable (struct config_file *cfg, char *str, u_char recursive); void post_load_config (struct config_file *cfg); struct rspamd_regexp* parse_regexp (memory_pool_t *pool, char *line); +struct expression* parse_expression (memory_pool_t *pool, char *line); int yylex (void); int yyparse (void); diff --git a/cfg_file.l b/cfg_file.l index 3cb8441bd..198f65792 100644 --- a/cfg_file.l +++ b/cfg_file.l @@ -24,6 +24,7 @@ extern struct config_file *cfg; ^[ \t]*#.* /* ignore comments */; .include BEGIN(incl); .module BEGIN(module); +composites return COMPOSITES; tempdir return TEMPDIR; pidfile return PIDFILE; workers return WORKERS; diff --git a/cfg_file.y b/cfg_file.y index ae901964b..c5badb437 100644 --- a/cfg_file.y +++ b/cfg_file.y @@ -17,6 +17,7 @@ #include #include "cfg_file.h" +#include "main.h" #define YYDEBUG 1 @@ -48,7 +49,7 @@ struct metric *cur_metric = NULL; %token MEMCACHED WORKERS REQUIRE MODULE %token MODULE_OPT PARAM VARIABLE %token HEADER_FILTERS MIME_FILTERS MESSAGE_FILTERS URL_FILTERS FACTORS METRIC NAME -%token REQUIRED_SCORE FUNCTION FRACT +%token REQUIRED_SCORE FUNCTION FRACT COMPOSITES %type STRING %type VARIABLE @@ -85,6 +86,7 @@ command : | variable | factors | metric + | composites ; tempdir : @@ -351,6 +353,25 @@ requirecmd: } ; +composites: + COMPOSITES OBRACE compositesbody EBRACE + ; + +compositesbody: + compositescmd SEMICOLON + | compositesbody compositescmd SEMICOLON + ; + +compositescmd: + QUOTEDSTRING EQSIGN QUOTEDSTRING { + struct expression *expr; + if ((expr = parse_expression (cfg->cfg_pool, $3)) == NULL) { + yyerror ("yyparse: cannot parse composite expression: %s", $3); + YYERROR; + } + g_hash_table_insert (cfg->composite_symbols, $1, expr); + } + ; module_opt: MODULE_OPT OBRACE moduleoptbody EBRACE { g_hash_table_insert (cfg->modules_opts, $1, cur_module_opt); diff --git a/cfg_utils.c b/cfg_utils.c index 8630a0963..ae0dce5e3 100644 --- a/cfg_utils.c +++ b/cfg_utils.c @@ -134,6 +134,7 @@ init_defaults (struct config_file *cfg) cfg->metrics = g_hash_table_new (g_str_hash, g_str_equal); cfg->factors = g_hash_table_new (g_str_hash, g_str_equal); cfg->c_modules = g_hash_table_new (g_str_hash, g_str_equal); + cfg->composite_symbols = g_hash_table_new (g_str_hash, g_str_equal); LIST_INIT (&cfg->perl_modules); } @@ -151,6 +152,8 @@ free_config (struct config_file *cfg) g_hash_table_unref (cfg->factors); g_hash_table_remove_all (cfg->c_modules); g_hash_table_unref (cfg->c_modules); + g_hash_table_remove_all (cfg->composite_symbols); + g_hash_table_unref (cfg->composite_symbols); memory_pool_delete (cfg->cfg_pool); } diff --git a/filter.c b/filter.c index a69a9efa9..d1edbb930 100644 --- a/filter.c +++ b/filter.c @@ -12,7 +12,6 @@ void insert_result (struct worker_task *task, const char *metric_name, const char *symbol, u_char flag) { - struct filter_result *result; struct metric *metric; struct metric_result *metric_res; @@ -21,20 +20,18 @@ insert_result (struct worker_task *task, const char *metric_name, const char *sy return; } - result = memory_pool_alloc (task->task_pool, sizeof (struct filter_result)); - result->symbol = symbol; - result->flag = flag; metric_res = g_hash_table_lookup (task->results, metric_name); if (metric_res == NULL) { /* Create new metric chain */ metric_res = memory_pool_alloc (task->task_pool, sizeof (struct metric_result)); - LIST_INIT (&metric_res->results); + metric_res->symbols = g_hash_table_new (g_str_hash, g_str_equal); + memory_pool_add_destructor (task->task_pool, (pool_destruct_func)g_hash_table_destroy, metric_res->symbols); metric_res->metric = metric; g_hash_table_insert (task->results, (gpointer)metric_name, metric_res); } - LIST_INSERT_HEAD (&metric_res->results, result, next); + g_hash_table_insert (metric_res->symbols, (gpointer)symbol, GSIZE_TO_POINTER (flag)); } /* @@ -44,28 +41,31 @@ double factor_consolidation_func (struct worker_task *task, const char *metric_name) { struct metric_result *metric_res; - struct filter_result *result; double *factor; double res = 0.; + GList *symbols = NULL, *cur; metric_res = g_hash_table_lookup (task->results, metric_name); if (metric_res == NULL) { return res; } - - LIST_FOREACH (result, &metric_res->results, next) { - if (result->flag) { - factor = g_hash_table_lookup (task->worker->srv->cfg->factors, result->symbol); - if (factor == NULL) { - /* Default multiplier is 1 */ - res ++; - } - else { - res += *factor; - } + + symbols = g_hash_table_get_keys (metric_res->symbols); + cur = g_list_first (symbols); + while (cur) { + factor = g_hash_table_lookup (task->worker->srv->cfg->factors, cur->data); + if (factor == NULL) { + /* Default multiplier is 1 */ + res ++; } + else { + res += *factor; + } + cur = g_list_next (cur); } + g_list_free (symbols); + return res; } @@ -240,3 +240,97 @@ process_filters (struct worker_task *task) g_hash_table_foreach (task->results, metric_process_callback, task); return 1; } + +struct composites_data { + struct worker_task *task; + struct metric_result *metric_res; +}; + +static void +composites_foreach_callback (gpointer key, gpointer value, void *data) +{ + struct composites_data *cd = (struct composites_data *)data; + struct expression *expr = (struct expression *)value; + GQueue *stack; + GList *symbols = NULL, *s; + gsize cur, op1, op2; + + stack = g_queue_new (); + + while (expr) { + if (expr->type == EXPR_OPERAND) { + /* Find corresponding symbol */ + if (g_hash_table_lookup (cd->metric_res->symbols, expr->content.operand) == NULL) { + cur = 0; + } + else { + cur = 1; + symbols = g_list_append (symbols, expr->content.operand); + } + g_queue_push_head (stack, GSIZE_TO_POINTER (cur)); + } + else { + if (g_queue_is_empty (stack)) { + /* Queue has no operands for operation, exiting */ + g_list_free (symbols); + g_queue_free (stack); + return; + } + switch (expr->content.operation) { + case '!': + op1 = GPOINTER_TO_SIZE (g_queue_pop_head (stack)); + op1 = !op1; + g_queue_push_head (stack, GSIZE_TO_POINTER (op1)); + break; + case '&': + op1 = GPOINTER_TO_SIZE (g_queue_pop_head (stack)); + op2 = GPOINTER_TO_SIZE (g_queue_pop_head (stack)); + g_queue_push_head (stack, GSIZE_TO_POINTER (op1 && op2)); + case '|': + op1 = GPOINTER_TO_SIZE (g_queue_pop_head (stack)); + op2 = GPOINTER_TO_SIZE (g_queue_pop_head (stack)); + g_queue_push_head (stack, GSIZE_TO_POINTER (op1 || op2)); + default: + expr = expr->next; + continue; + } + } + expr = expr->next; + } + if (!g_queue_is_empty (stack)) { + op1 = GPOINTER_TO_SIZE (g_queue_pop_head (stack)); + if (op1) { + /* Remove all symbols that are in composite symbol */ + s = g_list_first (symbols); + while (s) { + g_hash_table_remove (cd->metric_res->symbols, s->data); + s = g_list_next (s); + } + /* Add new symbol */ + g_hash_table_insert (cd->metric_res->symbols, key, GSIZE_TO_POINTER (op1)); + } + } + + g_queue_free (stack); + g_list_free (symbols); + + return; +} + +static void +composites_metric_callback (gpointer key, gpointer value, void *data) +{ + struct worker_task *task = (struct worker_task *)data; + struct composites_data *cd = memory_pool_alloc (task->task_pool, sizeof (struct composites_data)); + struct metric_result *metric_res = (struct metric_result *)value; + + cd->task = task; + cd->metric_res = (struct metric_result *)metric_res; + + g_hash_table_foreach (task->cfg->composite_symbols, composites_foreach_callback, cd); +} + +void make_composites (struct worker_task *task) +{ + g_hash_table_foreach (task->results, composites_metric_callback, task); +} diff --git a/filter.h b/filter.h index d7f494dc6..ce8be7ecd 100644 --- a/filter.h +++ b/filter.h @@ -29,20 +29,15 @@ struct metric { double required_score; }; -struct filter_result { - const char *symbol; - u_char flag; - LIST_ENTRY (filter_result) next; -}; - struct metric_result { struct metric *metric; double score; - LIST_HEAD (resultq, filter_result) results; + GHashTable *symbols; }; int process_filters (struct worker_task *task); void insert_result (struct worker_task *task, const char *metric_name, const char *symbol, u_char flag); +void make_composites (struct worker_task *task); double factor_consolidation_func (struct worker_task *task, const char *metric_name); #endif diff --git a/main.h b/main.h index f111ba1b4..0d9e8ca10 100644 --- a/main.h +++ b/main.h @@ -163,7 +163,6 @@ struct c_module { }; void start_worker (struct rspamd_worker *worker, int listen_sock); -struct expression* parse_expression (memory_pool_t *pool, char *line); #endif diff --git a/protocol.c b/protocol.c index 832a14281..0881b9788 100644 --- a/protocol.c +++ b/protocol.c @@ -363,23 +363,25 @@ show_metric_symbols (gpointer metric_name, gpointer metric_value, void *user_dat struct worker_task *task = (struct worker_task *)user_data; int r = 0; char outbuf[OUTBUFSIZ]; - struct filter_result *result; + GList *symbols = NULL, *cur; struct metric_result *metric_res = (struct metric_result *)metric_value; if (task->proto == RSPAMC_PROTO) { r = snprintf (outbuf, sizeof (outbuf), "%s: ", (char *)metric_name); } - LIST_FOREACH (result, &metric_res->results, next) { - if (result->flag) { - if (LIST_NEXT (result, next) != NULL) { - r += snprintf (outbuf + r, sizeof (outbuf) - r, "%s,", result->symbol); - } - else { - r += snprintf (outbuf + r, sizeof (outbuf) - r, "%s", result->symbol); - } + symbols = g_hash_table_get_keys (metric_res->symbols); + cur = symbols; + while (cur) { + if (g_list_next (cur) != NULL) { + r += snprintf (outbuf + r, sizeof (outbuf) - r, "%s,", (char *)cur->data); + } + else { + r += snprintf (outbuf + r, sizeof (outbuf) - r, "%s", (char *)cur->data); } + cur = g_list_next (cur); } + g_list_free (symbols); outbuf[r++] = '\r'; outbuf[r] = '\n'; bufferevent_write (task->bev, outbuf, r); }