Você não pode selecionar mais de 25 tópicos Os tópicos devem começar com uma letra ou um número, podem incluir traços ('-') e podem ter até 35 caracteres.

lua_worker.c 13KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522
  1. /* Copyright (c) 2010-2012, Vsevolod Stakhov
  2. * All rights reserved.
  3. *
  4. * Redistribution and use in source and binary forms, with or without
  5. * modification, are permitted provided that the following conditions are met:
  6. * * Redistributions of source code must retain the above copyright
  7. * notice, this list of conditions and the following disclaimer.
  8. * * Redistributions in binary form must reproduce the above copyright
  9. * notice, this list of conditions and the following disclaimer in the
  10. * documentation and/or other materials provided with the distribution.
  11. *
  12. * THIS SOFTWARE IS PROVIDED ''AS IS'' AND ANY
  13. * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  14. * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  15. * DISCLAIMED. IN NO EVENT SHALL AUTHOR BE LIABLE FOR ANY
  16. * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  17. * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  18. * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  19. * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  20. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  21. * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  22. */
  23. #include "config.h"
  24. #include "util.h"
  25. #include "main.h"
  26. #include "protocol.h"
  27. #include "upstream.h"
  28. #include "cfg_file.h"
  29. #include "cfg_xml.h"
  30. #include "url.h"
  31. #include "message.h"
  32. #include "map.h"
  33. #include "dns.h"
  34. #include "lua/lua_common.h"
  35. #ifdef WITH_GPERF_TOOLS
  36. # include <glib/gprintf.h>
  37. #endif
  38. /* 60 seconds for worker's IO */
  39. #define DEFAULT_WORKER_IO_TIMEOUT 60000
  40. gpointer init_lua_worker (void);
  41. void start_lua_worker (struct rspamd_worker *worker);
  42. worker_t lua_worker = {
  43. "lua", /* Name */
  44. init_lua_worker, /* Init function */
  45. start_lua_worker, /* Start function */
  46. TRUE, /* Has socket */
  47. FALSE, /* Non unique */
  48. FALSE, /* Non threaded */
  49. TRUE, /* Killable */
  50. SOCK_STREAM /* TCP socket */
  51. };
  52. /*
  53. * Worker's context
  54. */
  55. struct rspamd_lua_worker_ctx {
  56. /* DNS resolver */
  57. struct rspamd_dns_resolver *resolver;
  58. /* Events base */
  59. struct event_base *ev_base;
  60. /* Other params */
  61. GHashTable *params;
  62. /* Lua script to load */
  63. gchar *file;
  64. /* Lua state */
  65. lua_State *L;
  66. /* Callback for accept */
  67. gint cbref_accept;
  68. /* Callback for finishing */
  69. gint cbref_fin;
  70. /* Config file */
  71. struct config_file *cfg;
  72. };
  73. /* Lua bindings */
  74. LUA_FUNCTION_DEF (worker, get_ev_base);
  75. LUA_FUNCTION_DEF (worker, register_accept_callback);
  76. LUA_FUNCTION_DEF (worker, register_exit_callback);
  77. LUA_FUNCTION_DEF (worker, get_option);
  78. LUA_FUNCTION_DEF (worker, get_resolver);
  79. LUA_FUNCTION_DEF (worker, get_cfg);
  80. static const struct luaL_reg lua_workerlib_m[] = {
  81. LUA_INTERFACE_DEF (worker, get_ev_base),
  82. LUA_INTERFACE_DEF (worker, register_accept_callback),
  83. LUA_INTERFACE_DEF (worker, register_exit_callback),
  84. LUA_INTERFACE_DEF (worker, get_option),
  85. LUA_INTERFACE_DEF (worker, get_resolver),
  86. LUA_INTERFACE_DEF (worker, get_cfg),
  87. {"__tostring", lua_class_tostring},
  88. {NULL, NULL}
  89. };
  90. static sig_atomic_t wanna_die = 0;
  91. /* Basic functions of LUA API for worker object */
  92. static gint
  93. luaopen_lua_worker (lua_State * L)
  94. {
  95. lua_newclass (L, "rspamd{worker}", lua_workerlib_m);
  96. luaL_register (L, "rspamd_worker", null_reg);
  97. lua_pop (L, 1); /* remove metatable from stack */
  98. return 1;
  99. }
  100. struct rspamd_lua_worker_ctx *
  101. lua_check_lua_worker (lua_State * L)
  102. {
  103. void *ud = luaL_checkudata (L, 1, "rspamd{worker}");
  104. luaL_argcheck (L, ud != NULL, 1, "'worker' expected");
  105. return ud ? *((struct rspamd_lua_worker_ctx **)ud) : NULL;
  106. }
  107. static int
  108. lua_worker_get_ev_base (lua_State *L)
  109. {
  110. struct rspamd_lua_worker_ctx *ctx = lua_check_lua_worker (L);
  111. struct event_base **pbase;
  112. if (ctx) {
  113. pbase = lua_newuserdata (L, sizeof (struct event_base *));
  114. lua_setclass (L, "rspamd{ev_base}", -1);
  115. *pbase = ctx->ev_base;
  116. }
  117. else {
  118. lua_pushnil (L);
  119. }
  120. return 1;
  121. }
  122. static int
  123. lua_worker_register_accept_callback (lua_State *L)
  124. {
  125. struct rspamd_lua_worker_ctx *ctx = lua_check_lua_worker (L);
  126. if (ctx) {
  127. if (!lua_isfunction (L, 2)) {
  128. msg_err ("invalid callback passed");
  129. lua_pushnil (L);
  130. }
  131. else {
  132. lua_pushvalue (L, 2);
  133. ctx->cbref_accept = luaL_ref (L, LUA_REGISTRYINDEX);
  134. return 0;
  135. }
  136. }
  137. else {
  138. lua_pushnil (L);
  139. }
  140. return 1;
  141. }
  142. static int
  143. lua_worker_register_exit_callback (lua_State *L)
  144. {
  145. struct rspamd_lua_worker_ctx *ctx = lua_check_lua_worker (L);
  146. if (ctx) {
  147. if (!lua_isfunction (L, 2)) {
  148. msg_err ("invalid callback passed");
  149. lua_pushnil (L);
  150. }
  151. else {
  152. lua_pushvalue (L, 2);
  153. ctx->cbref_fin = luaL_ref (L, LUA_REGISTRYINDEX);
  154. return 0;
  155. }
  156. }
  157. else {
  158. lua_pushnil (L);
  159. }
  160. return 1;
  161. }
  162. static int
  163. lua_worker_get_option (lua_State *L)
  164. {
  165. struct rspamd_lua_worker_ctx *ctx = lua_check_lua_worker (L);
  166. GList *val;
  167. gint i;
  168. const gchar *name;
  169. if (ctx) {
  170. name = luaL_checkstring (L, 2);
  171. if (name == NULL) {
  172. msg_err ("no name specified");
  173. lua_pushnil (L);
  174. }
  175. else {
  176. val = g_hash_table_lookup (ctx->params, name);
  177. if (val == NULL) {
  178. lua_pushnil (L);
  179. }
  180. else {
  181. /* Push the array */
  182. i = 1;
  183. lua_newtable (L);
  184. while (val) {
  185. lua_pushstring (L, val->data);
  186. lua_rawseti (L, -2, i++);
  187. val = g_list_next (val);
  188. }
  189. }
  190. }
  191. }
  192. else {
  193. lua_pushnil (L);
  194. }
  195. return 1;
  196. }
  197. static int
  198. lua_worker_get_resolver (lua_State *L)
  199. {
  200. struct rspamd_lua_worker_ctx *ctx = lua_check_lua_worker (L);
  201. struct rspamd_dns_resolver **presolver;
  202. if (ctx) {
  203. presolver = lua_newuserdata (L, sizeof (gpointer));
  204. lua_setclass (L, "rspamd{resolver}", -1);
  205. *presolver = ctx->resolver;
  206. }
  207. else {
  208. lua_pushnil (L);
  209. }
  210. return 1;
  211. }
  212. static int
  213. lua_worker_get_cfg (lua_State *L)
  214. {
  215. struct rspamd_lua_worker_ctx *ctx = lua_check_lua_worker (L);
  216. struct config_file **pcfg;
  217. if (ctx) {
  218. pcfg = lua_newuserdata (L, sizeof (gpointer));
  219. lua_setclass (L, "rspamd{config}", -1);
  220. *pcfg = ctx->cfg;
  221. }
  222. else {
  223. lua_pushnil (L);
  224. }
  225. return 1;
  226. }
  227. /* End of lua API */
  228. /* Signal handlers */
  229. #ifndef HAVE_SA_SIGINFO
  230. static void
  231. sig_handler (gint signo)
  232. #else
  233. static void
  234. sig_handler (gint signo, siginfo_t * info, void *unused)
  235. #endif
  236. {
  237. struct timeval tv;
  238. switch (signo) {
  239. case SIGINT:
  240. case SIGTERM:
  241. if (!wanna_die) {
  242. wanna_die = 1;
  243. tv.tv_sec = 0;
  244. tv.tv_usec = 0;
  245. event_loopexit (&tv);
  246. #ifdef WITH_GPERF_TOOLS
  247. ProfilerStop ();
  248. #endif
  249. }
  250. break;
  251. }
  252. }
  253. /*
  254. * Config reload is designed by sending sigusr2 to active workers and pending shutdown of them
  255. */
  256. static void
  257. sigusr2_handler (gint fd, short what, void *arg)
  258. {
  259. struct rspamd_worker *worker = (struct rspamd_worker *) arg;
  260. /* Do not accept new connections, preparing to end worker's process */
  261. struct timeval tv;
  262. if (!wanna_die) {
  263. tv.tv_sec = SOFT_SHUTDOWN_TIME;
  264. tv.tv_usec = 0;
  265. event_del (&worker->sig_ev_usr1);
  266. event_del (&worker->sig_ev_usr2);
  267. worker_stop_accept (worker);
  268. msg_info ("worker's shutdown is pending in %d sec", SOFT_SHUTDOWN_TIME);
  269. event_loopexit (&tv);
  270. }
  271. return;
  272. }
  273. /*
  274. * Reopen log is designed by sending sigusr1 to active workers and pending shutdown of them
  275. */
  276. static void
  277. sigusr1_handler (gint fd, short what, void *arg)
  278. {
  279. struct rspamd_worker *worker = (struct rspamd_worker *) arg;
  280. reopen_log (worker->srv->logger);
  281. return;
  282. }
  283. static gboolean
  284. handle_lua_param (struct config_file *cfg, struct rspamd_xml_userdata *unused, GHashTable *attrs, gchar *data, gpointer user_data, gpointer dest_struct, gint offset)
  285. {
  286. struct rspamd_lua_worker_ctx *ctx = dest_struct;
  287. GList *val;
  288. gchar *tag = user_data;
  289. val = g_hash_table_lookup (ctx->params, tag);
  290. if (val == NULL) {
  291. g_hash_table_insert (ctx->params, g_strdup (tag), g_list_prepend (NULL, data));
  292. }
  293. else {
  294. val = g_list_append (val, data);
  295. }
  296. return TRUE;
  297. }
  298. /*
  299. * Accept new connection and construct task
  300. */
  301. static void
  302. lua_accept_socket (gint fd, short what, void *arg)
  303. {
  304. struct rspamd_worker *worker = (struct rspamd_worker *) arg;
  305. struct rspamd_lua_worker_ctx *ctx, **pctx;
  306. union sa_union su;
  307. socklen_t addrlen = sizeof (su.ss);
  308. gint nfd;
  309. struct in_addr addr;
  310. gchar *addr_str = NULL;
  311. lua_State *L;
  312. ctx = worker->ctx;
  313. L = ctx->L;
  314. if ((nfd =
  315. accept_from_socket (fd, (struct sockaddr *) &su.ss, &addrlen)) == -1) {
  316. msg_warn ("accept failed: %s", strerror (errno));
  317. return;
  318. }
  319. /* Check for EAGAIN */
  320. if (nfd == 0){
  321. return;
  322. }
  323. if (su.ss.ss_family == AF_UNIX) {
  324. msg_info ("accepted connection from unix socket");
  325. addr.s_addr = INADDR_NONE;
  326. addr_str = "127.0.0.1";
  327. }
  328. else if (su.ss.ss_family == AF_INET) {
  329. msg_info ("accepted connection from %s port %d",
  330. inet_ntoa (su.s4.sin_addr), ntohs (su.s4.sin_port));
  331. memcpy (&addr, &su.s4.sin_addr,
  332. sizeof (struct in_addr));
  333. addr_str = g_strdup (inet_ntoa (su.s4.sin_addr));
  334. }
  335. else if (su.ss.ss_family == AF_INET6) {
  336. addr_str = g_malloc0 (INET6_ADDRSTRLEN + 1);
  337. /* XXX: support ipv6 addresses here */
  338. addr.s_addr = INADDR_NONE;
  339. inet_ntop (AF_INET6, &su.s6.sin6_addr, addr_str, INET6_ADDRSTRLEN);
  340. msg_info ("accepted connection from [%s] port %d",
  341. addr_str, ntohs (su.s6.sin6_port));
  342. }
  343. else {
  344. addr.s_addr = INADDR_NONE;
  345. msg_err ("accepted connection from unsupported address family: %d", su.ss.ss_family);
  346. close (nfd);
  347. return;
  348. }
  349. /* Call finalizer function */
  350. lua_rawgeti (L, LUA_REGISTRYINDEX, ctx->cbref_accept);
  351. pctx = lua_newuserdata (L, sizeof (gpointer));
  352. lua_setclass (L, "rspamd{worker}", -1);
  353. *pctx = ctx;
  354. lua_pushinteger (L, nfd);
  355. lua_pushstring (L, addr_str);
  356. lua_pushinteger (L, addr.s_addr);
  357. if (lua_pcall (L, 4, 0, 0) != 0) {
  358. msg_info ("call to worker accept failed: %s", lua_tostring (L, -1));
  359. }
  360. if (addr_str) {
  361. g_free (addr_str);
  362. }
  363. }
  364. gpointer
  365. init_lua_worker (void)
  366. {
  367. struct rspamd_lua_worker_ctx *ctx;
  368. GQuark type;
  369. type = g_quark_try_string ("lua");
  370. ctx = g_malloc0 (sizeof (struct rspamd_lua_worker_ctx));
  371. ctx->params = g_hash_table_new_full (rspamd_str_hash, rspamd_str_equal, g_free, (GDestroyNotify)g_list_free);
  372. register_worker_opt (type, "file", xml_handle_string, ctx, G_STRUCT_OFFSET (struct rspamd_lua_worker_ctx, file));
  373. register_worker_opt (type, "*", handle_lua_param, ctx, 0);
  374. return ctx;
  375. }
  376. /*
  377. * Start worker process
  378. */
  379. void
  380. start_lua_worker (struct rspamd_worker *worker)
  381. {
  382. struct rspamd_lua_worker_ctx *ctx = worker->ctx, **pctx;
  383. lua_State *L;
  384. #ifdef WITH_PROFILER
  385. extern void _start (void), etext (void);
  386. monstartup ((u_long) & _start, (u_long) & etext);
  387. #endif
  388. ctx->ev_base = prepare_worker (worker, "lua_worker", sig_handler, lua_accept_socket);
  389. L = worker->srv->cfg->lua_state;
  390. ctx->L = L;
  391. ctx->cfg = worker->srv->cfg;
  392. /* SIGUSR2 handler */
  393. signal_set (&worker->sig_ev_usr2, SIGUSR2, sigusr2_handler, (void *) worker);
  394. event_base_set (ctx->ev_base, &worker->sig_ev_usr2);
  395. signal_add (&worker->sig_ev_usr2, NULL);
  396. /* SIGUSR1 handler */
  397. signal_set (&worker->sig_ev_usr1, SIGUSR1, sigusr1_handler, (void *) worker);
  398. event_base_set (ctx->ev_base, &worker->sig_ev_usr1);
  399. signal_add (&worker->sig_ev_usr1, NULL);
  400. ctx->resolver = dns_resolver_init (ctx->ev_base, worker->srv->cfg);
  401. /* Open worker's lib */
  402. luaopen_lua_worker (L);
  403. if (ctx->file == NULL) {
  404. msg_err ("No lua script defined, so no reason to exist");
  405. exit (EXIT_SUCCESS);
  406. }
  407. if (access (ctx->file, R_OK) == -1) {
  408. msg_err ("Error reading lua script %s: %s", ctx->file, strerror (errno));
  409. exit (EXIT_SUCCESS);
  410. }
  411. pctx = lua_newuserdata (L, sizeof (gpointer));
  412. lua_setclass (L, "rspamd{worker}", -1);
  413. lua_setglobal (L, "rspamd_worker");
  414. *pctx = ctx;
  415. if (luaL_dofile (L, ctx->file) != 0) {
  416. msg_err ("Error executing lua script %s: %s", ctx->file, lua_tostring (L, -1));
  417. exit (EXIT_SUCCESS);
  418. }
  419. if (ctx->cbref_accept == 0) {
  420. msg_err ("No accept function defined, so no reason to exist");
  421. exit (EXIT_SUCCESS);
  422. }
  423. /* Maps events */
  424. start_map_watch (worker->srv->cfg, ctx->ev_base);
  425. event_base_loop (ctx->ev_base, 0);
  426. luaL_unref (L, LUA_REGISTRYINDEX, ctx->cbref_accept);
  427. if (ctx->cbref_fin != 0) {
  428. /* Call finalizer function */
  429. lua_rawgeti (L, LUA_REGISTRYINDEX, ctx->cbref_fin);
  430. pctx = lua_newuserdata (L, sizeof (gpointer));
  431. lua_setclass (L, "rspamd{worker}", -1);
  432. *pctx = ctx;
  433. if (lua_pcall (L, 1, 0, 0) != 0) {
  434. msg_info ("call to worker finalizer failed: %s", lua_tostring (L, -1));
  435. }
  436. /* Free resources */
  437. luaL_unref (L, LUA_REGISTRYINDEX, ctx->cbref_fin);
  438. }
  439. close_log (rspamd_main->logger);
  440. exit (EXIT_SUCCESS);
  441. }
  442. /*
  443. * vi:ts=4
  444. */