From 618e3f4887b61c69915f1c641ea47044695d6e7f Mon Sep 17 00:00:00 2001 From: Vsevolod Stakhov Date: Fri, 3 Dec 2010 21:57:38 +0300 Subject: * Start new rspamd 0.3.4 * Add ability to manage per-module, per-worker and per-classifier options in XML parser --- CMakeLists.txt | 3 +- src/cfg_xml.c | 252 +++++++++++++++++++++++++++++++++++++++++++--------- src/cfg_xml.h | 27 +++++- src/controller.c | 36 ++++++-- src/fuzzy_storage.c | 133 ++++++++++++++------------- src/fuzzy_storage.h | 1 + src/logger.c | 25 +----- src/logger.h | 12 --- src/main.c | 44 ++++----- src/main.h | 10 ++- src/smtp.c | 95 ++++++++++---------- src/smtp.h | 9 +- src/util.c | 54 +++++++++++ src/util.h | 30 +++++++ src/worker.c | 121 ++++++++++++------------- 15 files changed, 561 insertions(+), 291 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index cfaa95ed3..7945ae059 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -7,7 +7,7 @@ PROJECT(rspamd C) SET(RSPAMD_VERSION_MAJOR 0) SET(RSPAMD_VERSION_MINOR 3) -SET(RSPAMD_VERSION_PATCH 3) +SET(RSPAMD_VERSION_PATCH 4) SET(RSPAMD_VERSION "${RSPAMD_VERSION_MAJOR}.${RSPAMD_VERSION_MINOR}.${RSPAMD_VERSION_PATCH}") @@ -486,6 +486,7 @@ IF(NOT DESTDIR) ENDIF(NOT DESTDIR) # Try to detect tip version from hg +UNSET(ID CACHE) SET(ID "unknown") FIND_PROGRAM(HG "hg") diff --git a/src/cfg_xml.c b/src/cfg_xml.c index 67523c845..ddf995481 100644 --- a/src/cfg_xml.c +++ b/src/cfg_xml.c @@ -51,6 +51,13 @@ NULL \ } \ +#define NULL_DEF_ATTR \ +{ \ + NULL, \ + 0, \ + NULL \ +} \ + enum xml_config_section { XML_SECTION_MAIN, XML_SECTION_LOGGING, @@ -64,16 +71,22 @@ enum xml_config_section { }; struct xml_config_param { - const gchar *name; - element_handler_func handler; - gint offset; - gpointer user_data; + const gchar *name; + element_handler_func handler; + gint offset; + gpointer user_data; +}; + +struct xml_default_config_param { + element_default_handler_func handler; + gint offset; + gpointer user_data; }; struct xml_parser_rule { enum xml_config_section section; struct xml_config_param params[MAX_PARAM]; - struct xml_config_param default_param; + struct xml_default_config_param default_param; }; /* Here we describes our basic grammar */ @@ -165,7 +178,7 @@ static struct xml_parser_rule grammar[] = { }, NULL_ATTR }, - NULL_ATTR + NULL_DEF_ATTR }, { XML_SECTION_LOGGING, { { @@ -206,7 +219,7 @@ static struct xml_parser_rule grammar[] = { }, NULL_ATTR }, - NULL_ATTR + NULL_DEF_ATTR }, { XML_SECTION_WORKER, { { @@ -242,7 +255,6 @@ static struct xml_parser_rule grammar[] = { NULL_ATTR }, { - NULL, worker_handle_param, 0, NULL @@ -287,7 +299,7 @@ static struct xml_parser_rule grammar[] = { }, NULL_ATTR }, - NULL_ATTR + NULL_DEF_ATTR }, { XML_SECTION_CLASSIFIER, { { @@ -302,15 +314,13 @@ static struct xml_parser_rule grammar[] = { 0, NULL }, - { - "option", - handle_classifier_opt, - 0, - NULL - }, NULL_ATTR }, - NULL_ATTR + { + handle_classifier_opt, + 0, + NULL + } }, { XML_SECTION_STATFILE, { { @@ -357,13 +367,12 @@ static struct xml_parser_rule grammar[] = { }, NULL_ATTR }, - NULL_ATTR + NULL_DEF_ATTR }, { XML_SECTION_MODULE, { NULL_ATTR }, { - NULL, handle_module_opt, 0, NULL @@ -378,7 +387,7 @@ static struct xml_parser_rule grammar[] = { }, NULL_ATTR }, - NULL_ATTR + NULL_DEF_ATTR }, { XML_SECTION_VIEW, { { @@ -419,10 +428,14 @@ static struct xml_parser_rule grammar[] = { }, NULL_ATTR }, - NULL_ATTR + NULL_DEF_ATTR }, }; +static GHashTable *module_options = NULL, + *worker_options = NULL, + *classifier_options = NULL; + GQuark xml_error_quark (void) { @@ -510,9 +523,8 @@ call_param_handler (struct rspamd_xml_userdata *ctx, const gchar *name, gchar *v param ++; } if (rule->default_param.handler != NULL) { - param = &rule->default_param; /* Call default handler */ - return param->handler (ctx->cfg, ctx, ctx->cur_attrs, value, param->user_data, dest_struct, param->offset); + return rule->default_param.handler (ctx->cfg, ctx, name, ctx->cur_attrs, value, param->user_data, dest_struct, param->offset); } } } @@ -625,17 +637,32 @@ handle_log_level (struct config_file *cfg, struct rspamd_xml_userdata *ctx, GHas /* Worker section */ gboolean -worker_handle_param (struct config_file *cfg, struct rspamd_xml_userdata *ctx, GHashTable *attrs, gchar *data, gpointer user_data, gpointer dest_struct, gint offset) +worker_handle_param (struct config_file *cfg, struct rspamd_xml_userdata *ctx, const gchar *tag, GHashTable *attrs, gchar *data, gpointer user_data, gpointer dest_struct, gint offset) { struct worker_conf *wrk = ctx->section_pointer; - gchar *name; + const gchar *name; + struct xml_config_param *cparam; + GHashTable *worker_config; - if ((name = g_hash_table_lookup (attrs, "name")) == NULL) { - msg_err ("worker param tag must have \"name\" attribute"); - return FALSE; + if (g_ascii_strcasecmp (tag, "option") == 0 || g_ascii_strcasecmp (tag, "param") == 0) { + if ((name = g_hash_table_lookup (attrs, "name")) == NULL) { + msg_err ("worker param tag must have \"name\" attribute"); + return FALSE; + } + } + else { + name = tag; } - g_hash_table_insert (wrk->params, name, memory_pool_strdup (cfg->cfg_pool, data)); + if (!worker_options || + (worker_config = g_hash_table_lookup (worker_options, &wrk->type)) == NULL || + (cparam = g_hash_table_lookup (worker_config, name)) == NULL) { + msg_warn ("unregistered worker attribute '%s' for worker %s", name, process_to_str (wrk->type)); + g_hash_table_insert (wrk->params, (char *)name, memory_pool_strdup (cfg->cfg_pool, data)); + } + else { + return cparam->handler (cfg, ctx, attrs, data, NULL, cparam->user_data, cparam->offset); + } return TRUE; } @@ -765,27 +792,36 @@ handle_metric_symbol (struct config_file *cfg, struct rspamd_xml_userdata *ctx, /* Modules section */ gboolean -handle_module_opt (struct config_file *cfg, struct rspamd_xml_userdata *ctx, GHashTable *attrs, gchar *data, gpointer user_data, gpointer dest_struct, gint offset) +handle_module_opt (struct config_file *cfg, struct rspamd_xml_userdata *ctx, const gchar *tag, GHashTable *attrs, gchar *data, gpointer user_data, gpointer dest_struct, gint offset) { - gchar *name, *val; + gchar *val; struct module_opt *cur; gboolean is_lua = FALSE; - - if ((name = g_hash_table_lookup (attrs, "name")) == NULL) { - msg_err ("param tag must have \"name\" attribute"); - return FALSE; + const gchar *name; + + if (g_ascii_strcasecmp (tag, "option") == 0 || g_ascii_strcasecmp (tag, "param") == 0) { + if ((name = g_hash_table_lookup (attrs, "name")) == NULL) { + msg_err ("worker param tag must have \"name\" attribute"); + return FALSE; + } } - + else { + name = tag; + } + /* Check for lua */ if ((val = g_hash_table_lookup (attrs, "lua")) != NULL) { if (g_ascii_strcasecmp (val, "yes") == 0) { is_lua = TRUE; } } + /* XXX: in fact we cannot check for lua modules and need to do it in post-config procedure + * so just insert any options provided and try to handle them in further process + */ /* Insert option */ cur = memory_pool_alloc0 (cfg->cfg_pool, sizeof (struct module_opt)); - cur->param = name; + cur->param = (char *)name; cur->value = data; cur->is_lua = is_lua; ctx->section_pointer = g_list_prepend (ctx->section_pointer, cur); @@ -1048,17 +1084,33 @@ handle_classifier_tokenizer (struct config_file *cfg, struct rspamd_xml_userdata } gboolean -handle_classifier_opt (struct config_file *cfg, struct rspamd_xml_userdata *ctx, GHashTable *attrs, gchar *data, gpointer user_data, gpointer dest_struct, gint offset) +handle_classifier_opt (struct config_file *cfg, struct rspamd_xml_userdata *ctx, const gchar *tag, GHashTable *attrs, gchar *data, gpointer user_data, gpointer dest_struct, gint offset) { - struct classifier_config *ccf = ctx->section_pointer; - gchar *val; - - if ((val = g_hash_table_lookup (attrs, "name")) == NULL) { - msg_err ("'name' attribute is required for tag 'option'"); - return FALSE; + struct classifier_config *ccf = ctx->section_pointer; + const gchar *name; + struct xml_config_param *cparam; + GHashTable *classifier_config; + + if (g_ascii_strcasecmp (tag, "option") == 0 || g_ascii_strcasecmp (tag, "param") == 0) { + if ((name = g_hash_table_lookup (attrs, "name")) == NULL) { + msg_err ("worker param tag must have \"name\" attribute"); + return FALSE; + } + } + else { + name = tag; + } + + if (!classifier_options || + (classifier_config = g_hash_table_lookup (classifier_options, ccf->classifier->name)) == NULL || + (cparam = g_hash_table_lookup (classifier_config, name)) == NULL) { + msg_warn ("unregistered classifier attribute '%s' for classifier %s", name, ccf->classifier->name); + g_hash_table_insert (ccf->opts, (char *)name, memory_pool_strdup (cfg->cfg_pool, data)); + } + else { + return cparam->handler (cfg, ctx, attrs, data, NULL, cparam->user_data, cparam->offset); } - g_hash_table_insert (ccf->opts, val, memory_pool_strdup (cfg->cfg_pool, data)); return TRUE; } @@ -1633,6 +1685,118 @@ rspamd_xml_error (GMarkupParseContext *context, GError *error, gpointer user_dat msg_err ("xml parser error: %s, at state \"%s\"", error->message, xml_state_to_string (ud)); } +/* Register handlers for specific parts of config */ +/* Register new module option */ +void +register_module_opt (const gchar *mname, const gchar *optname, element_handler_func func, gpointer dest_struct, gint offset) +{ + struct xml_config_param *param; + GHashTable *module; + + if (module_options == NULL) { + module_options = g_hash_table_new (g_str_hash, g_str_equal); + } + if ((module = g_hash_table_lookup (module_options, mname)) == NULL) { + module = g_hash_table_new (g_str_hash, g_str_equal); + g_hash_table_insert (module_options, (char *)mname, module); + } + if ((param = g_hash_table_lookup (module, optname)) == NULL) { + /* Register new param */ + param = g_malloc (sizeof (struct xml_config_param)); + param->handler = func; + param->user_data = dest_struct; + param->offset = offset; + param->name = optname; + g_hash_table_insert (module, (char *)optname, param); + } + else { + /* Param already exists replace it */ + msg_warn ("replace old handler for param '%s'", optname); + g_free (param); + param = g_malloc (sizeof (struct xml_config_param)); + param->handler = func; + param->user_data = dest_struct; + param->offset = offset; + param->name = optname; + g_hash_table_insert (module, (char *)optname, param); + } +} + +/* Register new worker's options */ +void +register_worker_opt (gint wtype, const gchar *optname, element_handler_func func, gpointer dest_struct, gint offset) +{ + struct xml_config_param *param; + GHashTable *worker; + gint *new_key; + + if (worker_options == NULL) { + worker_options = g_hash_table_new (g_int_hash, g_int_equal); + } + if ((worker = g_hash_table_lookup (worker_options, &wtype)) == NULL) { + worker = g_hash_table_new (g_str_hash, g_str_equal); + new_key = g_malloc (sizeof (gint)); + *new_key = wtype; + g_hash_table_insert (worker_options, new_key, worker); + } + if ((param = g_hash_table_lookup (worker, optname)) == NULL) { + /* Register new param */ + param = g_malloc (sizeof (struct xml_config_param)); + param->handler = func; + param->user_data = dest_struct; + param->offset = offset; + param->name = optname; + g_hash_table_insert (worker, (char *)optname, param); + } + else { + /* Param already exists replace it */ + msg_warn ("replace old handler for param '%s'", optname); + g_free (param); + param = g_malloc (sizeof (struct xml_config_param)); + param->handler = func; + param->user_data = dest_struct; + param->offset = offset; + param->name = optname; + g_hash_table_insert (worker, (char *)optname, param); + } +} + +/* Register new classifier option */ +void +register_classifier_opt (const gchar *ctype, const gchar *optname, element_handler_func func, gpointer dest_struct, gint offset) +{ + struct xml_config_param *param; + GHashTable *classifier; + + if (classifier_options == NULL) { + classifier_options = g_hash_table_new (g_str_hash, g_str_equal); + } + if ((classifier = g_hash_table_lookup (classifier_options, ctype)) == NULL) { + classifier = g_hash_table_new (g_str_hash, g_str_equal); + g_hash_table_insert (classifier_options, (char *)ctype, classifier); + } + if ((param = g_hash_table_lookup (classifier, optname)) == NULL) { + /* Register new param */ + param = g_malloc (sizeof (struct xml_config_param)); + param->handler = func; + param->user_data = dest_struct; + param->offset = offset; + param->name = optname; + g_hash_table_insert (classifier, (char *)optname, param); + } + else { + /* Param already exists replace it */ + msg_warn ("replace old handler for param '%s'", optname); + g_free (param); + param = g_malloc (sizeof (struct xml_config_param)); + param->handler = func; + param->user_data = dest_struct; + param->offset = offset; + param->name = optname; + g_hash_table_insert (classifier, (char *)optname, param); + } +} + /* Dumper part */ diff --git a/src/cfg_xml.h b/src/cfg_xml.h index 456d37fa8..dc55d2c86 100644 --- a/src/cfg_xml.h +++ b/src/cfg_xml.h @@ -39,6 +39,7 @@ struct rspamd_xml_userdata { /* Text is NULL terminated here */ typedef gboolean (*element_handler_func) (struct config_file *cfg, struct rspamd_xml_userdata *ctx, GHashTable *attrs, gchar *data, gpointer user_data, gpointer dest_struct, gint offset); +typedef gboolean (*element_default_handler_func) (struct config_file *cfg, struct rspamd_xml_userdata *ctx, const gchar *tag, GHashTable *attrs, gchar *data, gpointer user_data, gpointer dest_struct, gint offset); /* Callbacks */ @@ -88,42 +89,62 @@ gboolean xml_handle_uint16 (struct config_file *cfg, struct rspamd_xml_userdata gboolean xml_handle_boolean (struct config_file *cfg, struct rspamd_xml_userdata *ctx, GHashTable *attrs, gchar *data, gpointer user_data, gpointer dest_struct, gint offset); /* Specific params */ -gboolean worker_handle_param (struct config_file *cfg, struct rspamd_xml_userdata *ctx, GHashTable *attrs, gchar *data, gpointer user_data, gpointer dest_struct, gint offset); +/* Handle workers param */ +gboolean worker_handle_param (struct config_file *cfg, struct rspamd_xml_userdata *ctx, const gchar *tag, GHashTable *attrs, gchar *data, gpointer user_data, gpointer dest_struct, gint offset); gboolean worker_handle_type (struct config_file *cfg, struct rspamd_xml_userdata *ctx, GHashTable *attrs, gchar *data, gpointer user_data, gpointer dest_struct, gint offset); gboolean worker_handle_bind (struct config_file *cfg, struct rspamd_xml_userdata *ctx, GHashTable *attrs, gchar *data, gpointer user_data, gpointer dest_struct, gint offset); +/* Handle metric symbol */ gboolean handle_metric_symbol (struct config_file *cfg, struct rspamd_xml_userdata *ctx, GHashTable *attrs, gchar *data, gpointer user_data, gpointer dest_struct, gint offset); gboolean handle_metric_action (struct config_file *cfg, struct rspamd_xml_userdata *ctx, GHashTable *attrs, gchar *data, gpointer user_data, gpointer dest_struct, gint offset); -gboolean handle_module_opt (struct config_file *cfg, struct rspamd_xml_userdata *ctx, GHashTable *attrs, gchar *data, gpointer user_data, gpointer dest_struct, gint offset); +/* Handle common module option */ +gboolean handle_module_opt (struct config_file *cfg, struct rspamd_xml_userdata *ctx, const gchar *tag, GHashTable *attrs, gchar *data, gpointer user_data, gpointer dest_struct, gint offset); +/* Handle loging params */ gboolean handle_log_type (struct config_file *cfg, struct rspamd_xml_userdata *ctx, GHashTable *attrs, gchar *data, gpointer user_data, gpointer dest_struct, gint offset); gboolean handle_log_level (struct config_file *cfg, struct rspamd_xml_userdata *ctx, GHashTable *attrs, gchar *data, gpointer user_data, gpointer dest_struct, gint offset); +/* Handle lua include */ gboolean handle_lua (struct config_file *cfg, struct rspamd_xml_userdata *ctx, GHashTable *attrs, gchar *data, gpointer user_data, gpointer dest_struct, gint offset); +/* Handle path to modules */ gboolean handle_module_path (struct config_file *cfg, struct rspamd_xml_userdata *ctx, GHashTable *attrs, gchar *data, gpointer user_data, gpointer dest_struct, gint offset); +/* Handle variables and composites */ gboolean handle_variable (struct config_file *cfg, struct rspamd_xml_userdata *ctx, GHashTable *attrs, gchar *data, gpointer user_data, gpointer dest_struct, gint offset); gboolean handle_composite (struct config_file *cfg, struct rspamd_xml_userdata *ctx, GHashTable *attrs, gchar *data, gpointer user_data, gpointer dest_struct, gint offset); +/* Handle views */ gboolean handle_view_ip (struct config_file *cfg, struct rspamd_xml_userdata *ctx, GHashTable *attrs, gchar *data, gpointer user_data, gpointer dest_struct, gint offset); gboolean handle_view_client_ip (struct config_file *cfg, struct rspamd_xml_userdata *ctx, GHashTable *attrs, gchar *data, gpointer user_data, gpointer dest_struct, gint offset); gboolean handle_view_from (struct config_file *cfg, struct rspamd_xml_userdata *ctx, GHashTable *attrs, gchar *data, gpointer user_data, gpointer dest_struct, gint offset); gboolean handle_view_rcpt (struct config_file *cfg, struct rspamd_xml_userdata *ctx, GHashTable *attrs, gchar *data, gpointer user_data, gpointer dest_struct, gint offset); gboolean handle_view_symbols (struct config_file *cfg, struct rspamd_xml_userdata *ctx, GHashTable *attrs, gchar *data, gpointer user_data, gpointer dest_struct, gint offset); +/* Handle settings */ gboolean handle_user_settings (struct config_file *cfg, struct rspamd_xml_userdata *ctx, GHashTable *attrs, gchar *data, gpointer user_data, gpointer dest_struct, gint offset); gboolean handle_domain_settings (struct config_file *cfg, struct rspamd_xml_userdata *ctx, GHashTable *attrs, gchar *data, gpointer user_data, gpointer dest_struct, gint offset); +/* Handle classifier */ gboolean handle_classifier_tokenizer (struct config_file *cfg, struct rspamd_xml_userdata *ctx, GHashTable *attrs, gchar *data, gpointer user_data, gpointer dest_struct, gint offset); -gboolean handle_classifier_opt (struct config_file *cfg, struct rspamd_xml_userdata *ctx, GHashTable *attrs, gchar *data, gpointer user_data, gpointer dest_struct, gint offset); +gboolean handle_classifier_opt (struct config_file *cfg, struct rspamd_xml_userdata *ctx, const gchar *tag, GHashTable *attrs, gchar *data, gpointer user_data, gpointer dest_struct, gint offset); +/* Handle statfile */ gboolean handle_statfile_normalizer (struct config_file *cfg, struct rspamd_xml_userdata *ctx, GHashTable *attrs, gchar *data, gpointer user_data, gpointer dest_struct, gint offset); gboolean handle_statfile_binlog (struct config_file *cfg, struct rspamd_xml_userdata *ctx, GHashTable *attrs, gchar *data, gpointer user_data, gpointer dest_struct, gint offset); gboolean handle_statfile_binlog_rotate (struct config_file *cfg, struct rspamd_xml_userdata *ctx, GHashTable *attrs, gchar *data, gpointer user_data, gpointer dest_struct, gint offset); gboolean handle_statfile_binlog_master (struct config_file *cfg, struct rspamd_xml_userdata *ctx, GHashTable *attrs, gchar *data, gpointer user_data, gpointer dest_struct, gint offset); +/* Register new module option */ +void register_module_opt (const gchar *mname, const gchar *optname, element_handler_func func, gpointer dest_struct, gint offset); + +/* Register new worker's options */ +void register_worker_opt (gint wtype, const gchar *optname, element_handler_func func, gpointer dest_struct, gint offset); + +/* Register new classifier option */ +void register_classifier_opt (const gchar *ctype, const gchar *optname, element_handler_func func, gpointer dest_struct, gint offset); + /* Dumper functions */ gboolean xml_dump_config (struct config_file *cfg, const gchar *filename); diff --git a/src/controller.c b/src/controller.c index 42c034013..617821bf6 100644 --- a/src/controller.c +++ b/src/controller.c @@ -29,6 +29,7 @@ #include "protocol.h" #include "upstream.h" #include "cfg_file.h" +#include "cfg_xml.h" #include "modules.h" #include "tokenizers/tokenizers.h" #include "classifiers/classifiers.h" @@ -67,6 +68,11 @@ struct custom_controller_command { controller_func_t handler; }; +struct rspamd_controller_ctx { + char *password; + guint32 timeout; +}; + static struct controller_command commands[] = { {"password", FALSE, COMMAND_PASSWORD}, {"quit", FALSE, COMMAND_QUIT}, @@ -421,9 +427,9 @@ process_command (struct controller_command *cmd, gchar **cmd_args, struct contro gchar out_buf[BUFSIZ], *arg, *err_str; gint r = 0, days, hours, minutes; time_t uptime; - guint32 size = 0; + guint32 size = 0; struct classifier_config *cl; - gchar *password = g_hash_table_lookup (session->worker->cf->params, "password"); + struct rspamd_controller_ctx *ctx = session->worker->ctx; switch (cmd->type) { case COMMAND_PASSWORD: @@ -436,14 +442,14 @@ process_command (struct controller_command *cmd, gchar **cmd_args, struct contro } return TRUE; } - if (password == NULL) { + if (ctx->password == NULL) { r = rspamd_snprintf (out_buf, sizeof (out_buf), "password command disabled in config, authorized access unallowed" CRLF); if (! rspamd_dispatcher_write (session->dispatcher, out_buf, r, FALSE, FALSE)) { return FALSE; } return TRUE; } - if (strncmp (arg, password, strlen (arg)) == 0) { + if (strncmp (arg, ctx->password, strlen (arg)) == 0) { session->authorized = 1; r = rspamd_snprintf (out_buf, sizeof (out_buf), "password accepted" CRLF); if (! rspamd_dispatcher_write (session->dispatcher, out_buf, r, FALSE, FALSE)) { @@ -1023,6 +1029,9 @@ accept_socket (gint fd, short what, void *arg) struct timeval *io_tv; socklen_t addrlen = sizeof (ss); gint nfd; + struct rspamd_controller_ctx *ctx; + + ctx = worker->ctx; if ((nfd = accept_from_socket (fd, (struct sockaddr *)&ss, &addrlen)) == -1) { msg_warn ("accept failed: %s", strerror (errno)); @@ -1044,8 +1053,8 @@ accept_socket (gint fd, short what, void *arg) /* Set up dispatcher */ io_tv = memory_pool_alloc (new_session->session_pool, sizeof (struct timeval)); - io_tv->tv_sec = CONTROLLER_IO_TIMEOUT; - io_tv->tv_usec = 0; + io_tv->tv_sec = ctx->timeout / 1000; + io_tv->tv_usec = ctx->timeout - io_tv->tv_sec * 1000; new_session->s = new_async_session (new_session->session_pool, free_session, new_session); @@ -1055,6 +1064,21 @@ accept_socket (gint fd, short what, void *arg) } } +gpointer +init_controller (void) +{ + struct rspamd_controller_ctx *ctx; + + ctx = g_malloc0 (sizeof (struct rspamd_controller_ctx)); + + ctx->timeout = CONTROLLER_IO_TIMEOUT * 1000; + + register_worker_opt (TYPE_CONTROLLER, "password", xml_handle_string, ctx, G_STRUCT_OFFSET (struct rspamd_controller_ctx, password)); + register_worker_opt (TYPE_CONTROLLER, "timeout", xml_handle_seconds, ctx, G_STRUCT_OFFSET (struct rspamd_controller_ctx, timeout)); + + return ctx; +} + void start_controller (struct rspamd_worker *worker) { diff --git a/src/fuzzy_storage.c b/src/fuzzy_storage.c index dc18a694d..f8d4a855a 100644 --- a/src/fuzzy_storage.c +++ b/src/fuzzy_storage.c @@ -32,6 +32,7 @@ #include "protocol.h" #include "upstream.h" #include "cfg_file.h" +#include "cfg_xml.h" #include "url.h" #include "modules.h" #include "message.h" @@ -66,20 +67,24 @@ static GQueue *hashes[BUCKETS]; static GQueue *frequent; #ifdef WITH_JUDY static gpointer jtree; -static gboolean use_judy = FALSE; #endif static bloom_filter_t *bf; /* Number of cache modifications */ static guint32 mods = 0; -static guint32 max_mods = DEFAULT_MOD_LIMIT; -/* Frequent score number */ -static guint32 frequent_score = DEFAULT_FREQUENT_SCORE; /* For evtimer */ static struct timeval tmv; static struct event tev; static struct rspamd_stat *server_stat; +struct rspamd_fuzzy_storage_ctx { + gboolean use_judy; + char *hashfile; + guint32 expire; + guint32 frequent_score; + guint32 max_mods; +}; + struct rspamd_fuzzy_node { gint32 value; gint32 flag; @@ -120,32 +125,27 @@ static void sync_cache (struct rspamd_worker *wrk) { gint fd, i; - gchar *filename, *exp_str, header[4]; + gchar *filename, header[4]; GList *cur, *tmp; struct rspamd_fuzzy_node *node; guint64 expire, now; + struct rspamd_fuzzy_storage_ctx *ctx = wrk->ctx; #ifdef WITH_JUDY PPvoid_t pvalue; gchar indexbuf[1024], tmpindex[1024]; #endif /* Check for modifications */ - if (mods < max_mods) { + if (mods < ctx->max_mods) { return; } msg_info ("syncing fuzzy hash storage"); - filename = g_hash_table_lookup (wrk->cf->params, "hashfile"); + filename = ctx->hashfile; if (filename == NULL) { return; } - exp_str = g_hash_table_lookup (wrk->cf->params, "expire"); - if (exp_str != NULL) { - expire = parse_seconds (exp_str) / 1000; - } - else { - expire = DEFAULT_EXPIRE; - } + expire = ctx->expire; if ((fd = open (filename, O_WRONLY | O_TRUNC | O_CREAT, S_IWUSR | S_IRUSR | S_IRGRP | S_IROTH)) == -1) { msg_err ("cannot create hash file %s: %s", filename, strerror (errno)); @@ -165,7 +165,7 @@ sync_cache (struct rspamd_worker *wrk) } #ifdef WITH_JUDY - if (use_judy) { + if (ctx->use_judy) { indexbuf[0] = '\0'; pvalue = JudySLFirst (jtree, indexbuf, PJE0); while (pvalue) { @@ -234,12 +234,14 @@ static void sigterm_handler (gint fd, short what, void *arg) { struct rspamd_worker *worker = (struct rspamd_worker *)arg; + struct rspamd_fuzzy_storage_ctx *ctx; static struct timeval tv = { .tv_sec = 0, .tv_usec = 0 }; - mods = max_mods + 1; + ctx = worker->ctx; + mods = ctx->max_mods + 1; sync_cache (worker); close (worker->cf->listen_sock); (void)event_loopexit (&tv); @@ -254,7 +256,9 @@ sigusr_handler (gint fd, short what, void *arg) struct rspamd_worker *worker = (struct rspamd_worker *)arg; /* Do not accept new connections, preparing to end worker's process */ struct timeval tv; + struct rspamd_fuzzy_storage_ctx *ctx; + ctx = worker->ctx; tv.tv_sec = SOFT_SHUTDOWN_TIME; tv.tv_usec = 0; event_del (&worker->sig_ev); @@ -263,7 +267,7 @@ sigusr_handler (gint fd, short what, void *arg) do_reopen_log = 1; msg_info ("worker's shutdown is pending in %d sec", SOFT_SHUTDOWN_TIME); event_loopexit (&tv); - mods = max_mods + 1; + mods = ctx->max_mods + 1; sync_cache (worker); return; } @@ -276,6 +280,7 @@ read_hashes_file (struct rspamd_worker *wrk) gchar *filename, header[4]; gboolean touch_stat = TRUE; struct rspamd_fuzzy_node *node; + struct rspamd_fuzzy_storage_ctx *ctx = wrk->ctx; struct { gint32 value; guint64 time; @@ -288,7 +293,7 @@ read_hashes_file (struct rspamd_worker *wrk) touch_stat = FALSE; } - if (use_judy) { + if (ctx->use_judy) { jtree = NULL; } else { @@ -301,7 +306,7 @@ read_hashes_file (struct rspamd_worker *wrk) } #endif - filename = g_hash_table_lookup (wrk->cf->params, "hashfile"); + filename = ctx->hashfile; if (filename == NULL) { return FALSE; } @@ -354,13 +359,13 @@ read_hashes_file (struct rspamd_worker *wrk) } } #ifdef WITH_JUDY - if (use_judy) { + if (ctx->use_judy) { pvalue = JudySLIns (&jtree, node->h.hash_pipe, PJE0); *pvalue = node; } else { #endif - if (node->value > frequent_score) { + if (node->value > ctx->frequent_score) { g_queue_push_head (frequent, node); } else { @@ -376,7 +381,7 @@ read_hashes_file (struct rspamd_worker *wrk) } #ifdef WITH_JUDY - if (!use_judy) { + if (!ctx->use_judy) { #endif /* Sort everything */ g_queue_sort (frequent, compare_nodes, NULL); @@ -402,7 +407,7 @@ read_hashes_file (struct rspamd_worker *wrk) } static inline struct rspamd_fuzzy_node * -check_hash_node (GQueue *hash, fuzzy_hash_t *s, gint update_value) +check_hash_node (GQueue *hash, fuzzy_hash_t *s, gint update_value, struct rspamd_fuzzy_storage_ctx *ctx) { GList *cur; struct rspamd_fuzzy_node *h; @@ -410,7 +415,7 @@ check_hash_node (GQueue *hash, fuzzy_hash_t *s, gint update_value) #ifdef WITH_JUDY PPvoid_t pvalue; - if (use_judy) { + if (ctx->use_judy) { pvalue = JudySLGet (jtree, s->hash_pipe, PJE0); if (pvalue != NULL) { h = *((struct rspamd_fuzzy_node **)pvalue); @@ -449,7 +454,7 @@ check_hash_node (GQueue *hash, fuzzy_hash_t *s, gint update_value) h->value += update_value; msg_info ("new hash weight: %d", h->value); } - if (h->value > frequent_score) { + if (h->value > ctx->frequent_score) { g_queue_unlink (hash, cur); g_queue_push_head_link (frequent, cur); msg_info ("moved hash to frequent list"); @@ -466,11 +471,12 @@ check_hash_node (GQueue *hash, fuzzy_hash_t *s, gint update_value) } static gint -process_check_command (struct fuzzy_cmd *cmd, gint *flag) +process_check_command (struct fuzzy_cmd *cmd, gint *flag, struct rspamd_fuzzy_storage_ctx *ctx) { fuzzy_hash_t s; struct rspamd_fuzzy_node *h; + if (!bloom_check (bf, cmd->hash)) { return 0; } @@ -478,7 +484,7 @@ process_check_command (struct fuzzy_cmd *cmd, gint *flag) memcpy (s.hash_pipe, cmd->hash, sizeof (s.hash_pipe)); s.block_size = cmd->blocksize; - h = check_hash_node (hashes[cmd->blocksize % BUCKETS], &s, 0); + h = check_hash_node (hashes[cmd->blocksize % BUCKETS], &s, 0, ctx); if (h == NULL) { return 0; @@ -490,7 +496,7 @@ process_check_command (struct fuzzy_cmd *cmd, gint *flag) } static gboolean -update_hash (struct fuzzy_cmd *cmd) +update_hash (struct fuzzy_cmd *cmd, struct rspamd_fuzzy_storage_ctx *ctx) { fuzzy_hash_t s; @@ -498,11 +504,11 @@ update_hash (struct fuzzy_cmd *cmd) s.block_size = cmd->blocksize; mods ++; - return check_hash_node (hashes[cmd->blocksize % BUCKETS], &s, cmd->value) != NULL; + return check_hash_node (hashes[cmd->blocksize % BUCKETS], &s, cmd->value, ctx) != NULL; } static gboolean -process_write_command (struct fuzzy_cmd *cmd) +process_write_command (struct fuzzy_cmd *cmd, struct rspamd_fuzzy_storage_ctx *ctx) { struct rspamd_fuzzy_node *h; #ifdef WITH_JUDY @@ -510,7 +516,7 @@ process_write_command (struct fuzzy_cmd *cmd) #endif if (bloom_check (bf, cmd->hash)) { - if (update_hash (cmd)) { + if (update_hash (cmd, ctx)) { return TRUE; } } @@ -522,7 +528,7 @@ process_write_command (struct fuzzy_cmd *cmd) h->value = cmd->value; h->flag = cmd->flag; #ifdef WITH_JUDY - if (use_judy) { + if (ctx->use_judy) { pvalue = JudySLIns (&jtree, h->h.hash_pipe, PJE0); *pvalue = h; } @@ -542,7 +548,7 @@ process_write_command (struct fuzzy_cmd *cmd) } static gboolean -delete_hash (GQueue *hash, fuzzy_hash_t *s) +delete_hash (GQueue *hash, fuzzy_hash_t *s, struct rspamd_fuzzy_storage_ctx *ctx) { GList *cur, *tmp; struct rspamd_fuzzy_node *h; @@ -551,7 +557,7 @@ delete_hash (GQueue *hash, fuzzy_hash_t *s) PPvoid_t pvalue; gpointer data; - if (use_judy) { + if (ctx->use_judy) { pvalue = JudySLGet (jtree, s->hash_pipe, PJE0); if (pvalue) { data = *pvalue; @@ -593,7 +599,7 @@ delete_hash (GQueue *hash, fuzzy_hash_t *s) } static gboolean -process_delete_command (struct fuzzy_cmd *cmd) +process_delete_command (struct fuzzy_cmd *cmd, struct rspamd_fuzzy_storage_ctx *ctx) { fuzzy_hash_t s; gboolean res = FALSE; @@ -605,17 +611,17 @@ process_delete_command (struct fuzzy_cmd *cmd) memcpy (s.hash_pipe, cmd->hash, sizeof (s.hash_pipe)); s.block_size = cmd->blocksize; #ifdef WITH_JUDY - if (use_judy) { - return delete_hash (NULL, &s); + if (ctx->use_judy) { + return delete_hash (NULL, &s, ctx); } else { #endif - res = delete_hash (frequent, &s); + res = delete_hash (frequent, &s, ctx); if (!res) { - res = delete_hash (hashes[cmd->blocksize % BUCKETS], &s); + res = delete_hash (hashes[cmd->blocksize % BUCKETS], &s, ctx); } else { - (void)delete_hash (hashes[cmd->blocksize % BUCKETS], &s); + (void)delete_hash (hashes[cmd->blocksize % BUCKETS], &s, ctx); } #ifdef WITH_JUDY } @@ -626,7 +632,7 @@ process_delete_command (struct fuzzy_cmd *cmd) #define CMD_PROCESS(x) \ do { \ -if (process_##x##_command (&session->cmd)) { \ +if (process_##x##_command (&session->cmd, session->worker->ctx)) { \ if (sendto (session->fd, "OK" CRLF, sizeof ("OK" CRLF) - 1, 0, (struct sockaddr *)&session->sa, session->salen) == -1) { \ msg_err ("error while writing reply: %s", strerror (errno)); \ } \ @@ -646,7 +652,7 @@ process_fuzzy_command (struct fuzzy_session *session) switch (session->cmd.cmd) { case FUZZY_CHECK: - r = process_check_command (&session->cmd, &flag); + r = process_check_command (&session->cmd, &flag, session->worker->ctx); if (r != 0) { r = rspamd_snprintf (buf, sizeof (buf), "OK %d %d" CRLF, r, flag); if (sendto (session->fd, buf, r, 0, (struct sockaddr *)&session->sa, session->salen) == -1) { @@ -687,8 +693,8 @@ accept_fuzzy_socket (gint fd, short what, void *arg) ssize_t r; struct { u_char cmd; - guint32 blocksize; - gint32 value; + guint32 blocksize; + gint32 value; u_char hash[FUZZY_HASHLEN]; } legacy_cmd; @@ -739,6 +745,28 @@ sync_callback (gint fd, short what, void *arg) sync_cache (worker); } +gpointer +init_fuzzy_storage (void) +{ + struct rspamd_fuzzy_storage_ctx *ctx; + + ctx = g_malloc0 (sizeof (struct rspamd_fuzzy_storage_ctx)); + + ctx->max_mods = DEFAULT_MOD_LIMIT; + ctx->frequent_score = DEFAULT_FREQUENT_SCORE; + + register_worker_opt (TYPE_FUZZY, "hashfile", xml_handle_string, ctx, + G_STRUCT_OFFSET (struct rspamd_fuzzy_storage_ctx, hashfile)); + register_worker_opt (TYPE_FUZZY, "max_mods", xml_handle_uint32, ctx, + G_STRUCT_OFFSET (struct rspamd_fuzzy_storage_ctx, max_mods)); + register_worker_opt (TYPE_FUZZY, "frequent_score", xml_handle_uint32, ctx, + G_STRUCT_OFFSET (struct rspamd_fuzzy_storage_ctx, frequent_score)); + register_worker_opt (TYPE_FUZZY, "use_judy", xml_handle_boolean, ctx, + G_STRUCT_OFFSET (struct rspamd_fuzzy_storage_ctx, use_judy)); + + return ctx; +} + /* * Start worker process */ @@ -748,7 +776,6 @@ start_fuzzy_storage (struct rspamd_worker *worker) struct sigaction signals; struct event sev; gint retries = 0; - gchar *value; worker->srv->pid = getpid (); worker->srv->type = TYPE_FUZZY; @@ -765,20 +792,6 @@ start_fuzzy_storage (struct rspamd_worker *worker) signal_add (&worker->sig_ev, NULL); signal_set (&sev, SIGTERM, sigterm_handler, (void *)worker); signal_add (&sev, NULL); - /* Get params */ - if ((value = g_hash_table_lookup (worker->cf->params, "frequent_score")) != NULL) { - frequent_score = strtol (value, NULL, 10); - } - if ((value = g_hash_table_lookup (worker->cf->params, "max_mods")) != NULL) { - max_mods = strtol (value, NULL, 10); - } - if ((value = g_hash_table_lookup (worker->cf->params, "use_judy")) != NULL) { -#ifdef WITH_JUDY - use_judy = TRUE; -#else - msg_err ("cannot use judy storage as judy support is not compiled in"); -#endif - } /* Listen event */ while ((worker->cf->listen_sock = make_udp_socket (&worker->cf->bind_addr, worker->cf->bind_port, TRUE, TRUE)) == -1) { @@ -802,13 +815,11 @@ start_fuzzy_storage (struct rspamd_worker *worker) tmv.tv_usec = 0; evtimer_add (&tev, &tmv); - event_set (&worker->bind_ev, worker->cf->listen_sock, EV_READ | EV_PERSIST, accept_fuzzy_socket, (void *)worker); event_add (&worker->bind_ev, NULL); gperf_profiler_init (worker->srv->cfg, "fuzzy"); - event_loop (0); exit (EXIT_SUCCESS); } diff --git a/src/fuzzy_storage.h b/src/fuzzy_storage.h index 5a02d4871..f5196b1d6 100644 --- a/src/fuzzy_storage.h +++ b/src/fuzzy_storage.h @@ -27,6 +27,7 @@ struct fuzzy_session { struct sockaddr_storage sa; }; +gpointer init_fuzzy_storage (void); void start_fuzzy_storage (struct rspamd_worker *worker); #endif diff --git a/src/logger.c b/src/logger.c index eda67f161..85bd2fc90 100644 --- a/src/logger.c +++ b/src/logger.c @@ -542,29 +542,8 @@ file_log_function (const gchar * log_domain, const gchar *function, GLogLevelFla tms = localtime (&now); strftime (timebuf, sizeof (timebuf), "%F %H:%M:%S", tms); - switch (rspamd_log->process_type) { - case TYPE_MAIN: - cptype = "main"; - break; - case TYPE_WORKER: - cptype = "worker"; - break; - case TYPE_CONTROLLER: - cptype = "controller"; - break; - case TYPE_LMTP: - cptype = "lmtp"; - break; - case TYPE_SMTP: - cptype = "smtp"; - break; - case TYPE_FUZZY: - cptype = "fuzzy"; - break; - case TYPE_GREYLIST: - cptype = "greylist"; - break; - } + cptype = process_to_str (rspamd_log->process_type); + if (function == NULL) { r = rspamd_snprintf (tmpbuf, sizeof (tmpbuf), "%s #%P(%s) ", timebuf, rspamd_log->pid, cptype); } diff --git a/src/logger.h b/src/logger.h index f2adf65c6..7a3fade7c 100644 --- a/src/logger.h +++ b/src/logger.h @@ -6,18 +6,6 @@ #include "radix.h" #include "util.h" -/** - * Process type: main or worker - */ -enum process_type { - TYPE_MAIN, - TYPE_WORKER, - TYPE_CONTROLLER, - TYPE_LMTP, - TYPE_SMTP, - TYPE_FUZZY, - TYPE_GREYLIST -}; typedef void (*rspamd_log_func_t)(const gchar * log_domain, const gchar *function, GLogLevelFlags log_level, const gchar * message, diff --git a/src/main.c b/src/main.c index 591dd6183..0fcd4e89a 100644 --- a/src/main.c +++ b/src/main.c @@ -339,6 +339,7 @@ fork_worker (struct rspamd_main *rspamd, struct worker_conf *cf) cur->type = cf->type; cur->pid = fork (); cur->cf = g_malloc (sizeof (struct worker_conf)); + cur->ctx = rspamd->workers_ctx[cf->type]; memcpy (cur->cf, cf, sizeof (struct worker_conf)); cur->pending = FALSE; switch (cur->pid) { @@ -564,29 +565,6 @@ spawn_workers (struct rspamd_main *rspamd) } } -static const gchar * -get_process_type (enum process_type type) -{ - switch (type) { - case TYPE_MAIN: - return "main"; - case TYPE_WORKER: - return "worker"; - case TYPE_FUZZY: - return "fuzzy"; - case TYPE_GREYLIST: - return "greylist"; - case TYPE_CONTROLLER: - return "controller"; - case TYPE_LMTP: - return "lmtp"; - case TYPE_SMTP: - return "smtp"; - } - - return NULL; -} - static void kill_old_workers (gpointer key, gpointer value, gpointer unused) { @@ -604,7 +582,7 @@ wait_for_workers (gpointer key, gpointer value, gpointer unused) waitpid (w->pid, &res, 0); - msg_debug ("%s process %P terminated", get_process_type (w->type), w->pid); + msg_debug ("%s process %P terminated", process_to_str (w->type), w->pid); g_free (w->cf); g_free (w); @@ -755,6 +733,15 @@ print_symbols_cache (struct config_file *cfg) } } +static void +init_workers_ctx (struct rspamd_main *main) +{ + main->workers_ctx[TYPE_WORKER] = init_worker (); + main->workers_ctx[TYPE_CONTROLLER] = init_controller (); + main->workers_ctx[TYPE_FUZZY] = init_fuzzy_storage (); + main->workers_ctx[TYPE_SMTP] = init_smtp_worker (); +} + gint main (gint argc, gchar **argv, gchar **env) { @@ -829,6 +816,9 @@ main (gint argc, gchar **argv, gchar **env) /* Init listen sockets hash */ listen_sockets = g_hash_table_new (g_direct_hash, g_direct_equal); + /* Init contextes */ + init_workers_ctx (rspamd); + if (! load_rspamd_config (rspamd->cfg, TRUE)) { exit (EXIT_FAILURE); } @@ -958,14 +948,14 @@ main (gint argc, gchar **argv, gchar **env) if (WIFEXITED (res) && WEXITSTATUS (res) == 0) { /* Normal worker termination, do not fork one more */ - msg_info ("%s process %P terminated normally", get_process_type (cur->type), cur->pid); + msg_info ("%s process %P terminated normally", process_to_str (cur->type), cur->pid); } else { if (WIFSIGNALED (res)) { - msg_warn ("%s process %P terminated abnormally by signal: %d", get_process_type (cur->type), cur->pid, WTERMSIG (res)); + msg_warn ("%s process %P terminated abnormally by signal: %d", process_to_str (cur->type), cur->pid, WTERMSIG (res)); } else { - msg_warn ("%s process %P terminated abnormally", get_process_type (cur->type), cur->pid); + msg_warn ("%s process %P terminated abnormally", process_to_str (cur->type), cur->pid); } /* Fork another worker in replace of dead one */ delay_fork (cur->cf); diff --git a/src/main.h b/src/main.h index a482cb1b1..b934ae31e 100644 --- a/src/main.h +++ b/src/main.h @@ -41,8 +41,6 @@ #define CR '\r' #define LF '\n' - - /** * Worker process structure */ @@ -91,9 +89,11 @@ struct rspamd_main { /* Pid file structure */ struct pidfh *pfh; /**< struct pidfh for pidfile */ enum process_type type; /**< process type */ - guint ev_initialized; /**< is event system is initialized */ + guint ev_initialized; /**< is event system is initialized */ struct rspamd_stat *stat; /**< pointer to statistics */ + gpointer workers_ctx[TYPE_MAX]; /** Array of workers' contexts */ + memory_pool_t *server_pool; /**< server's memory pool */ statfile_pool_t *statfile_pool; /**< shared statfiles pool */ GHashTable *workers; /**< workers pool indexed by pid */ @@ -245,8 +245,12 @@ struct c_module { struct module_ctx *ctx; /**< pointer to context */ }; +/* Workers' initialization and start functions */ +gpointer init_worker (void); void start_worker (struct rspamd_worker *worker); +gpointer init_controller (void); void start_controller (struct rspamd_worker *worker); +gpointer init_greylist (void); void start_greylist_storage (struct rspamd_worker *worker); /** diff --git a/src/smtp.c b/src/smtp.c index a76858547..d1bef023a 100644 --- a/src/smtp.c +++ b/src/smtp.c @@ -25,6 +25,7 @@ #include "config.h" #include "main.h" #include "cfg_file.h" +#include "cfg_xml.h" #include "util.h" #include "smtp.h" #include "smtp_proto.h" @@ -895,25 +896,59 @@ make_capabilities (struct smtp_worker_ctx *ctx, const gchar *line) g_strfreev (strv); } - -static gboolean -config_smtp_worker (struct rspamd_worker *worker) +gpointer +init_smtp_worker (void) { struct smtp_worker_ctx *ctx; - gchar *value; - guint32 timeout; ctx = g_malloc0 (sizeof (struct smtp_worker_ctx)); ctx->pool = memory_pool_new (memory_pool_get_size ()); /* Set default values */ - ctx->smtp_timeout.tv_sec = 300; - ctx->smtp_timeout.tv_usec = 0; + ctx->smtp_timeout_raw = 300000; ctx->smtp_delay = 0; ctx->smtp_banner = "220 ESMTP Ready." CRLF; bzero (ctx->smtp_filters, sizeof (GList *) * SMTP_STAGE_MAX); + ctx->max_errors = DEFAULT_MAX_ERRORS; + ctx->reject_message = DEFAULT_REJECT_MESSAGE; + + register_worker_opt (TYPE_SMTP, "upstreams", xml_handle_string, ctx, + G_STRUCT_OFFSET (struct smtp_worker_ctx, upstreams_str)); + register_worker_opt (TYPE_SMTP, "banner", xml_handle_string, ctx, + G_STRUCT_OFFSET (struct smtp_worker_ctx, smtp_banner_str)); + register_worker_opt (TYPE_SMTP, "timeout", xml_handle_seconds, ctx, + G_STRUCT_OFFSET (struct smtp_worker_ctx, smtp_timeout_raw)); + register_worker_opt (TYPE_SMTP, "delay", xml_handle_seconds, ctx, + G_STRUCT_OFFSET (struct smtp_worker_ctx, smtp_delay)); + register_worker_opt (TYPE_SMTP, "jitter", xml_handle_seconds, ctx, + G_STRUCT_OFFSET (struct smtp_worker_ctx, delay_jitter)); + register_worker_opt (TYPE_SMTP, "capabilities", xml_handle_string, ctx, + G_STRUCT_OFFSET (struct smtp_worker_ctx, smtp_capabilities_str)); + register_worker_opt (TYPE_SMTP, "xclient", xml_handle_boolean, ctx, + G_STRUCT_OFFSET (struct smtp_worker_ctx, use_xclient)); + register_worker_opt (TYPE_SMTP, "reject_message", xml_handle_string, ctx, + G_STRUCT_OFFSET (struct smtp_worker_ctx, reject_message)); + register_worker_opt (TYPE_SMTP, "max_errors", xml_handle_uint32, ctx, + G_STRUCT_OFFSET (struct smtp_worker_ctx, max_errors)); + register_worker_opt (TYPE_SMTP, "max_size", xml_handle_size, ctx, + G_STRUCT_OFFSET (struct smtp_worker_ctx, max_size)); + + return ctx; +} - if ((value = g_hash_table_lookup (worker->cf->params, "upstreams")) != NULL) { +/* Make post-init configuration */ +static gboolean +config_smtp_worker (struct rspamd_worker *worker) +{ + struct smtp_worker_ctx *ctx = worker->ctx; + gchar *value; + + /* Init timeval */ + ctx->smtp_timeout.tv_sec = ctx->smtp_timeout_raw / 1000; + ctx->smtp_timeout.tv_usec = (ctx->smtp_timeout_raw - ctx->smtp_timeout.tv_sec * 1000) * 1000; + + /* Init upstreams */ + if ((value = ctx->upstreams_str) != NULL) { if (!parse_upstreams_line (ctx, value)) { return FALSE; } @@ -922,53 +957,19 @@ config_smtp_worker (struct rspamd_worker *worker) msg_err ("no upstreams defined, don't know what to do"); return FALSE; } - if ((value = g_hash_table_lookup (worker->cf->params, "smtp_banner")) != NULL) { + /* Create smtp banner */ + if ((ctx->smtp_banner_str) != NULL) { parse_smtp_banner (ctx, value); } - if ((value = g_hash_table_lookup (worker->cf->params, "smtp_timeout")) != NULL) { - errno = 0; - timeout = parse_seconds (value); - ctx->smtp_timeout.tv_sec = timeout / 1000; - ctx->smtp_timeout.tv_usec = (timeout - ctx->smtp_timeout.tv_sec * 1000) * 1000; - } - if ((value = g_hash_table_lookup (worker->cf->params, "smtp_delay")) != NULL) { - ctx->smtp_delay = parse_seconds (value); - } - if ((value = g_hash_table_lookup (worker->cf->params, "smtp_jitter")) != NULL) { - ctx->delay_jitter = parse_seconds (value); - } - if ((value = g_hash_table_lookup (worker->cf->params, "smtp_capabilities")) != NULL) { + + /* Parse capabilities */ + if ((value = ctx->smtp_capabilities_str) != NULL) { make_capabilities (ctx, value); } - if ((value = g_hash_table_lookup (worker->cf->params, "smtp_use_xclient")) != NULL) { - ctx->use_xclient = parse_flag (value); - } - if ((value = g_hash_table_lookup (worker->cf->params, "smtp_metric")) != NULL) { - ctx->metric = memory_pool_strdup (ctx->pool, value); - } - else { - ctx->metric = DEFAULT_METRIC; - } - if ((value = g_hash_table_lookup (worker->cf->params, "smtp_max_errors")) != NULL) { - ctx->max_errors = strtoul (value, NULL, 10); - } - else { - ctx->max_errors = DEFAULT_MAX_ERRORS; - } - if ((value = g_hash_table_lookup (worker->cf->params, "smtp_reject_message")) != NULL) { - ctx->reject_message = memory_pool_strdup (ctx->pool, value); - } - else { - ctx->reject_message = DEFAULT_REJECT_MESSAGE; - } ctx->resolver = dns_resolver_init (worker->srv->cfg); - - /* Set ctx */ - worker->ctx = ctx; return TRUE; - } diff --git a/src/smtp.h b/src/smtp.h index 1933376c3..ddb302487 100644 --- a/src/smtp.h +++ b/src/smtp.h @@ -31,19 +31,23 @@ enum rspamd_smtp_stage { struct smtp_worker_ctx { struct smtp_upstream upstreams[MAX_UPSTREAM]; size_t upstream_num; + gchar *upstreams_str; memory_pool_t *pool; gchar *smtp_banner; + gchar *smtp_banner_str; guint32 smtp_delay; guint32 delay_jitter; + guint32 smtp_timeout_raw; struct timeval smtp_timeout; gboolean use_xclient; gboolean helo_required; gchar *smtp_capabilities; + gchar *smtp_capabilities_str; gchar *reject_message; - size_t max_size; - guint max_errors; + gsize max_size; + guint32 max_errors; gchar *metric; GList *smtp_filters[SMTP_STAGE_MAX]; struct rspamd_dns_resolver *resolver; @@ -115,6 +119,7 @@ struct smtp_filter { gpointer filter_data; }; +gpointer init_smtp_worker (void); void start_smtp_worker (struct rspamd_worker *worker); void register_smtp_filter (struct smtp_worker_ctx *ctx, enum rspamd_smtp_stage stage, smtp_filter_t filter, gpointer filter_data); diff --git a/src/util.c b/src/util.c index 78be8cbaf..a420493dc 100644 --- a/src/util.c +++ b/src/util.c @@ -1641,6 +1641,60 @@ rspamd_strlcpy (gchar *dst, const gchar *src, gsize siz) return (s - src - 1); /* count does not include NUL */ } +/* Convert process type to its name */ +const gchar * +process_to_str (enum process_type type) +{ + switch (type) { + case TYPE_MAIN: + return "main"; + case TYPE_WORKER: + return "worker"; + case TYPE_FUZZY: + return "fuzzy"; + case TYPE_GREYLIST: + return "greylist"; + case TYPE_CONTROLLER: + return "controller"; + case TYPE_LMTP: + return "lmtp"; + case TYPE_SMTP: + return "smtp"; + default: + return "unknown"; + } + + return NULL; +} +/* Convert string to process type */ +enum process_type +str_to_process (const gchar *str) +{ + if (g_ascii_strcasecmp (str, "main") == 0) { + return TYPE_MAIN; + } + else if (g_ascii_strcasecmp (str, "worker") == 0) { + return TYPE_WORKER; + } + else if (g_ascii_strcasecmp (str, "fuzzy") == 0) { + return TYPE_FUZZY; + } + else if (g_ascii_strcasecmp (str, "greylist") == 0) { + return TYPE_GREYLIST; + } + else if (g_ascii_strcasecmp (str, "controller") == 0) { + return TYPE_CONTROLLER; + } + else if (g_ascii_strcasecmp (str, "smtp") == 0) { + return TYPE_SMTP; + } + else if (g_ascii_strcasecmp (str, "lmtp") == 0) { + return TYPE_LMTP; + } + + return TYPE_UNKNOWN; +} + /* * vi:ts=4 */ diff --git a/src/util.h b/src/util.h index 36d650877..2ba01d05e 100644 --- a/src/util.h +++ b/src/util.h @@ -12,6 +12,21 @@ struct workq; struct statfile; struct classifier_config; +/** + * Process type: main or worker + */ +enum process_type { + TYPE_UNKNOWN=-1, + TYPE_MAIN, + TYPE_WORKER, + TYPE_CONTROLLER, + TYPE_LMTP, + TYPE_SMTP, + TYPE_FUZZY, + TYPE_GREYLIST, + TYPE_MAX=255 +}; + /* Create socket and bind or connect it to specified address and port */ gint make_tcp_socket (struct in_addr *, u_short, gboolean is_server, gboolean async); /* Create socket and bind or connect it to specified address and port */ @@ -143,4 +158,19 @@ gsize rspamd_strlcpy (gchar *dst, const gchar *src, gsize siz); */ gchar * rspamd_escape_string (gchar *dst, const gchar *src, gsize len); +/* + * Convert process type to its name + * + * @param type numeric type + * @return string representation of type + */ +const gchar * process_to_str (enum process_type type); +/* + * Convert string to process type + * + * @param type numeric type + * @return string representation of type + */ +enum process_type str_to_process (const gchar *str); + #endif diff --git a/src/worker.c b/src/worker.c index 80c7dc48c..d6112ff9d 100644 --- a/src/worker.c +++ b/src/worker.c @@ -32,6 +32,7 @@ #include "protocol.h" #include "upstream.h" #include "cfg_file.h" +#include "cfg_xml.h" #include "url.h" #include "modules.h" #include "message.h" @@ -261,54 +262,54 @@ parse_line_custom (struct worker_task *task, f_str_t * in) void free_task (struct worker_task *task, gboolean is_soft) { - GList *part; - struct mime_part *p; + GList *part; + struct mime_part *p; - if (task) - { - debug_task ("free pointer %p", task); - while ((part = g_list_first (task->parts))) - { - task->parts = g_list_remove_link (task->parts, part); - p = (struct mime_part *) part->data; - g_byte_array_free (p->content, TRUE); - g_list_free_1 (part); - } - if (task->text_parts) - { - g_list_free (task->text_parts); - } - if (task->urls) - { - g_list_free (task->urls); - } - if (task->images) - { - g_list_free (task->images); - } - if (task->messages) + if (task) { - g_list_free (task->messages); - } - memory_pool_delete (task->task_pool); - if (task->dispatcher) - { - if (is_soft) - { - /* Plan dispatcher shutdown */ - task->dispatcher->wanna_die = 1; - } - else - { - rspamd_remove_dispatcher (task->dispatcher); - } - } - if (task->sock != -1) - { - close (task->sock); + debug_task ("free pointer %p", task); + while ((part = g_list_first (task->parts))) + { + task->parts = g_list_remove_link (task->parts, part); + p = (struct mime_part *) part->data; + g_byte_array_free (p->content, TRUE); + g_list_free_1 (part); + } + if (task->text_parts) + { + g_list_free (task->text_parts); + } + if (task->urls) + { + g_list_free (task->urls); + } + if (task->images) + { + g_list_free (task->images); + } + if (task->messages) + { + g_list_free (task->messages); + } + memory_pool_delete (task->task_pool); + if (task->dispatcher) + { + if (is_soft) + { + /* Plan dispatcher shutdown */ + task->dispatcher->wanna_die = 1; + } + else + { + rspamd_remove_dispatcher (task->dispatcher); + } + } + if (task->sock != -1) + { + close (task->sock); + } + g_free (task); } - g_free (task); - } } void @@ -733,6 +734,18 @@ unload_custom_filters (struct rspamd_worker_ctx *ctx) #endif +gpointer +init_worker (void) +{ + struct rspamd_worker_ctx *ctx; + + ctx = g_malloc0 (sizeof (struct rspamd_worker_ctx)); + + register_worker_opt (TYPE_WORKER, "mime", xml_handle_boolean, ctx, G_STRUCT_OFFSET (struct rspamd_worker_ctx, is_mime)); + + return ctx; +} + /* * Start worker process */ @@ -740,9 +753,8 @@ void start_worker (struct rspamd_worker *worker) { struct sigaction signals; - gchar *is_mime_str; gchar *is_custom_str; - struct rspamd_worker_ctx *ctx; + struct rspamd_worker_ctx *ctx = worker->ctx; #ifdef WITH_PROFILER extern void _start (void), etext (void); @@ -767,9 +779,6 @@ start_worker (struct rspamd_worker *worker) accept_socket, (void *) worker); event_add (&worker->bind_ev, NULL); - /* Fill ctx */ - ctx = g_malloc0 (sizeof (struct rspamd_worker_ctx)); - worker->ctx = ctx; #ifndef BUILD_STATIC /* Check if this worker is not usual rspamd worker, but uses custom filters from specified path */ @@ -786,18 +795,6 @@ start_worker (struct rspamd_worker *worker) #endif /* Maps events */ start_map_watch (); - /* Check whether we are mime worker */ - is_mime_str = g_hash_table_lookup (worker->cf->params, "mime"); - if (is_mime_str != NULL - && (g_ascii_strcasecmp (is_mime_str, "no") == 0 - || g_ascii_strcasecmp (is_mime_str, "false") == 0)) - { - ctx->is_mime = FALSE; - } - else - { - ctx->is_mime = TRUE; - } #ifndef BUILD_STATIC } #endif -- cgit v1.2.3