]> git.ipfire.org Git - thirdparty/rspamd.git/commitdiff
* Add DNS resolver lua bindings.
authorVsevolod Stakhov <vsevolod@rambler-co.ru>
Mon, 13 Aug 2012 16:40:50 +0000 (20:40 +0400)
committerVsevolod Stakhov <vsevolod@rambler-co.ru>
Mon, 13 Aug 2012 16:40:50 +0000 (20:40 +0400)
Make lua http library working without task object.
Fix a problem with resolver in lua_worker.
Added some utility functions to lua api.

src/lua/CMakeLists.txt
src/lua/lua_buffer.c
src/lua/lua_common.c
src/lua/lua_common.h
src/lua/lua_dns.c [new file with mode: 0644]
src/lua/lua_http.c
src/lua/lua_session.c
src/lua_worker.c

index 92cf3df4b7f3d2a3f2ca227923f6f3a6786bdcdd..10609f782f1b4a1d814bbf28cfbb7a278d5023e4 100644 (file)
@@ -13,7 +13,8 @@ SET(LUASRC                      lua_common.c
                                          lua_upstream.c
                                          lua_mempool.c
                                          lua_session.c
-                                         lua_buffer.c)
+                                         lua_buffer.c
+                                         lua_dns.c)
 
 ADD_LIBRARY(rspamd-lua ${LINK_TYPE} ${LUASRC})
 SET_TARGET_PROPERTIES(rspamd-lua PROPERTIES VERSION ${RSPAMD_VERSION})
index 9c18ef5cf0068cd882f00a8a47f12418ed8a803a..43df6a6d88bca1696f860b1edd66e0847c790200 100644 (file)
@@ -100,7 +100,7 @@ lua_io_read_cb (f_str_t * in, void *arg)
                msg_info ("call to session finalizer failed: %s", lua_tostring (cbdata->L, -1));
        }
 
-       res = lua_toboolean (cbdata->L, 1);
+       res = lua_toboolean (cbdata->L, -1);
        lua_pop (cbdata->L, 1);
 
        if (need_unlock) {
@@ -133,7 +133,7 @@ lua_io_write_cb (void *arg)
                        msg_info ("call to session finalizer failed: %s", lua_tostring (cbdata->L, -1));
                }
 
-               res = lua_toboolean (cbdata->L, 1);
+               res = lua_toboolean (cbdata->L, -1);
                lua_pop (cbdata->L, 1);
 
                if (need_unlock) {
index 3f66c3fcd21d3e4610077eff2dc064f062890449..cb114bb34d9ea420492214ff3854b10e47864620 100644 (file)
@@ -444,6 +444,7 @@ init_lua (struct config_file *cfg)
        (void)lua_add_actions_global (L);
        (void)luaopen_session (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);
@@ -789,3 +790,24 @@ lua_dumpstack (lua_State *L)
        }
        msg_info (buf);
 }
+
+gpointer
+lua_check_class (lua_State *L, gint index, const gchar *name)
+{
+       gpointer                                        p;
+
+       if (lua_type (L, index) == LUA_TUSERDATA) {
+               p = lua_touserdata (L, index);
+               if (p) {
+                       if (lua_getmetatable (L, index)) {
+                               lua_getfield (L, LUA_REGISTRYINDEX, name);  /* get correct metatable */
+                               if (lua_rawequal (L, -1, -2)) {  /* does it have the correct mt? */
+                                       lua_pop (L, 2);  /* remove both metatables */
+                                       return p;
+                               }
+                               lua_pop (L, 2);
+                       }
+               }
+       }
+       return NULL;
+}
index f9ab43d9172b560169076321855977c2a14aa8f2..0ec0466e027c6da5095f57d18ad7b9ab39d5817f 100644 (file)
@@ -46,6 +46,11 @@ void lua_set_table_index (lua_State *L, const gchar *index, const gchar *value);
  */
 gint lua_class_tostring (lua_State *L);
 
+/**
+ * Check whether the argument at specified index is of the specified class
+ */
+gpointer lua_check_class (lua_State *L, gint index, const gchar *name);
+
 /**
  * Open libraries functions
  */
@@ -71,11 +76,8 @@ gint luaopen_upstream (lua_State * L);
 gint luaopen_mempool (lua_State * L);
 gint luaopen_session (lua_State * L);
 gint luaopen_io_dispatcher (lua_State * L);
+gint luaopen_dns_resolver (lua_State * L);
 
-void init_lua (struct config_file *cfg);
-gboolean init_lua_filters (struct config_file *cfg);
-
-/* Filters functions */
 gint lua_call_filter (const gchar *function, struct worker_task *task);
 gint lua_call_chain_filter (const gchar *function, struct worker_task *task, gint *marks, guint number);
 double lua_consolidation_func (struct worker_task *task, const gchar *metric_name, const gchar *function_name);
diff --git a/src/lua/lua_dns.c b/src/lua/lua_dns.c
new file mode 100644 (file)
index 0000000..b31cac6
--- /dev/null
@@ -0,0 +1,292 @@
+/* Copyright (c) 2010-2012, 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 "dns.h"
+
+/* Public prototypes */
+struct rspamd_dns_resolver *lua_check_dns_resolver (lua_State * L);
+gint luaopen_dns_resolver (lua_State * L);
+
+/* Lua bindings */
+LUA_FUNCTION_DEF (dns_resolver, init);
+LUA_FUNCTION_DEF (dns_resolver, resolve_a);
+LUA_FUNCTION_DEF (dns_resolver, resolve_ptr);
+LUA_FUNCTION_DEF (dns_resolver, resolve_txt);
+
+static const struct luaL_reg    dns_resolverlib_f[] = {
+       LUA_INTERFACE_DEF (dns_resolver, init),
+       {NULL, NULL}
+};
+
+static const struct luaL_reg    dns_resolverlib_m[] = {
+       LUA_INTERFACE_DEF (dns_resolver, resolve_a),
+       LUA_INTERFACE_DEF (dns_resolver, resolve_ptr),
+       LUA_INTERFACE_DEF (dns_resolver, resolve_txt),
+       {"__tostring", lua_class_tostring},
+       {NULL, NULL}
+};
+
+struct rspamd_dns_resolver      *
+lua_check_dns_resolver (lua_State * L)
+{
+       void                                                            *ud = luaL_checkudata (L, 1, "rspamd{resolver}");
+       luaL_argcheck (L, ud != NULL, 1, "'resolver' expected");
+       return ud ? *((struct rspamd_dns_resolver **)ud) : NULL;
+}
+
+struct lua_dns_cbdata {
+       lua_State                      *L;
+       struct rspamd_dns_resolver         *resolver;
+       gint                                                    cbref;
+       const gchar                    *to_resolve;
+};
+
+static void
+lua_dns_callback (struct rspamd_dns_reply *reply, gpointer arg)
+{
+       struct lua_dns_cbdata              *cd = arg;
+       gint                            i = 0;
+       struct in_addr                  ina;
+       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));
+       lua_setclass (cd->L, "rspamd{resolver}", -1);
+
+       *presolver = cd->resolver;
+       lua_pushstring (cd->L, cd->to_resolve);
+
+       if (reply->code == DNS_RC_NOERROR) {
+               if (reply->type == DNS_REQUEST_A) {
+
+                       lua_newtable (cd->L);
+                       cur = reply->elements;
+                       while (cur) {
+                               elt = cur->data;
+                               memcpy (&ina, &elt->a.addr[0], sizeof (struct in_addr));
+                               /* Actually this copy memory, so using of inet_ntoa is valid */
+                               lua_pushstring (cd->L, inet_ntoa (ina));
+                               lua_rawseti (cd->L, -2, ++i);
+                               cur = g_list_next (cur);
+                       }
+                       lua_pushnil (cd->L);
+               }
+               else if (reply->type == DNS_REQUEST_PTR) {
+                       lua_newtable (cd->L);
+                       cur = reply->elements;
+                       while (cur) {
+                               elt = cur->data;
+                               lua_pushstring (cd->L, elt->ptr.name);
+                               lua_rawseti (cd->L, -2, ++i);
+                               cur = g_list_next (cur);
+                       }
+                       lua_pushnil (cd->L);
+
+               }
+               else if (reply->type == DNS_REQUEST_TXT) {
+                       lua_newtable (cd->L);
+                       cur = reply->elements;
+                       while (cur) {
+                               elt = cur->data;
+                               lua_pushstring (cd->L, elt->txt.data);
+                               lua_rawseti (cd->L, -2, ++i);
+                               cur = g_list_next (cur);
+                       }
+                       lua_pushnil (cd->L);
+
+               }
+               else {
+                       lua_pushnil (cd->L);
+                       lua_pushstring (cd->L, "Unknown reply type");
+               }
+       }
+       else {
+               lua_pushnil (cd->L);
+               lua_pushstring (cd->L, dns_strerror (reply->code));
+       }
+
+       if (lua_pcall (cd->L, 4, 0, 0) != 0) {
+               msg_info ("call to dns_callback failed: %s", lua_tostring (cd->L, -1));
+       }
+
+       /* Unref function */
+       luaL_unref (cd->L, LUA_REGISTRYINDEX, cd->cbref);
+
+       if (need_unlock) {
+               g_mutex_unlock (lua_mtx);
+       }
+}
+
+static int
+lua_dns_resolver_init (lua_State *L)
+{
+       struct rspamd_dns_resolver                                      *resolver, **presolver;
+       struct config_file                                                      *cfg, **pcfg;
+       struct event_base                                                       *base, **pbase;
+
+       /* Check args */
+       pbase = luaL_checkudata (L, 1, "rspamd{ev_base}");
+       luaL_argcheck (L, pbase != NULL, 1, "'ev_base' expected");
+       base = pbase ? *(pbase) : NULL;
+       pcfg = luaL_checkudata (L, 2, "rspamd{config}");
+       luaL_argcheck (L, pcfg != NULL, 2, "'config' expected");
+       cfg = pcfg ? *(pcfg) : NULL;
+
+       if (base != NULL && cfg != NULL) {
+               resolver = dns_resolver_init (base, cfg);
+               if (resolver) {
+                       presolver = lua_newuserdata (L, sizeof (gpointer));
+                       lua_setclass (L, "rspamd{resolver}", -1);
+                       *presolver = resolver;
+               }
+               else {
+                       lua_pushnil (L);
+               }
+       }
+       else {
+               lua_pushnil (L);
+       }
+
+       return 1;
+}
+
+static int
+lua_dns_resolver_resolve_common (lua_State *L, struct rspamd_dns_resolver *resolver, enum rspamd_request_type type)
+{
+       struct rspamd_async_session                                     *session, **psession;
+       memory_pool_t                                                           *pool, **ppool;
+       const gchar                                                                     *to_resolve;
+       struct in_addr                                                           ina;
+       struct lua_dns_cbdata                                           *cbdata;
+
+       /* Check arguments */
+       psession = luaL_checkudata (L, 2, "rspamd{session}");
+       luaL_argcheck (L, psession != NULL, 2, "'session' expected");
+       session = psession ? *(psession) : NULL;
+       ppool = luaL_checkudata (L, 3, "rspamd{mempool}");
+       luaL_argcheck (L, ppool != NULL, 3, "'mempool' expected");
+       pool = ppool ? *(ppool) : NULL;
+       to_resolve = luaL_checkstring (L, 4);
+
+       if (pool != NULL && session != NULL && to_resolve != NULL && lua_isfunction (L, 5)) {
+               if (type == DNS_REQUEST_PTR) {
+                       if (inet_aton (to_resolve, &ina) == 0) {
+                               msg_err ("wrong resolve string to PTR request: %s", to_resolve);
+                               lua_pushnil (L);
+                               return 1;
+                       }
+               }
+               cbdata = memory_pool_alloc (pool, sizeof (struct lua_dns_cbdata));
+               cbdata->L = L;
+               cbdata->resolver = resolver;
+               lua_pushvalue (L, 5);
+               cbdata->cbref = luaL_ref (L, LUA_REGISTRYINDEX);
+               if (type == DNS_REQUEST_PTR) {
+                       make_dns_request (resolver, session, pool, lua_dns_callback, cbdata, type, &ina);
+               }
+               else {
+                       make_dns_request (resolver, session, pool, lua_dns_callback, cbdata, type, to_resolve);
+               }
+               lua_pushboolean (L, TRUE);
+       }
+       else {
+               msg_err ("invalid arguments to lua_resolve");
+               lua_pushnil (L);
+       }
+
+       return 1;
+
+}
+
+static int
+lua_dns_resolver_resolve_a (lua_State *L)
+{
+       struct rspamd_dns_resolver                                      *dns_resolver = lua_check_dns_resolver (L);
+
+       if (dns_resolver) {
+               return lua_dns_resolver_resolve_common (L, dns_resolver, DNS_REQUEST_A);
+       }
+       else {
+               lua_pushnil (L);
+       }
+
+       return 1;
+}
+
+static int
+lua_dns_resolver_resolve_ptr (lua_State *L)
+{
+       struct rspamd_dns_resolver                                      *dns_resolver = lua_check_dns_resolver (L);
+
+       if (dns_resolver) {
+               return lua_dns_resolver_resolve_common (L, dns_resolver, DNS_REQUEST_PTR);
+       }
+       else {
+               lua_pushnil (L);
+       }
+
+       return 1;
+}
+
+static int
+lua_dns_resolver_resolve_txt (lua_State *L)
+{
+       struct rspamd_dns_resolver                                      *dns_resolver = lua_check_dns_resolver (L);
+
+       if (dns_resolver) {
+               return lua_dns_resolver_resolve_common (L, dns_resolver, DNS_REQUEST_TXT);
+       }
+       else {
+               lua_pushnil (L);
+       }
+
+       return 1;
+}
+
+gint
+luaopen_dns_resolver (lua_State * L)
+{
+       luaL_newmetatable (L, "rspamd{resolver}");
+       lua_pushstring (L, "__index");
+       lua_pushvalue (L, -2);
+       lua_settable (L, -3);
+
+       lua_pushstring (L, "class");
+       lua_pushstring (L, "rspamd{resolver}");
+       lua_rawset (L, -3);
+
+       luaL_openlib (L, NULL, dns_resolverlib_m, 0);
+       luaL_openlib(L, "rspamd_resolver", dns_resolverlib_f, 0);
+
+       lua_pop (L, 1);                      /* remove metatable from stack */
+       return 1;       
+}
index 68faee2e77789b5f081406b27e4111b754ab1f60..8f85ebee112cb754e13b098abf81228513d1713d 100644 (file)
@@ -43,10 +43,15 @@ struct lua_http_header {
 };
 
 struct lua_http_ud {
-       gint parser_state;
        struct worker_task *task;
+       gint parser_state;
+       struct rspamd_async_session *s;
+       memory_pool_t *pool;
+       struct rspamd_dns_resolver *resolver;
+       struct event_base *ev_base;
        lua_State *L;
        const gchar *callback;
+       gint cbref;
        gchar *req_buf;
        gint req_len;
        gint port;
@@ -58,19 +63,15 @@ struct lua_http_ud {
        GList *headers;
 };
 
-static struct worker_task      *
-lua_check_task (lua_State * L)
-{
-       void                           *ud = luaL_checkudata (L, 1, "rspamd{task}");
-       luaL_argcheck (L, ud != NULL, 1, "'task' expected");
-       return ud ? *((struct worker_task **)ud) : NULL;
-}
-
 static void
 lua_http_fin (void *arg)
 {
        struct lua_http_ud             *ud = arg;
 
+       if (ud->callback == NULL) {
+               /* Unref callback */
+               luaL_unref (ud->L, LUA_REGISTRYINDEX, ud->cbref);
+       }
        rspamd_remove_dispatcher (ud->io_dispatcher);
        close (ud->fd);
 }
@@ -79,21 +80,35 @@ static void
 lua_http_push_error (gint code, struct lua_http_ud *ud)
 {
        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 */
-       lua_getglobal (ud->L, ud->callback);
-       ptask = lua_newuserdata (ud->L, sizeof (struct worker_task *));
-       lua_setclass (ud->L, "rspamd{task}", -1);
+       if (ud->callback) {
+               lua_getglobal (ud->L, ud->callback);
+               ptask = lua_newuserdata (ud->L, sizeof (struct worker_task *));
+               lua_setclass (ud->L, "rspamd{task}", -1);
+               *ptask = ud->task;
+               num = 4;
+       }
+       else {
+               lua_rawgeti (ud->L, LUA_REGISTRYINDEX, ud->cbref);
+               num = 3;
+       }
 
-       *ptask = ud->task;
        /* Code */
        lua_pushnumber (ud->L, code);
        /* Headers */
        lua_pushnil (ud->L);
        /* Reply */
        lua_pushnil (ud->L);
-       if (lua_pcall (ud->L, 4, 0, 0) != 0) {
-               msg_info ("call to %s failed: %s", ud->callback, lua_tostring (ud->L, -1));
+       if (lua_pcall (ud->L, num, 0, 0) != 0) {
+               msg_info ("call to %s failed: %s", ud->callback ? ud->callback : "local function", lua_tostring (ud->L, -1));
        }
 
        if (ud->headers != NULL) {
@@ -102,7 +117,10 @@ lua_http_push_error (gint code, struct lua_http_ud *ud)
        }
 
        ud->parser_state = 3;
-       remove_normal_event (ud->task->s, lua_http_fin, ud);
+       remove_normal_event (ud->s, lua_http_fin, ud);
+       if (need_unlock) {
+               g_mutex_unlock (lua_mtx);
+       }
 }
 
 static void
@@ -111,13 +129,27 @@ lua_http_push_reply (f_str_t *in, struct lua_http_ud *ud)
        GList                          *cur;
        struct lua_http_header         *header;
        struct worker_task            **ptask;
+       gint                                                    num;
+       gboolean                                                need_unlock = FALSE;
 
-       /* Push error */
-       lua_getglobal (ud->L, ud->callback);
-       ptask = lua_newuserdata (ud->L, sizeof (struct worker_task *));
-       lua_setclass (ud->L, "rspamd{task}", -1);
+       /* 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 */
+               lua_getglobal (ud->L, ud->callback);
+               ptask = lua_newuserdata (ud->L, sizeof (struct worker_task *));
+               lua_setclass (ud->L, "rspamd{task}", -1);
 
-       *ptask = ud->task;
+               *ptask = ud->task;
+               num = 4;
+       }
+       else {
+               lua_rawgeti (ud->L, LUA_REGISTRYINDEX, ud->cbref);
+               num = 3;
+       }
        /* Code */
        lua_pushnumber (ud->L, ud->code);
        /* Headers */
@@ -134,8 +166,8 @@ lua_http_push_reply (f_str_t *in, struct lua_http_ud *ud)
        /* Reply */
        lua_pushlstring (ud->L, in->begin, in->len);
 
-       if (lua_pcall (ud->L, 4, 0, 0) != 0) {
-               msg_info ("call to %s failed: %s", ud->callback, lua_tostring (ud->L, -1));
+       if (lua_pcall (ud->L, num, 0, 0) != 0) {
+               msg_info ("call to %s failed: %s", ud->callback ? ud->callback : "local function", lua_tostring (ud->L, -1));
        }
 
        if (ud->headers != NULL) {
@@ -143,7 +175,10 @@ lua_http_push_reply (f_str_t *in, struct lua_http_ud *ud)
                ud->headers = NULL;
        }
 
-       remove_normal_event (ud->task->s, lua_http_fin, ud);
+       remove_normal_event (ud->s, lua_http_fin, ud);
+       if (need_unlock) {
+               g_mutex_unlock (lua_mtx);
+       }
 }
 
 /*
@@ -184,8 +219,8 @@ lua_http_parse_header_line (struct lua_http_ud *ud, f_str_t *in)
                return FALSE;
        }
        /* Copy name */
-       new = memory_pool_alloc (ud->task->task_pool, sizeof (struct lua_http_header));
-       new->name = memory_pool_alloc (ud->task->task_pool, p - in->begin + 1);
+       new = memory_pool_alloc (ud->pool, sizeof (struct lua_http_header));
+       new->name = memory_pool_alloc (ud->pool, p - in->begin + 1);
        rspamd_strlcpy (new->name, in->begin, p - in->begin + 1);
 
        p ++;
@@ -193,7 +228,7 @@ lua_http_parse_header_line (struct lua_http_ud *ud, f_str_t *in)
        while (p < in->begin + in->len && g_ascii_isspace (*p)) {
                p ++;
        }
-       new->value = memory_pool_alloc (ud->task->task_pool, in->begin + in->len - p + 1);
+       new->value = memory_pool_alloc (ud->pool, in->begin + in->len - p + 1);
        rspamd_strlcpy (new->value, p, in->begin + in->len - p + 1);
 
        /* Check content-length */
@@ -260,7 +295,7 @@ lua_http_err_cb (GError * err, void *arg)
                lua_http_push_error (500, ud);
        }
        else {
-               remove_normal_event (ud->task->s, lua_http_fin, ud);
+               remove_normal_event (ud->s, lua_http_fin, ud);
        }
 }
 
@@ -292,10 +327,10 @@ lua_http_dns_callback (struct rspamd_dns_reply *reply, gpointer arg)
 
        /* Create dispatcher for HTTP protocol */
        msec_to_tv (ud->timeout, &tv);
-       ud->io_dispatcher = rspamd_create_dispatcher (ud->task->ev_base, ud->fd, BUFFER_LINE, lua_http_read_cb, NULL,
+       ud->io_dispatcher = rspamd_create_dispatcher (ud->ev_base, ud->fd, BUFFER_LINE, lua_http_read_cb, NULL,
                        lua_http_err_cb, &tv, ud);
        /* Write request */
-       register_async_event (ud->task->s, lua_http_fin, ud, g_quark_from_static_string ("lua http"));
+       register_async_event (ud->s, lua_http_fin, ud, g_quark_from_static_string ("lua http"));
 
        if (!rspamd_dispatcher_write (ud->io_dispatcher, ud->req_buf, ud->req_len, TRUE, TRUE)) {
                lua_http_push_error (450, ud);
@@ -320,6 +355,9 @@ lua_http_make_request_common (lua_State *L, struct worker_task *task, const gcha
 
        ud = memory_pool_alloc0 (task->task_pool, sizeof (struct lua_http_ud));
        ud->L = L;
+       ud->s = task->s;
+       ud->pool = task->task_pool;
+       ud->ev_base = task->ev_base;
        ud->task = task;
        /* Preallocate buffer */
        ud->req_buf = memory_pool_alloc (task->task_pool, s);
@@ -376,6 +414,106 @@ lua_http_make_request_common (lua_State *L, struct worker_task *task, const gcha
        return 0;
 }
 
+/**
+ * Common request function (new version)
+ */
+static gint
+lua_http_make_request_common_new (lua_State *L, struct rspamd_async_session *session, memory_pool_t *pool, struct event_base *base, gint cbref,
+               const gchar *hostname, const gchar *path, const gchar *data, gint top)
+{
+       gint                           r, s, datalen;
+       struct lua_http_ud                        *ud;
+       struct in_addr                             ina;
+       struct timeval                 tv;
+
+       /* Calculate buffer size */
+       datalen = (data != NULL) ? strlen (data) : 0;
+       s = MAX_HEADERS_SIZE + sizeof (CRLF) * 3 + strlen (hostname) + strlen (path) + datalen
+                       + sizeof ("POST HTTP/1.1");
+
+       ud = memory_pool_alloc0 (pool, sizeof (struct lua_http_ud));
+       ud->L = L;
+       ud->pool = pool;
+       ud->s = session;
+       ud->ev_base = base;
+       /* Preallocate buffer */
+       ud->req_buf = memory_pool_alloc (pool, s);
+       ud->callback = NULL;
+       ud->cbref = cbref;
+
+       /* Print request */
+       r = rspamd_snprintf (ud->req_buf, s, "%s %s HTTP/1.1" CRLF
+                                                                                "Connection: close" CRLF,
+                                                                                (data != NULL) ? "POST" : "GET", path);
+       if (datalen > 0) {
+               r += rspamd_snprintf (ud->req_buf + r, s - r, "Content-Length: %d" CRLF, datalen);
+       }
+       /* Now assume that we have a table with headers at the top of the stack */
+
+       if (lua_gettop (L) > top && lua_istable (L, top + 1)) {
+               /* Add headers */
+               lua_pushnil (L);  /* first key */
+               while (lua_next (L, top + 1) != 0) {
+                       r += rspamd_snprintf (ud->req_buf + r, s - r, "%s: %s" CRLF, lua_tostring (L, -2), lua_tostring (L, -1));
+                       lua_pop (L, 1);
+               }
+       }
+       /* Now check port and timeout */
+       if (lua_gettop (L) > top + 1) {
+               ud->port = lua_tonumber (L, top + 2);
+       }
+       else {
+               ud->port = 80;
+       }
+       if (lua_gettop (L) > top + 2) {
+               ud->timeout = lua_tonumber (L, top + 3);
+       }
+       else {
+               /* Assume default timeout as 1000 msec */
+               ud->timeout = 1000;
+       }
+
+       if (datalen > 0) {
+               r += rspamd_snprintf (ud->req_buf + r, s - r, CRLF "%s", data);
+       }
+       else {
+               r += rspamd_snprintf (ud->req_buf + r, s - r, CRLF);
+       }
+
+       ud->req_len = r;
+
+       if (inet_aton (hostname, &ina) == 0) {
+               msg_err ("%s is not valid ip address", hostname);
+               luaL_unref (L, LUA_REGISTRYINDEX, cbref);
+               lua_pushnil (L);
+               return 1;
+       }
+
+       ud->fd = make_tcp_socket (&ina, ud->port, FALSE, TRUE);
+
+       if (ud->fd == -1) {
+               luaL_unref (L, LUA_REGISTRYINDEX, cbref);
+               lua_pushnil (L);
+               return 1;
+       }
+
+       /* Create dispatcher for HTTP protocol */
+       msec_to_tv (ud->timeout, &tv);
+       ud->io_dispatcher = rspamd_create_dispatcher (ud->ev_base, ud->fd, BUFFER_LINE, lua_http_read_cb, NULL,
+                       lua_http_err_cb, &tv, ud);
+       /* Write request */
+       register_async_event (ud->s, lua_http_fin, ud, g_quark_from_static_string ("lua http"));
+
+       if (!rspamd_dispatcher_write (ud->io_dispatcher, ud->req_buf, ud->req_len, TRUE, TRUE)) {
+               luaL_unref (L, LUA_REGISTRYINDEX, cbref);
+               lua_pushnil (L);
+               return 1;
+       }
+
+       return 0;
+}
+
+
 /*
  * Typical usage:
  * rspamd_http.post_request(task, 'callback', 'hostname', 'path', 'data'[, headers -> { name = 'value' }])
@@ -383,21 +521,55 @@ lua_http_make_request_common (lua_State *L, struct worker_task *task, const gcha
 static gint
 lua_http_make_post_request (lua_State *L)
 {
-       struct worker_task            *task = lua_check_task (L);
+       struct worker_task            *task, **ptask;
+       memory_pool_t                             *pool, **ppool;
+       struct rspamd_async_session       *session, **psession;
+       struct event_base                         *base, **pbase;
        const gchar                   *hostname, *path, *data, *callback;
+       gint                                               cbref;
+
+
+       /* Check whether we have a task object */
+       ptask = lua_check_class (L, 1, "rspamd{task}");
+       task = ptask ? *(ptask) : NULL;
+
+       if (!task) {
+               psession = luaL_checkudata (L, 1, "rspamd{session}");
+               luaL_argcheck (L, psession != NULL, 1, "'session' expected");
+               session = psession ? *(psession) : NULL;
+               ppool = luaL_checkudata (L, 2, "rspamd{mempool}");
+               luaL_argcheck (L, ppool != NULL, 2, "'mempool' expected");
+               pool = ppool ? *(ppool) : NULL;
+               pbase = luaL_checkudata (L, 3, "rspamd{ev_base}");
+               luaL_argcheck (L, ppool != NULL, 3, "'ev_base' expected");
+               base = pbase ? *(pbase) : NULL;
+       }
 
        /* Now extract hostname, path and data */
 
-       callback = memory_pool_strdup (task->task_pool, luaL_checkstring (L, 2));
-       hostname = memory_pool_strdup (task->task_pool, luaL_checkstring (L, 3));
-       path = memory_pool_strdup (task->task_pool, luaL_checkstring (L, 4));
-       data = memory_pool_strdup (task->task_pool, luaL_checkstring (L, 5));
+       if (task) {
+               callback = memory_pool_strdup (task->task_pool, luaL_checkstring (L, 2));
+               hostname = memory_pool_strdup (task->task_pool, luaL_checkstring (L, 3));
+               path = memory_pool_strdup (task->task_pool, luaL_checkstring (L, 4));
+               data = memory_pool_strdup (task->task_pool, luaL_checkstring (L, 5));
 
-       if (callback != NULL && hostname != NULL && path != NULL && data != NULL) {
-               return lua_http_make_request_common (L, task, callback, hostname, path, data, 5);
+               if (callback != NULL && hostname != NULL && path != NULL && data != NULL) {
+                       return lua_http_make_request_common (L, task, callback, hostname, path, data, 5);
+               }
+               else {
+                       msg_info ("invalid arguments number");
+               }
        }
        else {
-               msg_info ("invalid arguments number");
+               /* Common version */
+               hostname = memory_pool_strdup (pool, luaL_checkstring (L, 4));
+               path = memory_pool_strdup (pool, luaL_checkstring (L, 5));
+               data = memory_pool_strdup (pool, luaL_checkstring (L, 6));
+               if (session != NULL && pool != NULL && hostname != NULL && path != NULL && data != NULL && lua_isfunction (L, 7)) {
+                       lua_pushvalue (L, 7);
+                       cbref = luaL_ref (L, LUA_REGISTRYINDEX);
+                       return lua_http_make_request_common_new (L, session, pool, base, cbref, hostname, path, data, 7);
+               }
        }
 
        return 0;
@@ -410,20 +582,53 @@ lua_http_make_post_request (lua_State *L)
 static gint
 lua_http_make_get_request (lua_State *L)
 {
-       struct worker_task            *task = lua_check_task (L);
+       struct worker_task            *task, **ptask;
+       memory_pool_t                             *pool, **ppool;
+       struct rspamd_async_session       *session, **psession;
+       struct event_base                         *base, **pbase;
        const gchar                   *hostname, *path, *callback;
+       gint                                               cbref;
+
+
+       /* Check whether we have a task object */
+       ptask = lua_check_class (L, 1, "rspamd{task}");
+       task = ptask ? *(ptask) : NULL;
+
+       if (!task) {
+               psession = luaL_checkudata (L, 1, "rspamd{session}");
+               luaL_argcheck (L, psession != NULL, 1, "'session' expected");
+               session = psession ? *(psession) : NULL;
+               ppool = luaL_checkudata (L, 2, "rspamd{mempool}");
+               luaL_argcheck (L, ppool != NULL, 2, "'mempool' expected");
+               pool = ppool ? *(ppool) : NULL;
+               pbase = luaL_checkudata (L, 3, "rspamd{ev_base}");
+               luaL_argcheck (L, ppool != NULL, 3, "'ev_base' expected");
+               base = pbase ? *(pbase) : NULL;
+       }
 
        /* Now extract hostname, path and data */
 
-       callback = memory_pool_strdup (task->task_pool, luaL_checkstring (L, 2));
-       hostname = memory_pool_strdup (task->task_pool, luaL_checkstring (L, 3));
-       path = memory_pool_strdup (task->task_pool, luaL_checkstring (L, 4));
+       if (task) {
+               callback = memory_pool_strdup (task->task_pool, luaL_checkstring (L, 2));
+               hostname = memory_pool_strdup (task->task_pool, luaL_checkstring (L, 3));
+               path = memory_pool_strdup (task->task_pool, luaL_checkstring (L, 4));
 
-       if (callback != NULL && hostname != NULL && path != NULL) {
-               return lua_http_make_request_common (L, task, callback, hostname, path, NULL, 4);
+               if (callback != NULL && hostname != NULL && path != NULL) {
+                       return lua_http_make_request_common (L, task, callback, hostname, path, NULL, 4);
+               }
+               else {
+                       msg_info ("invalid arguments number");
+               }
        }
        else {
-               msg_info ("invalid arguments number");
+               /* Common version */
+               hostname = memory_pool_strdup (pool, luaL_checkstring (L, 4));
+               path = memory_pool_strdup (pool, luaL_checkstring (L, 5));
+               if (session != NULL && pool != NULL && hostname != NULL && path != NULL && lua_isfunction (L, 6)) {
+                       lua_pushvalue (L, 6);
+                       cbref = luaL_ref (L, LUA_REGISTRYINDEX);
+                       return lua_http_make_request_common_new (L, session, pool, base, cbref, hostname, path, NULL, 6);
+               }
        }
 
        return 0;
index 9f4af288230a6812599c5a90ee772f8d8a90c8fe..a2536343077d48ae67b3df3fe98ff53304295343 100644 (file)
@@ -38,7 +38,7 @@ static const struct luaL_reg    sessionlib_m[] = {
        LUA_INTERFACE_DEF (session, register_async_event),
        LUA_INTERFACE_DEF (session, remove_normal_event),
        LUA_INTERFACE_DEF (session, check_session_pending),
-       {"__gc", lua_session_delete},
+       LUA_INTERFACE_DEF (session, delete),
        {"__tostring", lua_class_tostring},
        {NULL, NULL}
 };
@@ -89,7 +89,7 @@ static gboolean
 lua_session_finalizer (gpointer ud)
 {
        struct lua_session_udata                                        *cbdata = ud;
-       gboolean                                                                        need_unlock = FALSE;
+       gboolean                                                                        need_unlock = FALSE, res;
 
        /* Avoid LOR here as mutex can be acquired before in lua_call */
        if (g_mutex_trylock (lua_mtx)) {
@@ -98,15 +98,17 @@ lua_session_finalizer (gpointer ud)
 
        /* Call finalizer function */
        lua_rawgeti (cbdata->L, LUA_REGISTRYINDEX, cbdata->cbref_fin);
-       if (lua_pcall (cbdata->L, 0, 0, 0) != 0) {
+       if (lua_pcall (cbdata->L, 0, 1, 0) != 0) {
                msg_info ("call to session finalizer failed: %s", lua_tostring (cbdata->L, -1));
        }
+       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 TRUE;
+       return res;
 }
 
 static void
index b7daf7ce7db66932e93318c60609daaa8750905c..51066624b47ba138ed67c0baa9502dfd44ecb84c 100644 (file)
@@ -225,9 +225,12 @@ static int
 lua_worker_get_resolver (lua_State *L)
 {
        struct rspamd_lua_worker_ctx                                    *ctx = lua_check_lua_worker (L);
+       struct rspamd_dns_resolver                                              **presolver;
 
        if (ctx) {
-               /* XXX: implement resolver API */
+               presolver = lua_newuserdata (L, sizeof (gpointer));
+               lua_setclass (L, "rspamd{resolver}", -1);
+               *presolver = ctx->resolver;
        }
        else {
                lua_pushnil (L);
@@ -460,6 +463,8 @@ start_lua_worker (struct rspamd_worker *worker)
        event_base_set (ctx->ev_base, &worker->bind_ev);
        event_add (&worker->bind_ev, NULL);
 
+       ctx->resolver = dns_resolver_init (ctx->ev_base, worker->srv->cfg);
+
        /* Open worker's lib */
        luaopen_lua_worker (L);
 
@@ -489,7 +494,6 @@ start_lua_worker (struct rspamd_worker *worker)
 
        /* Maps events */
        start_map_watch (ctx->ev_base);
-       ctx->resolver = dns_resolver_init (ctx->ev_base, worker->srv->cfg);
 
        event_base_loop (ctx->ev_base, 0);
        luaL_unref (L, LUA_REGISTRYINDEX, ctx->cbref_accept);