commit 996b828: [Project] Allow to set custom Lua handlers for main commands

Vsevolod Stakhov vsevolod at highsecure.ru
Sat Sep 14 16:07:11 UTC 2019


Author: Vsevolod Stakhov
Date: 2019-09-14 13:45:43 +0100
URL: https://github.com/rspamd/rspamd/commit/996b82869dfff08cd00a5c025f476e819187cc42 (HEAD -> master)

[Project] Allow to set custom Lua handlers for main commands

---
 src/lua/lua_worker.c | 142 +++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 142 insertions(+)

diff --git a/src/lua/lua_worker.c b/src/lua/lua_worker.c
index c3c9e729e..1768b1c2a 100644
--- a/src/lua/lua_worker.c
+++ b/src/lua/lua_worker.c
@@ -25,6 +25,7 @@
 #endif
 
 #include <sys/wait.h>
+#include <src/libserver/rspamd_control.h>
 
 /***
  * @module rspamd_worker
@@ -42,6 +43,7 @@ LUA_FUNCTION_DEF (worker, is_scanner);
 LUA_FUNCTION_DEF (worker, is_primary_controller);
 LUA_FUNCTION_DEF (worker, spawn_process);
 LUA_FUNCTION_DEF (worker, get_mem_stats);
+LUA_FUNCTION_DEF (worker, add_control_handler);
 
 const luaL_reg worker_reg[] = {
 		LUA_INTERFACE_DEF (worker, get_name),
@@ -53,6 +55,7 @@ const luaL_reg worker_reg[] = {
 		LUA_INTERFACE_DEF (worker, is_scanner),
 		LUA_INTERFACE_DEF (worker, is_primary_controller),
 		LUA_INTERFACE_DEF (worker, get_mem_stats),
+		LUA_INTERFACE_DEF (worker, add_control_handler),
 		{"__tostring", rspamd_lua_class_tostring},
 		{NULL, NULL}
 };
@@ -240,6 +243,145 @@ lua_worker_is_primary_controller (lua_State *L)
 	return 1;
 }
 
+struct rspamd_control_cbdata {
+	lua_State *L;
+	rspamd_mempool_t *pool;
+	struct rspamd_worker *w;
+	struct rspamd_config *cfg;
+	struct ev_loop *event_loop;
+	struct rspamd_async_session *session;
+	enum rspamd_control_type cmd;
+	gint cbref;
+	gint fd;
+};
+
+static gboolean
+lua_worker_control_fin_session (void *ud)
+{
+	struct rspamd_control_reply rep;
+	struct rspamd_control_cbdata *cbd = (struct rspamd_control_cbdata *)ud;
+	rspamd_mempool_t *pool;
+	lua_State *L;
+
+	L = cbd->L;
+	pool = cbd->pool;
+
+	memset (&rep, 0, sizeof (rep));
+	rep.type = cbd->cmd;
+
+	if (write (cbd->fd, &rep, sizeof (rep)) != sizeof (rep)) {
+		msg_err_pool ("cannot write reply to the control socket: %s",
+				strerror (errno));
+	}
+
+	return TRUE;
+}
+
+static void
+lua_worker_control_session_dtor (void *ud)
+{
+	struct rspamd_control_cbdata *cbd = (struct rspamd_control_cbdata *)ud;
+
+	rspamd_mempool_delete (cbd->pool);
+}
+
+static gboolean
+lua_worker_control_handler (struct rspamd_main *rspamd_main,
+							struct rspamd_worker *worker,
+							gint fd,
+							gint attached_fd,
+							struct rspamd_control_command *cmd,
+							gpointer ud)
+{
+	struct rspamd_async_session *session, **psession;
+	struct rspamd_control_cbdata *cbd = (struct rspamd_control_cbdata *)ud;
+	rspamd_mempool_t *pool;
+	lua_State *L;
+	gint err_idx;
+
+	L = cbd->L;
+	pool = cbd->pool;
+	session = rspamd_session_create (cbd->pool,
+			lua_worker_control_fin_session,
+			NULL,
+			lua_worker_control_session_dtor,
+			cbd);
+	cbd->session = session;
+	cbd->fd = fd;
+
+	lua_pushcfunction (L, &rspamd_lua_traceback);
+	err_idx = lua_gettop (L);
+	lua_rawgeti (L, LUA_REGISTRYINDEX, cbd->cbref);
+	psession = lua_newuserdata (L, sizeof (*psession));
+	rspamd_lua_setclass (L, "rspamd{session}", -1);
+	*psession = session;
+
+	if (lua_pcall (L, 1, 0, err_idx) != 0) {
+		msg_err_pool ("cannot init lua parser script: %s", lua_tostring (L, -1));
+		lua_settop (L, err_idx - 1);
+
+		struct rspamd_control_reply rep;
+
+		memset (&rep, 0, sizeof (rep));
+		rep.type = cbd->cmd;
+		rep.reply.monitored_change.status = -1;
+
+		if (write (fd, &rep, sizeof (rep)) != sizeof (rep)) {
+			msg_err_pool ("cannot write reply to the control socket: %s",
+					strerror (errno));
+		}
+
+		rspamd_session_destroy (session);
+	}
+	else {
+		lua_settop (L, err_idx - 1);
+		rspamd_session_pending (session);
+	}
+
+	return TRUE;
+}
+
+static gint
+lua_worker_add_control_handler (lua_State *L)
+{
+	struct rspamd_worker *w = lua_check_worker (L, 1);
+	struct rspamd_config *cfg = lua_check_config (L, 2);
+	struct ev_loop *event_loop = lua_check_ev_base (L, 3);
+	const gchar *cmd_name = luaL_checkstring (L, 4);
+	enum rspamd_control_type cmd;
+	struct rspamd_control_cbdata *cbd;
+
+	if (w && cfg && event_loop && cmd_name && lua_isfunction (L, 5)) {
+		cmd = rspamd_control_command_from_string (cmd_name);
+
+		if (cmd == RSPAMD_CONTROL_MAX) {
+			return luaL_error (L, "invalid command type: %s", cmd_name);
+		}
+
+		rspamd_mempool_t *pool = rspamd_mempool_new (
+				rspamd_mempool_suggest_size (), "lua_control");
+		cbd = rspamd_mempool_alloc0 (pool, sizeof (*cbd));
+		cbd->pool = pool;
+		cbd->event_loop = event_loop;
+		cbd->w = w;
+		cbd->cfg = cfg;
+		cbd->cmd = cmd;
+		cbd->L = L;
+		/* Refcount callback */
+		lua_pushvalue (L, 5);
+		cbd->cbref = luaL_ref (L, LUA_REGISTRYINDEX);
+
+		rspamd_control_worker_add_cmd_handler (w, cmd, lua_worker_control_handler,
+				cbd);
+	}
+	else {
+		return luaL_error (L, "invalid arguments, need worker, cfg, "
+						"ev_loop, cmd_name and callback function");
+	}
+
+	return 0;
+}
+
 #ifdef WITH_JEMALLOC
 static void
 lua_worker_jemalloc_stats_cb (void *ud, const char *msg)


More information about the Commits mailing list