aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/cfg_file.h2
-rw-r--r--src/classifiers/winnow.c24
-rw-r--r--src/lua/CMakeLists.txt3
-rw-r--r--src/lua/lua_classifier.c257
-rw-r--r--src/lua/lua_common.c2
-rw-r--r--src/lua/lua_common.h5
-rw-r--r--src/lua/lua_config.c36
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;