static void rspamd_log_write_ringbuffer (rspamd_logger_t *rspamd_log, const gchar *module, const gchar *id, const gchar *data, glong len) { guint32 row_num; struct rspamd_logger_error_log *elog; struct rspamd_logger_error_elt *elt; if (!rspamd_log->errlog) { return; } elog = rspamd_log->errlog; g_atomic_int_compare_and_exchange (&elog->cur_row, elog->max_elts, 0); #if ((GLIB_MAJOR_VERSION == 2) && (GLIB_MINOR_VERSION > 30)) row_num = g_atomic_int_add (&elog->cur_row, 1); #else row_num = g_atomic_int_exchange_and_add (&elog->cur_row, 1); #endif if (row_num < elog->max_elts) { elt = (struct rspamd_logger_error_elt *)(((guchar *)elog->elts) + (sizeof (*elt) + elog->elt_len) * row_num); g_atomic_int_set (&elt->completed, 0); } else { /* Race condition */ elog->cur_row = 0; return; } elt->pid = rspamd_log->pid; elt->ptype = rspamd_log->process_type; elt->ts = rspamd_get_calendar_ticks (); if (id) { rspamd_strlcpy (elt->id, id, sizeof (elt->id)); } else { rspamd_strlcpy (elt->id, "", sizeof (elt->id)); } if (module) { rspamd_strlcpy (elt->module, module, sizeof (elt->module)); } else { rspamd_strlcpy (elt->module, "", sizeof (elt->module)); } rspamd_strlcpy (elt->message, data, MIN (len + 1, elog->elt_len)); g_atomic_int_set (&elt->completed, 1); }
struct rspamd_worker * rspamd_fork_worker (struct rspamd_main *rspamd_main, struct rspamd_worker_conf *cf, guint index, struct event_base *ev_base) { struct rspamd_worker *wrk; gint rc; struct rlimit rlim; /* Starting worker process */ wrk = (struct rspamd_worker *) g_malloc0 (sizeof (struct rspamd_worker)); if (!rspamd_socketpair (wrk->control_pipe)) { msg_err ("socketpair failure: %s", strerror (errno)); exit (-errno); } if (!rspamd_socketpair (wrk->srv_pipe)) { msg_err ("socketpair failure: %s", strerror (errno)); exit (-errno); } wrk->srv = rspamd_main; wrk->type = cf->type; wrk->cf = cf; REF_RETAIN (cf); wrk->index = index; wrk->ctx = cf->ctx; wrk->finish_actions = g_ptr_array_new (); wrk->pid = fork (); switch (wrk->pid) { case 0: /* Update pid for logging */ rspamd_log_update_pid (cf->type, rspamd_main->logger); /* Init PRNG after fork */ rc = ottery_init (rspamd_main->cfg->libs_ctx->ottery_cfg); if (rc != OTTERY_ERR_NONE) { msg_err_main ("cannot initialize PRNG: %d", rc); abort (); } rspamd_random_seed_fast (); #ifdef HAVE_EVUTIL_RNG_INIT evutil_secure_rng_init (); #endif /* Remove the inherited event base */ event_reinit (rspamd_main->ev_base); event_base_free (rspamd_main->ev_base); /* Drop privilleges */ rspamd_worker_drop_priv (rspamd_main); /* Set limits */ rspamd_worker_set_limits (rspamd_main, cf); /* Re-set stack limit */ getrlimit (RLIMIT_STACK, &rlim); rlim.rlim_cur = 100 * 1024 * 1024; rlim.rlim_max = rlim.rlim_cur; setrlimit (RLIMIT_STACK, &rlim); setproctitle ("%s process", cf->worker->name); rspamd_pidfile_close (rspamd_main->pfh); /* Do silent log reopen to avoid collisions */ rspamd_log_close (rspamd_main->logger); rspamd_log_open (rspamd_main->logger); wrk->start_time = rspamd_get_calendar_ticks (); #if ((GLIB_MAJOR_VERSION == 2) && (GLIB_MINOR_VERSION <= 30)) # if (GLIB_MINOR_VERSION > 20) /* Ugly hack for old glib */ if (!g_thread_get_initialized ()) { g_thread_init (NULL); } # else g_thread_init (NULL); # endif #endif msg_info_main ("starting %s process %P (%d)", cf->worker->name, getpid (), index); /* Close parent part of socketpair */ close (wrk->control_pipe[0]); close (wrk->srv_pipe[0]); rspamd_socket_nonblocking (wrk->control_pipe[1]); rspamd_socket_nonblocking (wrk->srv_pipe[1]); /* Execute worker */ cf->worker->worker_start_func (wrk); exit (EXIT_FAILURE); break; case -1: msg_err_main ("cannot fork main process. %s", strerror (errno)); rspamd_pidfile_remove (rspamd_main->pfh); exit (-errno); break; default: /* Close worker part of socketpair */ close (wrk->control_pipe[1]); close (wrk->srv_pipe[1]); rspamd_socket_nonblocking (wrk->control_pipe[0]); rspamd_socket_nonblocking (wrk->srv_pipe[0]); rspamd_srv_start_watching (wrk, ev_base); /* Insert worker into worker's table, pid is index */ g_hash_table_insert (rspamd_main->workers, GSIZE_TO_POINTER ( wrk->pid), wrk); break; } return wrk; }
struct rspamd_worker * rspamd_fork_worker (struct rspamd_main *rspamd_main, struct rspamd_worker_conf *cf, guint index) { struct rspamd_worker *cur; /* Starting worker process */ cur = (struct rspamd_worker *) g_malloc0 (sizeof (struct rspamd_worker)); if (!rspamd_socketpair (cur->control_pipe)) { msg_err ("socketpair failure: %s", strerror (errno)); exit (-errno); } cur->srv = rspamd_main; cur->type = cf->type; cur->cf = g_malloc (sizeof (struct rspamd_worker_conf)); memcpy (cur->cf, cf, sizeof (struct rspamd_worker_conf)); cur->index = index; cur->ctx = cf->ctx; cur->pid = fork (); switch (cur->pid) { case 0: /* Update pid for logging */ rspamd_log_update_pid (cf->type, rspamd_main->logger); /* Lock statfile pool if possible XXX */ /* Init PRNG after fork */ ottery_init (NULL); g_random_set_seed (ottery_rand_uint32 ()); /* Drop privilleges */ rspamd_worker_drop_priv (rspamd_main); /* Set limits */ rspamd_worker_set_limits (rspamd_main, cf); setproctitle ("%s process", cf->worker->name); rspamd_pidfile_close (rspamd_main->pfh); /* Do silent log reopen to avoid collisions */ rspamd_log_close (rspamd_main->logger); rspamd_log_open (rspamd_main->logger); cur->start_time = rspamd_get_calendar_ticks (); #if ((GLIB_MAJOR_VERSION == 2) && (GLIB_MINOR_VERSION <= 30)) # if (GLIB_MINOR_VERSION > 20) /* Ugly hack for old glib */ if (!g_thread_get_initialized ()) { g_thread_init (NULL); } # else g_thread_init (NULL); # endif #endif msg_info_main ("starting %s process %P", cf->worker->name, getpid ()); /* Close parent part of socketpair */ close (cur->control_pipe[0]); rspamd_socket_nonblocking (cur->control_pipe[1]); /* Execute worker */ cf->worker->worker_start_func (cur); break; case -1: msg_err_main ("cannot fork main process. %s", strerror (errno)); rspamd_pidfile_remove (rspamd_main->pfh); exit (-errno); break; default: /* Close worker part of socketpair */ close (cur->control_pipe[1]); rspamd_socket_nonblocking (cur->control_pipe[0]); /* Insert worker into worker's table, pid is index */ g_hash_table_insert (rspamd_main->workers, GSIZE_TO_POINTER ( cur->pid), cur); break; } return cur; }
void rspamd_rrd_test_func () { gchar tmpfile[PATH_MAX]; struct rrd_rra_def rra[4]; struct rrd_ds_def ds[2]; GArray ar; GError *err = NULL; struct rspamd_rrd_file *rrd; gdouble ticks; gint i; gdouble t[2], cnt = 0.0; rspamd_snprintf (tmpfile, sizeof (tmpfile), "/tmp/rspamd_rrd.rrd"); unlink (tmpfile); /* Create sample rrd */ ticks = rspamd_get_calendar_ticks (); g_assert ((rrd = rspamd_rrd_create (tmpfile, 2, 4, 1, ticks, &err)) != NULL); /* Add RRA */ rrd_make_default_rra ("AVERAGE", pdp_per_cdp, rows_cnt, &rra[0]); rrd_make_default_rra ("AVERAGE", pdp_per_cdp / 2, rows_cnt, &rra[1]); rrd_make_default_rra ("AVERAGE", pdp_per_cdp / 4, rows_cnt, &rra[2]); rrd_make_default_rra ("AVERAGE", pdp_per_cdp / 10, rows_cnt, &rra[3]); ar.data = rra; ar.len = sizeof (rra); g_assert (rspamd_rrd_add_rra (rrd, &ar, &err)); /* Add DS */ rrd_make_default_ds ("test", "COUNTER", 1, &ds[0]); rrd_make_default_ds ("test1", "COUNTER", 1, &ds[1]); ar.data = ds; ar.len = sizeof (ds); g_assert (rspamd_rrd_add_ds (rrd, &ar, &err)); /* Finalize */ g_assert (rspamd_rrd_finalize (rrd, &err)); /* Close */ rspamd_rrd_close (rrd); /* Reopen */ g_assert ((rrd = rspamd_rrd_open (tmpfile, &err)) != NULL); /* Add some points */ for (i = 0; i < pdp_per_cdp * rows_cnt / 2; i ++) { t[0] = i; t[1] = cnt ++; ar.data = t; ar.len = sizeof (t); ticks += 1.0; g_assert (rspamd_rrd_add_record (rrd, &ar, ticks, &err)); } /* Add some more points */ for (i = 0; i < pdp_per_cdp * rows_cnt / 4; i ++) { t[0] = i + rspamd_time_jitter (1.0, 0.0); t[1] = cnt ++; ar.data = t; ar.len = sizeof (t); ticks += 1.0; g_assert (rspamd_rrd_add_record (rrd, &ar, ticks, &err)); } /* Add undefined interval */ ticks += 200; /* Add some more points */ for (i = 0; i < pdp_per_cdp * rows_cnt / 8; i ++) { t[0] = i; t[1] = cnt ++; ar.data = t; ar.len = sizeof (t); ticks += 1.0; g_assert (rspamd_rrd_add_record (rrd, &ar, ticks, &err)); } /* Finish */ rspamd_rrd_close (rrd); /* unlink (tmpfile); */ }