You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

lua_worker.c 9.2KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421
  1. /*-
  2. * Copyright 2016 Vsevolod Stakhov
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. #include "config.h"
  17. #include "util.h"
  18. #include "rspamd.h"
  19. #include "libserver/worker_util.h"
  20. #include "protocol.h"
  21. #include "upstream.h"
  22. #include "cfg_file.h"
  23. #include "url.h"
  24. #include "message.h"
  25. #include "map.h"
  26. #include "dns.h"
  27. #include "unix-std.h"
  28. #include "lua/lua_common.h"
  29. #ifdef WITH_GPERF_TOOLS
  30. # include <glib/gprintf.h>
  31. #endif
  32. /* 60 seconds for worker's IO */
  33. #define DEFAULT_WORKER_IO_TIMEOUT 60000
  34. gpointer init_lua_worker (struct rspamd_config *cfg);
  35. void start_lua_worker (struct rspamd_worker *worker);
  36. worker_t lua_worker = {
  37. "lua", /* Name */
  38. init_lua_worker, /* Init function */
  39. start_lua_worker, /* Start function */
  40. TRUE, /* Has socket */
  41. FALSE, /* Non unique */
  42. FALSE, /* Non threaded */
  43. TRUE, /* Killable */
  44. SOCK_STREAM, /* TCP socket */
  45. RSPAMD_WORKER_VER /* Version info */
  46. };
  47. /*
  48. * Worker's context
  49. */
  50. struct rspamd_lua_worker_ctx {
  51. /* DNS resolver */
  52. struct rspamd_dns_resolver *resolver;
  53. /* Events base */
  54. struct event_base *ev_base;
  55. /* Other params */
  56. GHashTable *params;
  57. /* Lua script to load */
  58. gchar *file;
  59. /* Lua state */
  60. lua_State *L;
  61. /* Callback for accept */
  62. gint cbref_accept;
  63. /* Callback for finishing */
  64. gint cbref_fin;
  65. /* Config file */
  66. struct rspamd_config *cfg;
  67. /* The rest options */
  68. ucl_object_t *opts;
  69. };
  70. /* Lua bindings */
  71. LUA_FUNCTION_DEF (worker, get_ev_base);
  72. LUA_FUNCTION_DEF (worker, register_accept_callback);
  73. LUA_FUNCTION_DEF (worker, register_exit_callback);
  74. LUA_FUNCTION_DEF (worker, get_option);
  75. LUA_FUNCTION_DEF (worker, get_resolver);
  76. LUA_FUNCTION_DEF (worker, get_cfg);
  77. static const struct luaL_reg lua_workerlib_m[] = {
  78. LUA_INTERFACE_DEF (worker, get_ev_base),
  79. LUA_INTERFACE_DEF (worker, register_accept_callback),
  80. LUA_INTERFACE_DEF (worker, register_exit_callback),
  81. LUA_INTERFACE_DEF (worker, get_option),
  82. LUA_INTERFACE_DEF (worker, get_resolver),
  83. LUA_INTERFACE_DEF (worker, get_cfg),
  84. {"__tostring", rspamd_lua_class_tostring},
  85. {NULL, NULL}
  86. };
  87. /* Basic functions of LUA API for worker object */
  88. static gint
  89. luaopen_lua_worker (lua_State * L)
  90. {
  91. rspamd_lua_new_class (L, "rspamd{worker}", lua_workerlib_m);
  92. luaL_register (L, "rspamd_worker", null_reg);
  93. lua_pop (L, 1); /* remove metatable from stack */
  94. return 1;
  95. }
  96. struct rspamd_lua_worker_ctx *
  97. lua_check_lua_worker (lua_State * L)
  98. {
  99. void *ud = luaL_checkudata (L, 1, "rspamd{worker}");
  100. luaL_argcheck (L, ud != NULL, 1, "'worker' expected");
  101. return ud ? *((struct rspamd_lua_worker_ctx **)ud) : NULL;
  102. }
  103. static int
  104. lua_worker_get_ev_base (lua_State *L)
  105. {
  106. struct rspamd_lua_worker_ctx *ctx = lua_check_lua_worker (L);
  107. struct event_base **pbase;
  108. if (ctx) {
  109. pbase = lua_newuserdata (L, sizeof (struct event_base *));
  110. rspamd_lua_setclass (L, "rspamd{ev_base}", -1);
  111. *pbase = ctx->ev_base;
  112. }
  113. else {
  114. lua_pushnil (L);
  115. }
  116. return 1;
  117. }
  118. static int
  119. lua_worker_register_accept_callback (lua_State *L)
  120. {
  121. struct rspamd_lua_worker_ctx *ctx = lua_check_lua_worker (L);
  122. if (ctx) {
  123. if (!lua_isfunction (L, 2)) {
  124. msg_err ("invalid callback passed");
  125. lua_pushnil (L);
  126. }
  127. else {
  128. lua_pushvalue (L, 2);
  129. ctx->cbref_accept = luaL_ref (L, LUA_REGISTRYINDEX);
  130. return 0;
  131. }
  132. }
  133. else {
  134. lua_pushnil (L);
  135. }
  136. return 1;
  137. }
  138. static int
  139. lua_worker_register_exit_callback (lua_State *L)
  140. {
  141. struct rspamd_lua_worker_ctx *ctx = lua_check_lua_worker (L);
  142. if (ctx) {
  143. if (!lua_isfunction (L, 2)) {
  144. msg_err ("invalid callback passed");
  145. lua_pushnil (L);
  146. }
  147. else {
  148. lua_pushvalue (L, 2);
  149. ctx->cbref_fin = luaL_ref (L, LUA_REGISTRYINDEX);
  150. return 0;
  151. }
  152. }
  153. else {
  154. lua_pushnil (L);
  155. }
  156. return 1;
  157. }
  158. /* XXX: This fucntions should be rewritten completely */
  159. static int
  160. lua_worker_get_option (lua_State *L)
  161. {
  162. struct rspamd_lua_worker_ctx *ctx = lua_check_lua_worker (L);
  163. const ucl_object_t *val;
  164. const gchar *name;
  165. if (ctx) {
  166. name = luaL_checkstring (L, 2);
  167. if (name == NULL) {
  168. msg_err ("no name specified");
  169. lua_pushnil (L);
  170. }
  171. else {
  172. val = ucl_object_find_key (ctx->opts, name);
  173. if (val == NULL) {
  174. lua_pushnil (L);
  175. }
  176. else {
  177. ucl_object_push_lua (L, val, TRUE);
  178. }
  179. }
  180. }
  181. else {
  182. lua_pushnil (L);
  183. }
  184. return 1;
  185. }
  186. static int
  187. lua_worker_get_resolver (lua_State *L)
  188. {
  189. struct rspamd_lua_worker_ctx *ctx = lua_check_lua_worker (L);
  190. struct rspamd_dns_resolver **presolver;
  191. if (ctx) {
  192. presolver = lua_newuserdata (L, sizeof (gpointer));
  193. rspamd_lua_setclass (L, "rspamd{resolver}", -1);
  194. *presolver = ctx->resolver;
  195. }
  196. else {
  197. lua_pushnil (L);
  198. }
  199. return 1;
  200. }
  201. static int
  202. lua_worker_get_cfg (lua_State *L)
  203. {
  204. struct rspamd_lua_worker_ctx *ctx = lua_check_lua_worker (L);
  205. struct rspamd_config **pcfg;
  206. if (ctx) {
  207. pcfg = lua_newuserdata (L, sizeof (gpointer));
  208. rspamd_lua_setclass (L, "rspamd{config}", -1);
  209. *pcfg = ctx->cfg;
  210. }
  211. else {
  212. lua_pushnil (L);
  213. }
  214. return 1;
  215. }
  216. /* End of lua API */
  217. /*
  218. * Accept new connection and construct task
  219. */
  220. static void
  221. lua_accept_socket (gint fd, short what, void *arg)
  222. {
  223. struct rspamd_worker *worker = (struct rspamd_worker *) arg;
  224. struct rspamd_lua_worker_ctx *ctx, **pctx;
  225. gint nfd;
  226. lua_State *L;
  227. rspamd_inet_addr_t *addr;
  228. ctx = worker->ctx;
  229. L = ctx->L;
  230. if ((nfd =
  231. rspamd_accept_from_socket (fd, &addr)) == -1) {
  232. msg_warn ("accept failed: %s", strerror (errno));
  233. return;
  234. }
  235. /* Check for EAGAIN */
  236. if (nfd == 0) {
  237. return;
  238. }
  239. msg_info ("accepted connection from %s port %d",
  240. rspamd_inet_address_to_string (addr),
  241. rspamd_inet_address_get_port (addr));
  242. /* Call finalizer function */
  243. lua_rawgeti (L, LUA_REGISTRYINDEX, ctx->cbref_accept);
  244. pctx = lua_newuserdata (L, sizeof (gpointer));
  245. rspamd_lua_setclass (L, "rspamd{worker}", -1);
  246. *pctx = ctx;
  247. lua_pushinteger (L, nfd);
  248. rspamd_lua_ip_push (L, addr);
  249. lua_pushinteger (L, 0);
  250. if (lua_pcall (L, 4, 0, 0) != 0) {
  251. msg_info ("call to worker accept failed: %s", lua_tostring (L, -1));
  252. lua_pop (L, 1);
  253. }
  254. rspamd_inet_address_destroy (addr);
  255. close (nfd);
  256. }
  257. static gboolean
  258. rspamd_lua_worker_parser (ucl_object_t *obj, gpointer ud)
  259. {
  260. struct rspamd_lua_worker_ctx *ctx = ud;
  261. ctx->opts = obj;
  262. return TRUE;
  263. }
  264. gpointer
  265. init_lua_worker (struct rspamd_config *cfg)
  266. {
  267. struct rspamd_lua_worker_ctx *ctx;
  268. GQuark type;
  269. type = g_quark_try_string ("lua");
  270. ctx = g_malloc0 (sizeof (struct rspamd_lua_worker_ctx));
  271. ctx->params = g_hash_table_new_full (rspamd_str_hash,
  272. rspamd_str_equal,
  273. g_free,
  274. (GDestroyNotify)g_list_free);
  275. rspamd_rcl_register_worker_option (cfg,
  276. type,
  277. "file",
  278. rspamd_rcl_parse_struct_string,
  279. ctx,
  280. G_STRUCT_OFFSET (struct rspamd_lua_worker_ctx, file),
  281. 0,
  282. "Run the following lua script when accepting a connection");
  283. rspamd_rcl_register_worker_parser (cfg, type, rspamd_lua_worker_parser,
  284. ctx);
  285. return ctx;
  286. }
  287. /*
  288. * Start worker process
  289. */
  290. void
  291. start_lua_worker (struct rspamd_worker *worker)
  292. {
  293. struct rspamd_lua_worker_ctx *ctx = worker->ctx, **pctx;
  294. lua_State *L;
  295. #ifdef WITH_PROFILER
  296. extern void _start (void), etext (void);
  297. monstartup ((u_long) & _start, (u_long) & etext);
  298. #endif
  299. ctx->ev_base = rspamd_prepare_worker (worker,
  300. "lua_worker",
  301. lua_accept_socket);
  302. L = worker->srv->cfg->lua_state;
  303. ctx->L = L;
  304. ctx->cfg = worker->srv->cfg;
  305. ctx->resolver = dns_resolver_init (worker->srv->logger,
  306. ctx->ev_base,
  307. worker->srv->cfg);
  308. /* Open worker's lib */
  309. luaopen_lua_worker (L);
  310. if (ctx->file == NULL) {
  311. msg_err ("No lua script defined, so no reason to exist");
  312. exit (EXIT_SUCCESS);
  313. }
  314. if (access (ctx->file, R_OK) == -1) {
  315. msg_err ("Error reading lua script %s: %s", ctx->file,
  316. strerror (errno));
  317. exit (EXIT_SUCCESS);
  318. }
  319. pctx = lua_newuserdata (L, sizeof (gpointer));
  320. rspamd_lua_setclass (L, "rspamd{worker}", -1);
  321. lua_setglobal (L, "rspamd_worker");
  322. *pctx = ctx;
  323. if (luaL_dofile (L, ctx->file) != 0) {
  324. msg_err ("Error executing lua script %s: %s", ctx->file,
  325. lua_tostring (L, -1));
  326. exit (EXIT_SUCCESS);
  327. }
  328. if (ctx->cbref_accept == 0) {
  329. msg_err ("No accept function defined, so no reason to exist");
  330. exit (EXIT_SUCCESS);
  331. }
  332. /* Maps events */
  333. rspamd_map_watch (worker->srv->cfg, ctx->ev_base);
  334. event_base_loop (ctx->ev_base, 0);
  335. rspamd_worker_block_signals ();
  336. luaL_unref (L, LUA_REGISTRYINDEX, ctx->cbref_accept);
  337. if (ctx->cbref_fin != 0) {
  338. /* Call finalizer function */
  339. lua_rawgeti (L, LUA_REGISTRYINDEX, ctx->cbref_fin);
  340. pctx = lua_newuserdata (L, sizeof (gpointer));
  341. rspamd_lua_setclass (L, "rspamd{worker}", -1);
  342. *pctx = ctx;
  343. if (lua_pcall (L, 1, 0, 0) != 0) {
  344. msg_info ("call to worker finalizer failed: %s", lua_tostring (L,
  345. -1));
  346. lua_pop (L, 1);
  347. }
  348. /* Free resources */
  349. luaL_unref (L, LUA_REGISTRYINDEX, ctx->cbref_fin);
  350. }
  351. rspamd_log_close (worker->srv->logger);
  352. exit (EXIT_SUCCESS);
  353. }
  354. /*
  355. * vi:ts=4
  356. */