int tor_init_libevent_rng(void) { int rv = 0; #ifdef HAVE_EVUTIL_SECURE_RNG_INIT char buf[256]; if (evutil_secure_rng_init() < 0) { rv = -1; } /* Older libevent -- manually initialize the RNG */ crypto_rand(buf, 32); evutil_secure_rng_add_bytes(buf, 32); evutil_secure_rng_get_bytes(buf, sizeof(buf)); #endif return rv; }
int main( int argc, char *argv[] ) { size_t i; int ret, opt, longIndex = 0; struct event *evsig_int; #ifdef _WIN32 WSADATA WSAData; #endif pthread_t tcp_thread, *job_threads; if ( evutil_secure_rng_init() < 0 ) { ED2KD_LOGERR("failed to seed random number generator"); return EXIT_FAILURE; } /* parse command line arguments */ opt = getopt_long( argc, argv, optString, longOpts, &longIndex ); while( opt != -1 ) { switch( opt ) { case 'v': display_version(); return EXIT_SUCCESS; case 'g': { unsigned char hash[ED2K_HASH_SIZE]; char hex_hash[sizeof(hash)*2+1]; get_random_user_hash(hash); bin2hex(hash, hex_hash, sizeof(hex_hash)); puts(hex_hash); return EXIT_SUCCESS; } case 'h': display_usage(); return EXIT_SUCCESS; default: return EXIT_FAILURE; } opt = getopt_long( argc, argv, optString, longOpts, &longIndex ); } #ifdef _WIN32 if ( 0 != WSAStartup(0x0201, &WSAData) ) { ED2KD_LOGERR("WSAStartup failed!"); return EXIT_FAILURE; } #endif if ( !server_load_config(NULL) ) { ED2KD_LOGERR("failed to load configuration file"); return EXIT_FAILURE; } display_libevent_info(); #ifdef EVTHREAD_USE_WINDOWS_THREADS_IMPLEMENTED ret = evthread_use_windows_threads(); #elif EVTHREAD_USE_PTHREADS_IMPLEMENTED ret = evthread_use_pthreads(); #else #error "unable to determine threading model" #endif if ( ret < 0 ) { ED2KD_LOGERR("failed to init libevent threading model"); return EXIT_FAILURE; } g_srv.evbase_main = event_base_new(); if ( NULL == g_srv.evbase_main ) { ED2KD_LOGERR("failed to create main event loop"); return EXIT_FAILURE; } g_srv.evbase_tcp = event_base_new(); if ( NULL == g_srv.evbase_tcp ) { ED2KD_LOGERR("failed to create tcp event loop"); return EXIT_FAILURE; } evsig_int = evsignal_new(g_srv.evbase_main, SIGINT, sigint_cb, NULL); evsignal_add(evsig_int, NULL); // common timers timevals g_srv.portcheck_timeout_tv = event_base_init_common_timeout(g_srv.evbase_tcp, &g_srv.cfg->portcheck_timeout_tv); g_srv.status_notify_tv = event_base_init_common_timeout(g_srv.evbase_tcp, &g_srv.cfg->status_notify_tv); if ( !db_create() ) { ED2KD_LOGERR("failed to create database"); return EXIT_FAILURE; } g_srv.thread_count = omp_get_num_procs() + 1; pthread_cond_init(&g_srv.job_cond, NULL); pthread_mutex_init(&g_srv.job_mutex, NULL); TAILQ_INIT(&g_srv.jqueue); job_threads = (pthread_t *)malloc(g_srv.thread_count * sizeof(*job_threads)); // start tcp worker threads for ( i=0; i<g_srv.thread_count; ++i ) { pthread_create(&job_threads[i], NULL, server_job_worker, NULL); } // start tcp dispatch thread pthread_create(&tcp_thread, NULL, server_base_worker, g_srv.evbase_tcp); // start tcp listen loop if ( !server_listen() ) { ED2KD_LOGERR("failed to start server listener"); server_stop(); } pthread_join(tcp_thread, NULL); while ( EBUSY == pthread_cond_destroy(&g_srv.job_cond) ) { pthread_cond_broadcast(&g_srv.job_cond); //pthread_yield(); } pthread_mutex_destroy(&g_srv.job_mutex); for ( i=0; i<g_srv.thread_count; ++i ) { pthread_join(job_threads[i], NULL); } free(job_threads); // todo: free job queue items evconnlistener_free(g_srv.tcp_listener); event_free(evsig_int); event_base_free(g_srv.evbase_tcp); event_base_free(g_srv.evbase_main); if ( db_destroy() < 0 ) { ED2KD_LOGERR("failed to destroy database"); } server_free_config(); return EXIT_SUCCESS; }
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; }
static gint lua_worker_spawn_process (lua_State *L) { struct rspamd_worker *w = lua_check_worker (L, 1); struct rspamd_lua_process_cbdata *cbdata; struct rspamd_abstract_worker_ctx *actx; struct rspamd_srv_command srv_cmd; const gchar *cmdline = NULL, *input = NULL; gsize inputlen = 0; pid_t pid; GError *err = NULL; gint func_cbref, cb_cbref; if (!rspamd_lua_parse_table_arguments (L, 2, &err, "func=F;exec=S;stdin=V;*on_complete=F", &func_cbref, &cmdline, &inputlen, &input, &cb_cbref)) { msg_err ("cannot get parameters list: %e", err); if (err) { g_error_free (err); } return 0; } cbdata = g_malloc0 (sizeof (*cbdata)); cbdata->cb_cbref = cb_cbref; cbdata->func_cbref = func_cbref; if (input) { cbdata->out_buf = g_string_new_len (input, inputlen); cbdata->out_pos = 0; } if (rspamd_socketpair (cbdata->sp, TRUE) == -1) { msg_err ("cannot spawn socketpair: %s", strerror (errno)); luaL_unref (L, LUA_REGISTRYINDEX, cbdata->func_cbref); luaL_unref (L, LUA_REGISTRYINDEX, cbdata->cb_cbref); g_free (cbdata); return 0; } actx = w->ctx; cbdata->wrk = w; cbdata->L = L; cbdata->ev_base = actx->ev_base; cbdata->sz = (guint64)-1; pid = fork (); if (pid == -1) { msg_err ("cannot spawn process: %s", strerror (errno)); close (cbdata->sp[0]); close (cbdata->sp[1]); luaL_unref (L, LUA_REGISTRYINDEX, cbdata->func_cbref); luaL_unref (L, LUA_REGISTRYINDEX, cbdata->cb_cbref); g_free (cbdata); return 0; } else if (pid == 0) { /* Child */ gint rc; gchar inbuf[4]; rspamd_log_update_pid (w->cf->type, w->srv->logger); rc = ottery_init (w->srv->cfg->libs_ctx->ottery_cfg); if (rc != OTTERY_ERR_NONE) { msg_err ("cannot initialize PRNG: %d", rc); abort (); } rspamd_random_seed_fast (); #ifdef HAVE_EVUTIL_RNG_INIT evutil_secure_rng_init (); #endif close (cbdata->sp[0]); /* Here we assume that we can block on writing results */ rspamd_socket_blocking (cbdata->sp[1]); event_reinit (cbdata->ev_base); g_hash_table_remove_all (w->signal_events); rspamd_worker_unblock_signals (); rspamd_lua_execute_lua_subprocess (L, cbdata); /* Wait for parent to reply and exit */ rc = read (cbdata->sp[1], inbuf, sizeof (inbuf)); if (memcmp (inbuf, "\0\0\0\0", 4) == 0) { exit (EXIT_SUCCESS); } else { msg_err ("got invalid reply from parent"); exit (EXIT_FAILURE); } } cbdata->cpid = pid; cbdata->io_buf = g_string_sized_new (8); /* Notify main */ memset (&srv_cmd, 0, sizeof (srv_cmd)); srv_cmd.type = RSPAMD_SRV_ON_FORK; srv_cmd.cmd.on_fork.state = child_create; srv_cmd.cmd.on_fork.cpid = pid; srv_cmd.cmd.on_fork.ppid = getpid (); rspamd_srv_send_command (w, cbdata->ev_base, &srv_cmd, -1, NULL, NULL); close (cbdata->sp[1]); rspamd_socket_nonblocking (cbdata->sp[0]); /* Parent */ rspamd_worker_set_signal_handler (SIGCHLD, w, cbdata->ev_base, rspamd_lua_cld_handler, cbdata); /* Add result pipe waiting */ event_set (&cbdata->ev, cbdata->sp[0], EV_READ | EV_PERSIST, rspamd_lua_subprocess_io, cbdata); event_base_set (cbdata->ev_base, &cbdata->ev); /* TODO: maybe add timeout? */ event_add (&cbdata->ev, NULL); return 0; }
int main(int argc, char **argv) { int error; app_subsys **ss; int exit_signals[2] = {SIGTERM, SIGINT}; struct event terminators[2]; bool conftest = false; int opt; int i; evutil_secure_rng_init(); while ((opt = getopt(argc, argv, "h?vtc:p:")) != -1) { switch (opt) { case 't': conftest = true; break; case 'c': confname = optarg; break; case 'p': pidfile = optarg; break; case 'v': puts(redsocks_version); printf("Built with libevent-%s\n", LIBEVENT_VERSION); printf("Runs with libevent-%s\n", event_get_version()); if (LIBEVENT_VERSION_NUMBER != event_get_version_number()) { printf("Warning: libevent version number mismatch.\n" " Headers: %8x\n" " Runtime: %8x\n", LIBEVENT_VERSION_NUMBER, event_get_version_number()); } return EXIT_SUCCESS; default: printf( "Usage: %s [-?hvt] [-c config] [-p pidfile]\n" " -h, -? this message\n" " -v print version\n" " -t test config syntax\n" " -p write pid to pidfile\n", argv[0]); return (opt == '?' || opt == 'h') ? EXIT_SUCCESS : EXIT_FAILURE; } } if (event_get_struct_event_size() != sizeof(struct event)) { puts("libevent event_get_struct_event_size() != sizeof(struct event)! Check `redsocks -v` and recompile redsocks"); return EXIT_FAILURE; } FILE *f = fopen(confname, "r"); if (!f) { perror("Unable to open config file"); return EXIT_FAILURE; } parser_context* parser = parser_start(f); if (!parser) { perror("Not enough memory for parser"); return EXIT_FAILURE; } FOREACH(ss, subsystems) if ((*ss)->conf_section) parser_add_section(parser, (*ss)->conf_section); error = parser_run(parser); parser_stop(parser); fclose(f); if (error) return EXIT_FAILURE; if (conftest) return EXIT_SUCCESS; struct event_base* evbase = event_init(); memset(terminators, 0, sizeof(terminators)); FOREACH(ss, subsystems) { if ((*ss)->init) { error = (*ss)->init(evbase); if (error) goto shutdown; } } if (pidfile) { f = fopen(pidfile, "w"); if (!f) { perror("Unable to open pidfile for write"); return EXIT_FAILURE; } fprintf(f, "%d\n", getpid()); fclose(f); } assert(SIZEOF_ARRAY(exit_signals) == SIZEOF_ARRAY(terminators)); for (i = 0; i < SIZEOF_ARRAY(exit_signals); i++) { signal_set(&terminators[i], exit_signals[i], terminate, NULL); if (signal_add(&terminators[i], NULL) != 0) { log_errno(LOG_ERR, "signal_add"); goto shutdown; } } if (LIBEVENT_VERSION_NUMBER != event_get_version_number()) { log_error(LOG_WARNING, "libevent version mismatch! headers %8x, runtime %8x\n", LIBEVENT_VERSION_NUMBER, event_get_version_number()); } log_error(LOG_NOTICE, "redsocks started, conn_max=%u", redsocks_conn_max()); event_dispatch(); log_error(LOG_NOTICE, "redsocks goes down"); shutdown: for (i = 0; i < SIZEOF_ARRAY(exit_signals); i++) { if (signal_initialized(&terminators[i])) { if (signal_del(&terminators[i]) != 0) log_errno(LOG_WARNING, "signal_del"); memset(&terminators[i], 0, sizeof(terminators[i])); } } for (--ss; ss >= subsystems; ss--) if ((*ss)->fini) (*ss)->fini(); event_base_free(evbase); return !error ? EXIT_SUCCESS : EXIT_FAILURE; }