From 33d45e26503db6e1a770e982e31f87ae31854ba7 Mon Sep 17 00:00:00 2001 From: Vsevolod Stakhov Date: Wed, 2 Oct 2013 13:44:01 +0100 Subject: [PATCH] Add an emitter from rcl object to lua. --- src/cfg_file.h | 11 +-- src/cfg_utils.c | 93 +++----------------------- src/lua/CMakeLists.txt | 3 +- src/lua/lua_common.h | 8 +++ src/lua/lua_config.c | 80 +++------------------- src/lua/lua_rcl.c | 148 +++++++++++++++++++++++++++++++++++++++++ 6 files changed, 178 insertions(+), 165 deletions(-) create mode 100644 src/lua/lua_rcl.c diff --git a/src/cfg_file.h b/src/cfg_file.h index 89e4870db..e7e122977 100644 --- a/src/cfg_file.h +++ b/src/cfg_file.h @@ -348,8 +348,7 @@ struct config_file { GList *workers; /**< linked list of all workers params */ struct rspamd_worker_cfg_parser *wrk_parsers; /**< hash for worker config parsers, indexed by worker quarks */ gchar *filters_str; /**< string of filters */ - GHashTable* modules_opts; /**< hash for module options indexed by module name */ - GHashTable* modules_metas; /**< hash for module meta options indexed by module name*/ + rspamd_cl_object_t *rcl_obj; /**< rcl object */ GHashTable* variables; /**< hash of $variables defined in config, indexed by variable name */ GHashTable* metrics; /**< hash of metrics indexed by metric name */ GList* symbols_groups; /**< groups of symbols */ @@ -449,7 +448,8 @@ void free_config (struct config_file *cfg); * @param opt_name name of option to get * @return module value or NULL if option does not defined */ -gchar* get_module_opt (struct config_file *cfg, gchar *module_name, gchar *opt_name); +rspamd_cl_object_t* get_module_opt (struct config_file *cfg, const gchar *module_name, + const gchar *opt_name); /** * Parse limit @@ -534,11 +534,6 @@ gboolean parse_normalizer (struct config_file *cfg, struct statfile *st, const g */ gboolean read_xml_config (struct config_file *cfg, const gchar *filename); -/* - * Check modules configuration for semantic validity - */ -gboolean check_modules_config (struct config_file *cfg); - /* * Register symbols of classifiers inside metrics */ diff --git a/src/cfg_utils.c b/src/cfg_utils.c index e7e57cd8a..906f4406f 100644 --- a/src/cfg_utils.c +++ b/src/cfg_utils.c @@ -241,8 +241,6 @@ init_defaults (struct config_file *cfg) cfg->max_diff = 20480; cfg->max_statfile_size = DEFAULT_STATFILE_SIZE; - cfg->modules_opts = g_hash_table_new (rspamd_str_hash, rspamd_str_equal); - cfg->modules_metas = g_hash_table_new (rspamd_str_hash, rspamd_str_equal); cfg->variables = g_hash_table_new (rspamd_str_hash, rspamd_str_equal); cfg->metrics = g_hash_table_new (rspamd_str_hash, rspamd_str_equal); cfg->c_modules = g_hash_table_new (rspamd_str_hash, rspamd_str_equal); @@ -267,9 +265,7 @@ free_config (struct config_file *cfg) struct symbols_group *gr; remove_all_maps (cfg); - g_hash_table_remove_all (cfg->modules_opts); - g_hash_table_unref (cfg->modules_opts); - g_hash_table_unref (cfg->modules_metas); + rspamd_cl_obj_unref (cfg->rcl_obj); g_hash_table_remove_all (cfg->variables); g_hash_table_unref (cfg->variables); g_hash_table_remove_all (cfg->metrics); @@ -303,51 +299,17 @@ free_config (struct config_file *cfg) memory_pool_delete (cfg->cfg_pool); } -gchar * -get_module_opt (struct config_file *cfg, gchar *module_name, gchar *opt_name) +rspamd_cl_object_t * +get_module_opt (struct config_file *cfg, const gchar *module_name, const gchar *opt_name) { - GList *cur_opt; - struct module_opt *cur; - static gchar numbuf[64]; + rspamd_cl_object_t *res = NULL, *sec; - cur_opt = g_hash_table_lookup (cfg->modules_opts, module_name); - if (cur_opt == NULL) { - return NULL; + sec = rspamd_cl_obj_get_key (cfg->rcl_obj, module_name); + if (sec != NULL) { + res = rspamd_cl_obj_get_key (cfg->rcl_obj, opt_name); } - while (cur_opt) { - cur = cur_opt->data; - if (strcmp (cur->param, opt_name) == 0) { - /* Check if it is lua variable */ - if (! cur->is_lua) { - /* Plain variable */ - return cur->value; - } - else { - /* Check type */ - switch (cur->lua_type) { - case LUA_VAR_NUM: - /* numbuf is static, so it is safe to return it "as is" */ - snprintf (numbuf, sizeof (numbuf), "%f", *(double *)cur->actual_data); - return numbuf; - case LUA_VAR_BOOLEAN: - snprintf (numbuf, sizeof (numbuf), "%s", *(gboolean *)cur->actual_data ? "yes" : "no"); - return numbuf; - case LUA_VAR_STRING: - return (gchar *)cur->actual_data; - case LUA_VAR_FUNCTION: - msg_info ("option %s is dynamic, so it cannot be aqquired statically", opt_name); - return NULL; - case LUA_VAR_UNKNOWN: - msg_info ("option %s has unknown type, maybe there is error in LUA code", opt_name); - return NULL; - } - } - } - cur_opt = g_list_next (cur_opt); - } - - return NULL; + return res; } guint64 @@ -696,7 +658,6 @@ post_load_config (struct config_file *cfg) struct metric *def_metric; g_hash_table_foreach (cfg->variables, substitute_all_variables, cfg); - g_hash_table_foreach (cfg->modules_opts, substitute_module_variables, cfg); fill_cfg_params (cfg); #ifdef HAVE_CLOCK_GETTIME @@ -1042,44 +1003,6 @@ read_xml_config (struct config_file *cfg, const gchar *filename) return res; } -static void -modules_config_callback (gpointer key, gpointer value, gpointer ud) -{ - extern GHashTable *module_options; - GHashTable *cur_module; - GList *cur; - struct module_opt *opt; - const gchar *mname = key; - gboolean *res = ud; - - if ((cur_module = g_hash_table_lookup (module_options, mname)) == NULL) { - msg_warn ("module %s has not registered any options but is presented in configuration", mname); - *res = FALSE; - return; - } - - cur = value; - while (cur) { - opt = cur->data; - - if (!opt->is_lua && !check_module_option (mname, opt->param, opt->value)) { - *res = FALSE; - return; - } - - cur = g_list_next (cur); - } -} - -gboolean -check_modules_config (struct config_file *cfg) -{ - gboolean res = TRUE; - - g_hash_table_foreach (cfg->modules_opts, modules_config_callback, &res); - return res; -} - static void symbols_classifiers_callback (gpointer key, gpointer value, gpointer ud) { diff --git a/src/lua/CMakeLists.txt b/src/lua/CMakeLists.txt index 765d3041d..762c9a10d 100644 --- a/src/lua/CMakeLists.txt +++ b/src/lua/CMakeLists.txt @@ -15,7 +15,8 @@ SET(LUASRC lua_common.c lua_session.c lua_buffer.c lua_dns.c - lua_rsa.c) + lua_rsa.c + lua_rcl.c) ADD_LIBRARY(rspamd-lua ${LINK_TYPE} ${LUASRC}) SET_TARGET_PROPERTIES(rspamd-lua PROPERTIES VERSION ${RSPAMD_VERSION}) diff --git a/src/lua/lua_common.h b/src/lua/lua_common.h index d03fba0ce..c83433d81 100644 --- a/src/lua/lua_common.h +++ b/src/lua/lua_common.h @@ -6,6 +6,7 @@ #include "main.h" #include "cfg_file.h" +#include "rcl/rcl.h" #include #include #include @@ -101,6 +102,13 @@ struct lua_locked_state* init_lua_locked (struct config_file *cfg); */ void free_lua_locked (struct lua_locked_state *st); +/** + * Push an rcl object to lua + * @param L lua state + * @param obj object to push + */ +gint lua_rcl_obj_push (lua_State *L, rspamd_cl_object_t *obj); + /** * Open libraries functions */ diff --git a/src/lua/lua_config.c b/src/lua/lua_config.c index 1da50ad19..d3b7c6af9 100644 --- a/src/lua/lua_config.c +++ b/src/lua/lua_config.c @@ -153,17 +153,17 @@ static gint lua_config_get_module_opt (lua_State * L) { struct config_file *cfg = lua_check_config (L); - const gchar *mname, *optname, *val; + const gchar *mname, *optname; + rspamd_cl_object_t *obj; if (cfg) { mname = luaL_checkstring (L, 2); optname = luaL_checkstring (L, 3); if (mname && optname) { - val = get_module_opt (cfg, (gchar *)mname, (gchar *)optname); - if (val) { - lua_pushstring (L, val); - return 1; + obj = get_module_opt (cfg, mname, optname); + if (obj) { + return lua_rcl_obj_push (L, obj); } } } @@ -185,83 +185,21 @@ lua_config_get_mempool (lua_State * L) return 1; } -static gint -opt_compare (gconstpointer a, gconstpointer b) -{ - const struct module_opt *o1 = a, - *o2 = b; - - return g_ascii_strcasecmp (o1->param, o2->param); -} - static gint lua_config_get_all_opt (lua_State * L) { struct config_file *cfg = lua_check_config (L); const gchar *mname; - GList *cur_opt, *next_opt; - struct module_opt *opt, *tmp; - gint i; + rspamd_cl_object_t *obj; if (cfg) { mname = luaL_checkstring (L, 2); if (mname) { - cur_opt = g_hash_table_lookup (cfg->modules_opts, mname); - if (cur_opt == NULL) { - lua_pushnil (L); - return 1; + obj = rspamd_cl_obj_get_key (cfg->rcl_obj, mname); + if (obj != NULL) { + return lua_rcl_obj_push (L, obj); } - /* Sort options in alphabet order by param name */ - cur_opt = g_list_sort (cur_opt, opt_compare); - g_hash_table_insert (cfg->modules_opts, (gpointer)mname, cur_opt); - - lua_newtable (L); - while (cur_opt) { - opt = cur_opt->data; - next_opt = g_list_next (cur_opt); - if (next_opt) { - tmp = next_opt->data; - if (g_ascii_strcasecmp (tmp->param, opt->param) == 0) { - /* We have some common values */ - lua_pushstring (L, opt->param); - lua_newtable (L); - /* Now stack looks like: - * table - parent associated table of options - * key - string key of this option - * table - array of values, beginig from 1 - */ - - for (i = 1; ; i++) { - lua_pushinteger (L, i); - lua_pushstring (L, opt->value); - lua_settable (L, -3); - - cur_opt = g_list_next (cur_opt); - if (!cur_opt) { - break; - } - tmp = cur_opt->data; - if (g_ascii_strcasecmp (tmp->param, opt->param) != 0) { - break; - } - opt = tmp; - } - /* Now set index in parent table */ - lua_settable (L, -3); - /* Now continue in outter cycle */ - continue; - } - else { - lua_set_table_index (L, opt->param, opt->value); - } - } - else { - lua_set_table_index (L, opt->param, opt->value); - } - cur_opt = next_opt; - } - return 1; } } lua_pushnil (L); diff --git a/src/lua/lua_rcl.c b/src/lua/lua_rcl.c new file mode 100644 index 000000000..c992b553e --- /dev/null +++ b/src/lua/lua_rcl.c @@ -0,0 +1,148 @@ +/* Copyright (c) 2013, Vsevolod Stakhov + * 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 ''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 AUTHOR 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 "rcl/rcl.h" + +/** + * @file lua rcl bindings + */ + +static gint lua_rcl_obj_push_array (lua_State *L, rspamd_cl_object_t *obj); +static gint lua_rcl_obj_push_simple (lua_State *L, rspamd_cl_object_t *obj); + +/** + * Push a single element of an object to lua + * @param L + * @param key + * @param obj + */ +static void +lua_rcl_obj_push_elt (lua_State *L, const char *key, rspamd_cl_object_t *obj) +{ + lua_pushstring (L, key); + lua_push_obj_simple (L, obj); + lua_settable (L, -3); +} + +/** + * Push a single object to lua + * @param L + * @param obj + * @return + */ +static gint +lua_rcl_obj_push_obj (lua_State *L, rspamd_cl_object_t *obj) +{ + rspamd_cl_object_t *cur, *tmp; + + if (obj->next != NULL) { + /* Actually we need to push this as an array */ + return lua_rcl_obj_push_array (L, obj); + } + + lua_newtable (L); + HASH_ITER (hh, obj, cur, tmp) { + lua_rcl_obj_push_elt (L, obj->key, obj); + } + + return 1; +} + +/** + * Push an array to lua as table indexed by integers + * @param L + * @param obj + * @return + */ +static gint +lua_rcl_obj_push_array (lua_State *L, rspamd_cl_object_t *obj) +{ + rspamd_cl_object_t *cur; + gint i = 1; + + lua_newtable (L); + + LL_FOREACH (obj, cur) { + lua_rcl_obj_push (L, cur); + lua_rawseti (L, -2, i); + i ++; + } + + return 1; +} + +/** + * Push a simple object to lua depending on its actual type + */ +static gint +lua_rcl_obj_push_simple (lua_State *L, rspamd_cl_object_t *obj) +{ + if (obj->next != NULL) { + /* Actually we need to push this as an array */ + return lua_rcl_obj_push_array (L, obj); + } + + switch (obj->type) { + case RSPAMD_CL_BOOLEAN: + lua_pushboolean (L, rspamd_cl_obj_toboolean (obj)); + break; + case RSPAMD_CL_STRING: + lua_pushstring (L, rspamd_cl_obj_tostring (obj)); + break; + case RSPAMD_CL_INT: +#if LUA_VERSION_NUM >= 501 + lua_pushinteger (L, rspamd_cl_obj_toint (obj)); +#else + lua_pushnumber (L, rspamd_cl_obj_toint (obj)); +#endif + break; + case RSPAMD_CL_FLOAT: + case RSPAMD_CL_TIME: + lua_pushnumber (L, rspamd_cl_obj_todouble (obj)); + break; + default: + lua_pushnil (L); + break; + } + + return 1; +} + +/** + * Push an object to lua + * @param L lua state + * @param obj object to push + */ +gint +lua_rcl_obj_push (lua_State *L, rspamd_cl_object_t *obj) +{ + switch (obj->type) { + case RSPAMD_CL_OBJECT: + return lua_rcl_obj_push_obj (L, obj->value.ov); + case RSPAMD_CL_ARRAY: + return lua_rcl_obj_push_array (L, obj->value.ov); + default: + return lua_rcl_obj_push_simple (L, obj); + } +} -- 2.39.5