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.

main.c 11KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427
  1. #include <sys/types.h>
  2. #include <sys/time.h>
  3. #include <sys/wait.h>
  4. #include <sys/param.h>
  5. #include <unistd.h>
  6. #include <stdio.h>
  7. #include <stdlib.h>
  8. #include <string.h>
  9. #include <time.h>
  10. #include <errno.h>
  11. #include <signal.h>
  12. #ifdef HAVE_LIBUTIL_H
  13. #include <libutil.h>
  14. #endif
  15. #include <syslog.h>
  16. #include <EXTERN.h> /* from the Perl distribution */
  17. #include <perl.h> /* from the Perl distribution */
  18. #include "main.h"
  19. #include "cfg_file.h"
  20. #include "util.h"
  21. struct config_file *cfg;
  22. static void sig_handler (int );
  23. static struct rspamd_worker * fork_worker (struct rspamd_main *, int, int, enum process_type);
  24. sig_atomic_t do_restart;
  25. sig_atomic_t do_terminate;
  26. sig_atomic_t child_dead;
  27. sig_atomic_t child_ready;
  28. extern int yynerrs;
  29. extern FILE *yyin;
  30. extern void boot_DynaLoader (pTHX_ CV* cv);
  31. extern void boot_Socket (pTHX_ CV* cv);
  32. PerlInterpreter *perl_interpreter;
  33. /* XXX: remove this shit when it would be clear why perl need this line */
  34. PerlInterpreter *my_perl;
  35. static
  36. void sig_handler (int signo)
  37. {
  38. switch (signo) {
  39. case SIGHUP:
  40. do_restart = 1;
  41. do_reopen_log = 1;
  42. break;
  43. case SIGINT:
  44. case SIGTERM:
  45. do_terminate = 1;
  46. break;
  47. case SIGCHLD:
  48. child_dead = 1;
  49. break;
  50. case SIGUSR2:
  51. child_ready = 1;
  52. break;
  53. }
  54. }
  55. void
  56. xs_init(pTHX)
  57. {
  58. dXSUB_SYS;
  59. /* DynaLoader is a special case */
  60. newXS ("DynaLoader::boot_DynaLoader", boot_DynaLoader, __FILE__);
  61. }
  62. static void
  63. init_filters (struct config_file *cfg)
  64. {
  65. struct perl_module *module;
  66. LIST_FOREACH (module, &cfg->perl_modules, next) {
  67. if (module->path) {
  68. require_pv (module->path);
  69. }
  70. }
  71. }
  72. static struct rspamd_worker *
  73. fork_worker (struct rspamd_main *rspamd, int listen_sock, int reconfig, enum process_type type)
  74. {
  75. struct rspamd_worker *cur;
  76. char *cfg_file;
  77. FILE *f;
  78. struct config_file *tmp_cfg;
  79. /* Starting worker process */
  80. cur = (struct rspamd_worker *)g_malloc (sizeof (struct rspamd_worker));
  81. if (cur) {
  82. /* Reconfig needed */
  83. if (reconfig) {
  84. tmp_cfg = (struct config_file *) g_malloc (sizeof (struct config_file));
  85. if (tmp_cfg) {
  86. bzero (tmp_cfg, sizeof (struct config_file));
  87. tmp_cfg->cfg_pool = memory_pool_new (32768);
  88. cfg_file = memory_pool_strdup (tmp_cfg->cfg_pool, rspamd->cfg->cfg_name);
  89. f = fopen (rspamd->cfg->cfg_name , "r");
  90. if (f == NULL) {
  91. msg_warn ("fork_worker: cannot open file: %s", rspamd->cfg->cfg_name );
  92. }
  93. else {
  94. yyin = f;
  95. yyrestart (yyin);
  96. if (yyparse() != 0 || yynerrs > 0) {
  97. msg_warn ("fork_worker: yyparse: cannot parse config file, %d errors", yynerrs);
  98. fclose (f);
  99. }
  100. else {
  101. free_config (rspamd->cfg);
  102. g_free (rspamd->cfg);
  103. rspamd->cfg = tmp_cfg;
  104. rspamd->cfg->cfg_name = cfg_file;
  105. }
  106. }
  107. }
  108. }
  109. bzero (cur, sizeof (struct rspamd_worker));
  110. TAILQ_INSERT_HEAD (&rspamd->workers, cur, next);
  111. cur->srv = rspamd;
  112. cur->pid = fork();
  113. switch (cur->pid) {
  114. case 0:
  115. /* TODO: add worker code */
  116. switch (type) {
  117. case TYPE_CONTROLLER:
  118. setproctitle ("controller process");
  119. pidfile_close (rspamd->pfh);
  120. msg_info ("fork_worker: starting controller process %d", getpid ());
  121. cur->type = TYPE_CONTROLLER;
  122. start_controller (cur);
  123. break;
  124. case TYPE_WORKER:
  125. default:
  126. setproctitle ("worker process");
  127. pidfile_close (rspamd->pfh);
  128. msg_info ("fork_worker: starting worker process %d", getpid ());
  129. cur->type = TYPE_WORKER;
  130. start_worker (cur, listen_sock);
  131. break;
  132. }
  133. break;
  134. case -1:
  135. msg_err ("fork_worker: cannot fork main process. %m");
  136. pidfile_remove (rspamd->pfh);
  137. exit (-errno);
  138. break;
  139. }
  140. }
  141. return cur;
  142. }
  143. int
  144. main (int argc, char **argv)
  145. {
  146. struct rspamd_main *rspamd;
  147. struct module_ctx *cur_module = NULL;
  148. int res = 0, i, listen_sock;
  149. struct sigaction signals;
  150. struct rspamd_worker *cur, *cur_tmp, *active_worker;
  151. struct sockaddr_un *un_addr;
  152. FILE *f;
  153. pid_t wrk;
  154. char *args[] = { "", "-e", "0", NULL };
  155. rspamd = (struct rspamd_main *)g_malloc (sizeof (struct rspamd_main));
  156. bzero (rspamd, sizeof (struct rspamd_main));
  157. rspamd->server_pool = memory_pool_new (memory_pool_get_size ());
  158. cfg = (struct config_file *)g_malloc (sizeof (struct config_file));
  159. rspamd->cfg = cfg;
  160. if (!rspamd || !rspamd->cfg) {
  161. fprintf(stderr, "Cannot allocate memory\n");
  162. exit(-errno);
  163. }
  164. do_terminate = 0;
  165. do_restart = 0;
  166. child_dead = 0;
  167. child_ready = 0;
  168. do_reopen_log = 0;
  169. active_worker = NULL;
  170. rspamd->stat = memory_pool_alloc_shared (rspamd->server_pool, sizeof (struct rspamd_stat));
  171. bzero (rspamd->stat, sizeof (struct rspamd_stat));
  172. bzero (rspamd->cfg, sizeof (struct config_file));
  173. rspamd->cfg->cfg_pool = memory_pool_new (memory_pool_get_size ());
  174. init_defaults (rspamd->cfg);
  175. bzero (&signals, sizeof (struct sigaction));
  176. rspamd->cfg->cfg_name = memory_pool_strdup (rspamd->cfg->cfg_pool, FIXED_CONFIG_FILE);
  177. read_cmd_line (argc, argv, rspamd->cfg);
  178. msg_warn ("(main) starting...");
  179. #ifndef HAVE_SETPROCTITLE
  180. init_title (argc, argv, environ);
  181. #endif
  182. f = fopen (rspamd->cfg->cfg_name , "r");
  183. if (f == NULL) {
  184. msg_warn ("cannot open file: %s", rspamd->cfg->cfg_name );
  185. return EBADF;
  186. }
  187. yyin = f;
  188. if (yyparse() != 0 || yynerrs > 0) {
  189. msg_warn ("yyparse: cannot parse config file, %d errors", yynerrs);
  190. return EBADF;
  191. }
  192. fclose (f);
  193. rspamd->cfg->cfg_name = memory_pool_strdup (rspamd->cfg->cfg_pool, rspamd->cfg->cfg_name );
  194. /* Strictly set temp dir */
  195. if (!rspamd->cfg->temp_dir) {
  196. msg_warn ("tempdir is not set, trying to use $TMPDIR");
  197. rspamd->cfg->temp_dir = memory_pool_strdup (rspamd->cfg->cfg_pool, getenv ("TMPDIR"));
  198. if (!rspamd->cfg->temp_dir) {
  199. msg_warn ("$TMPDIR is empty too, using /tmp as default");
  200. rspamd->cfg->temp_dir = memory_pool_strdup (rspamd->cfg->cfg_pool, "/tmp");
  201. }
  202. }
  203. switch (cfg->log_type) {
  204. case RSPAMD_LOG_CONSOLE:
  205. if (!rspamd->cfg->no_fork) {
  206. fprintf (stderr, "Cannot log to console while daemonized, disable logging");
  207. cfg->log_fd = -1;
  208. }
  209. else {
  210. cfg->log_fd = 2;
  211. }
  212. g_log_set_default_handler (file_log_function, cfg);
  213. break;
  214. case RSPAMD_LOG_FILE:
  215. if (cfg->log_file == NULL || open_log (cfg) == -1) {
  216. fprintf (stderr, "Fatal error, cannot open logfile, exiting");
  217. exit (EXIT_FAILURE);
  218. }
  219. g_log_set_default_handler (file_log_function, cfg);
  220. break;
  221. case RSPAMD_LOG_SYSLOG:
  222. if (open_log (cfg) == -1) {
  223. fprintf (stderr, "Fatal error, cannot open syslog facility, exiting");
  224. exit (EXIT_FAILURE);
  225. }
  226. g_log_set_default_handler (syslog_log_function, cfg);
  227. break;
  228. }
  229. if (!rspamd->cfg->no_fork && daemon (1, 1) == -1) {
  230. fprintf (stderr, "Cannot daemonize\n");
  231. exit (-errno);
  232. }
  233. if (write_pid (rspamd) == -1) {
  234. msg_err ("main: cannot write pid file %s", rspamd->cfg->pid_file);
  235. exit (-errno);
  236. }
  237. /* Init C modules */
  238. for (i = 0; i < MODULES_NUM; i ++) {
  239. cur_module = memory_pool_alloc (rspamd->cfg->cfg_pool, sizeof (struct module_ctx));
  240. if (modules[i].module_init_func(cfg, &cur_module) == 0) {
  241. g_hash_table_insert (cfg->c_modules, (gpointer)modules[i].name, cur_module);
  242. }
  243. }
  244. rspamd->pid = getpid();
  245. rspamd->type = TYPE_MAIN;
  246. init_signals (&signals, sig_handler);
  247. /* Init perl interpreter */
  248. PERL_SYS_INIT3 (&argc, &argv, &env);
  249. perl_interpreter = perl_alloc ();
  250. if (perl_interpreter == NULL) {
  251. msg_err ("main: cannot allocate perl interpreter, %m");
  252. exit (-errno);
  253. }
  254. my_perl = perl_interpreter;
  255. PERL_SET_CONTEXT (perl_interpreter);
  256. perl_construct (perl_interpreter);
  257. PL_exit_flags |= PERL_EXIT_DESTRUCT_END;
  258. perl_parse (perl_interpreter, xs_init, 3, args, NULL);
  259. /* Block signals to use sigsuspend in future */
  260. sigprocmask(SIG_BLOCK, &signals.sa_mask, NULL);
  261. if (rspamd->cfg->bind_family == AF_INET) {
  262. if ((listen_sock = make_socket (rspamd->cfg->bind_host, rspamd->cfg->bind_port)) == -1) {
  263. msg_err ("main: cannot create tcp listen socket. %m");
  264. exit(-errno);
  265. }
  266. }
  267. else {
  268. un_addr = (struct sockaddr_un *) g_malloc (sizeof (struct sockaddr_un));
  269. if (!un_addr || (listen_sock = make_unix_socket (rspamd->cfg->bind_host, un_addr)) == -1) {
  270. msg_err ("main: cannot create unix listen socket. %m");
  271. exit(-errno);
  272. }
  273. }
  274. if (listen (listen_sock, -1) == -1) {
  275. msg_err ("main: cannot listen on socket. %m");
  276. exit(-errno);
  277. }
  278. TAILQ_INIT (&rspamd->workers);
  279. setproctitle ("main process");
  280. for (i = 0; i < cfg->workers_number; i++) {
  281. fork_worker (rspamd, listen_sock, 0, TYPE_WORKER);
  282. }
  283. /* Start controller if enabled */
  284. if (cfg->controller_enabled) {
  285. fork_worker (rspamd, listen_sock, 0, TYPE_CONTROLLER);
  286. }
  287. /* Signal processing cycle */
  288. for (;;) {
  289. msg_debug ("main: calling sigsuspend");
  290. sigemptyset (&signals.sa_mask);
  291. sigsuspend (&signals.sa_mask);
  292. if (do_terminate) {
  293. msg_debug ("main: catch termination signal, waiting for childs");
  294. pass_signal_worker (&rspamd->workers, SIGTERM);
  295. break;
  296. }
  297. if (child_dead) {
  298. child_dead = 0;
  299. msg_debug ("main: catch SIGCHLD signal, finding terminated worker");
  300. /* Remove dead child form childs list */
  301. wrk = waitpid (0, &res, 0);
  302. TAILQ_FOREACH_SAFE (cur, &rspamd->workers, next, cur_tmp) {
  303. if (wrk == cur->pid) {
  304. /* Catch situations if active worker is abnormally terminated */
  305. if (cur == active_worker) {
  306. active_worker = NULL;
  307. }
  308. TAILQ_REMOVE(&rspamd->workers, cur, next);
  309. if (cur->type == TYPE_CONTROLLER) {
  310. msg_info ("main: do not restart dead controller");
  311. g_free (cur);
  312. break;
  313. }
  314. if (WIFEXITED (res) && WEXITSTATUS (res) == 0) {
  315. /* Normal worker termination, do not fork one more */
  316. msg_info ("main: worker process %d terminated normally", cur->pid);
  317. }
  318. else {
  319. if (WIFSIGNALED (res)) {
  320. msg_warn ("main: worker process %d terminated abnormally by signal: %d",
  321. cur->pid, WTERMSIG(res));
  322. }
  323. else {
  324. msg_warn ("main: worker process %d terminated abnormally", cur->pid);
  325. }
  326. /* Fork another worker in replace of dead one */
  327. fork_worker (rspamd, listen_sock, 0, cur->type);
  328. }
  329. g_free (cur);
  330. }
  331. }
  332. }
  333. if (do_restart) {
  334. do_restart = 0;
  335. if (active_worker == NULL) {
  336. /* Start new worker that would reread configuration*/
  337. active_worker = fork_worker (rspamd, listen_sock, 1, TYPE_WORKER);
  338. }
  339. /* Do not start new workers untill active worker is not ready for accept */
  340. }
  341. if (child_ready) {
  342. child_ready = 0;
  343. if (active_worker != NULL) {
  344. msg_info ("main: worker process %d has been successfully started", active_worker->pid);
  345. TAILQ_FOREACH_SAFE (cur, &rspamd->workers, next, cur_tmp) {
  346. if (cur != active_worker && !cur->is_dying) {
  347. /* Send to old workers SIGUSR2 */
  348. kill (cur->pid, SIGUSR2);
  349. cur->is_dying = 1;
  350. }
  351. }
  352. active_worker = NULL;
  353. }
  354. }
  355. }
  356. /* Wait for workers termination */
  357. while (!TAILQ_EMPTY(&rspamd->workers)) {
  358. cur = TAILQ_FIRST(&rspamd->workers);
  359. waitpid (cur->pid, &res, 0);
  360. msg_debug ("main(cleaning): worker process %d terminated", cur->pid);
  361. TAILQ_REMOVE(&rspamd->workers, cur, next);
  362. g_free(cur);
  363. }
  364. msg_info ("main: terminating...");
  365. if (rspamd->cfg->bind_family == AF_UNIX) {
  366. unlink (rspamd->cfg->bind_host);
  367. }
  368. free_config (rspamd->cfg);
  369. g_free (rspamd->cfg);
  370. g_free (rspamd);
  371. return (res);
  372. }
  373. /*
  374. * vi:ts=4
  375. */