Fixed several memory leaks with modern glib.
Fixed memory leak in dkim code.
Fixed a problem with static global variables in shared libraries.
return FALSE;
}
-#if ((GLIB_MAJOR_VERSION == 2) && (GLIB_MINOR_VERSION <= 30))
-static void
-bayes_mutex_free (gpointer data)
-{
- GMutex *mtx = data;
-
- g_mutex_free (mtx);
-}
-#endif
-
struct classifier_ctx*
bayes_init (memory_pool_t *pool, struct classifier_config *cfg)
{
ctx->pool = pool;
ctx->cfg = cfg;
ctx->debug = FALSE;
-#if ((GLIB_MAJOR_VERSION == 2) && (GLIB_MINOR_VERSION <= 30))
- ctx->mtx = g_mutex_new ();
- memory_pool_add_destructor (pool, (pool_destruct_func) bayes_mutex_free, ctx->mtx);
-#else
- ctx->mtx = memory_pool_alloc (pool, sizeof (GMutex));
- g_mutex_init (ctx->mtx);
-#endif
return ctx;
}
gboolean
-bayes_classify (struct classifier_ctx* ctx, statfile_pool_t *pool, GTree *input, struct worker_task *task)
+bayes_classify (struct classifier_ctx* ctx, statfile_pool_t *pool, GTree *input, struct worker_task *task, lua_State *L)
{
struct bayes_callback_data data;
gchar *value;
}
}
- /* Critical section as here can be lua callbacks calling */
- g_mutex_lock (ctx->mtx);
- cur = call_classifier_pre_callbacks (ctx->cfg, task, FALSE, FALSE);
+ cur = call_classifier_pre_callbacks (ctx->cfg, task, FALSE, FALSE, L);
if (cur) {
memory_pool_add_destructor (task->task_pool, (pool_destruct_func)g_list_free, cur);
}
else {
cur = ctx->cfg->statfiles;
}
- g_mutex_unlock (ctx->mtx);
data.statfiles_num = g_list_length (cur);
data.statfiles = g_new0 (struct bayes_statfile_data, data.statfiles_num);
gboolean
bayes_learn_spam (struct classifier_ctx* ctx, statfile_pool_t *pool,
- GTree *input, struct worker_task *task, gboolean is_spam, GError **err)
+ GTree *input, struct worker_task *task, gboolean is_spam, lua_State *L, GError **err)
{
struct bayes_callback_data data;
gchar *value;
}
}
- cur = call_classifier_pre_callbacks (ctx->cfg, task, FALSE, FALSE);
+ cur = call_classifier_pre_callbacks (ctx->cfg, task, FALSE, FALSE, L);
if (cur) {
memory_pool_add_destructor (task->task_pool, (pool_destruct_func)g_list_free, cur);
}
#include "mem_pool.h"
#include "statfile.h"
#include "tokenizers/tokenizers.h"
+#include <lua.h>
/* Consider this value as 0 */
#define ALPHA 0.0001
GHashTable *results;
gboolean debug;
struct classifier_config *cfg;
- GMutex *mtx;
};
struct classify_weight {
struct classifier {
char *name;
struct classifier_ctx* (*init_func)(memory_pool_t *pool, struct classifier_config *cf);
- gboolean (*classify_func)(struct classifier_ctx* ctx, statfile_pool_t *pool, GTree *input, struct worker_task *task);
+ gboolean (*classify_func)(struct classifier_ctx* ctx, statfile_pool_t *pool, GTree *input, struct worker_task *task, lua_State *L);
gboolean (*learn_func)(struct classifier_ctx* ctx, statfile_pool_t *pool,
const char *symbol, GTree *input, gboolean in_class,
double *sum, double multiplier, GError **err);
gboolean (*learn_spam_func)(struct classifier_ctx* ctx, statfile_pool_t *pool,
- GTree *input, struct worker_task *task, gboolean is_spam, GError **err);
+ GTree *input, struct worker_task *task, gboolean is_spam, lua_State *L, GError **err);
GList* (*weights_func)(struct classifier_ctx* ctx, statfile_pool_t *pool, GTree *input, struct worker_task *task);
};
/* Winnow algorithm */
struct classifier_ctx* winnow_init (memory_pool_t *pool, struct classifier_config *cf);
-gboolean winnow_classify (struct classifier_ctx* ctx, statfile_pool_t *pool, GTree *input, struct worker_task *task);
+gboolean winnow_classify (struct classifier_ctx* ctx, statfile_pool_t *pool, GTree *input, struct worker_task *task, lua_State *L);
gboolean winnow_learn (struct classifier_ctx* ctx, statfile_pool_t *pool, const char *symbol, GTree *input,
gboolean in_class, double *sum, double multiplier, GError **err);
gboolean winnow_learn_spam (struct classifier_ctx* ctx, statfile_pool_t *pool,
- GTree *input, struct worker_task *task, gboolean is_spam, GError **err);
+ GTree *input, struct worker_task *task, gboolean is_spam, lua_State *L, GError **err);
GList *winnow_weights (struct classifier_ctx* ctx, statfile_pool_t *pool, GTree *input, struct worker_task *task);
/* Bayes algorithm */
struct classifier_ctx* bayes_init (memory_pool_t *pool, struct classifier_config *cf);
-gboolean bayes_classify (struct classifier_ctx* ctx, statfile_pool_t *pool, GTree *input, struct worker_task *task);
+gboolean bayes_classify (struct classifier_ctx* ctx, statfile_pool_t *pool, GTree *input, struct worker_task *task, lua_State *L);
gboolean bayes_learn (struct classifier_ctx* ctx, statfile_pool_t *pool, const char *symbol, GTree *input,
gboolean in_class, double *sum, double multiplier, GError **err);
gboolean bayes_learn_spam (struct classifier_ctx* ctx, statfile_pool_t *pool,
- GTree *input, struct worker_task *task, gboolean is_spam, GError **err);
+ GTree *input, struct worker_task *task, gboolean is_spam, lua_State *L, GError **err);
GList *bayes_weights (struct classifier_ctx* ctx, statfile_pool_t *pool, GTree *input, struct worker_task *task);
/* Array of all defined classifiers */
extern struct classifier classifiers[];
}
gboolean
-winnow_classify (struct classifier_ctx *ctx, statfile_pool_t * pool, GTree * input, struct worker_task *task)
+winnow_classify (struct classifier_ctx *ctx, statfile_pool_t * pool, GTree * input, struct worker_task *task, lua_State *L)
{
struct winnow_callback_data data;
char *sumbuf, *value;
}
}
- cur = call_classifier_pre_callbacks (ctx->cfg, task, FALSE, FALSE);
+ cur = call_classifier_pre_callbacks (ctx->cfg, task, FALSE, FALSE, L);
if (cur) {
memory_pool_add_destructor (task->task_pool, (pool_destruct_func)g_list_free, cur);
}
if (sel != NULL) {
#ifdef WITH_LUA
- max = call_classifier_post_callbacks (ctx->cfg, task, max);
+ max = call_classifier_post_callbacks (ctx->cfg, task, max, L);
#endif
#ifdef HAVE_TANHL
max = tanhl (max);
gboolean
winnow_learn_spam (struct classifier_ctx* ctx, statfile_pool_t *pool,
- GTree *input, struct worker_task *task, gboolean is_spam, GError **err)
+ GTree *input, struct worker_task *task, gboolean is_spam, lua_State *L, GError **err)
{
g_set_error (err,
winnow_error_quark(), /* error domain */
g_mutex_init (new->mtx);
new->cond = memory_pool_alloc (pool, sizeof (GCond));
g_cond_init (new->cond);
+ memory_pool_add_destructor (pool, (pool_destruct_func) g_mutex_clear, new->mtx);
+ memory_pool_add_destructor (pool, (pool_destruct_func) g_cond_clear, new->cond);
#endif
new->threads = 0;
}
gboolean
-call_expression_function (struct expression_function * func, struct worker_task * task)
+call_expression_function (struct expression_function * func, struct worker_task * task, lua_State *L)
{
struct _fl *selected, key;
selected = bsearch (&key, list_ptr, functions_number, sizeof (struct _fl), fl_cmp);
if (selected == NULL) {
/* Try to check lua function */
-#if 0
- if (! lua_call_expression_func (NULL, func->name, task, func->args, &res)) {
- msg_warn ("call to undefined function %s", key.name);
- return FALSE;
- }
- else {
- return res;
- }
-#else
return FALSE;
-#endif
}
return selected->func (task, func->args, selected->user_data);
}
else if (expr->type == EXPR_FUNCTION && !want_string) {
res->type = EXPRESSION_ARGUMENT_BOOL;
- cur = call_expression_function (expr->content.operand, task);
+ cur = call_expression_function (expr->content.operand, task, NULL);
res->data = GSIZE_TO_POINTER (cur);
}
else {
return res;
}
else if (it->type == EXPR_FUNCTION) {
- cur = (gsize) call_expression_function ((struct expression_function *)it->content.operand, task);
+ cur = (gsize) call_expression_function ((struct expression_function *)it->content.operand, task, NULL);
debug_task ("function %s returned %s", ((struct expression_function *)it->content.operand)->name, cur ? "true" : "false");
}
else if (it->type == EXPR_OPERATION) {
#define RSPAMD_EXPRESSIONS_H
#include "config.h"
+#include <lua.h>
struct worker_task;
struct rspamd_regexp;
* Call specified fucntion and return boolean result
* @param func function to call
* @param task task object
+ * @param L lua specific state
* @return TRUE or FALSE depending on function result
*/
-gboolean call_expression_function (struct expression_function *func, struct worker_task *task);
+gboolean call_expression_function (struct expression_function *func, struct worker_task *task, lua_State *L);
/**
* Register specified function to rspamd internal functions list
g_hash_table_foreach (task->results, composites_metric_callback, task);
}
+struct classifiers_cbdata {
+ struct worker_task *task;
+ struct lua_locked_state *nL;
+};
+
static void
classifiers_callback (gpointer value, void *arg)
{
- struct worker_task *task = arg;
+ struct classifiers_cbdata *cbdata = arg;
+ struct worker_task *task;
struct classifier_config *cl = value;
struct classifier_ctx *ctx;
struct mime_text_part *text_part, *p1, *p2;
gint *dist = NULL, diff;
gboolean is_twopart = FALSE;
+ task = cbdata->task;
+
if ((header = g_hash_table_lookup (cl->opts, "header")) != NULL) {
cur = message_get_header (task->task_pool, task->message, header, FALSE);
if (cur) {
/* Take care of subject */
tokenize_subject (task, &tokens);
- cl->classifier->classify_func (ctx, task->worker->srv->statfile_pool, tokens, task);
+ if (cbdata->nL != NULL) {
+ rspamd_mutex_lock (cbdata->nL->m);
+ cl->classifier->classify_func (ctx, task->worker->srv->statfile_pool, tokens, task, cbdata->nL->L);
+ rspamd_mutex_unlock (cbdata->nL->m);
+ }
+ else {
+ /* Non-threaded case */
+ cl->classifier->classify_func (ctx, task->worker->srv->statfile_pool, tokens, task, task->cfg->lua_state);
+ }
/* Autolearning */
cur = g_list_first (cl->statfiles);
void
process_statfiles (struct worker_task *task)
{
+ struct classifiers_cbdata cbdata;
if (task->is_skipped) {
return;
task->tokens = g_hash_table_new (g_direct_hash, g_direct_equal);
memory_pool_add_destructor (task->task_pool, (pool_destruct_func)g_hash_table_unref, task->tokens);
}
-
- g_list_foreach (task->cfg->classifiers, classifiers_callback, task);
+ cbdata.task = task;
+ cbdata.nL = NULL;
+ g_list_foreach (task->cfg->classifiers, classifiers_callback, &cbdata);
/* Process results */
make_composites (task);
process_statfiles_threaded (gpointer data, gpointer user_data)
{
struct worker_task *task = (struct worker_task *)data;
+ struct lua_locked_state *nL = user_data;
+ struct classifiers_cbdata cbdata;
if (task->is_skipped) {
return;
memory_pool_add_destructor (task->task_pool, (pool_destruct_func)g_hash_table_unref, task->tokens);
}
- g_list_foreach (task->cfg->classifiers, classifiers_callback, task);
+ cbdata.task = task;
+ cbdata.nL = nL;
+ g_list_foreach (task->cfg->classifiers, classifiers_callback, &cbdata);
remove_async_thread (task->s);
}
/* Learn */
if (!cl->classifier->learn_spam_func (
cls_ctx, task->worker->srv->statfile_pool,
- tokens, task, is_spam, err)) {
+ tokens, task, is_spam, task->cfg->lua_state, err)) {
if (*err) {
msg_info ("learn failed for message <%s>, learn error: %s", task->message_id, (*err)->message);
return FALSE;
#include "html.h"
#include "url.h"
-sig_atomic_t tags_sorted = 0;
+static sig_atomic_t tags_sorted = 0;
static struct html_tag tag_defs[] = {
/* W3C defined elements */
{Tag_WBR, "wbr", (CM_INLINE | CM_EMPTY)},
};
-sig_atomic_t entities_sorted = 0;
+static sig_atomic_t entities_sorted = 0;
struct _entity;
typedef struct _entity entity;
{"euro", 8364, "E"},
};
-static entity *entities_defs_num = NULL;
+static entity entities_defs_num[ (G_N_ELEMENTS (entities_defs)) ];
static gint
tag_cmp (const void *m1, const void *m2)
}
if (!entities_sorted) {
qsort (entities_defs, G_N_ELEMENTS (entities_defs), sizeof (entity), entity_cmp);
- entities_defs_num = g_new (entity, G_N_ELEMENTS (entities_defs));
memcpy (entities_defs_num, entities_defs, sizeof (entities_defs));
qsort (entities_defs_num, G_N_ELEMENTS (entities_defs), sizeof (entity), entity_cmp_num);
entities_sorted = 1;
lua_io_read_cb (f_str_t * in, void *arg)
{
struct lua_dispatcher_cbdata *cbdata = arg;
- gboolean need_unlock = FALSE, res;
+ gboolean res;
rspamd_io_dispatcher_t **pdispatcher;
- /* Avoid LOR here as mutex can be acquired before in lua_call */
- if (g_mutex_trylock (lua_mtx)) {
- need_unlock = TRUE;
- }
/* callback (dispatcher, data) */
lua_rawgeti (cbdata->L, LUA_REGISTRYINDEX, cbdata->cbref_read);
pdispatcher = lua_newuserdata (cbdata->L, sizeof (struct rspamd_io_dispatcher_s *));
res = lua_toboolean (cbdata->L, -1);
lua_pop (cbdata->L, 1);
- if (need_unlock) {
- g_mutex_unlock (lua_mtx);
- }
-
return res;
}
lua_io_write_cb (void *arg)
{
struct lua_dispatcher_cbdata *cbdata = arg;
- gboolean need_unlock = FALSE, res;
+ gboolean res;
rspamd_io_dispatcher_t **pdispatcher;
if (cbdata->cbref_write) {
- /* Avoid LOR here as mutex can be acquired before in lua_call */
- if (g_mutex_trylock (lua_mtx)) {
- need_unlock = TRUE;
- }
lua_rawgeti (cbdata->L, LUA_REGISTRYINDEX, cbdata->cbref_read);
/* callback (dispatcher) */
pdispatcher = lua_newuserdata (cbdata->L, sizeof (struct rspamd_io_dispatcher_s *));
res = lua_toboolean (cbdata->L, -1);
lua_pop (cbdata->L, 1);
-
- if (need_unlock) {
- g_mutex_unlock (lua_mtx);
- }
}
return res;
lua_io_err_cb (GError * err, void *arg)
{
struct lua_dispatcher_cbdata *cbdata = arg;
- gboolean need_unlock = FALSE;
rspamd_io_dispatcher_t **pdispatcher;
- /* Avoid LOR here as mutex can be acquired before in lua_call */
- if (g_mutex_trylock (lua_mtx)) {
- need_unlock = TRUE;
- }
/* callback (dispatcher, err) */
lua_rawgeti (cbdata->L, LUA_REGISTRYINDEX, cbdata->cbref_err);
pdispatcher = lua_newuserdata (cbdata->L, sizeof (struct rspamd_io_dispatcher_s *));
msg_info ("call to session finalizer failed: %s", lua_tostring (cbdata->L, -1));
}
- if (need_unlock) {
- g_mutex_unlock (lua_mtx);
- }
/* Unref callbacks */
luaL_unref (cbdata->L, LUA_REGISTRYINDEX, cbdata->cbref_read);
if (cbdata->cbref_write) {
/* Return list of statfiles that should be checked for this message */
GList *
call_classifier_pre_callbacks (struct classifier_config *ccf, struct worker_task *task,
- gboolean is_learn, gboolean is_spam)
+ gboolean is_learn, gboolean is_spam, lua_State *L)
{
GList *res = NULL, *cur;
struct classifier_callback_data *cd;
- lua_State *L;
/* 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);
+ lua_getglobal (L, cd->name);
- res = g_list_concat (res, call_classifier_pre_callback (ccf, task, cd->L, is_learn, is_spam));
+ res = g_list_concat (res, call_classifier_pre_callback (ccf, task, L, is_learn, is_spam));
cur = g_list_next (cur);
}
-
- g_mutex_lock (lua_mtx);
+
if (res == NULL) {
- L = task->cfg->lua_state;
/* Check function from global table 'classifiers' */
lua_getglobal (L, "classifiers");
if (lua_istable (L, -1)) {
}
lua_pop (L, 1);
}
- g_mutex_unlock (lua_mtx);
return res;
}
/* Return result mark for statfile */
double
-call_classifier_post_callbacks (struct classifier_config *ccf, struct worker_task *task, double in)
+call_classifier_post_callbacks (struct classifier_config *ccf, struct worker_task *task, double in, lua_State *L)
{
struct classifier_callback_data *cd;
struct classifier_config **pccf;
double out = in;
GList *cur;
- g_mutex_lock (lua_mtx);
/* 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);
+ lua_getglobal (L, cd->name);
- pccf = lua_newuserdata (cd->L, sizeof (struct classifier_config *));
- lua_setclass (cd->L, "rspamd{classifier}", -1);
+ pccf = lua_newuserdata (L, sizeof (struct classifier_config *));
+ lua_setclass (L, "rspamd{classifier}", -1);
*pccf = ccf;
- ptask = lua_newuserdata (cd->L, sizeof (struct worker_task *));
- lua_setclass (cd->L, "rspamd{task}", -1);
+ ptask = lua_newuserdata (L, sizeof (struct worker_task *));
+ lua_setclass (L, "rspamd{task}", -1);
*ptask = task;
- lua_pushnumber (cd->L, out);
+ lua_pushnumber (L, out);
- if (lua_pcall (cd->L, 3, 1, 0) != 0) {
- msg_warn ("error running function %s: %s", cd->name, lua_tostring (cd->L, -1));
+ if (lua_pcall (L, 3, 1, 0) != 0) {
+ msg_warn ("error running function %s: %s", cd->name, lua_tostring (L, -1));
}
else {
- if (lua_isnumber (cd->L, 1)) {
- out = lua_tonumber (cd->L, 1);
+ if (lua_isnumber (L, 1)) {
+ out = lua_tonumber (L, 1);
}
- lua_pop (cd->L, 1);
+ lua_pop (L, 1);
}
cur = g_list_next (cur);
}
- g_mutex_unlock (lua_mtx);
return out;
/* Lua module init function */
#define MODULE_INIT_FUNC "module_init"
-/* Global lua mutex */
-GMutex *lua_mtx = NULL;
-
const luaL_reg null_reg[] = {
{"__tostring", lua_class_tostring},
{NULL, NULL}
lua_setglobal (L, "rspamd_actions");
}
-void
+lua_State *
init_lua (struct config_file *cfg)
{
lua_State *L;
L = lua_open ();
luaL_openlibs (L);
-#if ((GLIB_MAJOR_VERSION == 2) && (GLIB_MINOR_VERSION <= 30))
- lua_mtx = g_mutex_new ();
-#else
- lua_mtx = g_malloc (sizeof (GMutex));
- g_mutex_init (lua_mtx);
-#endif
-
(void)luaopen_rspamd (L);
(void)luaopen_logger (L);
(void)luaopen_util (L);
(void)luaopen_io_dispatcher (L);
(void)luaopen_dns_resolver (L);
- cfg->lua_state = L;
- memory_pool_add_destructor (cfg->cfg_pool, (pool_destruct_func)lua_close, L);
+ return L;
+}
+
+/**
+ * Initialize new locked lua_State structure
+ */
+struct lua_locked_state*
+init_lua_locked (struct config_file *cfg)
+{
+ struct lua_locked_state *new;
+
+ new = g_slice_alloc (sizeof (struct lua_locked_state));
+ new->L = init_lua (cfg);
+ new->m = rspamd_mutex_new ();
+
+ return new;
+}
+
+
+/**
+ * Free locked state structure
+ */
+void
+free_lua_locked (struct lua_locked_state *st)
+{
+ g_assert (st != NULL);
+
+ lua_close (st->L);
+
+ rspamd_mutex_free (st->m);
+ g_slice_free1 (sizeof (struct lua_locked_state), st);
}
gboolean
struct worker_task **ptask;
lua_State *L = task->cfg->lua_state;
- g_mutex_lock (lua_mtx);
lua_getglobal (L, function);
ptask = lua_newuserdata (L, sizeof (struct worker_task *));
lua_setclass (L, "rspamd{task}", -1);
}
result = lua_tonumber (L, -1);
lua_pop (L, 1); /* pop returned value */
- g_mutex_unlock (lua_mtx);
return result;
}
guint i;
lua_State *L = task->cfg->lua_state;
- g_mutex_lock (lua_mtx);
lua_getglobal (L, function);
for (i = 0; i < number; i++) {
}
result = lua_tonumber (L, -1);
lua_pop (L, 1); /* pop returned value */
- g_mutex_unlock (lua_mtx);
return result;
}
struct expression_argument *arg;
int nargs = 1, pop = 0;
- g_mutex_lock (lua_mtx);
/* Call specified function and expect result of given expected_type */
/* First check function in config table */
lua_getglobal (L, "config");
if (lua_pcall (L, nargs, 1, 0) != 0) {
msg_info ("call to %s failed: %s", function, lua_tostring (L, -1));
- g_mutex_unlock (lua_mtx);
return FALSE;
}
pop ++;
if (!lua_isboolean (L, -1)) {
lua_pop (L, pop);
msg_info ("function %s must return a boolean", function);
- g_mutex_unlock (lua_mtx);
return FALSE;
}
*res = lua_toboolean (L, -1);
lua_pop (L, pop);
- g_mutex_unlock (lua_mtx);
return TRUE;
}
struct consolidation_callback_data *data = (struct consolidation_callback_data *)arg;
lua_State *L = data->task->cfg->lua_state;
- g_mutex_lock (lua_mtx);
lua_getglobal (L, data->func);
lua_pushstring (L, (const gchar *)key);
res = lua_tonumber (L, -1);
lua_pop (L, 1); /* pop returned value */
data->score += res;
- g_mutex_unlock (lua_mtx);
}
double
return score;
}
- g_mutex_lock (lua_mtx);
lua_getglobal (L, p->data);
lua_pushnumber (L, score);
res = lua_tonumber (L, -1);
lua_pop (L, 1);
- g_mutex_unlock (lua_mtx);
return res;
}
#define LUA_INTERFACE_DEF(class, name) { #name, lua_##class##_##name }
extern const luaL_reg null_reg[];
-extern GMutex *lua_mtx;
#define RSPAMD_LUA_API_VERSION 12
+/* Locked lua state with mutex */
+struct lua_locked_state {
+ lua_State *L;
+ rspamd_mutex_t *m;
+};
+
/* Common utility functions */
/**
/**
* Initialize lua and bindings
*/
-void init_lua (struct config_file *cfg);
+lua_State* init_lua (struct config_file *cfg);
/**
* Load and initialize lua plugins
*/
gboolean init_lua_filters (struct config_file *cfg);
+/**
+ * Initialize new locked lua_State structure
+ */
+struct lua_locked_state* init_lua_locked (struct config_file *cfg);
+/**
+ * Free locked state structure
+ */
+void free_lua_locked (struct lua_locked_state *st);
+
/**
* Open libraries functions
*/
void add_luabuf (const gchar *line);
/* Classify functions */
-GList *call_classifier_pre_callbacks (struct classifier_config *ccf, struct worker_task *task, gboolean is_learn, gboolean is_spam);
-double call_classifier_post_callbacks (struct classifier_config *ccf, struct worker_task *task, double in);
+GList *call_classifier_pre_callbacks (struct classifier_config *ccf, struct worker_task *task, gboolean is_learn, gboolean is_spam, lua_State *L);
+double call_classifier_post_callbacks (struct classifier_config *ccf, struct worker_task *task, double in, lua_State *L);
double lua_normalizer_func (struct config_file *cfg, long double score, void *params);
GList *cur;
gboolean res = FALSE;
- g_mutex_lock (lua_mtx);
if (cd->cb_is_ref) {
lua_rawgeti (cd->L, LUA_REGISTRYINDEX, cd->callback.ref);
}
}
lua_pop (cd->L, 1);
}
- g_mutex_unlock (lua_mtx);
return res;
}
struct worker_task **ptask;
GList *cur;
- g_mutex_lock (lua_mtx);
cur = task->cfg->post_filters;
while (cur) {
cd = cur->data;
}
cur = g_list_next (cur);
}
- g_mutex_unlock (lua_mtx);
}
static gint
struct worker_task **ptask;
GList *cur;
- g_mutex_lock (lua_mtx);
cur = task->cfg->pre_filters;
while (cur) {
cd = cur->data;
}
cur = g_list_next (cur);
}
- g_mutex_unlock (lua_mtx);
}
static gint
struct lua_callback_data *cd = ud;
struct worker_task **ptask;
- g_mutex_lock (lua_mtx);
if (cd->cb_is_ref) {
lua_rawgeti (cd->L, LUA_REGISTRYINDEX, cd->callback.ref);
}
msg_info ("call to %s failed: %s", cd->cb_is_ref ? "local function" :
cd->callback.name, lua_tostring (cd->L, -1));
}
- g_mutex_unlock (lua_mtx);
}
static gint
struct rspamd_dns_resolver **presolver;
union rspamd_reply_element *elt;
GList *cur;
- gboolean need_unlock = FALSE;
-
- /* Avoid LOR here as mutex can be acquired before in lua_call */
- if (g_mutex_trylock (lua_mtx)) {
- need_unlock = TRUE;
- }
lua_rawgeti (cd->L, LUA_REGISTRYINDEX, cd->cbref);
presolver = lua_newuserdata (cd->L, sizeof (gpointer));
/* Unref function */
luaL_unref (cd->L, LUA_REGISTRYINDEX, cd->cbref);
-
- if (need_unlock) {
- g_mutex_unlock (lua_mtx);
- }
}
static int
{
struct worker_task **ptask;
gint num;
- gboolean need_unlock = FALSE;
-
- /* Avoid LOR here as mutex can be acquired before in lua_call */
- if (g_mutex_trylock (lua_mtx)) {
- need_unlock = TRUE;
- }
/* Push error */
if (ud->callback) {
g_list_free (ud->headers);
ud->headers = NULL;
}
- if (need_unlock) {
- g_mutex_unlock (lua_mtx);
- }
+
ud->parser_state = 3;
remove_normal_event (ud->s, lua_http_fin, ud);
struct lua_http_header *header;
struct worker_task **ptask;
gint num;
- gboolean need_unlock = FALSE;
-
- /* Avoid LOR here as mutex can be acquired before in lua_call */
- if (g_mutex_trylock (lua_mtx)) {
- need_unlock = TRUE;
- }
if (ud->callback) {
/* Push error */
ud->headers = NULL;
}
- if (need_unlock) {
- g_mutex_unlock (lua_mtx);
- }
remove_normal_event (ud->s, lua_http_fin, ud);
}
lua_mempool_destructor_func (gpointer p)
{
struct lua_mempool_udata *ud = p;
- gboolean need_unlock = FALSE;
- /* Avoid LOR here as mutex can be acquired before in lua_call */
- if (g_mutex_trylock (lua_mtx)) {
- need_unlock = TRUE;
- }
lua_rawgeti (ud->L, LUA_REGISTRYINDEX, ud->cbref);
if (lua_pcall (ud->L, 0, 0, 0) != 0) {
msg_info ("call to destructor failed: %s", lua_tostring (ud->L, -1));
}
luaL_unref (ud->L, LUA_REGISTRYINDEX, ud->cbref);
- if (need_unlock) {
- g_mutex_unlock (lua_mtx);
- }
}
static int
if (ud->ctx) {
redisAsyncFree (ud->ctx);
- g_mutex_lock (lua_mtx);
luaL_unref (ud->L, LUA_REGISTRYINDEX, ud->cbref);
- g_mutex_unlock (lua_mtx);
}
}
lua_redis_push_error (const gchar *err, struct lua_redis_userdata *ud, gboolean connected)
{
struct worker_task **ptask;
- gboolean need_unlock = FALSE;
- /* Avoid LOR here as mutex can be acquired before in lua_call */
- if (g_mutex_trylock (lua_mtx)) {
- need_unlock = TRUE;
- }
/* Push error */
lua_rawgeti (ud->L, LUA_REGISTRYINDEX, ud->cbref);
ptask = lua_newuserdata (ud->L, sizeof (struct worker_task *));
if (lua_pcall (ud->L, 3, 0, 0) != 0) {
msg_info ("call to callback failed: %s", lua_tostring (ud->L, -1));
}
- if (need_unlock) {
- g_mutex_unlock (lua_mtx);
- }
if (connected) {
remove_normal_event (ud->task->s, lua_redis_fin, ud);
lua_redis_push_data (const redisReply *r, struct lua_redis_userdata *ud)
{
struct worker_task **ptask;
- gboolean need_unlock = FALSE;
- if (g_mutex_trylock (lua_mtx)) {
- need_unlock = TRUE;
- }
/* Push error */
lua_rawgeti (ud->L, LUA_REGISTRYINDEX, ud->cbref);
ptask = lua_newuserdata (ud->L, sizeof (struct worker_task *));
if (lua_pcall (ud->L, 3, 0, 0) != 0) {
msg_info ("call to callback failed: %s", lua_tostring (ud->L, -1));
}
- if (need_unlock) {
- g_mutex_unlock (lua_mtx);
- }
remove_normal_event (ud->task->s, lua_redis_fin, ud);
}
lua_session_finalizer (gpointer ud)
{
struct lua_session_udata *cbdata = ud;
- gboolean need_unlock = FALSE, res;
-
- /* Avoid LOR here as mutex can be acquired before in lua_call */
- if (g_mutex_trylock (lua_mtx)) {
- need_unlock = TRUE;
- }
+ gboolean res;
/* Call finalizer function */
lua_rawgeti (cbdata->L, LUA_REGISTRYINDEX, cbdata->cbref_fin);
res = lua_toboolean (cbdata->L, -1);
lua_pop (cbdata->L, 1);
luaL_unref (cbdata->L, LUA_REGISTRYINDEX, cbdata->cbref_fin);
- if (need_unlock) {
- g_mutex_unlock (lua_mtx);
- }
+
return res;
}
lua_session_restore (gpointer ud)
{
struct lua_session_udata *cbdata = ud;
- gboolean need_unlock = FALSE;
if (cbdata->cbref_restore) {
- /* Avoid LOR here as mutex can be acquired before in lua_call */
- if (g_mutex_trylock (lua_mtx)) {
- need_unlock = TRUE;
- }
/* Call restorer function */
lua_rawgeti (cbdata->L, LUA_REGISTRYINDEX, cbdata->cbref_restore);
msg_info ("call to session restorer failed: %s", lua_tostring (cbdata->L, -1));
}
luaL_unref (cbdata->L, LUA_REGISTRYINDEX, cbdata->cbref_restore);
- if (need_unlock) {
- g_mutex_unlock (lua_mtx);
- }
}
}
lua_session_cleanup (gpointer ud)
{
struct lua_session_udata *cbdata = ud;
- gboolean need_unlock = FALSE;
if (cbdata->cbref_cleanup) {
- /* Avoid LOR here as mutex can be acquired before in lua_call */
- if (g_mutex_trylock (lua_mtx)) {
- need_unlock = TRUE;
- }
/* Call restorer function */
lua_rawgeti (cbdata->L, LUA_REGISTRYINDEX, cbdata->cbref_cleanup);
msg_info ("call to session cleanup failed: %s", lua_tostring (cbdata->L, -1));
}
luaL_unref (cbdata->L, LUA_REGISTRYINDEX, cbdata->cbref_cleanup);
- if (need_unlock) {
- g_mutex_unlock (lua_mtx);
- }
}
}
lua_event_fin (gpointer ud)
{
struct lua_event_udata *cbdata = ud;
- gboolean need_unlock = FALSE;
if (cbdata->cbref) {
- /* Avoid LOR here as mutex can be acquired before in lua_call */
- if (g_mutex_trylock (lua_mtx)) {
- need_unlock = TRUE;
- }
-
/* Call restorer function */
lua_rawgeti (cbdata->L, LUA_REGISTRYINDEX, cbdata->cbref);
if (lua_pcall (cbdata->L, 0, 0, 0) != 0) {
msg_info ("call to event finalizer failed: %s", lua_tostring (cbdata->L, -1));
}
luaL_unref (cbdata->L, LUA_REGISTRYINDEX, cbdata->cbref);
- if (need_unlock) {
- g_mutex_unlock (lua_mtx);
- }
}
}
union rspamd_reply_element *elt;
GList *cur;
- g_mutex_lock (lua_mtx);
if (cd->cb_is_ref) {
lua_rawgeti (cd->L, LUA_REGISTRYINDEX, cd->callback.ref);
}
if (cd->cb_is_ref) {
luaL_unref (cd->L, LUA_REGISTRYINDEX, cd->callback.ref);
}
- g_mutex_unlock (lua_mtx);
}
static gint
f.args = g_list_prepend (f.args, arg);
}
}
- res = call_expression_function (&f, task);
+ res = call_expression_function (&f, task, L);
lua_pushboolean (L, res);
if (f.args) {
g_list_free (f.args);
gdouble dnum;
/* Strip line */
- while (g_ascii_isspace (*text) && text_len > 0) {
+ while (text_len > 0 && g_ascii_isspace (*text)) {
text ++;
text_len --;
}
- while (g_ascii_isspace (text[text_len - 1]) && text_len > 0) {
+ while (text_len > 0 && g_ascii_isspace (text[text_len - 1])) {
text_len --;
}
G_MARKUP_TREAT_CDATA_AS_TEXT, &ud, NULL);
res = g_markup_parse_context_parse (ctx, data, s, &err);
+ g_markup_parse_context_free (ctx);
if (! res) {
- lua_pushnil (L);
+ lua_pushboolean (L, FALSE);
+ }
+ else {
+ lua_pushboolean (L, TRUE);
}
}
else {
- lua_pushnil (L);
+ lua_pushboolean (L, FALSE);
}
return 1;
cfg_file = memory_pool_strdup (tmp_cfg->cfg_pool, rspamd->cfg->cfg_name);
/* Save some variables */
tmp_cfg->cfg_name = cfg_file;
- init_lua (tmp_cfg);
+ tmp_cfg->lua_state = init_lua (tmp_cfg);
+ memory_pool_add_destructor (tmp_cfg->cfg_pool, (pool_destruct_func)lua_close, tmp_cfg->lua_state);
if (! load_rspamd_config (tmp_cfg, FALSE)) {
msg_err ("cannot parse new config file, revert to old one");
g_log_set_default_handler (rspamd_glib_log_function, rspamd_main->logger);
detect_priv (rspamd_main);
- init_lua (rspamd_main->cfg);
+ rspamd_main->cfg->lua_state = init_lua (rspamd_main->cfg);
+ memory_pool_add_destructor (rspamd_main->cfg->cfg_pool, (pool_destruct_func)lua_close, rspamd_main->cfg->lua_state);
pworker = &workers[0];
while (*pworker) {
mem_pool_stat->pools_freed++;
POOL_MTX_UNLOCK ();
+#if ((GLIB_MAJOR_VERSION == 2) && (GLIB_MINOR_VERSION > 30))
+ g_mutex_clear (&pool->mtx);
+#endif
g_slice_free (memory_pool_t, pool);
}
else {
/* Insert tempfail symbol */
msg_info ("cannot get key for domain %s", ctx->dns_key);
- insert_result (task, dkim_module_ctx->symbol_tempfail, 1, NULL);
+ if (err != NULL) {
+ insert_result (task, dkim_module_ctx->symbol_tempfail, 1, g_list_prepend (NULL, memory_pool_strdup (task->task_pool, err->message)));
+
+ }
+ else {
+ insert_result (task, dkim_module_ctx->symbol_tempfail, 1, NULL);
+ }
+ }
+
+ if (err) {
+ g_error_free (err);
}
}
}
static gboolean
-maybe_call_lua_function (const gchar *name, struct worker_task *task)
+maybe_call_lua_function (const gchar *name, struct worker_task *task, lua_State *L)
{
- lua_State *L = task->cfg->lua_state;
struct worker_task **ptask;
gboolean res;
- g_mutex_lock (lua_mtx);
lua_getglobal (L, name);
if (lua_isfunction (L, -1)) {
ptask = lua_newuserdata (L, sizeof (struct worker_task *));
/* Call function */
if (lua_pcall (L, 1, 1, 0) != 0) {
msg_info ("call to %s failed: %s", (gchar *)name, lua_tostring (L, -1));
- g_mutex_unlock (lua_mtx);
return FALSE;
}
res = lua_toboolean (L, -1);
lua_pop (L, 1);
- g_mutex_unlock (lua_mtx);
return res;
}
else {
lua_pop (L, 1);
}
- g_mutex_unlock (lua_mtx);
return FALSE;
}
}
static gboolean
-process_regexp_expression (struct expression *expr, gchar *symbol, struct worker_task *task, const gchar *additional)
+process_regexp_expression (struct expression *expr, gchar *symbol, struct worker_task *task, const gchar *additional, struct lua_locked_state *nL)
{
GQueue *stack;
gsize cur, op1, op2;
}
}
else if (it->type == EXPR_FUNCTION) {
- cur = (gsize) call_expression_function ((struct expression_function *)it->content.operand, task);
+ if (nL) {
+ rspamd_mutex_lock (nL->m);
+ cur = (gsize) call_expression_function ((struct expression_function *)it->content.operand, task, nL->L);
+ rspamd_mutex_unlock (nL->m);
+ }
+ else {
+ cur = (gsize) call_expression_function ((struct expression_function *)it->content.operand, task, task->cfg->lua_state);
+ }
debug_task ("function %s returned %s", ((struct expression_function *)it->content.operand)->name, cur ? "true" : "false");
if (try_optimize) {
try_optimize = optimize_regexp_expression (&it, stack, cur);
else if (it->type == EXPR_STR) {
/* This may be lua function, try to call it */
if (regexp_module_ctx->workers != NULL) {
- g_mutex_lock (workers_mtx);
- cur = maybe_call_lua_function ((const gchar*)it->content.operand, task);
- g_mutex_unlock (workers_mtx);
+ if (nL) {
+ rspamd_mutex_lock (nL->m);
+ cur = maybe_call_lua_function ((const gchar*)it->content.operand, task, nL->L);
+ rspamd_mutex_unlock (nL->m);
+ }
+ else {
+ cur = maybe_call_lua_function ((const gchar*)it->content.operand, task, task->cfg->lua_state);
+ }
}
debug_task ("function %s returned %s", (const gchar *)it->content.operand, cur ? "true" : "false");
if (try_optimize) {
process_regexp_item_threaded (gpointer data, gpointer user_data)
{
struct regexp_threaded_ud *ud = data;
+ struct lua_locked_state *nL = user_data;
/* Process expression */
- if (process_regexp_expression (ud->item->expr, ud->item->symbol, ud->task, NULL)) {
+ if (process_regexp_expression (ud->item->expr, ud->item->symbol, ud->task, NULL, nL)) {
g_mutex_lock (workers_mtx);
insert_result (ud->task, ud->item->symbol, 1, NULL);
g_mutex_unlock (workers_mtx);
gboolean res = FALSE;
struct regexp_threaded_ud *thr_ud;
GError *err = NULL;
+ struct lua_locked_state *nL;
if (!item->lua_function && regexp_module_ctx->max_threads > 1) {
workers_mtx = memory_pool_alloc (regexp_module_ctx->regexp_pool, sizeof (GMutex));
g_mutex_init (workers_mtx);
#endif
+ nL = init_lua_locked (task->cfg);
+ luaopen_regexp (nL->L);
regexp_module_ctx->workers = g_thread_pool_new (process_regexp_item_threaded,
- regexp_module_ctx, regexp_module_ctx->max_threads, TRUE, &err);
+ nL, regexp_module_ctx->max_threads, TRUE, &err);
if (err != NULL) {
msg_err ("thread pool creation failed: %s", err->message);
regexp_module_ctx->max_threads = 0;
thr_ud->item = item;
thr_ud->task = task;
+
register_async_thread (task->s);
g_thread_pool_push (regexp_module_ctx->workers, thr_ud, &err);
if (err != NULL) {
}
else {
/* Process expression */
- if (process_regexp_expression (item->expr, item->symbol, task, NULL)) {
+ if (process_regexp_expression (item->expr, item->symbol, task, NULL, NULL)) {
insert_result (task, item->symbol, 1, NULL);
}
}
}
}
else {
- if (process_regexp_expression (cur->data, "regexp_match_number", task, NULL)) {
+ if (process_regexp_expression (cur->data, "regexp_match_number", task, NULL, NULL)) {
res++;
}
if (res >= param_count) {
}
else if (arg != NULL) {
if (what != NULL) {
- if (process_regexp_expression (arg->data, "regexp_check_smtp_data", task, what)) {
+ if (process_regexp_expression (arg->data, "regexp_check_smtp_data", task, what, NULL)) {
return TRUE;
}
}
else {
while (rcpt_list) {
- if (process_regexp_expression (arg->data, "regexp_check_smtp_data", task, rcpt_list->data)) {
+ if (process_regexp_expression (arg->data, "regexp_check_smtp_data", task, rcpt_list->data, NULL)) {
return TRUE;
}
rcpt_list = g_list_next (rcpt_list);
}
cur = g_list_next (cur);
}
+ g_list_free (metric_symbols);
#endif /* GLIB_COMPAT */
return TRUE;
{
rspamd_mutex_t *new;
- new = g_malloc (sizeof (rspamd_mutex_t));
+ new = g_slice_alloc (sizeof (rspamd_mutex_t));
#if ((GLIB_MAJOR_VERSION == 2) && (GLIB_MINOR_VERSION > 30))
g_mutex_init (&new->mtx);
#else
#endif
}
+void
+rspamd_mutex_free (rspamd_mutex_t *mtx)
+{
+#if ((GLIB_MAJOR_VERSION == 2) && (GLIB_MINOR_VERSION > 30))
+ g_mutex_clear (&mtx->mtx);
+#endif
+ g_slice_free1 (sizeof (rspamd_mutex_t), mtx);
+}
+
/**
* Create new rwlock
* @return
#endif
}
+void
+rspamd_rwlock_free (rspamd_rwlock_t *mtx)
+{
+#if ((GLIB_MAJOR_VERSION == 2) && (GLIB_MINOR_VERSION > 30))
+ g_rw_lock_clear (&mtx->rwlock);
+#endif
+ g_slice_free1 (sizeof (rspamd_rwlock_t), mtx);
+}
struct rspamd_thread_data {
gchar *name;
*/
void rspamd_mutex_unlock (rspamd_mutex_t *mtx);
+/**
+ * Clear rspamd mutex
+ * @param mtx
+ */
+void rspamd_mutex_free (rspamd_mutex_t *mtx);
+
/**
* Create new rwloc
* @return
*/
void rspamd_rwlock_reader_unlock (rspamd_rwlock_t *mtx);
+/**
+ * Free rwlock
+ * @param mtx
+ */
+void rspamd_rwlock_free (rspamd_rwlock_t *mtx);
+
/**
* Create new named thread
* @param name name pattern
gchar *is_custom_str;
struct rspamd_worker_ctx *ctx = worker->ctx;
GError *err = NULL;
+ struct lua_locked_state *nL;
#ifdef WITH_PROFILER
extern void _start (void), etext (void);
/* Create classify pool */
ctx->classify_pool = NULL;
if (ctx->classify_threads > 1) {
- ctx->classify_pool = g_thread_pool_new (process_statfiles_threaded, ctx, ctx->classify_threads, TRUE, &err);
+ nL = init_lua_locked (worker->srv->cfg);
+ ctx->classify_pool = g_thread_pool_new (process_statfiles_threaded, nL, ctx->classify_threads, TRUE, &err);
if (err != NULL) {
msg_err ("pool create failed: %s", err->message);
ctx->classify_pool = NULL;