#
# Cmake configuration file
#
+
+############################# INITIAL SECTION #############################################
+
PROJECT(rspamd C)
SET(RSPAMD_VERSION_MAJOR 0)
SET(RSPAMD_VERSION_MINOR 4)
-SET(RSPAMD_VERSION_PATCH 6)
+SET(RSPAMD_VERSION_PATCH 7)
SET(RSPAMD_VERSION "${RSPAMD_VERSION_MAJOR}.${RSPAMD_VERSION_MINOR}.${RSPAMD_VERSION_PATCH}")
CMAKE_MINIMUM_REQUIRED(VERSION 2.6.0 FATAL_ERROR)
+############################# OPTIONS SECTION #############################################
+
OPTION(DEBUG_MODE "Enable debug output [default: ON]" ON)
OPTION(ENABLE_OPTIMIZATION "Enable optimization [default: OFF]" OFF)
OPTION(SKIP_RELINK_RPATH "Skip relinking and full RPATH for the install tree" OFF)
# Build optimized code for following CPU (default i386)
#SET(CPU_TUNE "i686")
-############################# CONFIG SECTION #############################################
+############################# INCLUDE SECTION #############################################
INCLUDE(CheckIncludeFiles)
INCLUDE(CheckFunctionExists)
INCLUDE(CheckCCompilerFlag)
INCLUDE(FindPerl)
+############################# MODULES SECTION #############################################
+
+MACRO(_AddModulesForced MLIST WLIST)
+# Generate unique string for this build
+ STRING(RANDOM LENGTH 8 _MODULES_ID)
+ SET(MODULES_ID ${_MODULES_ID} CACHE INTERNAL "Modules ID" FORCE)
+ FILE(WRITE "src/modules.c" "/* ${MODULES_ID} */\n#include \"config.h\"\n")
+ FOREACH(MOD IN LISTS ${MLIST})
+ FILE(APPEND "src/modules.c" "extern module_t ${MOD}_module;\n")
+ ENDFOREACH(MOD IN LISTS ${MLIST})
+
+ FILE(APPEND "src/modules.c" "\n\nmodule_t *modules[] = {\n")
+
+ FOREACH(MOD IN LISTS ${MLIST})
+ FILE(APPEND "src/modules.c" "&${MOD}_module,\n")
+ ENDFOREACH(MOD IN LISTS ${MLIST})
+ FILE(APPEND "src/modules.c" "NULL\n};\n")
+
+ FOREACH(WRK IN LISTS ${WLIST})
+ FILE(APPEND "src/modules.c" "extern worker_t ${WRK}_worker;\n")
+ ENDFOREACH(WRK IN LISTS ${WLIST})
+
+ FILE(APPEND "src/modules.c" "\n\nworker_t *workers[] = {\n")
+
+ FOREACH(WRK IN LISTS ${WLIST})
+ FILE(APPEND "src/modules.c" "&${WRK}_worker,\n")
+ ENDFOREACH(WRK IN LISTS ${WLIST})
+ FILE(APPEND "src/modules.c" "NULL\n};\n")
+ENDMACRO(_AddModulesForced MLIST WLIST)
+
+MACRO(AddModules MLIST WLIST)
+ _AddModulesForced(${MLIST} ${WLIST})
+ #IF(NOT EXISTS "src/modules.c")
+ # _AddModulesForced(${MLIST} ${WLIST})
+ #ELSE(NOT EXISTS "src/modules.c")
+ # FILE(STRINGS "src/modules.c" FILE_ID_RAW REGEX "^/.*[a-zA-Z0-9]+.*/$")
+ # STRING(REGEX MATCH "[a-zA-Z0-9]+" FILE_ID "${FILE_ID_RAW}")
+ # IF(NOT FILE_ID STREQUAL MODULES_ID)
+ # MESSAGE("Regenerate modules info")
+ # _AddModulesForced(${MLIST} ${WLIST})
+ # ENDIF(NOT FILE_ID STREQUAL MODULES_ID)
+ #ENDIF(NOT EXISTS "src/modules.c")
+ENDMACRO(AddModules MLIST WLIST)
+
+############################# CONFIG SECTION #############################################
# Initial set
IF(CMAKE_INSTALL_PREFIX)
src/plugins/chartable.c
src/plugins/fuzzy_check.c
src/plugins/spf.c)
+
+SET(MODULES_LIST surbl regexp chartable fuzzy_check spf)
+SET(WORKERS_LIST normal controller smtp lmtp fuzzy keystorage)
+AddModules(MODULES_LIST WORKERS_LIST)
################################ SUBDIRS SECTION ###########################
-ADD_CUSTOM_COMMAND(OUTPUT src/modules.c
- COMMAND ${CMAKE_SOURCE_DIR}/utils/gen-modules.sh ${PLUGINSSRC}
- WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/src)
-
ADD_SUBDIRECTORY(contrib/lgpl)
IF(GLIB_COMPAT)
INCLUDE_DIRECTORIES("${CMAKE_CURRENT_SOURCE_DIR}/contrib/lgpl")
/* Forwarded declaration */
struct module_ctx;
struct config_file;
+struct rspamd_worker;
typedef struct module_s {
- const char *name;
+ const gchar *name;
int (*module_init_func)(struct config_file *cfg, struct module_ctx **ctx);
int (*module_config_func)(struct config_file *cfg);
int (*module_reconfig_func)(struct config_file *cfg);
} module_t;
-extern module_t modules[];
+typedef struct worker_s {
+ const gchar *name;
+ gpointer (*worker_init_func)();
+ void (*worker_start_func)(struct rspamd_worker *worker);
+ gboolean has_socket;
+ gboolean unique;
+ gboolean threaded;
+ gboolean killable;
+} worker_t;
+
+extern module_t *modules[];
+extern worker_t *workers[];
#endif
* Config params for rspamd worker
*/
struct worker_conf {
- gint type; /**< worker type */
+ worker_t *worker; /**< pointer to worker type */
+ GQuark type; /**< type of worker */
gchar *bind_host; /**< bind line */
struct in_addr bind_addr; /**< bind address in case of TCP socket */
guint16 bind_port; /**< bind port in case of TCP socket */
GList *filters; /**< linked list of all filters */
GList *workers; /**< linked list of all workers params */
gchar *filters_str; /**< string of filters */
- guint modules_num;
GHashTable* modules_opts; /**< hash for module options indexed by module name */
GHashTable* variables; /**< hash of $variables defined in config, indexed by variable name */
GHashTable* metrics; /**< hash of metrics indexed by metric name */
{
gchar **strvec, **p;
struct filter *cur;
- guint i;
+ module_t **pmodule;
if (str == NULL) {
return;
while (*p) {
cur = NULL;
/* Search modules from known C modules */
- for (i = 0; i < cfg->modules_num; i++) {
+ pmodule = &modules[0];
+ while (*pmodule) {
g_strstrip (*p);
- if (modules[i].name != NULL && g_ascii_strcasecmp (modules[i].name, *p) == 0) {
+ if ((*pmodule)->name != NULL && g_ascii_strcasecmp ((*pmodule)->name, *p) == 0) {
cur = memory_pool_alloc (cfg->cfg_pool, sizeof (struct filter));
cur->type = C_FILTER;
msg_debug ("found C filter %s", *p);
cur->func_name = memory_pool_strdup (cfg->cfg_pool, *p);
- cur->module = &modules[i];
+ cur->module = (*pmodule);
cfg->filters = g_list_prepend (cfg->filters, cur);
break;
}
+ pmodule ++;
}
if (cur != NULL) {
/* Go to next iteration */
struct xml_config_param *cparam;
GHashTable *worker_config;
- if (cd->wrk->ctx == NULL) {
- cd->wrk->ctx = init_workers_ctx (cd->wrk->type);
- }
-
if (!worker_options || (worker_config = g_hash_table_lookup (worker_options, &cd->wrk->type)) == NULL ||
(cparam = g_hash_table_lookup (worker_config, k)) == NULL) {
- msg_warn ("unregistered worker attribute '%s' for worker %s", k, process_to_str (cd->wrk->type));
+ msg_warn ("unregistered worker attribute '%s' for worker %s", k, g_quark_to_string (cd->wrk->type));
}
else {
cparam->handler (cd->cfg, cd->ctx, NULL, v, NULL, cd->wrk->ctx, cparam->offset);
}
else {
- msg_err ("Bad error detected: module %s has not initialized its context", process_to_str (cd->wrk->type));
+ msg_err ("Bad error detected: module %s has not initialized its context", g_quark_to_string (cd->wrk->type));
}
}
}
worker_handle_type (struct config_file *cfg, struct rspamd_xml_userdata *ctx, GHashTable *attrs, gchar *data, gpointer user_data, gpointer dest_struct, gint offset)
{
struct worker_conf *wrk = ctx->section_pointer;
-
+ GQuark type;
- if (g_ascii_strcasecmp (data, "normal") == 0) {
- wrk->type = TYPE_WORKER;
- wrk->has_socket = TRUE;
- }
- else if (g_ascii_strcasecmp (data, "controller") == 0) {
- wrk->type = TYPE_CONTROLLER;
- wrk->has_socket = TRUE;
- }
- else if (g_ascii_strcasecmp (data, "lmtp") == 0) {
- wrk->type = TYPE_LMTP;
- wrk->has_socket = TRUE;
- }
- else if (g_ascii_strcasecmp (data, "smtp") == 0) {
- wrk->type = TYPE_SMTP;
- wrk->has_socket = TRUE;
- }
- else if (g_ascii_strcasecmp (data, "fuzzy") == 0) {
- wrk->type = TYPE_FUZZY;
- wrk->has_socket = FALSE;
- }
- else if (g_ascii_strcasecmp (data, "keystorage") == 0) {
- wrk->type = TYPE_KVSTORAGE;
- wrk->has_socket = TRUE;
+ type = g_quark_try_string (data);
+
+ if (type != 0) {
+ wrk->worker = get_worker_by_type (type);
+ if (wrk->worker == NULL) {
+ msg_err ("unknown worker type: %s", data);
+ return FALSE;
+ }
+ wrk->type = type;
+ if (wrk->worker->worker_init_func) {
+ wrk->ctx = wrk->worker->worker_init_func ();
+ }
}
else {
msg_err ("unknown worker type: %s", data);
wrk = cur->data;
rspamd_fprintf (f, "<worker>" EOL);
- switch (wrk->type) {
- case TYPE_WORKER:
- rspamd_fprintf (f, " <type>normal</type>" EOL);
- break;
- case TYPE_CONTROLLER:
- rspamd_fprintf (f, " <type>controller</type>" EOL);
- break;
- case TYPE_FUZZY:
- rspamd_fprintf (f, " <type>fuzzy</type>" EOL);
- break;
- case TYPE_LMTP:
- rspamd_fprintf (f, " <type>lmtp</type>" EOL);
- break;
- case TYPE_SMTP:
- rspamd_fprintf (f, " <type>smtp</type>" EOL);
- break;
- }
+
+ rspamd_fprintf (f, " <type>%s</type>" EOL, g_quark_to_string (wrk->type));
escaped_str = g_markup_escape_text (wrk->bind_host, -1);
rspamd_fprintf (f, " <bind_socket>%s</bind_socket>" EOL, escaped_str);
g_free (escaped_str);
#include "upstream.h"
#include "cfg_file.h"
#include "cfg_xml.h"
-#include "modules.h"
#include "map.h"
#include "dns.h"
#include "tokenizers/tokenizers.h"
/* 120 seconds for controller's IO */
#define CONTROLLER_IO_TIMEOUT 120
+/* Init functions */
+gpointer init_controller ();
+void start_controller (struct rspamd_worker *worker);
+
+worker_t controller_worker = {
+ "controller", /* Name */
+ init_controller, /* Init function */
+ start_controller, /* Start function */
+ TRUE, /* Has socket */
+ FALSE, /* Non unique */
+ FALSE, /* Non threaded */
+ TRUE /* Killable */
+};
+
enum command_type {
COMMAND_PASSWORD,
COMMAND_QUIT,
}
gpointer
-init_controller (void)
+init_controller ()
{
struct rspamd_controller_ctx *ctx;
+ GQuark type;
+ type = g_quark_try_string ("controller");
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));
+ register_worker_opt (type, "password", xml_handle_string, ctx, G_STRUCT_OFFSET (struct rspamd_controller_ctx, password));
+ register_worker_opt (type, "timeout", xml_handle_seconds, ctx, G_STRUCT_OFFSET (struct rspamd_controller_ctx, timeout));
return ctx;
}
#include "cfg_file.h"
#include "cfg_xml.h"
#include "url.h"
-#include "modules.h"
#include "message.h"
#include "fuzzy.h"
#include "bloom.h"
/* Current version of fuzzy hash file format */
#define CURRENT_FUZZY_VERSION 1
+/* Init functions */
+gpointer init_fuzzy ();
+void start_fuzzy (struct rspamd_worker *worker);
+
+worker_t fuzzy_worker = {
+ "fuzzy", /* Name */
+ init_fuzzy, /* Init function */
+ start_fuzzy, /* Start function */
+ TRUE, /* Has socket */
+ TRUE, /* Non unique */
+ FALSE, /* Non threaded */
+ FALSE /* Non killable */
+};
+
static GQueue *hashes[BUCKETS];
static GQueue *frequent;
#ifdef WITH_JUDY
}
gpointer
-init_fuzzy_storage (void)
+init_fuzzy (void)
{
struct rspamd_fuzzy_storage_ctx *ctx;
+ GQuark type;
+
+ type = g_quark_try_string ("fuzzy");
ctx = g_malloc0 (sizeof (struct rspamd_fuzzy_storage_ctx));
ctx->frequent_score = DEFAULT_FREQUENT_SCORE;
ctx->expire = DEFAULT_EXPIRE;
- register_worker_opt (TYPE_FUZZY, "hashfile", xml_handle_string, ctx,
+ register_worker_opt (type, "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,
+ register_worker_opt (type, "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,
+ register_worker_opt (type, "frequent_score", xml_handle_uint32, ctx,
G_STRUCT_OFFSET (struct rspamd_fuzzy_storage_ctx, frequent_score));
- register_worker_opt (TYPE_FUZZY, "expire", xml_handle_seconds, ctx,
+ register_worker_opt (type, "expire", xml_handle_seconds, ctx,
G_STRUCT_OFFSET (struct rspamd_fuzzy_storage_ctx, expire));
- register_worker_opt (TYPE_FUZZY, "use_judy", xml_handle_boolean, ctx,
+ register_worker_opt (type, "use_judy", xml_handle_boolean, ctx,
G_STRUCT_OFFSET (struct rspamd_fuzzy_storage_ctx, use_judy));
return ctx;
* Start worker process
*/
void
-start_fuzzy_storage (struct rspamd_worker *worker)
+start_fuzzy (struct rspamd_worker *worker)
{
struct sigaction signals;
struct event sev;
gint retries = 0;
worker->srv->pid = getpid ();
- worker->srv->type = TYPE_FUZZY;
event_init ();
struct sockaddr_storage sa;
};
-gpointer init_fuzzy_storage (void);
-void start_fuzzy_storage (struct rspamd_worker *worker);
-
#endif
g_static_mutex_unlock (thr->log_mtx); \
} while (0)
+/* Init functions */
+gpointer init_keystorage ();
+void start_keystorage (struct rspamd_worker *worker);
+
+worker_t keystorage_worker = {
+ "keystorage", /* Name */
+ init_keystorage, /* Init function */
+ start_keystorage, /* Start function */
+ TRUE, /* Has socket */
+ FALSE, /* Non unique */
+ TRUE, /* Non threaded */
+ FALSE /* Non killable */
+};
+
#ifndef HAVE_SA_SIGINFO
static void
sig_handler (gint signo)
}
gpointer
-init_kvstorage_worker (void)
+init_keystorage (void)
{
struct kvstorage_worker_ctx *ctx;
+ GQuark type;
+ type = g_quark_try_string ("keystorage");
ctx = g_malloc0 (sizeof (struct kvstorage_worker_ctx));
ctx->pool = memory_pool_new (memory_pool_get_size ());
/* Set default values */
ctx->timeout_raw = 300000;
- register_worker_opt (TYPE_KVSTORAGE, "timeout", xml_handle_seconds, ctx,
+ register_worker_opt (type, "timeout", xml_handle_seconds, ctx,
G_STRUCT_OFFSET (struct kvstorage_worker_ctx, timeout_raw));
- register_worker_opt (TYPE_KVSTORAGE, "redis", xml_handle_boolean, ctx,
+ register_worker_opt (type, "redis", xml_handle_boolean, ctx,
G_STRUCT_OFFSET (struct kvstorage_worker_ctx, is_redis));
return ctx;
}
* Start worker process
*/
void
-start_kvstorage_worker (struct rspamd_worker *worker)
+start_keystorage (struct rspamd_worker *worker)
{
struct sigaction signals;
struct kvstorage_worker_ctx *ctx = worker->ctx;
time_t now;
};
-gpointer init_kvstorage_worker (void);
-void start_kvstorage_worker (struct rspamd_worker *worker);
-
#endif /* KVSTORAGE_SERVER_H_ */
#include "cfg_file.h"
#include "util.h"
#include "url.h"
-#include "modules.h"
#include "message.h"
static gchar greetingbuf[1024];
static gboolean lmtp_write_socket (void *arg);
+void start_lmtp (struct rspamd_worker *worker);
+
+worker_t lmtp_worker = {
+ "controller", /* Name */
+ NULL, /* Init function */
+ start_lmtp, /* Start function */
+ TRUE, /* Has socket */
+ FALSE, /* Non unique */
+ FALSE, /* Non threaded */
+ TRUE /* Killable */
+};
+
#ifndef HAVE_SA_SIGINFO
static void
sig_handler (gint signo)
* Start lmtp worker process
*/
void
-start_lmtp_worker (struct rspamd_worker *worker)
+start_lmtp (struct rspamd_worker *worker)
{
struct sigaction signals;
- gint i;
gchar *hostbuf;
gsize hostmax;
+ module_t **mod;
worker->srv->pid = getpid ();
- worker->srv->type = TYPE_LMTP;
worker->ctx = event_init ();
g_mime_init (0);
event_add (&worker->bind_ev, NULL);
/* Perform modules configuring */
- for (i = 0; i < MODULES_NUM; i++) {
- modules[i].module_config_func (worker->srv->cfg);
+ mod = &modules[0];
+ while (*mod) {
+ (*mod)->module_config_func (worker->srv->cfg);
+ mod ++;
}
/* Fill hostname buf */
#define LMTP_NO_RCPT 554
#define LMTP_TEMP_FAIL 421
-void start_lmtp_worker (struct rspamd_worker *worker);
-
#endif
sig_atomic_t do_reopen_log;
enum rspamd_log_type type;
pid_t pid;
- enum process_type process_type;
+ GQuark process_type;
radix_tree_t *debug_ip;
guint32 last_line_cksum;
guint32 repeats;
* Setup logger
*/
void
-rspamd_set_logger (enum rspamd_log_type type, enum process_type ptype, struct rspamd_main *rspamd)
+rspamd_set_logger (enum rspamd_log_type type, GQuark ptype, struct rspamd_main *rspamd)
{
gchar **strvec, *p, *err;
gint num, i, k;
* Used after fork() for updating structure params
*/
void
-update_log_pid (enum process_type ptype, rspamd_logger_t *rspamd_log)
+update_log_pid (GQuark ptype, rspamd_logger_t *rspamd_log)
{
rspamd_log->pid = getpid ();
rspamd_log->process_type = ptype;
tms = localtime (&now);
strftime (timebuf, sizeof (timebuf), "%F %H:%M:%S", tms);
- cptype = process_to_str (rspamd_log->process_type);
+ cptype = g_quark_to_string (rspamd_log->process_type);
if (rspamd_log->cfg->log_color) {
if (log_level >= G_LOG_LEVEL_INFO) {
/**
* Init logger
*/
-void rspamd_set_logger (enum rspamd_log_type type, enum process_type ptype, struct rspamd_main *main);
+void rspamd_set_logger (enum rspamd_log_type type, GQuark ptype, struct rspamd_main *main);
/**
* Open log file or initialize other structures
*/
/**
* Set log pid
*/
-void update_log_pid (enum process_type ptype, rspamd_logger_t *logger);
+void update_log_pid (GQuark ptype, rspamd_logger_t *logger);
/**
* Flush log buffer for some types of logging
}
static void
-config_logger (struct rspamd_main *rspamd, gboolean is_fatal)
+config_logger (struct rspamd_main *rspamd, GQuark type, gboolean is_fatal)
{
- rspamd_set_logger (rspamd->cfg->log_type, TYPE_MAIN, rspamd);
+ rspamd_set_logger (rspamd->cfg->log_type, type, rspamd);
if (open_log_priv (rspamd->logger, rspamd->workers_uid, rspamd->workers_gid) == -1) {
if (is_fatal) {
fprintf (stderr, "Fatal error, cannot open logfile, exiting\n");
gchar *cfg_file;
GList *l;
struct filter *filt;
+ GQuark type;
tmp_cfg = (struct config_file *)g_malloc (sizeof (struct config_file));
if (tmp_cfg) {
bzero (tmp_cfg, sizeof (struct config_file));
tmp_cfg->cfg_pool = memory_pool_new (memory_pool_get_size ());
- tmp_cfg->modules_num = MODULES_NUM;
init_defaults (tmp_cfg);
cfg_file = memory_pool_strdup (tmp_cfg->cfg_pool, rspamd->cfg->cfg_name);
/* Save some variables */
if (is_debug) {
rspamd->cfg->log_level = G_LOG_LEVEL_DEBUG;
}
- config_logger (rspamd, FALSE);
+ type = g_quark_try_string ("main");
+ config_logger (rspamd, type, FALSE);
/* Pre-init of cache */
rspamd->cfg->cache = g_new0 (struct symbols_cache, 1);
rspamd->cfg->cache->static_pool = memory_pool_new (memory_pool_get_size ());
cur->type = cf->type;
cur->pid = fork ();
cur->cf = g_malloc (sizeof (struct worker_conf));
- /* Copy or init context */
- if (cf->ctx) {
- cur->ctx = cf->ctx;
- }
- else {
- cur->ctx = init_workers_ctx (cf->type);
- }
memcpy (cur->cf, cf, sizeof (struct worker_conf));
cur->pending = FALSE;
+ cur->ctx = cf->ctx;
switch (cur->pid) {
case 0:
/* Update pid for logging */
drop_priv (rspamd);
/* Set limits */
set_worker_limits (cf);
- switch (cf->type) {
- case TYPE_CONTROLLER:
- setproctitle ("controller process");
- rspamd_pidfile_close (rspamd->pfh);
- msg_info ("starting controller process %P", getpid ());
- start_controller (cur);
- break;
- case TYPE_LMTP:
- setproctitle ("lmtp process");
- rspamd_pidfile_close (rspamd->pfh);
- msg_info ("starting lmtp process %P", getpid ());
- start_lmtp_worker (cur);
- break;
- case TYPE_SMTP:
- setproctitle ("smtp process");
- rspamd_pidfile_close (rspamd->pfh);
- msg_info ("starting smtp process %P", getpid ());
- start_smtp_worker (cur);
- break;
- case TYPE_FUZZY:
- setproctitle ("fuzzy storage");
- rspamd_pidfile_close (rspamd->pfh);
- msg_info ("starting fuzzy storage process %P", getpid ());
- start_fuzzy_storage (cur);
- break;
- case TYPE_KVSTORAGE:
- setproctitle ("kv storage");
- rspamd_pidfile_close (rspamd->pfh);
- msg_info ("starting key-value storage process %P", getpid ());
- start_kvstorage_worker (cur);
- break;
- case TYPE_WORKER:
- default:
- setproctitle ("worker process");
- rspamd_pidfile_close (rspamd->pfh);
- msg_info ("starting worker process %P", getpid ());
- start_worker (cur);
- break;
- }
+ setproctitle ("%s process", cf->worker->name);
+ rspamd_pidfile_close (rspamd->pfh);
+ msg_info ("starting %s process %P", cf->worker->name, getpid ());
+ cf->worker->worker_start_func (cur);
break;
case -1:
msg_err ("cannot fork main process. %s", strerror (errno));
while (cur) {
cf = cur->data;
- if (cf->has_socket) {
+ if (cf->worker->has_socket) {
if ((p = g_hash_table_lookup (listen_sockets, GINT_TO_POINTER (
make_listen_key (&cf->bind_addr, cf->bind_port, cf->bind_family, cf->bind_host)))) == NULL) {
/* Create listen socket */
cf->listen_sock = listen_sock;
}
- if (cf->type == TYPE_FUZZY) {
+ if (cf->worker->unique) {
if (cf->count > 1) {
- msg_err ("cannot spawn more than 1 fuzzy storage worker, so spawn one");
+ msg_err ("cannot spawn more than 1 %s worker, so spawn one", cf->worker->name);
}
fork_worker (rspamd, cf);
}
- else if (cf->type == TYPE_KVSTORAGE) {
+ else if (cf->worker->threaded) {
fork_worker (rspamd, cf);
}
else {
if (waitpid (w->pid, &res, 0) == -1) {
if (errno == EINTR) {
got_alarm = 1;
- if (w->type != TYPE_KVSTORAGE) {
+ if (w->cf->worker->killable) {
msg_info ("terminate worker %P with SIGKILL", w->pid);
kill (w->pid, SIGKILL);
}
else {
- msg_info ("waiting for storages to sync");
+ msg_info ("waiting for workers to sync");
wait_for_workers (key, value, unused);
return TRUE;
}
}
}
- msg_info ("%s process %P terminated %s", process_to_str (w->type), w->pid,
+ msg_info ("%s process %P terminated %s", g_quark_to_string (w->type), w->pid,
got_alarm ? "hardly" : "softly");
g_free (w->cf);
g_free (w);
}
}
-gpointer
-init_workers_ctx (enum process_type type)
-{
- switch (type) {
- case TYPE_WORKER:
- return init_worker ();
- case TYPE_CONTROLLER:
- return init_controller ();
- case TYPE_FUZZY:
- return init_fuzzy_storage ();
- case TYPE_SMTP:
- return init_smtp_worker ();
- case TYPE_KVSTORAGE:
- return init_kvstorage_worker ();
- default:
- return NULL;
- }
-}
gint
main (gint argc, gchar **argv, gchar **env)
struct filter *filt;
pid_t wrk;
GList *l;
+ worker_t **pworker;
+ GQuark type;
#ifdef HAVE_SA_SIGINFO
signals_info = g_queue_new ();
memset (rspamd_main->cfg, 0, sizeof (struct config_file));
rspamd_main->cfg->cfg_pool = memory_pool_new (memory_pool_get_size ());
- rspamd_main->cfg->modules_num = MODULES_NUM;
init_defaults (rspamd_main->cfg);
memset (&signals, 0, sizeof (struct sigaction));
rspamd_main->cfg->log_level = G_LOG_LEVEL_CRITICAL;
}
+ type = g_quark_from_static_string ("main");
+
#ifdef HAVE_SETLOCALE
/* Set locale setting to C locale to avoid problems in future */
setlocale (LC_ALL, "C");
#endif
/* First set logger to console logger */
- rspamd_set_logger (RSPAMD_LOG_CONSOLE, TYPE_MAIN, rspamd_main);
+ rspamd_set_logger (RSPAMD_LOG_CONSOLE, type, rspamd_main);
(void)open_log (rspamd_main->logger);
g_log_set_default_handler (rspamd_glib_log_function, rspamd_main->logger);
detect_priv (rspamd_main);
init_lua (rspamd_main->cfg);
+ pworker = &workers[0];
+ while (*pworker) {
+ /* Init string quarks */
+ (void)g_quark_from_static_string ((*pworker)->name);
+ pworker ++;
+ }
+
/* Init counters */
counters = rspamd_hash_new_shared (rspamd_main->server_pool, g_str_hash, g_str_equal, 64);
/* Init listen sockets hash */
rlim.rlim_cur = 100 * 1024 * 1024;
setrlimit (RLIMIT_STACK, &rlim);
- config_logger (rspamd_main, TRUE);
+ config_logger (rspamd_main, type, TRUE);
msg_info ("rspamd " RVERSION " is starting, build id: " RID);
rspamd_main->cfg->cfg_name = memory_pool_strdup (rspamd_main->cfg->cfg_pool, rspamd_main->cfg->cfg_name);
/* Write info */
rspamd_main->pid = getpid ();
- rspamd_main->type = TYPE_MAIN;
+ rspamd_main->type = type;
init_signals (&signals, sig_handler);
if (WIFEXITED (res) && WEXITSTATUS (res) == 0) {
/* Normal worker termination, do not fork one more */
- msg_info ("%s process %P terminated normally", process_to_str (cur->type), cur->pid);
+ msg_info ("%s process %P terminated normally", g_quark_to_string (cur->type), cur->pid);
}
else {
if (WIFSIGNALED (res)) {
- msg_warn ("%s process %P terminated abnormally by signal: %d", process_to_str (cur->type), cur->pid, WTERMSIG (res));
+ msg_warn ("%s process %P terminated abnormally by signal: %d", g_quark_to_string (cur->type), cur->pid, WTERMSIG (res));
}
else {
- msg_warn ("%s process %P terminated abnormally", process_to_str (cur->type), cur->pid);
+ msg_warn ("%s process %P terminated abnormally", g_quark_to_string (cur->type), cur->pid);
}
/* Fork another worker in replace of dead one */
delay_fork (cur->cf);
gboolean is_dying; /**< if worker is going to shutdown */
gboolean pending; /**< if worker is pending to run */
struct rspamd_main *srv; /**< pointer to server structure */
- enum process_type type; /**< process type */
+ GQuark type; /**< process type */
struct event sig_ev_usr1; /**< signals event */
struct event sig_ev_usr2; /**< signals event */
struct event bind_ev; /**< socket events */
gpointer ctx; /**< worker's specific data */
};
+/**
+ * Module
+ */
+
struct pidfh;
struct config_file;
struct tokenizer;
struct config_file *cfg; /**< pointer to config structure */
pid_t pid; /**< main pid */
/* Pid file structure */
- rspamd_pidfh_t *pfh; /**< struct pidfh for pidfile */
- enum process_type type; /**< process type */
+ rspamd_pidfh_t *pfh; /**< struct pidfh for pidfile */
+ GQuark type; /**< process type */
guint ev_initialized; /**< is event system is initialized */
struct rspamd_stat *stat; /**< pointer to statistics */
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);
-
/**
* Register custom controller function
*/
void register_custom_controller_command (const gchar *name, controller_func_t handler, gboolean privilleged, gboolean require_message);
-/**
- * Initialize context for worker of specified type
- */
-gpointer init_workers_ctx (enum process_type type);
-
/**
* If set, reopen log file on next write
*/
#define DEFAULT_SYMBOL "R_CHARSET_MIXED"
#define DEFAULT_THRESHOLD 0.1
+/* Initialization */
+gint chartable_module_init (struct config_file *cfg, struct module_ctx **ctx);
+gint chartable_module_config (struct config_file *cfg);
+gint chartable_module_reconfig (struct config_file *cfg);
+
+module_t chartable_module = {
+ "chartable",
+ chartable_module_init,
+ chartable_module_config,
+ chartable_module_reconfig
+};
+
struct chartable_ctx {
gint (*filter) (struct worker_task * task);
gchar *symbol;
static void fuzzy_add_handler (gchar **args, struct controller_session *session);
static void fuzzy_delete_handler (gchar **args, struct controller_session *session);
+/* Initialization */
+gint fuzzy_check_module_init (struct config_file *cfg, struct module_ctx **ctx);
+gint fuzzy_check_module_config (struct config_file *cfg);
+gint fuzzy_check_module_reconfig (struct config_file *cfg);
+
+module_t fuzzy_check_module = {
+ "fuzzy_check",
+ fuzzy_check_module_init,
+ fuzzy_check_module_config,
+ fuzzy_check_module_reconfig
+};
+
/* Flags string is in format <numeric_flag>:<SYMBOL>:weight[, <numeric_flag>:<SYMBOL>:weight...] */
static void
parse_flags_string (struct config_file *cfg, gchar *str)
static gboolean rspamd_regexp_occurs_number (struct worker_task *task, GList * args, void *unused);
static void process_regexp_item (struct worker_task *task, void *user_data);
+/* Initialization */
+gint regexp_module_init (struct config_file *cfg, struct module_ctx **ctx);
+gint regexp_module_config (struct config_file *cfg);
+gint regexp_module_reconfig (struct config_file *cfg);
+
+module_t regexp_module = {
+ "regexp",
+ regexp_module_init,
+ regexp_module_config,
+ regexp_module_reconfig
+};
+
static gint
luaopen_regexp (lua_State * L)
{
static GList * spf_record_copy (GList *addrs);
static void spf_record_destroy (gpointer list);
+/* Initialization */
+gint spf_module_init (struct config_file *cfg, struct module_ctx **ctx);
+gint spf_module_config (struct config_file *cfg);
+gint spf_module_reconfig (struct config_file *cfg);
+
+module_t spf_module = {
+ "spf",
+ spf_module_init,
+ spf_module_config,
+ spf_module_reconfig
+};
+
gint
spf_module_init (struct config_file *cfg, struct module_ctx **ctx)
{
return g_quark_from_static_string ("surbl-error-quark");
}
+/* Initialization */
+gint surbl_module_init (struct config_file *cfg, struct module_ctx **ctx);
+gint surbl_module_config (struct config_file *cfg);
+gint surbl_module_reconfig (struct config_file *cfg);
+
+module_t surbl_module = {
+ "surbl",
+ surbl_module_init,
+ surbl_module_config,
+ surbl_module_reconfig
+};
+
static void
exception_insert (gpointer st, gconstpointer key, gpointer value)
{
static sig_atomic_t wanna_die = 0;
+/* Init functions */
+gpointer init_smtp ();
+void start_smtp (struct rspamd_worker *worker);
+
+worker_t smtp_worker = {
+ "smtp", /* Name */
+ init_smtp, /* Init function */
+ start_smtp, /* Start function */
+ TRUE, /* Has socket */
+ FALSE, /* Non unique */
+ FALSE, /* Non threaded */
+ TRUE /* Killable */
+};
#ifndef HAVE_SA_SIGINFO
static void
}
gpointer
-init_smtp_worker (void)
+init_smtp (void)
{
- struct smtp_worker_ctx *ctx;
+ struct smtp_worker_ctx *ctx;
+ GQuark type;
+
+ type = g_quark_try_string ("smtp");
ctx = g_malloc0 (sizeof (struct smtp_worker_ctx));
ctx->pool = memory_pool_new (memory_pool_get_size ());
ctx->max_errors = DEFAULT_MAX_ERRORS;
ctx->reject_message = DEFAULT_REJECT_MESSAGE;
- register_worker_opt (TYPE_SMTP, "upstreams", xml_handle_string, ctx,
+ register_worker_opt (type, "upstreams", xml_handle_string, ctx,
G_STRUCT_OFFSET (struct smtp_worker_ctx, upstreams_str));
- register_worker_opt (TYPE_SMTP, "banner", xml_handle_string, ctx,
+ register_worker_opt (type, "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,
+ register_worker_opt (type, "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,
+ register_worker_opt (type, "delay", xml_handle_seconds, ctx,
G_STRUCT_OFFSET (struct smtp_worker_ctx, smtp_delay));
- register_worker_opt (TYPE_SMTP, "jitter", xml_handle_seconds, ctx,
+ register_worker_opt (type, "jitter", xml_handle_seconds, ctx,
G_STRUCT_OFFSET (struct smtp_worker_ctx, delay_jitter));
- register_worker_opt (TYPE_SMTP, "capabilities", xml_handle_string, ctx,
+ register_worker_opt (type, "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,
+ register_worker_opt (type, "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,
+ register_worker_opt (type, "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,
+ register_worker_opt (type, "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,
+ register_worker_opt (type, "max_size", xml_handle_size, ctx,
G_STRUCT_OFFSET (struct smtp_worker_ctx, max_size));
return ctx;
* Start worker process
*/
void
-start_smtp_worker (struct rspamd_worker *worker)
+start_smtp (struct rspamd_worker *worker)
{
struct sigaction signals;
struct smtp_worker_ctx *ctx = worker->ctx;
gpointer filter_data;
};
-/*
- * Perform initialization of SMTP worker
- */
-gpointer init_smtp_worker (void);
-
-/*
- * Start SMTP worker
- */
-void start_smtp_worker (struct rspamd_worker *worker);
-
/*
* Register new SMTP filter
* XXX: work is still in progress
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_CONTROLLER:
- return "controller";
- case TYPE_LMTP:
- return "lmtp";
- case TYPE_SMTP:
- return "smtp";
- case TYPE_KVSTORAGE:
- return "keystorage";
- 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, "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;
-}
-
/* Compare two emails for building emails tree */
gint
compare_email_func (gconstpointer a, gconstpointer b)
#endif
}
+
+/**
+ * Return worker's control structure by its type
+ * @param type
+ * @return worker's control structure or NULL
+ */
+worker_t*
+get_worker_by_type (GQuark type)
+{
+ worker_t **cur;
+
+ cur = &workers[0];
+ while (*cur) {
+ if (g_quark_from_string ((*cur)->name) == type) {
+ return *cur;
+ }
+ cur ++;
+ }
+
+ return NULL;
+}
+
+
/*
* vi:ts=4
*/
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_KVSTORAGE,
- TYPE_MAX=255
-};
-
/*
* Create socket and bind or connect it to specified address and port
*/
*/
gsize rspamd_strlcpy (gchar *dst, const gchar *src, gsize siz);
-/*
- * 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);
-
/*
* Strip <> from email address
*/
*/
gint rspamd_fallocate (gint fd, off_t offset, off_t len);
+/**
+ * Return worker's control structure by its type
+ * @param type
+ * @return worker's control structure or NULL
+ */
+worker_t* get_worker_by_type (GQuark type);
+
#endif
#include "cfg_file.h"
#include "cfg_xml.h"
#include "url.h"
-#include "modules.h"
#include "message.h"
#include "map.h"
#include "dns.h"
/* 60 seconds for worker's IO */
#define DEFAULT_WORKER_IO_TIMEOUT 60000
+gpointer init_worker (void);
+void start_worker (struct rspamd_worker *worker);
+
+worker_t normal_worker = {
+ "normal", /* Name */
+ init_worker, /* Init function */
+ start_worker, /* Start function */
+ TRUE, /* Has socket */
+ FALSE, /* Non unique */
+ FALSE, /* Non threaded */
+ TRUE /* Killable */
+};
+
#ifndef BUILD_STATIC
#define MODULE_INIT_FUNC "module_init"
init_worker (void)
{
struct rspamd_worker_ctx *ctx;
+ GQuark type;
+
+ type = g_quark_try_string ("normal");
ctx = g_malloc0 (sizeof (struct rspamd_worker_ctx));
ctx->is_mime = TRUE;
ctx->timeout = DEFAULT_WORKER_IO_TIMEOUT;
- register_worker_opt (TYPE_WORKER, "mime", xml_handle_boolean, ctx, G_STRUCT_OFFSET (struct rspamd_worker_ctx, is_mime));
- register_worker_opt (TYPE_WORKER, "http", xml_handle_boolean, ctx, G_STRUCT_OFFSET (struct rspamd_worker_ctx, is_http));
- register_worker_opt (TYPE_WORKER, "json", xml_handle_boolean, ctx, G_STRUCT_OFFSET (struct rspamd_worker_ctx, is_json));
- register_worker_opt (TYPE_WORKER, "allow_learn", xml_handle_boolean, ctx, G_STRUCT_OFFSET (struct rspamd_worker_ctx, allow_learn));
- register_worker_opt (TYPE_WORKER, "timeout", xml_handle_seconds, ctx, G_STRUCT_OFFSET (struct rspamd_worker_ctx, timeout));
- register_worker_opt (TYPE_WORKER, "max_tasks", xml_handle_uint32, ctx, G_STRUCT_OFFSET (struct rspamd_worker_ctx, max_tasks));
+ register_worker_opt (type, "mime", xml_handle_boolean, ctx, G_STRUCT_OFFSET (struct rspamd_worker_ctx, is_mime));
+ register_worker_opt (type, "http", xml_handle_boolean, ctx, G_STRUCT_OFFSET (struct rspamd_worker_ctx, is_http));
+ register_worker_opt (type, "json", xml_handle_boolean, ctx, G_STRUCT_OFFSET (struct rspamd_worker_ctx, is_json));
+ register_worker_opt (type, "allow_learn", xml_handle_boolean, ctx, G_STRUCT_OFFSET (struct rspamd_worker_ctx, allow_learn));
+ register_worker_opt (type, "timeout", xml_handle_seconds, ctx, G_STRUCT_OFFSET (struct rspamd_worker_ctx, timeout));
+ register_worker_opt (type, "max_tasks", xml_handle_uint32, ctx, G_STRUCT_OFFSET (struct rspamd_worker_ctx, max_tasks));
return ctx;
}