]> source.dussan.org Git - rspamd.git/commitdiff
* Link dynamic configuration to the main build.
authorVsevolod Stakhov <vsevolod@rambler-co.ru>
Tue, 25 Sep 2012 18:12:07 +0000 (22:12 +0400)
committerVsevolod Stakhov <vsevolod@rambler-co.ru>
Tue, 25 Sep 2012 18:12:07 +0000 (22:12 +0400)
Add utility functions for dynamic config.

lib/CMakeLists.txt
src/dynamic_cfg.c

index d6d45fc919f834822d012ff8cc6f294c4a699698..0c05477b84f9d1c14ec0926ace1849f15709f6a3 100644 (file)
@@ -30,6 +30,7 @@ SET(LIBRSPAMDSERVERSRC
                                ../src/cfg_xml.c
                                ../src/dkim.c
                                ../src/dns.c
+                               ../src/dynamic_cfg.c
                                ../src/events.c
                                ../src/html.c
                                ../src/kvstorage.c
index 6f868271dd1c08c19a712fcbdc56ce5827028826..4f416788764980b01175ad3917356606ca8ad0fe 100644 (file)
 
 #include "config.h"
 #include "main.h"
+#include "map.h"
+#include "filter.h"
 #include "dynamic_cfg.h"
+#include "json/jansson.h"
 
-struct dynamic_cfg {
+struct dynamic_cfg_symbol {
+       gchar                                              *name;
+       gdouble                                             value;
+};
+
+struct dynamic_cfg_action {
+       enum rspamd_metric_action           action;
+       gdouble                                             value;
+};
 
+struct dynamic_cfg_metric {
+       GList                                              *symbols;
+       GList                                              *actions;
+       gchar                                              *name;
 };
 
 struct config_json_buf {
@@ -34,18 +49,111 @@ struct config_json_buf {
        gchar                          *pos;
        size_t                          buflen;
        struct config_file             *cfg;
+       GList                                              *config_metrics;
 };
 
+/**
+ * Free dynamic configuration
+ * @param conf_metrics
+ */
+static void
+dynamic_cfg_free (GList *conf_metrics)
+{
+       GList                                                           *cur, *cur_elt;
+       struct dynamic_cfg_metric                       *metric;
+       struct dynamic_cfg_symbol                       *sym;
+       struct dynamic_cfg_action                       *act;
+
+       if (conf_metrics) {
+               cur = conf_metrics;
+               while (cur) {
+                       metric = cur->data;
+                       if (metric->symbols) {
+                               cur_elt = metric->symbols;
+                               while (cur_elt) {
+                                       sym = cur_elt->data;
+                                       g_free (sym->name);
+                                       g_slice_free1 (sizeof (struct dynamic_cfg_symbol), sym);
+                                       cur_elt = g_list_next (cur_elt);
+                               }
+                               g_list_free (metric->symbols);
+                       }
+
+                       if (metric->actions) {
+                               cur_elt = metric->actions;
+                               while (cur_elt) {
+                                       act = cur_elt->data;
+                                       g_slice_free1 (sizeof (struct dynamic_cfg_symbol), act);
+                                       cur_elt = g_list_next (cur_elt);
+                               }
+                               g_list_free (metric->actions);
+                       }
+                       g_slice_free1 (sizeof (struct dynamic_cfg_metric), metric);
+                       cur = g_list_next (cur);
+               }
+               g_list_free (conf_metrics);
+       }
+}
+/**
+ * Apply configuration to the specified configuration
+ * @param conf_metrics
+ * @param cfg
+ */
+static void
+apply_dynamic_conf (GList *conf_metrics, struct config_file *cfg)
+{
+       GList                                                           *cur, *cur_elt, *tmp;
+       struct dynamic_cfg_metric                       *metric;
+       struct dynamic_cfg_symbol                       *sym;
+       struct dynamic_cfg_action                       *act;
+       struct metric                                           *real_metric;
+       struct metric_action                            *real_act;
+       gdouble                                                         *w;
+
+       cur = conf_metrics;
+       while (cur) {
+               metric = cur->data;
+               if ((real_metric = g_hash_table_lookup (cfg->metrics, metric->name)) != NULL) {
+                       cur_elt = metric->symbols;
+                       while (cur_elt) {
+                               sym = cur_elt->data;
+                               if ((w = g_hash_table_lookup (real_metric->symbols, sym->name)) != NULL) {
+                                       *w = sym->value;
+                               }
+                               else {
+                                       msg_info ("symbol %s is not found in the main configuration", sym->name);
+                               }
+                               cur_elt = g_list_next (cur_elt);
+                       }
+
+                       cur_elt = metric->actions;
+                       while (cur_elt) {
+                               act = cur_elt->data;
+                               tmp = real_metric->actions;
+                               while (tmp) {
+                                       real_act = tmp->data;
+                                       if (real_act->action == act->action) {
+                                               real_act->score = act->value;
+                                       }
+                                       tmp = g_list_next (tmp);
+                               }
+                               cur_elt = g_list_next (cur_elt);
+                       }
+               }
+               cur = g_list_next (cur);
+       }
+}
+
 /* Callbacks for reading json dynamic rules */
 gchar                         *
 json_config_read_cb (memory_pool_t * pool, gchar * chunk, gint len, struct map_cb_data *data)
 {
-       struct regexp_json_buf                          *jb;
+       struct config_json_buf                          *jb;
        gint                                                             free, off;
 
        if (data->cur_data == NULL) {
-               jb = g_malloc (sizeof (struct regexp_json_buf));
-               jb->cfg = ((struct regexp_json_buf *)data->prev_data)->cfg;
+               jb = g_malloc (sizeof (struct config_json_buf));
+               jb->cfg = ((struct config_json_buf *)data->prev_data)->cfg;
                jb->buf = NULL;
                jb->pos = NULL;
                data->cur_data = jb;
@@ -81,9 +189,13 @@ void
 json_config_fin_cb (memory_pool_t * pool, struct map_cb_data *data)
 {
        struct config_json_buf                          *jb;
-       guint                                                            nelts, i, j;
+       guint                                                            nelts, i, j, selts;
+       gint                                                             test_act;
        json_t                                                          *js, *cur_elt, *cur_nm, *it_val;
        json_error_t                                             je;
+       struct dynamic_cfg_metric                       *cur_metric;
+       struct dynamic_cfg_symbol                       *cur_symbol;
+       struct dynamic_cfg_action                       *cur_action;
 
        if (data->prev_data) {
                jb = data->prev_data;
@@ -120,6 +232,76 @@ json_config_fin_cb (memory_pool_t * pool, struct map_cb_data *data)
                msg_err ("loaded json is not an array");
                return;
        }
+
+       dynamic_cfg_free (jb->config_metrics);
+       jb->config_metrics = NULL;
+
+       /* Parse configuration */
+       nelts = json_array_size (js);
+       for (i = 0; i < nelts; i++) {
+               cur_elt = json_array_get (js, i);
+               if (!cur_elt || !json_is_object (cur_elt)) {
+                       msg_err ("loaded json array element is not an object");
+                       continue;
+               }
+
+               cur_nm = json_object_get (cur_elt, "name");
+               if (!cur_nm || !json_is_string (cur_nm)) {
+                       msg_err ("loaded json array element has no 'name' attribute");
+                       continue;
+               }
+               cur_metric = g_slice_alloc0 (sizeof (struct dynamic_cfg_metric));
+               cur_metric->name = g_strdup (json_string_value (cur_nm));
+               cur_nm = json_object_get (cur_elt, "symbols");
+               /* Parse symbols */
+               if (cur_nm && json_is_array (cur_nm)) {
+                       selts = json_array_size (cur_nm);
+                       for (j = 0; j < selts; j ++) {
+                               it_val = json_array_get (cur_nm, j);
+                               if (it_val && json_is_object (it_val)) {
+                                       if (json_object_get (it_val, "name") && json_object_get (it_val, "value")) {
+                                               cur_symbol = g_slice_alloc0 (sizeof (struct dynamic_cfg_symbol));
+                                               cur_symbol->name = g_strdup (json_string_value (json_object_get (it_val, "name")));
+                                               cur_symbol->value = json_number_value (json_object_get (it_val, "value"));
+                                               /* Insert symbol */
+                                               cur_metric->symbols = g_list_prepend (cur_metric->symbols, cur_symbol);
+                                       }
+                               }
+                       }
+               }
+               cur_nm = json_object_get (cur_elt, "actions");
+               /* Parse actions */
+               if (cur_nm && json_is_array (cur_nm)) {
+                       selts = json_array_size (cur_nm);
+                       for (j = 0; j < selts; j ++) {
+                               it_val = json_array_get (cur_nm, j);
+                               if (it_val && json_is_object (it_val)) {
+                                       if (json_object_get (it_val, "name") && json_object_get (it_val, "value")) {
+
+                                               cur_action = g_slice_alloc0 (sizeof (struct dynamic_cfg_action));
+                                               if (!check_action_str (json_string_value (json_object_get (it_val, "name")), &test_act)) {
+                                                       msg_err ("unknown action: %s", json_string_value (json_object_get (it_val, "name")));
+                                                       g_slice_free1 (sizeof (struct dynamic_cfg_action), cur_action);
+                                                       continue;
+                                               }
+                                               cur_action->action = test_act;
+                                               cur_action->value = json_number_value (json_object_get (it_val, "value"));
+                                               /* Insert action */
+                                               cur_metric->actions = g_list_prepend (cur_metric->actions, cur_action);
+                                       }
+                               }
+                       }
+               }
+               jb->config_metrics = g_list_prepend (jb->config_metrics, cur_metric);
+       }
+       /*
+        * Note about thread safety: we are updating values that are gdoubles so it is not atomic in general case
+        * but on the other hand all that data is used only in the main thread, so why it is *likely* safe
+        * to do this task in this way without explicit lock.
+        */
+       apply_dynamic_conf (jb->config_metrics, jb->cfg);
+
+       json_decref (js);
 }
 
 /**
@@ -129,7 +311,6 @@ json_config_fin_cb (memory_pool_t * pool, struct map_cb_data *data)
 void
 init_dynamic_config (struct config_file *cfg)
 {
-       gint                                                             fd;
        struct stat                                                      st;
        struct config_json_buf                          *jb, **pjb;
 
@@ -148,12 +329,12 @@ init_dynamic_config (struct config_file *cfg)
        }
 
        /* Now try to add map with json data */
-       jb = g_malloc (sizeof (struct regexp_json_buf));
-       pjb = g_malloc (sizeof (struct regexp_json_buf *));
+       jb = g_malloc (sizeof (struct config_json_buf));
+       pjb = g_malloc (sizeof (struct config_json_buf *));
        jb->buf = NULL;
        jb->cfg = cfg;
        *pjb = jb;
-       if (!add_map (cfg->dynamic_conf, json_config_read_cb, json_config_fin_cb, (void **)pjb)) {
+       if (!add_map (cfg, cfg->dynamic_conf, json_config_read_cb, json_config_fin_cb, (void **)pjb)) {
                msg_err ("cannot add map for configuration %s", cfg->dynamic_conf);
        }
 }