Nelze vybrat více než 25 témat Téma musí začínat písmenem nebo číslem, může obsahovat pomlčky („-“) a může být dlouhé až 35 znaků.

main.c 13KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482
  1. /*
  2. * Copyright (c) 2009, Rambler media
  3. * All rights reserved.
  4. *
  5. * Redistribution and use in source and binary forms, with or without
  6. * modification, are permitted provided that the following conditions are met:
  7. * * Redistributions of source code must retain the above copyright
  8. * notice, this list of conditions and the following disclaimer.
  9. * * Redistributions in binary form must reproduce the above copyright
  10. * notice, this list of conditions and the following disclaimer in the
  11. * documentation and/or other materials provided with the distribution.
  12. *
  13. * THIS SOFTWARE IS PROVIDED BY Rambler media ''AS IS'' AND ANY
  14. * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  15. * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  16. * DISCLAIMED. IN NO EVENT SHALL Rambler BE LIABLE FOR ANY
  17. * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  18. * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  19. * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  20. * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  21. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  22. * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  23. */
  24. #include "config.h"
  25. #include "main.h"
  26. #include "cfg_file.h"
  27. #include "util.h"
  28. #include "perl.h"
  29. #include "lmtp.h"
  30. /* 2 seconds to fork new process in place of dead one */
  31. #define SOFT_FORK_TIME 2
  32. struct config_file *cfg;
  33. static void sig_handler (int );
  34. static struct rspamd_worker * fork_worker (struct rspamd_main *, int, int, enum process_type);
  35. sig_atomic_t do_restart;
  36. sig_atomic_t do_terminate;
  37. sig_atomic_t child_dead;
  38. sig_atomic_t child_ready;
  39. sig_atomic_t got_alarm;
  40. extern int yynerrs;
  41. extern FILE *yyin;
  42. extern void xs_init(pTHX);
  43. extern PerlInterpreter *perl_interpreter;
  44. /* List of workers that are pending to start */
  45. static GList *workers_pending = NULL;
  46. static
  47. void sig_handler (int signo)
  48. {
  49. switch (signo) {
  50. case SIGHUP:
  51. do_restart = 1;
  52. do_reopen_log = 1;
  53. break;
  54. case SIGINT:
  55. case SIGTERM:
  56. do_terminate = 1;
  57. break;
  58. case SIGCHLD:
  59. child_dead = 1;
  60. break;
  61. case SIGUSR2:
  62. child_ready = 1;
  63. break;
  64. case SIGALRM:
  65. got_alarm = 1;
  66. break;
  67. }
  68. }
  69. static void
  70. config_logger (struct rspamd_main *rspamd, gboolean is_fatal)
  71. {
  72. switch (rspamd->cfg->log_type) {
  73. case RSPAMD_LOG_CONSOLE:
  74. if (!rspamd->cfg->no_fork) {
  75. if (is_fatal) {
  76. fprintf (stderr, "Cannot log to console while daemonized, disable logging");
  77. }
  78. rspamd->cfg->log_fd = -1;
  79. }
  80. else {
  81. rspamd->cfg->log_fd = 2;
  82. }
  83. g_log_set_default_handler (file_log_function, rspamd->cfg);
  84. break;
  85. case RSPAMD_LOG_FILE:
  86. if (rspamd->cfg->log_file == NULL || open_log (rspamd->cfg) == -1) {
  87. if (is_fatal) {
  88. fprintf (stderr, "Fatal error, cannot open logfile, exiting");
  89. exit (EXIT_FAILURE);
  90. }
  91. else {
  92. msg_err ("config_logger: cannot log to file, logfile unaccessable");
  93. }
  94. }
  95. else {
  96. g_log_set_default_handler (file_log_function, rspamd->cfg);
  97. }
  98. break;
  99. case RSPAMD_LOG_SYSLOG:
  100. if (open_log (rspamd->cfg) == -1) {
  101. if (is_fatal) {
  102. fprintf (stderr, "Fatal error, cannot open syslog facility, exiting");
  103. exit (EXIT_FAILURE);
  104. }
  105. else {
  106. msg_err ("config_logger: cannot log to syslog");
  107. }
  108. }
  109. else {
  110. g_log_set_default_handler (syslog_log_function, rspamd->cfg);
  111. }
  112. break;
  113. }
  114. }
  115. static struct rspamd_worker *
  116. fork_worker (struct rspamd_main *rspamd, int listen_sock, int reconfig, enum process_type type)
  117. {
  118. struct rspamd_worker *cur;
  119. char *cfg_file;
  120. FILE *f;
  121. struct config_file *tmp_cfg;
  122. /* Starting worker process */
  123. cur = (struct rspamd_worker *)g_malloc (sizeof (struct rspamd_worker));
  124. if (cur) {
  125. /* Reconfig needed */
  126. if (reconfig) {
  127. tmp_cfg = (struct config_file *) g_malloc (sizeof (struct config_file));
  128. if (tmp_cfg) {
  129. bzero (tmp_cfg, sizeof (struct config_file));
  130. tmp_cfg->cfg_pool = memory_pool_new (32768);
  131. cfg_file = memory_pool_strdup (tmp_cfg->cfg_pool, rspamd->cfg->cfg_name);
  132. f = fopen (rspamd->cfg->cfg_name , "r");
  133. if (f == NULL) {
  134. msg_warn ("fork_worker: cannot open file: %s", rspamd->cfg->cfg_name );
  135. }
  136. else {
  137. yyin = f;
  138. yyrestart (yyin);
  139. if (yyparse() != 0 || yynerrs > 0) {
  140. msg_warn ("fork_worker: yyparse: cannot parse config file, %d errors", yynerrs);
  141. fclose (f);
  142. }
  143. else {
  144. free_config (rspamd->cfg);
  145. g_free (rspamd->cfg);
  146. rspamd->cfg = tmp_cfg;
  147. rspamd->cfg->cfg_name = cfg_file;
  148. config_logger (rspamd, FALSE);
  149. }
  150. }
  151. }
  152. }
  153. bzero (cur, sizeof (struct rspamd_worker));
  154. TAILQ_INSERT_HEAD (&rspamd->workers, cur, next);
  155. cur->srv = rspamd;
  156. cur->type = type;
  157. cur->pid = fork();
  158. switch (cur->pid) {
  159. case 0:
  160. /* TODO: add worker code */
  161. switch (type) {
  162. case TYPE_CONTROLLER:
  163. setproctitle ("controller process");
  164. pidfile_close (rspamd->pfh);
  165. msg_info ("fork_worker: starting controller process %d", getpid ());
  166. start_controller (cur);
  167. break;
  168. case TYPE_LMTP:
  169. setproctitle ("lmtp process");
  170. pidfile_close (rspamd->pfh);
  171. msg_info ("fork_worker: starting lmtp process %d", getpid ());
  172. start_lmtp_worker (cur);
  173. case TYPE_WORKER:
  174. default:
  175. setproctitle ("worker process");
  176. pidfile_close (rspamd->pfh);
  177. msg_info ("fork_worker: starting worker process %d", getpid ());
  178. start_worker (cur, listen_sock);
  179. break;
  180. }
  181. break;
  182. case -1:
  183. msg_err ("fork_worker: cannot fork main process. %m");
  184. pidfile_remove (rspamd->pfh);
  185. exit (-errno);
  186. break;
  187. }
  188. }
  189. return cur;
  190. }
  191. static void
  192. delay_fork (enum process_type type)
  193. {
  194. workers_pending = g_list_prepend (workers_pending, GINT_TO_POINTER (type));
  195. (void)alarm (SOFT_FORK_TIME);
  196. }
  197. static void
  198. fork_delayed (struct rspamd_main *rspamd, int listen_sock)
  199. {
  200. GList *cur;
  201. while (workers_pending != NULL) {
  202. cur = workers_pending;
  203. workers_pending = g_list_remove_link (workers_pending, cur);
  204. fork_worker (rspamd, listen_sock, 0, GPOINTER_TO_INT (cur->data));
  205. g_list_free_1 (cur);
  206. }
  207. }
  208. int
  209. main (int argc, char **argv, char **env)
  210. {
  211. struct rspamd_main *rspamd;
  212. struct module_ctx *cur_module = NULL;
  213. int res = 0, i, listen_sock;
  214. struct sigaction signals;
  215. struct rspamd_worker *cur, *cur_tmp, *active_worker;
  216. struct sockaddr_un *un_addr;
  217. FILE *f;
  218. pid_t wrk;
  219. char *args[] = { "", "-e", "0", NULL };
  220. rspamd = (struct rspamd_main *)g_malloc (sizeof (struct rspamd_main));
  221. bzero (rspamd, sizeof (struct rspamd_main));
  222. rspamd->server_pool = memory_pool_new (memory_pool_get_size ());
  223. cfg = (struct config_file *)g_malloc (sizeof (struct config_file));
  224. rspamd->cfg = cfg;
  225. if (!rspamd || !rspamd->cfg) {
  226. fprintf(stderr, "Cannot allocate memory\n");
  227. exit(-errno);
  228. }
  229. do_terminate = 0;
  230. do_restart = 0;
  231. child_dead = 0;
  232. child_ready = 0;
  233. do_reopen_log = 0;
  234. active_worker = NULL;
  235. rspamd->stat = memory_pool_alloc_shared (rspamd->server_pool, sizeof (struct rspamd_stat));
  236. bzero (rspamd->stat, sizeof (struct rspamd_stat));
  237. bzero (rspamd->cfg, sizeof (struct config_file));
  238. rspamd->cfg->cfg_pool = memory_pool_new (memory_pool_get_size ());
  239. init_defaults (rspamd->cfg);
  240. bzero (&signals, sizeof (struct sigaction));
  241. rspamd->cfg->cfg_name = memory_pool_strdup (rspamd->cfg->cfg_pool, FIXED_CONFIG_FILE);
  242. read_cmd_line (argc, argv, rspamd->cfg);
  243. /* First set logger to console logger */
  244. cfg->log_fd = 2;
  245. g_log_set_default_handler (file_log_function, cfg);
  246. #ifndef HAVE_SETPROCTITLE
  247. init_title (argc, argv, environ);
  248. #endif
  249. f = fopen (rspamd->cfg->cfg_name , "r");
  250. if (f == NULL) {
  251. msg_err ("main: cannot open file: %s", rspamd->cfg->cfg_name );
  252. return EBADF;
  253. }
  254. yyin = f;
  255. if (yyparse() != 0 || yynerrs > 0) {
  256. msg_err ("main: cannot parse config file, %d errors", yynerrs);
  257. return EBADF;
  258. }
  259. fclose (f);
  260. config_logger (rspamd, TRUE);
  261. msg_info ("main: starting...");
  262. rspamd->cfg->cfg_name = memory_pool_strdup (rspamd->cfg->cfg_pool, rspamd->cfg->cfg_name );
  263. /* Strictly set temp dir */
  264. if (!rspamd->cfg->temp_dir) {
  265. msg_warn ("main: tempdir is not set, trying to use $TMPDIR");
  266. rspamd->cfg->temp_dir = memory_pool_strdup (rspamd->cfg->cfg_pool, getenv ("TMPDIR"));
  267. if (!rspamd->cfg->temp_dir) {
  268. msg_warn ("main: $TMPDIR is empty too, using /tmp as default");
  269. rspamd->cfg->temp_dir = memory_pool_strdup (rspamd->cfg->cfg_pool, "/tmp");
  270. }
  271. }
  272. if (!rspamd->cfg->no_fork && daemon (1, 1) == -1) {
  273. fprintf (stderr, "Cannot daemonize\n");
  274. exit (-errno);
  275. }
  276. if (write_pid (rspamd) == -1) {
  277. msg_err ("main: cannot write pid file %s", rspamd->cfg->pid_file);
  278. exit (-errno);
  279. }
  280. /* Init C modules */
  281. for (i = 0; i < MODULES_NUM; i ++) {
  282. cur_module = memory_pool_alloc (rspamd->cfg->cfg_pool, sizeof (struct module_ctx));
  283. if (modules[i].module_init_func(cfg, &cur_module) == 0) {
  284. g_hash_table_insert (cfg->c_modules, (gpointer)modules[i].name, cur_module);
  285. }
  286. }
  287. rspamd->pid = getpid();
  288. rspamd->type = TYPE_MAIN;
  289. init_signals (&signals, sig_handler);
  290. /* Init perl interpreter */
  291. dTHXa (perl_interpreter);
  292. PERL_SYS_INIT3 (&argc, &argv, &env);
  293. perl_interpreter = perl_alloc ();
  294. if (perl_interpreter == NULL) {
  295. msg_err ("main: cannot allocate perl interpreter, %m");
  296. exit (-errno);
  297. }
  298. PERL_SET_CONTEXT (perl_interpreter);
  299. perl_construct (perl_interpreter);
  300. perl_parse (perl_interpreter, xs_init, 3, args, NULL);
  301. /* Block signals to use sigsuspend in future */
  302. sigprocmask(SIG_BLOCK, &signals.sa_mask, NULL);
  303. if (rspamd->cfg->bind_family == AF_INET) {
  304. if ((listen_sock = make_socket (&rspamd->cfg->bind_addr, rspamd->cfg->bind_port)) == -1) {
  305. msg_err ("main: cannot create tcp listen socket. %m");
  306. exit(-errno);
  307. }
  308. }
  309. else {
  310. un_addr = (struct sockaddr_un *) g_malloc (sizeof (struct sockaddr_un));
  311. if (!un_addr || (listen_sock = make_unix_socket (rspamd->cfg->bind_host, un_addr)) == -1) {
  312. msg_err ("main: cannot create unix listen socket. %m");
  313. exit(-errno);
  314. }
  315. }
  316. if (listen (listen_sock, -1) == -1) {
  317. msg_err ("main: cannot listen on socket. %m");
  318. exit(-errno);
  319. }
  320. TAILQ_INIT (&rspamd->workers);
  321. setproctitle ("main process");
  322. /* Init statfile pool */
  323. rspamd->statfile_pool = statfile_pool_new (cfg->max_statfile_size);
  324. for (i = 0; i < cfg->workers_number; i++) {
  325. fork_worker (rspamd, listen_sock, 0, TYPE_WORKER);
  326. }
  327. /* Start controller if enabled */
  328. if (cfg->controller_enabled) {
  329. fork_worker (rspamd, listen_sock, 0, TYPE_CONTROLLER);
  330. }
  331. /* Start lmtp if enabled */
  332. if (cfg->lmtp_enable) {
  333. fork_worker (rspamd, listen_sock, 0, TYPE_LMTP);
  334. }
  335. /* Signal processing cycle */
  336. for (;;) {
  337. msg_debug ("main: calling sigsuspend");
  338. sigemptyset (&signals.sa_mask);
  339. sigsuspend (&signals.sa_mask);
  340. if (do_terminate) {
  341. msg_debug ("main: catch termination signal, waiting for childs");
  342. pass_signal_worker (&rspamd->workers, SIGTERM);
  343. break;
  344. }
  345. if (child_dead) {
  346. child_dead = 0;
  347. msg_debug ("main: catch SIGCHLD signal, finding terminated worker");
  348. /* Remove dead child form childs list */
  349. wrk = waitpid (0, &res, 0);
  350. TAILQ_FOREACH_SAFE (cur, &rspamd->workers, next, cur_tmp) {
  351. if (wrk == cur->pid) {
  352. /* Catch situations if active worker is abnormally terminated */
  353. if (cur == active_worker) {
  354. active_worker = NULL;
  355. }
  356. TAILQ_REMOVE(&rspamd->workers, cur, next);
  357. if (WIFEXITED (res) && WEXITSTATUS (res) == 0) {
  358. /* Normal worker termination, do not fork one more */
  359. msg_info ("main: %s process %d terminated normally",
  360. (cur->type != TYPE_WORKER) ? "controller" : "worker", cur->pid);
  361. }
  362. else {
  363. if (WIFSIGNALED (res)) {
  364. msg_warn ("main: %s process %d terminated abnormally by signal: %d",
  365. (cur->type != TYPE_WORKER) ? "controller" : "worker",
  366. cur->pid, WTERMSIG(res));
  367. }
  368. else {
  369. msg_warn ("main: %s process %d terminated abnormally",
  370. (cur->type != TYPE_WORKER) ? "controller" : "worker", cur->pid);
  371. }
  372. /* Fork another worker in replace of dead one */
  373. delay_fork (cur->type);
  374. }
  375. g_free (cur);
  376. }
  377. }
  378. }
  379. if (do_restart) {
  380. do_restart = 0;
  381. if (active_worker == NULL) {
  382. /* Start new worker that would reread configuration*/
  383. active_worker = fork_worker (rspamd, listen_sock, 1, TYPE_WORKER);
  384. }
  385. /* Do not start new workers untill active worker is not ready for accept */
  386. }
  387. if (child_ready) {
  388. child_ready = 0;
  389. if (active_worker != NULL) {
  390. msg_info ("main: worker process %d has been successfully started", active_worker->pid);
  391. TAILQ_FOREACH_SAFE (cur, &rspamd->workers, next, cur_tmp) {
  392. if (cur != active_worker && !cur->is_dying && cur->type == TYPE_WORKER) {
  393. /* Send to old workers SIGUSR2 */
  394. kill (cur->pid, SIGUSR2);
  395. cur->is_dying = 1;
  396. }
  397. }
  398. active_worker = NULL;
  399. }
  400. }
  401. if (got_alarm) {
  402. got_alarm = 0;
  403. fork_delayed (rspamd, listen_sock);
  404. }
  405. }
  406. /* Wait for workers termination */
  407. while (!TAILQ_EMPTY(&rspamd->workers)) {
  408. cur = TAILQ_FIRST(&rspamd->workers);
  409. waitpid (cur->pid, &res, 0);
  410. msg_debug ("main(cleaning): worker process %d terminated", cur->pid);
  411. TAILQ_REMOVE(&rspamd->workers, cur, next);
  412. g_free(cur);
  413. }
  414. msg_info ("main: terminating...");
  415. if (rspamd->cfg->bind_family == AF_UNIX) {
  416. unlink (rspamd->cfg->bind_host);
  417. }
  418. free_config (rspamd->cfg);
  419. g_free (rspamd->cfg);
  420. g_free (rspamd);
  421. return (res);
  422. }
  423. /*
  424. * vi:ts=4
  425. */