struct Admin* Admin_new(Dict* config, char* user, struct event_base* eventBase, struct ExceptionHandler* eh, struct Allocator* allocator) { errno = 0; int pipes[2][2]; if (pipe(pipes[0]) || pipe(pipes[1])) { eh->exception(__FILE__ " Failed to create pipes.", errno, eh); } int pgid = getpid(); int pid = fork(); if (pid < 0) { eh->exception(__FILE__ " Failed to fork()", errno, eh); } bool isChild = (pid == 0); int inFd = pipes[isChild][0]; close(pipes[!isChild][0]); int outFd = pipes[!isChild][1]; close(pipes[isChild][1]); if (isChild) { // Set the process group so that children will not // become orphaned if the parent gets signal 11 err um 9. setpgid(0, pgid); if (user) { Security_setUser(user, NULL, AbortHandler_INSTANCE); } struct ChildContext context; memset(&context, 0, sizeof(struct ChildContext)); context.inFd = inFd; context.outFd = outFd; context.allocator = allocator; event_reinit(eventBase); context.eventBase = eventBase; child(config, &context); exit(0); } setpgid(pid, pgid); struct Admin* admin = allocator->calloc(sizeof(struct Admin), 1, allocator); admin->inFd = inFd; admin->outFd = outFd; admin->allocator = allocator; admin->functionCount = 0; admin->eventBase = eventBase; admin->password = Dict_getString(config, BSTR("password")); admin->pipeEv = event_new(eventBase, inFd, EV_READ | EV_PERSIST, inFromChild, admin); event_add(admin->pipeEv, NULL); return admin; }
static void thread_basic(void *arg) { THREAD_T threads[NUM_THREADS]; struct event ev; struct timeval tv; int i; struct basic_test_data *data = arg; struct event_base *base = data->base; struct event *notification_event = NULL; struct event *sigchld_event = NULL; EVTHREAD_ALLOC_LOCK(count_lock, 0); tt_assert(count_lock); tt_assert(base); if (evthread_make_base_notifiable(base)<0) { tt_abort_msg("Couldn't make base notifiable!"); } #ifndef WIN32 if (data->setup_data && !strcmp(data->setup_data, "forking")) { pid_t pid; int status; sigchld_event = evsignal_new(base, SIGCHLD, sigchld_cb, base); /* This piggybacks on the th_notify_fd weirdly, and looks * inside libevent internals. Not a good idea in non-testing * code! */ notification_event = event_new(base, base->th_notify_fd[0], EV_READ|EV_PERSIST, notify_fd_cb, NULL); event_add(sigchld_event, NULL); event_add(notification_event, NULL); if ((pid = fork()) == 0) { event_del(notification_event); if (event_reinit(base) < 0) { TT_FAIL(("reinit")); exit(1); } event_assign(notification_event, base, base->th_notify_fd[0], EV_READ|EV_PERSIST, notify_fd_cb, NULL); event_add(notification_event, NULL); goto child; } event_base_dispatch(base); if (waitpid(pid, &status, 0) == -1) tt_abort_perror("waitpid"); TT_BLATHER(("Waitpid okay\n")); tt_assert(got_sigchld); tt_int_op(notification_fd_used, ==, 0); goto end; }
int server_start(struct server *s) { int i, ret; /* initialize libevent */ s->base = event_base_new(); if(s->cfg->daemonize) { server_daemonize(s->cfg->pidfile); /* sometimes event mech gets lost on fork */ if(event_reinit(s->base) != 0) { fprintf(stderr, "Error: event_reinit failed after fork"); } } /* ignore sigpipe */ #ifdef SIGPIPE signal(SIGPIPE, SIG_IGN); #endif slog_init(s); /* install signal handlers */ server_install_signal_handlers(s); /* start worker threads */ for(i = 0; i < s->cfg->http_threads; ++i) { worker_start(s->w[i]); } /* create socket */ s->fd = socket_setup(s, s->cfg->http_host, s->cfg->http_port); if(s->fd < 0) { return -1; } /*set keepalive socket option to do with half connection*/ int keep_alive = 1; setsockopt(s->fd , SOL_SOCKET, SO_KEEPALIVE, (void*)&keep_alive, sizeof(keep_alive)); /* start http server */ event_set(&s->ev, s->fd, EV_READ | EV_PERSIST, server_can_accept, s); event_base_set(s->base, &s->ev); ret = event_add(&s->ev, NULL); if(ret < 0) { slog(s, WEBDIS_ERROR, "Error calling event_add on socket", 0); return -1; } slog(s, WEBDIS_INFO, "Webdis " WEBDIS_VERSION " up and running", 0); event_base_dispatch(s->base); return 0; }
int main(int argc, char **argv) { int r, l; struct event_base *ev_base; struct job binlog_jobs = {}; progname = argv[0]; opts(argc, argv); if (detach && binlog_dir) { if (binlog_dir[0] != '/') { warnx("The -b option requires an absolute path when used with -d."); usage("Path is not absolute", binlog_dir); } } job_init(); prot_init(); /* We want to make sure that only one beanstalkd tries to use the binlog * directory at a time. So acquire a lock now and never release it. */ if (binlog_dir) { r = binlog_lock(); if (!r) twarnx("failed to lock binlog dir %s", binlog_dir), exit(10); } r = make_server_socket(host_addr, port); if (r == -1) twarnx("make_server_socket()"), exit(111); l = r; if (user) su(user); ev_base = event_init(); set_sig_handlers(); nudge_fd_limit(); r = listen(l, 1024); if (r == -1) twarn("listen()"); accept_handler = (evh)h_accept; unbrake(); binlog_jobs.prev = binlog_jobs.next = &binlog_jobs; binlog_init(&binlog_jobs); prot_replay_binlog(&binlog_jobs); if (detach) { daemonize(); event_reinit(ev_base); } event_dispatch(); twarnx("event_dispatch error"); binlog_shutdown(); return 0; }
int server_start(struct server *s) { int i, ret; /* setrlimit */ server_setrlimit(8192); /* daemonize */ if (s->cfg->daemonize) { server_daemonize(s->cfg->pid); /* sometimes event mech gets lost on fork */ if (event_reinit(s->base) != 0) { fprintf(stderr, "Error: event_reinit failed after fork"); } } /* ignore sigpipe */ #ifdef SIGPIPE signal(SIGPIPE, SIG_IGN); #endif /* lose root privileges if we have them */ /*ret = server_setuid(s->cfg->user); if(ret < 0) { return -1; }*/ /* slog init */ slog_init(s); /* install signal handlers */ server_install_signal_handlers(s); /* initialize libevent */ s->base = event_base_new(); /* start worker threads */ for (i = 0; i < s->cfg->worker_processes; ++i) { worker_start(s->w[i]); } /* create socket */ ret = socket_setup(s, s->cfg->http.servers); if(ret < 0) { return -1; } /* dispatch */ slog(s, LOG_INFO, "pbiws " PBIWS_VERSION " up and running", 0); event_base_dispatch(s->base); return 0; }
struct tmuxproc * proc_start(const char *name, struct event_base *base, int forkflag, void (*signalcb)(int)) { struct tmuxproc *tp; struct utsname u; #ifdef TMATE_SLAVE if (forkflag) fatal("can't fork"); #else if (forkflag) { switch (fork()) { case -1: fatal("fork failed"); case 0: break; default: return (NULL); } if (daemon(1, 0) != 0) fatal("daemon failed"); clear_signals(0); if (event_reinit(base) != 0) fatalx("event_reinit failed"); } log_open(name); #endif #ifdef HAVE_SETPROCTITLE setproctitle("%s (%s)", name, socket_path); #endif if (uname(&u) < 0) memset(&u, 0, sizeof u); log_debug("%s started (%ld): socket %s, protocol %d", name, (long)getpid(), socket_path, PROTOCOL_VERSION); log_debug("on %s %s %s; libevent %s (%s)", u.sysname, u.release, u.version, event_get_version(), event_get_method()); tp = xcalloc(1, sizeof *tp); tp->name = xstrdup(name); #ifndef TMATE_SLAVE tp->signalcb = signalcb; set_signals(proc_signal_cb, tp); #endif return (tp); }
int server_start(struct server *s) { int i, ret; /* initialize libevent */ s->base = event_base_new(); if(s->cfg->daemonize) { server_daemonize(); /* sometimes event mech gets lost on fork */ if(event_reinit(s->base) != 0) { fprintf(stderr, "Error: event_reinit failed after fork"); } } /* ignore sigpipe */ #ifdef SIGPIPE signal(SIGPIPE, SIG_IGN); #endif slog_init(s); /* start worker threads */ for(i = 0; i < s->cfg->http_threads; ++i) { worker_start(s->w[i]); } /* create socket */ s->fd = socket_setup(s->cfg->http_host, s->cfg->http_port); if(s->fd < 0) { return -1; } /* start http server */ event_set(&s->ev, s->fd, EV_READ | EV_PERSIST, server_can_accept, s); event_base_set(s->base, &s->ev); ret = event_add(&s->ev, NULL); if(ret < 0) { slog(s, WEBDIS_ERROR, "Error calling event_add on socket", 0); return -1; } event_base_dispatch(s->base); return 0; }
int CXtReactor::Reinit(void) { /* Call for after fork */ int nRet = FUN_RET_OK; if ( m_pEvtBase == NULL ) { return FUN_RET_ERR_ILLEGAL_CALL; } nRet = event_reinit( m_pEvtBase ); if ( nRet < 0 ) { return XT_REACT_INIT_FAIL; } return FUN_RET_OK; }
struct tmuxproc * proc_start(const char *name, struct event_base *base, int forkflag, void (*signalcb)(int)) { struct tmuxproc *tp; if (forkflag) { switch (fork()) { case -1: fatal("fork failed"); case 0: break; default: return (NULL); } if (daemon(1, 0) != 0) fatal("daemon failed"); clear_signals(0); if (event_reinit(base) != 0) fatalx("event_reinit failed"); } logfile(name); #ifdef HAVE_SETPROCTITLE setproctitle("%s (%s)", name, socket_path); #endif log_debug("%s started (%ld): socket %s, protocol %d", name, (long)getpid(), socket_path, PROTOCOL_VERSION); tp = xcalloc(1, sizeof *tp); tp->name = xstrdup(name); tp->signalcb = signalcb; set_signals(proc_signal_cb, tp); return (tp); }
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; }
void HttpServer::start(int port, int workers){ struct event_base *base; struct sockaddr_in sin; struct evconnlistener *listener; if(!port){ port = DEFAULT_PORT; } if(!workers){ workers = WORKERS_COUNT; } base = event_base_new(); if (!base) { throw std::runtime_error("Can't create base"); } memset(&sin, 0, sizeof(sin)); // setting IPv4 family addresses and localhost sin.sin_family = AF_INET; sin.sin_addr.s_addr = inet_addr("127.0.0.1"); // setting port sin.sin_port = htons(port); /* struct evconnlistener *evconnlistener_new_bind(struct event_base *base, evconnlistener_cb cb, void *ptr, unsigned flags, int backlog, const struct sockaddr *sa, int socklen); */ listener = evconnlistener_new_bind(base, connectionCallback, nullptr, LEV_OPT_CLOSE_ON_FREE|LEV_OPT_REUSEABLE, 1024, (struct sockaddr*) &sin, sizeof(sin)); if(listener == NULL){ event_base_free(base); throw std::runtime_error("Couldn't bind port"); } /* Fork mechanism */ for(int i=0; i<workers-1; i++){ pid_t pid = fork(); if (pid == 0) { std::cout<<"child process started. pid: " << getpid() << std::endl; event_reinit(base); } else if (pid > 0) { // parent process break; } else { // fork failed std::cout<<"fork failed!\n"; } } evconnlistener_set_error_cb(listener, errorCallback); event_base_dispatch(base); event_base_free(base); return; }
void Admin_sendMessage(Dict* message, String* txid, struct Admin* admin) { if (!admin) { return; } Assert_true(txid); uint8_t buff[MAX_API_REQUEST_SIZE + TXID_LEN]; // Write the inter-process txid. Bits_memcpyConst(buff, txid->bytes, TXID_LEN); uint8_t allocBuff[256]; struct Allocator* allocator = BufferAllocator_new(allocBuff, 256); // Bounce back the user-supplied txid. String userTxid = { .bytes = txid->bytes + TXID_LEN, .len = txid->len - TXID_LEN }; if (txid->len > TXID_LEN) { Dict_putString(message, TXID, &userTxid, allocator); } struct Writer* w = ArrayWriter_new(buff + TXID_LEN, MAX_API_REQUEST_SIZE, allocator); StandardBencSerializer_get()->serializeDictionary(w, message); write(admin->outFd, buff, w->bytesWritten(w) + TXID_LEN); } struct Admin* Admin_new(struct sockaddr_storage* addr, int addrLen, String* password, char* user, struct event_base* eventBase, struct ExceptionHandler* eh, struct Log* logger, struct Allocator* allocator) { errno = 0; int pipes[2][2]; if (pipe(pipes[0]) || pipe(pipes[1])) { eh->exception(__FILE__ " Failed to create pipes.", errno, eh); } int pgid = getpid(); int pid = fork(); if (pid < 0) { eh->exception(__FILE__ " Failed to fork()", errno, eh); } bool isChild = (pid == 0); int inFd = pipes[isChild][0]; close(pipes[!isChild][0]); int outFd = pipes[!isChild][1]; close(pipes[isChild][1]); if (isChild) { // Set the process group so that children will not // become orphaned if the parent gets signal 11 err um 9. setpgid(0, pgid); if (user) { Security_setUser(user, NULL, AbortHandler_INSTANCE); } struct ChildContext context; memset(&context, 0, sizeof(struct ChildContext)); context.inFd = inFd; context.outFd = outFd; context.allocator = allocator; event_reinit(eventBase); context.eventBase = eventBase; child(addr, addrLen, user, &context); fprintf(stderr, "Admin process exiting."); exit(0); } setpgid(pid, pgid); struct Admin* admin = allocator->calloc(sizeof(struct Admin), 1, allocator); admin->inFd = inFd; admin->outFd = outFd; admin->allocator = allocator; admin->logger = logger; admin->functionCount = 0; admin->eventBase = eventBase; admin->password = password; Bits_memcpyConst(&admin->address, addr, sizeof(struct sockaddr_storage)); admin->addressLength = addrLen; admin->pipeEv = event_new(eventBase, inFd, EV_READ | EV_PERSIST, inFromChild, admin); event_add(admin->pipeEv, NULL); event_base_dispatch(eventBase); return admin; }
static void libevent_ctx_reinitialize(void *priv) { event_reinit(priv); }
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 worker(struct event_base *ev_base) { event_reinit(ev_base); event_base_dispatch(ev_base); }
int main(int argc, char **argv) { init_config(argc, argv); open_authorizations("r"); init_webfinger(); /** OPEN MAGIC DATABASE **/ magic_cookie = magic_open(MAGIC_MIME); if(magic_load(magic_cookie, RS_MAGIC_DATABASE) != 0) { log_error("Failed to load magic database: %s", magic_error(magic_cookie)); exit(EXIT_FAILURE); } log_info("starting process: main"); if(prctl(PR_SET_NAME, "rs-serve [main]", 0, 0, 0) != 0) { log_error("Failed to set process name: %s", strerror(errno)); } /** SETUP EVENT BASE **/ rs_event_base = event_base_new(); ASSERT_NOT_NULL(rs_event_base, "event_base_new()"); log_debug("libevent method: %s", event_base_get_method(rs_event_base)); event_set_log_callback(log_event_base_message); // TODO: add error cb to base /** SETUP AUTH TOKENS HASH TABLE **/ auth_sessions = sm_new(1024); // FIXME: this a hardcoded value. /** SETUP MAIN LISTENER **/ struct sockaddr_in sin; memset(&sin, 0, sizeof(struct sockaddr_in)); sin.sin_family = AF_INET; sin.sin_addr.s_addr = htonl(0); sin.sin_port = htons(RS_PORT); evhtp_t *server = evhtp_new(rs_event_base, NULL); if(RS_USE_SSL) { evhtp_ssl_cfg_t ssl_config = { .pemfile = RS_SSL_CERT_PATH, .privfile = RS_SSL_KEY_PATH, .cafile = RS_SSL_CA_PATH, // what's this??? .capath = NULL, .ciphers = "RC4+RSA:HIGH:+MEDIUM:+LOW", .ssl_opts = SSL_OP_NO_SSLv2, .ssl_ctx_timeout = 60*60*48, .verify_peer = SSL_VERIFY_PEER, .verify_depth = 42, .x509_verify_cb = dummy_ssl_verify_callback, .x509_chk_issued_cb = dummy_check_issued_cb, .scache_type = evhtp_ssl_scache_type_internal, .scache_size = 1024, .scache_timeout = 1024, .scache_init = NULL, .scache_add = NULL, .scache_get = NULL, .scache_del = NULL }; if(evhtp_ssl_init(server, &ssl_config) != 0) { log_error("evhtp_ssl_init() failed"); exit(EXIT_FAILURE); } } /* WEBFINGER */ evhtp_callback_cb webfinger_cb = (RS_WEBFINGER_ENABLED ? handle_webfinger : reject_webfinger); evhtp_set_cb(server, "/.well-known/webfinger", webfinger_cb, NULL); // support legacy webfinger clients (we don't support XRD though): evhtp_set_cb(server, "/.well-known/host-meta", webfinger_cb, NULL); evhtp_set_cb(server, "/.well-known/host-meta.json", webfinger_cb, NULL); /* REMOTESTORAGE */ evhtp_callback_t *storage_cb = evhtp_set_regex_cb(server, "^/storage/([^/]+)/.*$", handle_storage, NULL); evhtp_set_hook(&storage_cb->hooks, evhtp_hook_on_request_fini, finish_request, NULL); if(evhtp_bind_sockaddr(server, (struct sockaddr*)&sin, sizeof(sin), 1024) != 0) { log_error("evhtp_bind_sockaddr() failed: %s", strerror(errno)); exit(EXIT_FAILURE); } /** SETUP AUTH LISTENER **/ memset(&sin, 0, sizeof(struct sockaddr_in)); sin.sin_family = AF_INET; sin.sin_addr.s_addr = htonl(0); sin.sin_port = htons(RS_AUTH_PORT); evhtp_t *server_auth = evhtp_new(rs_event_base, NULL); if(RS_USE_SSL) { evhtp_ssl_cfg_t ssl_config = { .pemfile = RS_SSL_CERT_PATH, .privfile = RS_SSL_KEY_PATH, .cafile = RS_SSL_CA_PATH, // what's this??? .capath = NULL, .ciphers = "RC4+RSA:HIGH:+MEDIUM:+LOW", .ssl_opts = SSL_OP_NO_SSLv2, .ssl_ctx_timeout = 60*60*48, .verify_peer = SSL_VERIFY_PEER, .verify_depth = 42, .x509_verify_cb = dummy_ssl_verify_callback, .x509_chk_issued_cb = dummy_check_issued_cb, .scache_type = evhtp_ssl_scache_type_internal, .scache_size = 1024, .scache_timeout = 1024, .scache_init = NULL, .scache_add = NULL, .scache_get = NULL, .scache_del = NULL }; if(evhtp_ssl_init(server_auth, &ssl_config) != 0) { log_error("evhtp_ssl_init() failed"); exit(EXIT_FAILURE); } } /* AUTH */ evhtp_set_cb(server_auth, "/authenticate", handle_authenticate, NULL); evhtp_set_cb(server_auth, "/authorizations", handle_authorizations, NULL); evhtp_set_hook(&storage_cb->hooks, evhtp_hook_on_request_fini, finish_request, NULL); if(evhtp_bind_sockaddr(server_auth, (struct sockaddr*)&sin, sizeof(sin), 1024) != 0) { log_error("evhtp_bind_sockaddr() failed: %s", strerror(errno)); exit(EXIT_FAILURE); } /** SETUP SIGNALS **/ sigset_t sigmask; sigemptyset(&sigmask); sigaddset(&sigmask, SIGINT); sigaddset(&sigmask, SIGTERM); sigaddset(&sigmask, SIGCHLD); ASSERT_ZERO(sigprocmask(SIG_BLOCK, &sigmask, NULL), "sigprocmask()"); int sfd = signalfd(-1, &sigmask, SFD_NONBLOCK); ASSERT_NOT_EQ(sfd, -1, "signalfd()"); struct event *signal_event = event_new(rs_event_base, sfd, EV_READ | EV_PERSIST, handle_signal, NULL); event_add(signal_event, NULL); /** RUN EVENT LOOP **/ if(RS_DETACH) { int pid = fork(); if(pid == 0) { event_reinit(rs_event_base); if(RS_LOG_FILE == stdout) { log_warn("No --log-file option given. Future output will be lost."); freopen("/dev/null", "r", stdout); freopen("/dev/null", "r", stderr); } return event_base_dispatch(rs_event_base); } else { printf("rs-serve detached with pid %d\n", pid); if(RS_PID_FILE) { fprintf(RS_PID_FILE, "%d", pid); fflush(RS_PID_FILE); } _exit(EXIT_SUCCESS); } } else { if(RS_PID_FILE) { fprintf(RS_PID_FILE, "%d", getpid()); fflush(RS_PID_FILE); } return event_base_dispatch(rs_event_base); } }