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.

worker_util.c 14KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555
  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 "rspamd.h"
  18. #include "message.h"
  19. #include "lua/lua_common.h"
  20. #include "worker_util.h"
  21. #include "unix-std.h"
  22. #include "utlist.h"
  23. #include "ottery.h"
  24. #include "rspamd_control.h"
  25. #ifdef WITH_GPERF_TOOLS
  26. #include <gperftools/profiler.h>
  27. #endif
  28. /* sys/resource.h */
  29. #ifdef HAVE_SYS_RESOURCE_H
  30. #include <sys/resource.h>
  31. #endif
  32. /* pwd and grp */
  33. #ifdef HAVE_PWD_H
  34. #include <pwd.h>
  35. #endif
  36. #ifdef HAVE_GRP_H
  37. #include <grp.h>
  38. #endif
  39. #ifdef HAVE_LIBUTIL_H
  40. #include <libutil.h>
  41. #endif
  42. /**
  43. * Return worker's control structure by its type
  44. * @param type
  45. * @return worker's control structure or NULL
  46. */
  47. worker_t *
  48. rspamd_get_worker_by_type (struct rspamd_config *cfg, GQuark type)
  49. {
  50. worker_t **cur;
  51. cur = cfg->compiled_workers;
  52. while (cur && *cur) {
  53. if (g_quark_from_string ((*cur)->name) == type) {
  54. return *cur;
  55. }
  56. cur++;
  57. }
  58. return NULL;
  59. }
  60. sig_atomic_t wanna_die = 0;
  61. /*
  62. * Config reload is designed by sending sigusr2 to active workers and pending shutdown of them
  63. */
  64. static void
  65. rspamd_worker_usr2_handler (struct rspamd_worker_signal_handler *sigh, void *arg)
  66. {
  67. /* Do not accept new connections, preparing to end worker's process */
  68. struct timeval tv;
  69. if (!wanna_die) {
  70. tv.tv_sec = SOFT_SHUTDOWN_TIME;
  71. tv.tv_usec = 0;
  72. wanna_die = 1;
  73. rspamd_default_log_function (G_LOG_LEVEL_INFO,
  74. sigh->worker->srv->server_pool->tag.tagname,
  75. sigh->worker->srv->server_pool->tag.uid,
  76. G_STRFUNC,
  77. "worker's shutdown is pending in %d sec",
  78. SOFT_SHUTDOWN_TIME);
  79. event_base_loopexit (sigh->base, &tv);
  80. rspamd_worker_stop_accept (sigh->worker);
  81. }
  82. }
  83. /*
  84. * Reopen log is designed by sending sigusr1 to active workers and pending shutdown of them
  85. */
  86. static void
  87. rspamd_worker_usr1_handler (struct rspamd_worker_signal_handler *sigh, void *arg)
  88. {
  89. rspamd_log_reopen (sigh->worker->srv->logger);
  90. }
  91. static void
  92. rspamd_worker_term_handler (struct rspamd_worker_signal_handler *sigh, void *arg)
  93. {
  94. struct timeval tv;
  95. if (!wanna_die) {
  96. rspamd_default_log_function (G_LOG_LEVEL_INFO,
  97. sigh->worker->srv->server_pool->tag.tagname,
  98. sigh->worker->srv->server_pool->tag.uid,
  99. G_STRFUNC,
  100. "terminating after receiving signal %s",
  101. g_strsignal (sigh->signo));
  102. wanna_die = 1;
  103. tv.tv_sec = 0;
  104. tv.tv_usec = 0;
  105. event_base_loopexit (sigh->base, &tv);
  106. #ifdef WITH_GPERF_TOOLS
  107. ProfilerStop ();
  108. #endif
  109. rspamd_worker_stop_accept (sigh->worker);
  110. }
  111. }
  112. static void
  113. rspamd_worker_signal_handler (int fd, short what, void *arg)
  114. {
  115. struct rspamd_worker_signal_handler *sigh =
  116. (struct rspamd_worker_signal_handler *) arg;
  117. struct rspamd_worker_signal_cb *cb;
  118. cb = sigh->cb;
  119. /* Call all signal handlers registered */
  120. while (cb) {
  121. cb->handler (sigh, cb->handler_data);
  122. cb = cb->next;
  123. }
  124. }
  125. static void
  126. rspamd_worker_ignore_signal (int signo)
  127. {
  128. struct sigaction sig;
  129. sigemptyset (&sig.sa_mask);
  130. sigaddset (&sig.sa_mask, signo);
  131. sig.sa_handler = SIG_IGN;
  132. sig.sa_flags = 0;
  133. sigaction (signo, &sig, NULL);
  134. }
  135. void
  136. rspamd_worker_set_signal_handler (int signo, struct rspamd_worker *worker,
  137. struct event_base *base,
  138. void (*handler)(struct rspamd_worker_signal_handler *sigh, void *),
  139. void *handler_data)
  140. {
  141. struct rspamd_worker_signal_handler *sigh;
  142. struct rspamd_worker_signal_cb *cb;
  143. sigh = g_hash_table_lookup (worker->signal_events, GINT_TO_POINTER (signo));
  144. if (sigh == NULL) {
  145. sigh = g_malloc0 (sizeof (*sigh));
  146. sigh->signo = signo;
  147. sigh->worker = worker;
  148. sigh->base = base;
  149. sigh->enabled = TRUE;
  150. signal_set (&sigh->ev, signo, rspamd_worker_signal_handler, sigh);
  151. event_base_set (base, &sigh->ev);
  152. signal_add (&sigh->ev, NULL);
  153. g_hash_table_insert (worker->signal_events,
  154. GINT_TO_POINTER (signo),
  155. sigh);
  156. }
  157. cb = g_malloc0 (sizeof (*cb));
  158. cb->handler = handler;
  159. cb->handler_data = handler_data;
  160. DL_APPEND (sigh->cb, cb);
  161. }
  162. static void
  163. rspamd_worker_init_signals (struct rspamd_worker *worker, struct event_base *base)
  164. {
  165. struct sigaction signals;
  166. /* We ignore these signals in the worker */
  167. rspamd_worker_ignore_signal (SIGPIPE);
  168. rspamd_worker_ignore_signal (SIGALRM);
  169. rspamd_worker_ignore_signal (SIGCHLD);
  170. /* A set of terminating signals */
  171. rspamd_worker_set_signal_handler (SIGTERM, worker, base,
  172. rspamd_worker_term_handler, NULL);
  173. rspamd_worker_set_signal_handler (SIGINT, worker, base,
  174. rspamd_worker_term_handler, NULL);
  175. rspamd_worker_set_signal_handler (SIGHUP, worker, base,
  176. rspamd_worker_term_handler, NULL);
  177. /* Special purpose signals */
  178. rspamd_worker_set_signal_handler (SIGUSR1, worker, base,
  179. rspamd_worker_usr1_handler, NULL);
  180. rspamd_worker_set_signal_handler (SIGUSR2, worker, base,
  181. rspamd_worker_usr2_handler, NULL);
  182. /* Unblock all signals processed */
  183. sigemptyset (&signals.sa_mask);
  184. sigaddset (&signals.sa_mask, SIGTERM);
  185. sigaddset (&signals.sa_mask, SIGINT);
  186. sigaddset (&signals.sa_mask, SIGHUP);
  187. sigaddset (&signals.sa_mask, SIGCHLD);
  188. sigaddset (&signals.sa_mask, SIGUSR1);
  189. sigaddset (&signals.sa_mask, SIGUSR2);
  190. sigaddset (&signals.sa_mask, SIGALRM);
  191. sigaddset (&signals.sa_mask, SIGPIPE);
  192. sigprocmask (SIG_UNBLOCK, &signals.sa_mask, NULL);
  193. }
  194. struct event_base *
  195. rspamd_prepare_worker (struct rspamd_worker *worker, const char *name,
  196. void (*accept_handler)(int, short, void *))
  197. {
  198. struct event_base *ev_base;
  199. struct event *accept_event;
  200. GList *cur;
  201. gint listen_socket;
  202. #ifdef WITH_PROFILER
  203. extern void _start (void), etext (void);
  204. monstartup ((u_long) & _start, (u_long) & etext);
  205. #endif
  206. gperf_profiler_init (worker->srv->cfg, name);
  207. worker->srv->pid = getpid ();
  208. worker->signal_events = g_hash_table_new_full (g_direct_hash, g_direct_equal,
  209. NULL, g_free);
  210. ev_base = event_init ();
  211. rspamd_worker_init_signals (worker, ev_base);
  212. rspamd_control_worker_add_default_handler (worker, ev_base);
  213. /* Accept all sockets */
  214. if (accept_handler) {
  215. cur = worker->cf->listen_socks;
  216. while (cur) {
  217. listen_socket = GPOINTER_TO_INT (cur->data);
  218. if (listen_socket != -1) {
  219. accept_event = g_slice_alloc0 (sizeof (struct event));
  220. event_set (accept_event, listen_socket, EV_READ | EV_PERSIST,
  221. accept_handler, worker);
  222. event_base_set (ev_base, accept_event);
  223. event_add (accept_event, NULL);
  224. worker->accept_events = g_list_prepend (worker->accept_events,
  225. accept_event);
  226. }
  227. cur = g_list_next (cur);
  228. }
  229. }
  230. return ev_base;
  231. }
  232. void
  233. rspamd_worker_stop_accept (struct rspamd_worker *worker)
  234. {
  235. GList *cur;
  236. struct event *event;
  237. GHashTableIter it;
  238. struct rspamd_worker_signal_handler *sigh;
  239. gpointer k, v;
  240. /* Remove all events */
  241. cur = worker->accept_events;
  242. while (cur) {
  243. event = cur->data;
  244. event_del (event);
  245. cur = g_list_next (cur);
  246. g_slice_free1 (sizeof (struct event), event);
  247. }
  248. if (worker->accept_events != NULL) {
  249. g_list_free (worker->accept_events);
  250. }
  251. g_hash_table_iter_init (&it, worker->signal_events);
  252. while (g_hash_table_iter_next (&it, &k, &v)) {
  253. sigh = (struct rspamd_worker_signal_handler *)v;
  254. g_hash_table_iter_steal (&it);
  255. if (sigh->enabled) {
  256. event_del (&sigh->ev);
  257. }
  258. g_free (sigh);
  259. }
  260. g_hash_table_unref (worker->signal_events);
  261. }
  262. void
  263. rspamd_controller_send_error (struct rspamd_http_connection_entry *entry,
  264. gint code, const gchar *error_msg, ...)
  265. {
  266. struct rspamd_http_message *msg;
  267. va_list args;
  268. msg = rspamd_http_new_message (HTTP_RESPONSE);
  269. va_start (args, error_msg);
  270. msg->status = rspamd_fstring_new ();
  271. rspamd_vprintf_fstring (&msg->status, error_msg, args);
  272. va_end (args);
  273. msg->date = time (NULL);
  274. msg->code = code;
  275. msg->body = rspamd_fstring_new ();
  276. rspamd_printf_fstring (&msg->body, "{\"error\":\"%V\"}", msg->status);
  277. rspamd_http_connection_reset (entry->conn);
  278. rspamd_http_connection_write_message (entry->conn,
  279. msg,
  280. NULL,
  281. "application/json",
  282. entry,
  283. entry->conn->fd,
  284. entry->rt->ptv,
  285. entry->rt->ev_base);
  286. entry->is_reply = TRUE;
  287. }
  288. void
  289. rspamd_controller_send_string (struct rspamd_http_connection_entry *entry,
  290. const gchar *str)
  291. {
  292. struct rspamd_http_message *msg;
  293. msg = rspamd_http_new_message (HTTP_RESPONSE);
  294. msg->date = time (NULL);
  295. msg->code = 200;
  296. msg->status = rspamd_fstring_new_init ("OK", 2);
  297. msg->body = rspamd_fstring_new_init (str, strlen (str));
  298. rspamd_http_connection_reset (entry->conn);
  299. rspamd_http_connection_write_message (entry->conn,
  300. msg,
  301. NULL,
  302. "application/json",
  303. entry,
  304. entry->conn->fd,
  305. entry->rt->ptv,
  306. entry->rt->ev_base);
  307. entry->is_reply = TRUE;
  308. }
  309. void
  310. rspamd_controller_send_ucl (struct rspamd_http_connection_entry *entry,
  311. ucl_object_t *obj)
  312. {
  313. struct rspamd_http_message *msg;
  314. msg = rspamd_http_new_message (HTTP_RESPONSE);
  315. msg->date = time (NULL);
  316. msg->code = 200;
  317. msg->status = rspamd_fstring_new_init ("OK", 2);
  318. msg->body = rspamd_fstring_sized_new (BUFSIZ);
  319. rspamd_ucl_emit_fstring (obj, UCL_EMIT_JSON_COMPACT, &msg->body);
  320. rspamd_http_connection_reset (entry->conn);
  321. rspamd_http_connection_write_message (entry->conn,
  322. msg,
  323. NULL,
  324. "application/json",
  325. entry,
  326. entry->conn->fd,
  327. entry->rt->ptv,
  328. entry->rt->ev_base);
  329. entry->is_reply = TRUE;
  330. }
  331. static void
  332. rspamd_worker_drop_priv (struct rspamd_main *rspamd_main)
  333. {
  334. if (rspamd_main->is_privilleged) {
  335. if (setgid (rspamd_main->workers_gid) == -1) {
  336. msg_err_main ("cannot setgid to %d (%s), aborting",
  337. (gint) rspamd_main->workers_gid,
  338. strerror (errno));
  339. exit (-errno);
  340. }
  341. if (rspamd_main->cfg->rspamd_user &&
  342. initgroups (rspamd_main->cfg->rspamd_user, rspamd_main->workers_gid) ==
  343. -1) {
  344. msg_err_main ("initgroups failed (%s), aborting", strerror (errno));
  345. exit (-errno);
  346. }
  347. if (setuid (rspamd_main->workers_uid) == -1) {
  348. msg_err_main ("cannot setuid to %d (%s), aborting",
  349. (gint) rspamd_main->workers_uid,
  350. strerror (errno));
  351. exit (-errno);
  352. }
  353. }
  354. }
  355. static void
  356. rspamd_worker_set_limits (struct rspamd_main *rspamd_main,
  357. struct rspamd_worker_conf *cf)
  358. {
  359. struct rlimit rlmt;
  360. if (cf->rlimit_nofile != 0) {
  361. rlmt.rlim_cur = (rlim_t) cf->rlimit_nofile;
  362. rlmt.rlim_max = (rlim_t) cf->rlimit_nofile;
  363. if (setrlimit (RLIMIT_NOFILE, &rlmt) == -1) {
  364. msg_warn_main ("cannot set files rlimit: %d, %s",
  365. cf->rlimit_nofile,
  366. strerror (errno));
  367. }
  368. }
  369. if (rspamd_main->cores_throttling) {
  370. msg_info_main ("disable core files for the new worker, as limits are reached");
  371. rlmt.rlim_cur = 0;
  372. rlmt.rlim_max = 0;
  373. if (setrlimit (RLIMIT_CORE, &rlmt) == -1) {
  374. msg_warn_main ("cannot disable core: %s",
  375. strerror (errno));
  376. }
  377. }
  378. else {
  379. if (cf->rlimit_maxcore != 0) {
  380. rlmt.rlim_cur = (rlim_t) cf->rlimit_maxcore;
  381. rlmt.rlim_max = (rlim_t) cf->rlimit_maxcore;
  382. if (setrlimit (RLIMIT_CORE, &rlmt) == -1) {
  383. msg_warn_main ("cannot set max core rlimit: %d, %s",
  384. cf->rlimit_maxcore,
  385. strerror (errno));
  386. }
  387. }
  388. }
  389. }
  390. struct rspamd_worker *
  391. rspamd_fork_worker (struct rspamd_main *rspamd_main,
  392. struct rspamd_worker_conf *cf,
  393. guint index,
  394. struct event_base *ev_base)
  395. {
  396. struct rspamd_worker *wrk;
  397. gint rc;
  398. /* Starting worker process */
  399. wrk = (struct rspamd_worker *) g_malloc0 (sizeof (struct rspamd_worker));
  400. if (!rspamd_socketpair (wrk->control_pipe)) {
  401. msg_err ("socketpair failure: %s", strerror (errno));
  402. exit (-errno);
  403. }
  404. if (!rspamd_socketpair (wrk->srv_pipe)) {
  405. msg_err ("socketpair failure: %s", strerror (errno));
  406. exit (-errno);
  407. }
  408. wrk->srv = rspamd_main;
  409. wrk->type = cf->type;
  410. wrk->cf = g_malloc (sizeof (struct rspamd_worker_conf));
  411. memcpy (wrk->cf, cf, sizeof (struct rspamd_worker_conf));
  412. wrk->index = index;
  413. wrk->ctx = cf->ctx;
  414. wrk->pid = fork ();
  415. switch (wrk->pid) {
  416. case 0:
  417. /* Update pid for logging */
  418. rspamd_log_update_pid (cf->type, rspamd_main->logger);
  419. /* Remove the inherited event base */
  420. event_reinit (rspamd_main->ev_base);
  421. event_base_free (rspamd_main->ev_base);
  422. /* Lock statfile pool if possible XXX */
  423. /* Init PRNG after fork */
  424. rc = ottery_init (rspamd_main->cfg->libs_ctx->ottery_cfg);
  425. if (rc != OTTERY_ERR_NONE) {
  426. msg_err_main ("cannot initialize PRNG: %d", rc);
  427. g_assert (0);
  428. }
  429. g_random_set_seed (ottery_rand_uint32 ());
  430. /* Drop privilleges */
  431. rspamd_worker_drop_priv (rspamd_main);
  432. /* Set limits */
  433. rspamd_worker_set_limits (rspamd_main, cf);
  434. setproctitle ("%s process", cf->worker->name);
  435. rspamd_pidfile_close (rspamd_main->pfh);
  436. /* Do silent log reopen to avoid collisions */
  437. rspamd_log_close (rspamd_main->logger);
  438. rspamd_log_open (rspamd_main->logger);
  439. wrk->start_time = rspamd_get_calendar_ticks ();
  440. #if ((GLIB_MAJOR_VERSION == 2) && (GLIB_MINOR_VERSION <= 30))
  441. # if (GLIB_MINOR_VERSION > 20)
  442. /* Ugly hack for old glib */
  443. if (!g_thread_get_initialized ()) {
  444. g_thread_init (NULL);
  445. }
  446. # else
  447. g_thread_init (NULL);
  448. # endif
  449. #endif
  450. msg_info_main ("starting %s process %P", cf->worker->name, getpid ());
  451. /* Close parent part of socketpair */
  452. close (wrk->control_pipe[0]);
  453. close (wrk->srv_pipe[0]);
  454. rspamd_socket_nonblocking (wrk->control_pipe[1]);
  455. rspamd_socket_nonblocking (wrk->srv_pipe[1]);
  456. /* Execute worker */
  457. cf->worker->worker_start_func (wrk);
  458. exit (EXIT_FAILURE);
  459. break;
  460. case -1:
  461. msg_err_main ("cannot fork main process. %s", strerror (errno));
  462. rspamd_pidfile_remove (rspamd_main->pfh);
  463. exit (-errno);
  464. break;
  465. default:
  466. /* Close worker part of socketpair */
  467. close (wrk->control_pipe[1]);
  468. close (wrk->srv_pipe[1]);
  469. rspamd_socket_nonblocking (wrk->control_pipe[0]);
  470. rspamd_socket_nonblocking (wrk->srv_pipe[0]);
  471. rspamd_srv_start_watching (wrk, ev_base);
  472. /* Insert worker into worker's table, pid is index */
  473. g_hash_table_insert (rspamd_main->workers, GSIZE_TO_POINTER (
  474. wrk->pid), wrk);
  475. break;
  476. }
  477. return wrk;
  478. }
  479. void
  480. rspamd_worker_block_signals (void)
  481. {
  482. sigset_t set;
  483. sigemptyset (&set);
  484. sigaddset (&set, SIGTERM);
  485. sigaddset (&set, SIGINT);
  486. sigaddset (&set, SIGHUP);
  487. sigaddset (&set, SIGUSR1);
  488. sigaddset (&set, SIGUSR2);
  489. sigprocmask (SIG_BLOCK, &set, NULL);
  490. }