diff options
-rw-r--r-- | src/cfg_file.h | 2 | ||||
-rw-r--r-- | src/classifiers/winnow.c | 24 | ||||
-rw-r--r-- | src/lua/CMakeLists.txt | 3 | ||||
-rw-r--r-- | src/lua/lua_classifier.c | 257 | ||||
-rw-r--r-- | src/lua/lua_common.c | 2 | ||||
-rw-r--r-- | src/lua/lua_common.h | 5 | ||||
-rw-r--r-- | src/lua/lua_config.c | 36 |
7 files changed, 325 insertions, 4 deletions
diff --git a/src/cfg_file.h b/src/cfg_file.h index 43d424c70..bb07a40c5 100644 --- a/src/cfg_file.h +++ b/src/cfg_file.h @@ -169,6 +169,8 @@ struct classifier_config { struct classifier *classifier; /**< classifier interface */ struct tokenizer *tokenizer; /**< tokenizer used for classifier */ GHashTable *opts; /**< other options */ + GList *pre_callbacks; /**< list of callbacks that are called before classification */ + GList *post_callbacks; /**< list of callbacks that are called after classification */ }; /** diff --git a/src/classifiers/winnow.c b/src/classifiers/winnow.c index 4b1bd5549..34e3dc209 100644 --- a/src/classifiers/winnow.c +++ b/src/classifiers/winnow.c @@ -30,6 +30,9 @@ #include "../main.h" #include "../filter.h" #include "../cfg_file.h" +#ifdef WITH_LUA +#include "../lua/lua_common.h" +#endif #define WINNOW_PROMOTION 1.23 #define WINNOW_DEMOTION 0.83 @@ -135,8 +138,20 @@ winnow_classify (struct classifier_ctx *ctx, statfile_pool_t * pool, GTree * inp data.count = 0; data.now = time (NULL); data.ctx = ctx; - - cur = ctx->cfg->statfiles; + + if (ctx->cfg->pre_callbacks) { +#ifdef WITH_LUA + cur = call_classifier_pre_callbacks (ctx->cfg, task); + if (cur) { + memory_pool_add_destructor (task->task_pool, (pool_destruct_func)g_list_free, cur); + } +#else + cur = ctx->cfg->statfiles; +#endif + } + else { + cur = ctx->cfg->statfiles; + } while (cur) { st = cur->data; if ((data.file = statfile_pool_is_open (pool, st->path)) == NULL) { @@ -170,7 +185,10 @@ winnow_classify (struct classifier_ctx *ctx, statfile_pool_t * pool, GTree * inp sumbuf = memory_pool_alloc (task->task_pool, 32); snprintf (sumbuf, 32, "%.2f", max); cur = g_list_prepend (NULL, sumbuf); - insert_result (task, ctx->cfg->metric, sel->symbol, 1, cur); +#ifdef WITH_LUA + max = call_classifier_post_callbacks (ctx->cfg, task, max); +#endif + insert_result (task, ctx->cfg->metric, sel->symbol, max, cur); } } diff --git a/src/lua/CMakeLists.txt b/src/lua/CMakeLists.txt index 5ae12c49e..298b81025 100644 --- a/src/lua/CMakeLists.txt +++ b/src/lua/CMakeLists.txt @@ -2,7 +2,8 @@ SET(LUASRC lua_common.c lua_task.c lua_message.c - lua_config.c) + lua_config.c + lua_classifier.c) ADD_LIBRARY(rspamd_lua STATIC ${LUASRC}) TARGET_LINK_LIBRARIES(rspamd_lua ${LUALIB}) diff --git a/src/lua/lua_classifier.c b/src/lua/lua_classifier.c new file mode 100644 index 000000000..ed6cdee42 --- /dev/null +++ b/src/lua/lua_classifier.c @@ -0,0 +1,257 @@ +/* + * Copyright (c) 2009, Rambler media + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY Rambler media ''AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Rambler BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +#include "lua_common.h" +#include "../cfg_file.h" +#include "../classifiers/classifiers.h" + +/* Classifier methods */ +LUA_FUNCTION_DEF (classifier, register_pre_callback); +LUA_FUNCTION_DEF (classifier, register_post_callback); +LUA_FUNCTION_DEF (classifier, get_statfiles); + +static const struct luaL_reg classifierlib_m[] = { + LUA_INTERFACE_DEF (classifier, register_pre_callback), + LUA_INTERFACE_DEF (classifier, register_post_callback), + LUA_INTERFACE_DEF (classifier, get_statfiles), + {"__tostring", lua_class_tostring}, + {NULL, NULL} +}; + + +static const struct luaL_reg statfilelib_m[] = { + {"__tostring", lua_class_tostring}, + {NULL, NULL} +}; + +struct classifier_callback_data { + lua_State *L; + const char *name; +}; + +static struct statfile* lua_check_statfile (lua_State * L); + +/* Classifier implementation */ + + +static struct classifier_config * +lua_check_classifier (lua_State * L) +{ + void *ud = luaL_checkudata (L, 1, "rspamd{classifier}"); + luaL_argcheck (L, ud != NULL, 1, "'classifier' expected"); + return *((struct classifier_config **)ud); +} + +/* Return list of statfiles that should be checked for this message */ +GList * +call_classifier_pre_callbacks (struct classifier_config *ccf, struct worker_task *task) +{ + GList *res = NULL, *cur; + struct classifier_callback_data *cd; + struct classifier_config **pccf; + struct worker_task **ptask; + struct statfile *st; + int i, len; + + /* Go throught all callbacks and call them, appending results to list */ + cur = g_list_first (ccf->pre_callbacks); + while (cur) { + cd = cur->data; + lua_getglobal (cd->L, cd->name); + + pccf = lua_newuserdata (cd->L, sizeof (struct classifier_config *)); + lua_setclass (cd->L, "rspamd{classifier}", -1); + *pccf = ccf; + + ptask = lua_newuserdata (cd->L, sizeof (struct worker_task *)); + lua_setclass (cd->L, "rspamd{task}", -1); + *ptask = task; + + if (lua_pcall (cd->L, 2, 1, 0) != 0) { + msg_warn ("call_classifier_pre_callbacks: error running function %s: %s", cd->name, lua_tostring (cd->L, -1)); + } + else { + if (lua_istable (cd->L, 1)) { + len = lua_objlen (cd->L, 1); + for (i = 1; i <= len; i ++) { + lua_rawgeti (cd->L, 1, i); + st = lua_check_statfile (cd->L); + if (st) { + res = g_list_prepend (res, st); + } + } + } + } + + cur = g_list_next (cur); + } + + return res; +} + +/* Return result mark for statfile */ +double +call_classifier_post_callbacks (struct classifier_config *ccf, struct worker_task *task, double in) +{ + struct classifier_callback_data *cd; + struct classifier_config **pccf; + struct worker_task **ptask; + double out = in; + GList *cur; + + /* Go throught all callbacks and call them, appending results to list */ + cur = g_list_first (ccf->pre_callbacks); + while (cur) { + cd = cur->data; + lua_getglobal (cd->L, cd->name); + + pccf = lua_newuserdata (cd->L, sizeof (struct classifier_config *)); + lua_setclass (cd->L, "rspamd{classifier}", -1); + *pccf = ccf; + + ptask = lua_newuserdata (cd->L, sizeof (struct worker_task *)); + lua_setclass (cd->L, "rspamd{task}", -1); + *ptask = task; + + lua_pushnumber (cd->L, out); + + if (lua_pcall (cd->L, 3, 1, 0) != 0) { + msg_warn ("call_classifier_pre_callbacks: error running function %s: %s", cd->name, lua_tostring (cd->L, -1)); + } + else { + if (lua_isnumber (cd->L, 1)) { + out = lua_tonumber (cd->L, 1); + } + } + + cur = g_list_next (cur); + } + + return out; + +} + +static int +lua_classifier_register_pre_callback (lua_State *L) +{ + struct classifier_config *ccf = lua_check_classifier (L); + struct classifier_callback_data *cd; + const char *name; + + if (ccf) { + name = luaL_checkstring (L, 2); + if (name) { + cd = g_malloc (sizeof (struct classifier_callback_data)); + cd->name = g_strdup (name); + cd->L = L; + ccf->pre_callbacks = g_list_prepend (ccf->pre_callbacks, cd); + } + } + + return 0; + +} + +static int +lua_classifier_register_post_callback (lua_State *L) +{ + struct classifier_config *ccf = lua_check_classifier (L); + struct classifier_callback_data *cd; + const char *name; + + if (ccf) { + name = luaL_checkstring (L, 2); + if (name) { + cd = g_malloc (sizeof (struct classifier_callback_data)); + cd->name = g_strdup (name); + cd->L = L; + ccf->pre_callbacks = g_list_prepend (ccf->pre_callbacks, cd); + } + } + + return 0; +} + +/* Return table of statfiles indexed by theirs name */ +static int +lua_classifier_get_statfiles (lua_State *L) +{ + struct classifier_config *ccf = lua_check_classifier (L); + GList *cur; + struct statfile *st, **pst; + + if (ccf) { + lua_newtable (L); + cur = g_list_first (ccf->statfiles); + while (cur) { + st = cur->data; + /* t['statfile_name'] = statfile */ + lua_pushstring (L, st->symbol); + pst = lua_newuserdata (L, sizeof (struct statfile *)); + lua_setclass (L, "rspamd{statfile}", -1); + *pst = st; + + lua_settable (L, -3); + + cur = g_list_next (cur); + } + } + else { + lua_pushnil (L); + } + + return 1; +} + +/* Statfile functions */ +static struct statfile * +lua_check_statfile (lua_State * L) +{ + void *ud = luaL_checkudata (L, 1, "rspamd{statfile}"); + luaL_argcheck (L, ud != NULL, 1, "'statfile' expected"); + return *((struct statfile **)ud); +} + + +/* Open functions */ + +int +luaopen_classifier (lua_State * L) +{ + lua_newclass (L, "rspamd{classifier}", classifierlib_m); + luaL_openlib (L, "rspamd_classifier", null_reg, 0); + + return 1; +} + +int +luaopen_statfile (lua_State * L) +{ + lua_newclass (L, "rspamd{statfile}", statfilelib_m); + luaL_openlib (L, "rspamd_statfile", null_reg, 0); + + return 1; +} + diff --git a/src/lua/lua_common.c b/src/lua/lua_common.c index 7e7caefda..1ad61aaf0 100644 --- a/src/lua/lua_common.c +++ b/src/lua/lua_common.c @@ -196,6 +196,8 @@ init_lua () (void)luaopen_task (L); (void)luaopen_textpart (L); (void)luaopen_message (L); + (void)luaopen_classifier (L); + (void)luaopen_statfile (L); } } diff --git a/src/lua/lua_common.h b/src/lua/lua_common.h index 9cd966e23..314f903e7 100644 --- a/src/lua/lua_common.h +++ b/src/lua/lua_common.h @@ -27,6 +27,8 @@ int luaopen_metric (lua_State *L); int luaopen_radix (lua_State *L); int luaopen_hash_table (lua_State *L); int luaopen_textpart (lua_State *L); +int luaopen_classifier (lua_State *L); +int luaopen_statfile (lua_State * L); void init_lua_filters (struct config_file *cfg); int lua_call_filter (const char *function, struct worker_task *task); @@ -34,5 +36,8 @@ int lua_call_chain_filter (const char *function, struct worker_task *task, int * double lua_consolidation_func (struct worker_task *task, const char *metric_name, const char *function_name); void add_luabuf (const char *line); +GList *call_classifier_pre_callbacks (struct classifier_config *ccf, struct worker_task *task); +double call_classifier_post_callbacks (struct classifier_config *ccf, struct worker_task *task, double in); + #endif /* WITH_LUA */ #endif /* RSPAMD_LUA_H */ diff --git a/src/lua/lua_config.c b/src/lua/lua_config.c index 377d72be5..fa23134a9 100644 --- a/src/lua/lua_config.c +++ b/src/lua/lua_config.c @@ -27,6 +27,7 @@ #include "../expressions.h" #include "../map.h" #include "../radix.h" +#include "../classifiers/classifiers.h" /* Config file methods */ LUA_FUNCTION_DEF (config, get_module_opt); @@ -35,6 +36,7 @@ LUA_FUNCTION_DEF (config, get_all_opt); LUA_FUNCTION_DEF (config, register_function); LUA_FUNCTION_DEF (config, add_radix_map); LUA_FUNCTION_DEF (config, add_hash_map); +LUA_FUNCTION_DEF (config, get_classifier); static const struct luaL_reg configlib_m[] = { LUA_INTERFACE_DEF (config, get_module_opt), @@ -43,6 +45,7 @@ static const struct luaL_reg configlib_m[] = { LUA_INTERFACE_DEF (config, register_function), LUA_INTERFACE_DEF (config, add_radix_map), LUA_INTERFACE_DEF (config, add_hash_map), + LUA_INTERFACE_DEF (config, get_classifier), {"__tostring", lua_class_tostring}, {NULL, NULL} }; @@ -236,6 +239,39 @@ lua_config_get_metric (lua_State * L) } +static int +lua_config_get_classifier (lua_State * L) +{ + struct config_file *cfg = lua_check_config (L); + struct classifier_config *clc = NULL, **pclc = NULL; + const char *name; + GList *cur; + + if (cfg) { + name = luaL_checkstring (L, 2); + + cur = g_list_first (cfg->classifiers); + while (cur) { + clc = cur->data; + if (g_ascii_strcasecmp (clc->classifier->name, name) == 0) { + pclc = &clc; + break; + } + cur = g_list_next (cur); + } + if (pclc) { + pclc = lua_newuserdata (L, sizeof (struct classifier_config *)); + lua_setclass (L, "rspamd{classifier}", -1); + *pclc = clc; + return 1; + } + } + + lua_pushnil (L); + return 1; + +} + struct lua_callback_data { const char *name; lua_State *L; |