From: Vsevolod Stakhov Date: Sun, 6 Mar 2016 18:12:33 +0000 (+0000) Subject: [Rework] Move maps code to a separate lua unit X-Git-Tag: 1.2.0~110 X-Git-Url: https://source.dussan.org/?a=commitdiff_plain;h=2f55351fca3143ed85ac9ebaa4590c5053ff014c;p=rspamd.git [Rework] Move maps code to a separate lua unit --- diff --git a/src/lua/CMakeLists.txt b/src/lua/CMakeLists.txt index 3d3a7cebf..cb97ca3ed 100644 --- a/src/lua/CMakeLists.txt +++ b/src/lua/CMakeLists.txt @@ -26,6 +26,7 @@ SET(LUASRC ${CMAKE_CURRENT_SOURCE_DIR}/lua_common.c ${CMAKE_CURRENT_SOURCE_DIR}/lua_html.c ${CMAKE_CURRENT_SOURCE_DIR}/lua_fann.c ${CMAKE_CURRENT_SOURCE_DIR}/lua_sqlite3.c - ${CMAKE_CURRENT_SOURCE_DIR}/lua_cryptobox.c) + ${CMAKE_CURRENT_SOURCE_DIR}/lua_cryptobox.c + ${CMAKE_CURRENT_SOURCE_DIR}/lua_map.c) SET(RSPAMD_LUA ${LUASRC} PARENT_SCOPE) diff --git a/src/lua/lua_common.h b/src/lua/lua_common.h index 8629d6366..d39f42793 100644 --- a/src/lua/lua_common.h +++ b/src/lua/lua_common.h @@ -43,6 +43,8 @@ luaL_register (lua_State *L, const gchar *name, const struct luaL_reg *methods) /* Interface definitions */ #define LUA_FUNCTION_DEF(class, name) static gint lua_ ## class ## _ ## name ( \ lua_State * L) +#define LUA_PUBLIC_FUNCTION_DEF(class, name) gint lua_ ## class ## _ ## name ( \ + lua_State * L) #define LUA_INTERFACE_DEF(class, name) { # name, lua_ ## class ## _ ## name } extern const luaL_reg null_reg[]; @@ -80,7 +82,6 @@ struct rspamd_lua_regexp { gint re_flags; }; - /* Common utility functions */ /** diff --git a/src/lua/lua_config.c b/src/lua/lua_config.c index 1fbf6efdc..9f97902bb 100644 --- a/src/lua/lua_config.c +++ b/src/lua/lua_config.c @@ -14,11 +14,10 @@ * limitations under the License. */ #include "lua_common.h" -#include "map.h" -#include "message.h" -#include "radix.h" -#include "expression.h" -#include "composites.h" +#include "libmime/message.h" +#include "libutil/expression.h" +#include "libserver/composites.h" +#include "lua/lua_map.h" #include "utlist.h" /*** @@ -78,7 +77,7 @@ local function foo(task) return false end */ -LUA_FUNCTION_DEF (config, add_radix_map); + /*** * @method rspamd_config:radix_from_config(mname, optname) * Creates new static map of IP/mask addresses from config. @@ -96,7 +95,6 @@ local function foo(task) return false end */ -LUA_FUNCTION_DEF (config, radix_from_config); /*** * @method rspamd_config:add_hash_map(mapline[, description]) * Creates new dynamic map string objects. @@ -114,7 +112,6 @@ local function foo(task) return false end */ -LUA_FUNCTION_DEF (config, add_hash_map); /*** * @method rspamd_config:add_kv_map(mapline[, description]) * Creates new dynamic map of key/values associations. @@ -135,7 +132,6 @@ local function foo(task) return false end */ -LUA_FUNCTION_DEF (config, add_kv_map); /*** * @method rspamd_config:add_map(mapline[, description], callback) * Creates new dynamic map with free-form callback @@ -152,7 +148,6 @@ end rspamd_config:add_map('http://example.com/map', "settings map", process_map) */ -LUA_FUNCTION_DEF (config, add_map); /*** * @method rspamd_config:get_classifier(name) * Returns classifier config. @@ -416,33 +411,6 @@ static const struct luaL_reg configlib_m[] = { {NULL, NULL} }; -enum rspamd_lua_map_type { - RSPAMD_LUA_MAP_RADIX = 0, - RSPAMD_LUA_MAP_SET, - RSPAMD_LUA_MAP_HASH, - RSPAMD_LUA_MAP_CALLBACK -}; - -struct rspamd_lua_map { - struct rspamd_map *map; - enum rspamd_lua_map_type type; - - union { - radix_compressed_t *radix; - GHashTable *hash; - gint cbref; - } data; -}; - -/* Radix tree */ -LUA_FUNCTION_DEF (map, get_key); - -static const struct luaL_reg maplib_m[] = { - LUA_INTERFACE_DEF (map, get_key), - {"__tostring", rspamd_lua_class_tostring}, - {NULL, NULL} -}; - struct rspamd_config * lua_check_config (lua_State * L, gint pos) { @@ -451,14 +419,6 @@ lua_check_config (lua_State * L, gint pos) return ud ? *((struct rspamd_config **)ud) : NULL; } -static struct rspamd_lua_map * -lua_check_map (lua_State * L) -{ - void *ud = luaL_checkudata (L, 1, "rspamd{map}"); - luaL_argcheck (L, ud != NULL, 1, "'map' expected"); - return ud ? *((struct rspamd_lua_map **)ud) : NULL; -} - /*** Config functions ***/ static gint lua_config_get_api_version (lua_State *L) @@ -761,161 +721,6 @@ lua_config_register_pre_filter (lua_State *L) return 1; } -static gint -lua_config_add_radix_map (lua_State *L) -{ - struct rspamd_config *cfg = lua_check_config (L, 1); - const gchar *map_line, *description; - struct rspamd_lua_map *map, **pmap; - struct rspamd_map *m; - - if (cfg) { - map_line = luaL_checkstring (L, 2); - description = lua_tostring (L, 3); - map = rspamd_mempool_alloc0 (cfg->cfg_pool, sizeof (*map)); - map->data.radix = radix_create_compressed (); - map->type = RSPAMD_LUA_MAP_RADIX; - - if ((m = rspamd_map_add (cfg, map_line, description, - rspamd_radix_read, - rspamd_radix_fin, - (void **)&map->data.radix)) == NULL) { - msg_warn_config ("invalid radix map %s", map_line); - radix_destroy_compressed (map->data.radix); - lua_pushnil (L); - return 1; - } - - map->map = m; - pmap = lua_newuserdata (L, sizeof (void *)); - *pmap = map; - rspamd_lua_setclass (L, "rspamd{map}", -1); - } - else { - return luaL_error (L, "invalid arguments"); - } - - return 1; - -} - -static gint -lua_config_radix_from_config (lua_State *L) -{ - struct rspamd_config *cfg = lua_check_config (L, 1); - const gchar *mname, *optname; - const ucl_object_t *obj; - struct rspamd_lua_map *map, **pmap; - - if (!cfg) { - return luaL_error (L, "invalid arguments"); - } - - mname = luaL_checkstring (L, 2); - optname = luaL_checkstring (L, 3); - - if (mname && optname) { - obj = rspamd_config_get_module_opt (cfg, mname, optname); - if (obj) { - map = rspamd_mempool_alloc0 (cfg->cfg_pool, sizeof (*map)); - map->data.radix = radix_create_compressed (); - map->type = RSPAMD_LUA_MAP_RADIX; - map->data.radix = radix_create_compressed (); - radix_add_generic_iplist (ucl_obj_tostring (obj), &map->data.radix); - pmap = lua_newuserdata (L, sizeof (void *)); - *pmap = map; - rspamd_lua_setclass (L, "rspamd{map}", -1); - } else { - msg_warn_config ("Couldnt find config option [%s][%s]", mname, - optname); - lua_pushnil (L); - } - - } - else { - return luaL_error (L, "invalid arguments"); - } - - return 1; -} - -static gint -lua_config_add_hash_map (lua_State *L) -{ - struct rspamd_config *cfg = lua_check_config (L, 1); - const gchar *map_line, *description; - struct rspamd_lua_map *map, **pmap; - struct rspamd_map *m; - - if (cfg) { - map_line = luaL_checkstring (L, 2); - description = lua_tostring (L, 3); - map = rspamd_mempool_alloc0 (cfg->cfg_pool, sizeof (*map)); - map->data.hash = g_hash_table_new (rspamd_strcase_hash, - rspamd_strcase_equal); - map->type = RSPAMD_LUA_MAP_SET; - - if ((m = rspamd_map_add (cfg, map_line, description, - rspamd_hosts_read, - rspamd_hosts_fin, - (void **)&map->data.hash)) == NULL) { - msg_warn_config ("invalid set map %s", map_line); - g_hash_table_destroy (map->data.hash); - lua_pushnil (L); - return 1; - } - - map->map = m; - pmap = lua_newuserdata (L, sizeof (void *)); - *pmap = map; - rspamd_lua_setclass (L, "rspamd{map}", -1); - } - else { - return luaL_error (L, "invalid arguments"); - } - - return 1; - -} - -static gint -lua_config_add_kv_map (lua_State *L) -{ - struct rspamd_config *cfg = lua_check_config (L, 1); - const gchar *map_line, *description; - struct rspamd_lua_map *map, **pmap; - struct rspamd_map *m; - - if (cfg) { - map_line = luaL_checkstring (L, 2); - description = lua_tostring (L, 3); - map = rspamd_mempool_alloc0 (cfg->cfg_pool, sizeof (*map)); - map->data.hash = g_hash_table_new (rspamd_strcase_hash, - rspamd_strcase_equal); - map->type = RSPAMD_LUA_MAP_HASH; - - if ((m = rspamd_map_add (cfg, map_line, description, - rspamd_kv_list_read, - rspamd_kv_list_fin, - (void **)&map->data.hash)) == NULL) { - msg_warn_config ("invalid hash map %s", map_line); - g_hash_table_destroy (map->data.hash); - lua_pushnil (L); - return 1; - } - - map->map = m; - pmap = lua_newuserdata (L, sizeof (void *)); - *pmap = map; - rspamd_lua_setclass (L, "rspamd{map}", -1); - } - else { - return luaL_error (L, "invalid arguments"); - } - - return 1; -} - static gint lua_config_get_key (lua_State *L) { @@ -1789,215 +1594,6 @@ lua_config_replace_regexp (lua_State *L) return 0; } -struct lua_map_callback_data { - lua_State *L; - gint ref; - GString *data; - struct rspamd_lua_map *lua_map; -}; - -static gchar * -lua_map_read (rspamd_mempool_t *pool, gchar *chunk, gint len, - struct map_cb_data *data) -{ - struct lua_map_callback_data *cbdata, *old; - - if (data->cur_data == NULL) { - cbdata = g_slice_alloc0 (sizeof (*cbdata)); - old = (struct lua_map_callback_data *)data->prev_data; - cbdata->L = old->L; - cbdata->ref = old->ref; - cbdata->lua_map = old->lua_map; - data->cur_data = cbdata; - } - else { - cbdata = (struct lua_map_callback_data *)data->cur_data; - } - - if (cbdata->data == NULL) { - cbdata->data = g_string_new_len (chunk, len); - } - else { - g_string_append_len (cbdata->data, chunk, len); - } - - return NULL; -} - -void -lua_map_fin (rspamd_mempool_t * pool, struct map_cb_data *data) -{ - struct lua_map_callback_data *cbdata, *old; - struct rspamd_lua_map **pmap; - - if (data->prev_data) { - /* Cleanup old data */ - old = (struct lua_map_callback_data *)data->prev_data; - if (old->data) { - g_string_free (old->data, TRUE); - } - g_slice_free1 (sizeof (*old), old); - data->prev_data = NULL; - } - - if (data->cur_data) { - cbdata = (struct lua_map_callback_data *)data->cur_data; - } - else { - msg_err_pool ("no data read for map"); - return; - } - - if (cbdata->data != NULL && cbdata->data->len != 0) { - lua_rawgeti (cbdata->L, LUA_REGISTRYINDEX, cbdata->ref); - lua_pushlstring (cbdata->L, cbdata->data->str, cbdata->data->len); - pmap = lua_newuserdata (cbdata->L, sizeof (void *)); - *pmap = cbdata->lua_map; - rspamd_lua_setclass (cbdata->L, "rspamd{map}", -1); - - if (lua_pcall (cbdata->L, -1, 0, 0) != 0) { - msg_info_pool ("call to %s failed: %s", "local function", - lua_tostring (cbdata->L, -1)); - lua_pop (cbdata->L, 1); - } - } -} - -static gint -lua_config_add_map (lua_State *L) -{ - struct rspamd_config *cfg = lua_check_config (L, 1); - const gchar *map_line, *description; - struct lua_map_callback_data *cbdata, **pcbdata; - struct rspamd_lua_map *map; - struct rspamd_map *m; - int cbidx; - - if (cfg) { - map_line = luaL_checkstring (L, 2); - - if (lua_gettop (L) == 4) { - description = lua_tostring (L, 3); - cbidx = 4; - } - else { - description = NULL; - cbidx = 3; - } - - if (lua_type (L, cbidx) == LUA_TFUNCTION) { - cbdata = g_slice_alloc (sizeof (*cbdata)); - cbdata->L = L; - cbdata->data = NULL; - lua_pushvalue (L, cbidx); - /* Get a reference */ - cbdata->ref = luaL_ref (L, LUA_REGISTRYINDEX); - map = rspamd_mempool_alloc (cfg->cfg_pool, sizeof (*map)); - map->type = RSPAMD_LUA_MAP_CALLBACK; - map->data.cbref = cbdata->ref; - cbdata->lua_map = map; - pcbdata = rspamd_mempool_alloc (cfg->cfg_pool, sizeof (cbdata)); - *pcbdata = cbdata; - - if ((m = rspamd_map_add (cfg, map_line, description, - lua_map_read, lua_map_fin, - (void **)pcbdata)) == NULL) { - msg_warn_config ("invalid hash map %s", map_line); - lua_pushboolean (L, false); - } - else { - map->map = m; - lua_pushboolean (L, true); - } - } - else { - msg_warn_config ("invalid callback argument for map %s", map_line); - lua_pushboolean (L, false); - } - } - else { - return luaL_error (L, "invalid arguments"); - } - - return 1; -} - -/* Radix and hash table functions */ -static gint -lua_map_get_key (lua_State * L) -{ - struct rspamd_lua_map *map = lua_check_map (L); - radix_compressed_t *radix; - struct rspamd_lua_ip *addr = NULL; - const gchar *key, *value = NULL; - gpointer ud; - guint32 key_num = 0; - gboolean ret = FALSE; - - if (map) { - if (map->type == RSPAMD_LUA_MAP_RADIX) { - radix = map->data.radix; - - if (lua_type (L, 2) == LUA_TNUMBER) { - key_num = luaL_checknumber (L, 2); - key_num = htonl (key_num); - } - else if (lua_type (L, 2) == LUA_TUSERDATA) { - ud = luaL_checkudata (L, 2, "rspamd{ip}"); - if (ud != NULL) { - addr = *((struct rspamd_lua_ip **)ud); - if (addr->addr == NULL) { - msg_err ("rspamd{ip} is not valid"); - addr = NULL; - } - } - else { - msg_err ("invalid userdata type provided, rspamd{ip} expected"); - } - } - - if (addr != NULL) { - if (radix_find_compressed_addr (radix, addr->addr) - != RADIX_NO_VALUE) { - ret = TRUE; - } - } - else if (key_num != 0) { - if (radix_find_compressed (radix, (guint8 *)&key_num, sizeof (key_num)) - != RADIX_NO_VALUE) { - ret = TRUE; - } - } - } - else if (map->type == RSPAMD_LUA_MAP_SET) { - key = lua_tostring (L, 2); - - if (key) { - ret = g_hash_table_lookup (map->data.hash, key) != NULL; - } - } - else { - /* key-value map */ - key = lua_tostring (L, 2); - - if (key) { - value = g_hash_table_lookup (map->data.hash, key); - - if (value) { - lua_pushstring (L, value); - return 1; - } - } - } - } - else { - return luaL_error (L, "invalid arguments"); - } - - lua_pushboolean (L, ret); - return 1; -} - void luaopen_config (lua_State * L) { @@ -2005,11 +1601,3 @@ luaopen_config (lua_State * L) lua_pop (L, 1); } - -void -luaopen_map (lua_State * L) -{ - rspamd_lua_new_class (L, "rspamd{map}", maplib_m); - - lua_pop (L, 1); -} diff --git a/src/lua/lua_map.c b/src/lua/lua_map.c new file mode 100644 index 000000000..ee9695c51 --- /dev/null +++ b/src/lua/lua_map.c @@ -0,0 +1,438 @@ +/*- + * Copyright 2016 Vsevolod Stakhov + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "lua_common.h" +#include "libutil/map.h" +#include "libutil/map_private.h" +#include "libutil/radix.h" +#include "lua/lua_map.h" + +/*** + * This module is used to manage rspamd maps and map like objects + * + * @module rspamd_map + */ + +/* Radix tree */ +LUA_FUNCTION_DEF (map, get_key); + +static const struct luaL_reg maplib_m[] = { + LUA_INTERFACE_DEF (map, get_key), + {"__tostring", rspamd_lua_class_tostring}, + {NULL, NULL} +}; + +enum rspamd_lua_map_type { + RSPAMD_LUA_MAP_RADIX = 0, + RSPAMD_LUA_MAP_SET, + RSPAMD_LUA_MAP_HASH, + RSPAMD_LUA_MAP_CALLBACK +}; + +struct rspamd_map; +struct radix_tree_compressed; + +struct rspamd_lua_map { + struct rspamd_map *map; + enum rspamd_lua_map_type type; + + union { + struct radix_tree_compressed *radix; + GHashTable *hash; + gint cbref; + } data; +}; + +struct lua_map_callback_data { + lua_State *L; + gint ref; + GString *data; + struct rspamd_lua_map *lua_map; +}; + +static struct rspamd_lua_map * +lua_check_map (lua_State * L) +{ + void *ud = luaL_checkudata (L, 1, "rspamd{map}"); + luaL_argcheck (L, ud != NULL, 1, "'map' expected"); + return ud ? *((struct rspamd_lua_map **)ud) : NULL; +} + +gint +lua_config_add_radix_map (lua_State *L) +{ + struct rspamd_config *cfg = lua_check_config (L, 1); + const gchar *map_line, *description; + struct rspamd_lua_map *map, **pmap; + struct rspamd_map *m; + + if (cfg) { + map_line = luaL_checkstring (L, 2); + description = lua_tostring (L, 3); + map = rspamd_mempool_alloc0 (cfg->cfg_pool, sizeof (*map)); + map->data.radix = radix_create_compressed (); + map->type = RSPAMD_LUA_MAP_RADIX; + + if ((m = rspamd_map_add (cfg, map_line, description, + rspamd_radix_read, + rspamd_radix_fin, + (void **)&map->data.radix)) == NULL) { + msg_warn_config ("invalid radix map %s", map_line); + radix_destroy_compressed (map->data.radix); + lua_pushnil (L); + return 1; + } + + map->map = m; + pmap = lua_newuserdata (L, sizeof (void *)); + *pmap = map; + rspamd_lua_setclass (L, "rspamd{map}", -1); + } + else { + return luaL_error (L, "invalid arguments"); + } + + return 1; + +} + +gint +lua_config_radix_from_config (lua_State *L) +{ + struct rspamd_config *cfg = lua_check_config (L, 1); + const gchar *mname, *optname; + const ucl_object_t *obj; + struct rspamd_lua_map *map, **pmap; + + if (!cfg) { + return luaL_error (L, "invalid arguments"); + } + + mname = luaL_checkstring (L, 2); + optname = luaL_checkstring (L, 3); + + if (mname && optname) { + obj = rspamd_config_get_module_opt (cfg, mname, optname); + if (obj) { + map = rspamd_mempool_alloc0 (cfg->cfg_pool, sizeof (*map)); + map->data.radix = radix_create_compressed (); + map->type = RSPAMD_LUA_MAP_RADIX; + map->data.radix = radix_create_compressed (); + radix_add_generic_iplist (ucl_obj_tostring (obj), &map->data.radix); + pmap = lua_newuserdata (L, sizeof (void *)); + *pmap = map; + rspamd_lua_setclass (L, "rspamd{map}", -1); + } else { + msg_warn_config ("Couldnt find config option [%s][%s]", mname, + optname); + lua_pushnil (L); + } + + } + else { + return luaL_error (L, "invalid arguments"); + } + + return 1; +} + +gint +lua_config_add_hash_map (lua_State *L) +{ + struct rspamd_config *cfg = lua_check_config (L, 1); + const gchar *map_line, *description; + struct rspamd_lua_map *map, **pmap; + struct rspamd_map *m; + + if (cfg) { + map_line = luaL_checkstring (L, 2); + description = lua_tostring (L, 3); + map = rspamd_mempool_alloc0 (cfg->cfg_pool, sizeof (*map)); + map->data.hash = g_hash_table_new (rspamd_strcase_hash, + rspamd_strcase_equal); + map->type = RSPAMD_LUA_MAP_SET; + + if ((m = rspamd_map_add (cfg, map_line, description, + rspamd_hosts_read, + rspamd_hosts_fin, + (void **)&map->data.hash)) == NULL) { + msg_warn_config ("invalid set map %s", map_line); + g_hash_table_destroy (map->data.hash); + lua_pushnil (L); + return 1; + } + + map->map = m; + pmap = lua_newuserdata (L, sizeof (void *)); + *pmap = map; + rspamd_lua_setclass (L, "rspamd{map}", -1); + } + else { + return luaL_error (L, "invalid arguments"); + } + + return 1; + +} + +gint +lua_config_add_kv_map (lua_State *L) +{ + struct rspamd_config *cfg = lua_check_config (L, 1); + const gchar *map_line, *description; + struct rspamd_lua_map *map, **pmap; + struct rspamd_map *m; + + if (cfg) { + map_line = luaL_checkstring (L, 2); + description = lua_tostring (L, 3); + map = rspamd_mempool_alloc0 (cfg->cfg_pool, sizeof (*map)); + map->data.hash = g_hash_table_new (rspamd_strcase_hash, + rspamd_strcase_equal); + map->type = RSPAMD_LUA_MAP_HASH; + + if ((m = rspamd_map_add (cfg, map_line, description, + rspamd_kv_list_read, + rspamd_kv_list_fin, + (void **)&map->data.hash)) == NULL) { + msg_warn_config ("invalid hash map %s", map_line); + g_hash_table_destroy (map->data.hash); + lua_pushnil (L); + return 1; + } + + map->map = m; + pmap = lua_newuserdata (L, sizeof (void *)); + *pmap = map; + rspamd_lua_setclass (L, "rspamd{map}", -1); + } + else { + return luaL_error (L, "invalid arguments"); + } + + return 1; +} + + +static gchar * +lua_map_read (rspamd_mempool_t *pool, gchar *chunk, gint len, + struct map_cb_data *data) +{ + struct lua_map_callback_data *cbdata, *old; + + if (data->cur_data == NULL) { + cbdata = g_slice_alloc0 (sizeof (*cbdata)); + old = (struct lua_map_callback_data *)data->prev_data; + cbdata->L = old->L; + cbdata->ref = old->ref; + cbdata->lua_map = old->lua_map; + data->cur_data = cbdata; + } + else { + cbdata = (struct lua_map_callback_data *)data->cur_data; + } + + if (cbdata->data == NULL) { + cbdata->data = g_string_new_len (chunk, len); + } + else { + g_string_append_len (cbdata->data, chunk, len); + } + + return NULL; +} + +static void +lua_map_fin (rspamd_mempool_t * pool, struct map_cb_data *data) +{ + struct lua_map_callback_data *cbdata, *old; + struct rspamd_lua_map **pmap; + + if (data->prev_data) { + /* Cleanup old data */ + old = (struct lua_map_callback_data *)data->prev_data; + if (old->data) { + g_string_free (old->data, TRUE); + } + g_slice_free1 (sizeof (*old), old); + data->prev_data = NULL; + } + + if (data->cur_data) { + cbdata = (struct lua_map_callback_data *)data->cur_data; + } + else { + msg_err_pool ("no data read for map"); + return; + } + + if (cbdata->data != NULL && cbdata->data->len != 0) { + lua_rawgeti (cbdata->L, LUA_REGISTRYINDEX, cbdata->ref); + lua_pushlstring (cbdata->L, cbdata->data->str, cbdata->data->len); + pmap = lua_newuserdata (cbdata->L, sizeof (void *)); + *pmap = cbdata->lua_map; + rspamd_lua_setclass (cbdata->L, "rspamd{map}", -1); + + if (lua_pcall (cbdata->L, -1, 0, 0) != 0) { + msg_info_pool ("call to %s failed: %s", "local function", + lua_tostring (cbdata->L, -1)); + lua_pop (cbdata->L, 1); + } + } +} + +gint +lua_config_add_map (lua_State *L) +{ + struct rspamd_config *cfg = lua_check_config (L, 1); + const gchar *map_line, *description; + struct lua_map_callback_data *cbdata, **pcbdata; + struct rspamd_lua_map *map; + struct rspamd_map *m; + int cbidx; + + if (cfg) { + map_line = luaL_checkstring (L, 2); + + if (lua_gettop (L) == 4) { + description = lua_tostring (L, 3); + cbidx = 4; + } + else { + description = NULL; + cbidx = 3; + } + + if (lua_type (L, cbidx) == LUA_TFUNCTION) { + cbdata = g_slice_alloc (sizeof (*cbdata)); + cbdata->L = L; + cbdata->data = NULL; + lua_pushvalue (L, cbidx); + /* Get a reference */ + cbdata->ref = luaL_ref (L, LUA_REGISTRYINDEX); + map = rspamd_mempool_alloc (cfg->cfg_pool, sizeof (*map)); + map->type = RSPAMD_LUA_MAP_CALLBACK; + map->data.cbref = cbdata->ref; + cbdata->lua_map = map; + pcbdata = rspamd_mempool_alloc (cfg->cfg_pool, sizeof (cbdata)); + *pcbdata = cbdata; + + if ((m = rspamd_map_add (cfg, map_line, description, + lua_map_read, lua_map_fin, + (void **)pcbdata)) == NULL) { + msg_warn_config ("invalid hash map %s", map_line); + lua_pushboolean (L, false); + } + else { + map->map = m; + lua_pushboolean (L, true); + } + } + else { + msg_warn_config ("invalid callback argument for map %s", map_line); + lua_pushboolean (L, false); + } + } + else { + return luaL_error (L, "invalid arguments"); + } + + return 1; +} + +/* Radix and hash table functions */ +static gint +lua_map_get_key (lua_State * L) +{ + struct rspamd_lua_map *map = lua_check_map (L); + radix_compressed_t *radix; + struct rspamd_lua_ip *addr = NULL; + const gchar *key, *value = NULL; + gpointer ud; + guint32 key_num = 0; + gboolean ret = FALSE; + + if (map) { + if (map->type == RSPAMD_LUA_MAP_RADIX) { + radix = map->data.radix; + + if (lua_type (L, 2) == LUA_TNUMBER) { + key_num = luaL_checknumber (L, 2); + key_num = htonl (key_num); + } + else if (lua_type (L, 2) == LUA_TUSERDATA) { + ud = luaL_checkudata (L, 2, "rspamd{ip}"); + if (ud != NULL) { + addr = *((struct rspamd_lua_ip **)ud); + if (addr->addr == NULL) { + msg_err ("rspamd{ip} is not valid"); + addr = NULL; + } + } + else { + msg_err ("invalid userdata type provided, rspamd{ip} expected"); + } + } + + if (addr != NULL) { + if (radix_find_compressed_addr (radix, addr->addr) + != RADIX_NO_VALUE) { + ret = TRUE; + } + } + else if (key_num != 0) { + if (radix_find_compressed (radix, (guint8 *)&key_num, sizeof (key_num)) + != RADIX_NO_VALUE) { + ret = TRUE; + } + } + } + else if (map->type == RSPAMD_LUA_MAP_SET) { + key = lua_tostring (L, 2); + + if (key) { + ret = g_hash_table_lookup (map->data.hash, key) != NULL; + } + } + else { + /* key-value map */ + key = lua_tostring (L, 2); + + if (key) { + value = g_hash_table_lookup (map->data.hash, key); + + if (value) { + lua_pushstring (L, value); + return 1; + } + } + } + } + else { + return luaL_error (L, "invalid arguments"); + } + + lua_pushboolean (L, ret); + return 1; +} + +void +luaopen_map (lua_State * L) +{ + rspamd_lua_new_class (L, "rspamd{map}", maplib_m); + + lua_pop (L, 1); +} diff --git a/src/lua/lua_map.h b/src/lua/lua_map.h new file mode 100644 index 000000000..01a7a639f --- /dev/null +++ b/src/lua/lua_map.h @@ -0,0 +1,28 @@ +/*- + * Copyright 2016 Vsevolod Stakhov + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef SRC_LUA_LUA_MAP_H_ +#define SRC_LUA_LUA_MAP_H_ + +#include "lua_common.h" + +LUA_PUBLIC_FUNCTION_DEF (config, add_radix_map); +LUA_PUBLIC_FUNCTION_DEF (config, radix_from_config); +LUA_PUBLIC_FUNCTION_DEF (config, add_map); +LUA_PUBLIC_FUNCTION_DEF (config, add_hash_map); +LUA_PUBLIC_FUNCTION_DEF (config, add_kv_map); +LUA_PUBLIC_FUNCTION_DEF (config, add_map); + +#endif /* SRC_LUA_LUA_MAP_H_ */