Esempio n. 1
0
EVQ_API int
evq_del (struct event *ev, const int reuse_fd)
{
  struct event_queue *evq = ev->evq;
  const unsigned int ev_flags = ev->flags;

  if (ev->tq) timeout_del(ev);

  ev->evq = NULL;
  evq->nevents--;

  if (ev_flags & EVENT_TIMER) return 0;

  if (ev_flags & EVENT_SIGNAL)
    return signal_del(evq, ev);

  if (ev_flags & EVENT_DIRWATCH)
    return close(ev->fd);

  if (!reuse_fd) return 0;

  return ((ev_flags & EVENT_READ)
    ? kqueue_set(evq, ev, EVFILT_READ, EV_DELETE) : 0)
   | ((ev_flags & EVENT_WRITE)
    ? kqueue_set(evq, ev, EVFILT_WRITE, EV_DELETE) : 0);
}
Esempio n. 2
0
void
proc_clear_signals(struct tmuxproc *tp, int defaults)
{
	struct sigaction	sa;

	memset(&sa, 0, sizeof sa);
	sigemptyset(&sa.sa_mask);
	sa.sa_flags = SA_RESTART;
	sa.sa_handler = SIG_DFL;

	sigaction(SIGINT, &sa, NULL);
	sigaction(SIGPIPE, &sa, NULL);
	sigaction(SIGTSTP, &sa, NULL);

	signal_del(&tp->ev_sighup);
	signal_del(&tp->ev_sigchld);
	signal_del(&tp->ev_sigcont);
	signal_del(&tp->ev_sigterm);
	signal_del(&tp->ev_sigusr1);
	signal_del(&tp->ev_sigusr2);
	signal_del(&tp->ev_sigwinch);

	if (defaults) {
		sigaction(SIGHUP, &sa, NULL);
		sigaction(SIGCHLD, &sa, NULL);
		sigaction(SIGCONT, &sa, NULL);
		sigaction(SIGTERM, &sa, NULL);
		sigaction(SIGUSR1, &sa, NULL);
		sigaction(SIGUSR2, &sa, NULL);
		sigaction(SIGWINCH, &sa, NULL);
	}
}
Esempio n. 3
0
static void
primwatch_terminate(
    int fd,
    short event,
    void *args)
{
	primwatch_t *primwatch = args;

	if (controller_stop(primwatch->controller)) {
		LOG(LOG_LV_WARNING, "failed in stop controller");
	}
	if (watcher_polling_stop(primwatch->watcher)) {
		LOG(LOG_LV_WARNING, "failed in stop polling");
	}
     	signal_del(&primwatch->sig_chld_event);
     	signal_del(&primwatch->sig_int_event);
     	signal_del(&primwatch->sig_term_event);
     	signal_del(&primwatch->sig_hup_event);
}
Esempio n. 4
0
File: poll.c Progetto: ezdiy/luasys
EVQ_API int
evq_del (struct event *ev, int reuse_fd)
{
    struct event_queue *evq = ev->evq;
    const unsigned int ev_flags = ev->flags;
    unsigned int npolls;
    int i;

    (void) reuse_fd;

    if (ev->tq) timeout_del(ev);

    ev->evq = NULL;
    evq->nevents--;

    if (ev_flags & EVENT_TIMER) return 0;

    if (ev_flags & EVENT_SIGNAL)
	return signal_del(evq, ev);

    npolls = --evq->npolls;
    if (ev->index < npolls) {
	struct event **events = evq->events;

	i = ev->index;
	events[i] = events[npolls];
	events[i]->index = i;
	evq->fdset[i] = evq->fdset[npolls];
    }

    if (npolls > NEVENT / 2 && npolls <= evq->max_polls / 4) {
	void *p;

	i = (evq->max_polls /= 2);
	if ((p = realloc(evq->events, i * sizeof(void *))))
	    evq->events = p;
	if ((p = realloc(evq->fdset, i * sizeof(struct pollfd))))
	    evq->fdset = p;
    }
    return 0;
}
Esempio n. 5
0
EVQ_API int
evq_del (struct event *ev, int reuse_fd)
{
  struct event_queue *evq = ev->evq;
  const unsigned int ev_flags = ev->flags;

  (void) reuse_fd;

  if (ev->tq) timeout_del(ev);

  ev->evq = NULL;
  evq->nevents--;

  if (ev_flags & EVENT_TIMER) return 0;

  if (ev_flags & EVENT_SIGNAL)
    return signal_del(evq, ev);

  {
    const unsigned int fd = (unsigned int) ev->fd;

    if (ev_flags & EVENT_READ)
      FD_CLR(fd, &evq->readset);
    else
      FD_CLR(fd, &evq->writeset);

    if (evq->max_fd == fd)
      evq->max_fd = -1;
  }

  if (ev->index < --evq->npolls) {
    struct event **events = evq->events;
    const int i = ev->index;

    events[i] = events[evq->npolls];
    events[i]->index = i;
  }
  return 0;
}
Esempio n. 6
0
EVQ_API int
evq_del (struct event *ev, const int reuse_fd)
{
    struct win32thr *wth = ev->wth;
    const unsigned int ev_flags = ev->flags;

    (void) reuse_fd;

    if (ev_flags & (EVENT_TIMER | EVENT_AIO | EVENT_SIGNAL | EVENT_WINMSG)) {
	struct event_queue *evq = wth->evq;

	if (ev->tq) timeout_del(ev);

	ev->wth = NULL;
	evq->nevents--;

	if (ev_flags & EVENT_AIO) {
	    if (ev_flags & EVENT_PENDING)
		win32iocp_cancel(ev, (EVENT_READ | EVENT_WRITE));
	    evq->iocp.n--;
	    return 0;
	}

	if (ev_flags & EVENT_SIGNAL)
	    return signal_del(ev);

	if (ev_flags & EVENT_WINMSG)
	    evq->win_msg = NULL;

	/* EVENT_TIMER */
	return 0;
    }

    if (!(ev_flags & EVENT_ACTIVE))
	win32thr_sleep(wth);

    return win32thr_del(wth, ev);
}
Esempio n. 7
0
static void
child_handler(struct signal_event *ev)
{
	struct scan_peer *peer;
	int status;

	if (waitpid(child_pid, &status, WNOHANG) == -1) {
		if (errno == ECHILD)
			return;
		err(1, "Could not wait for child");
	}
	if (status != 0)
		err(1, "Start script failed");

	clients_started = 1;
	signal_del(ev);

	while ((peer = LIST_FIRST(&inactive_peers)) != NULL) {
		LIST_REMOVE(peer, peer_link);
		assign_job(peer);
		if (peer-> job == NULL)
			break;
	}
}
Esempio n. 8
0
int chassis_mainloop(void *_chas) {
    chassis *chas = _chas;
    guint i;
    struct event ev_sigterm, ev_sigint;
#ifdef SIGHUP
    struct event ev_sighup;
#endif
    chassis_event_thread_t *mainloop_thread;

    /* redirect logging from libevent to glib */
    event_set_log_callback(event_log_use_glib);


    /* add a event-handler for the "main" events */
    mainloop_thread = chassis_event_thread_new(0);
    chassis_event_threads_init_thread(mainloop_thread, chas);
    g_ptr_array_add(chas->threads, mainloop_thread);

    chas->event_base = mainloop_thread->event_base; /* all global events go to the 1st thread */

    g_assert(chas->event_base);


    /* setup all plugins all plugins */
    for (i = 0; i < chas->modules->len; i++) {
        chassis_plugin *p = chas->modules->pdata[i];

        g_assert(p->apply_config);
        if (0 != p->apply_config(chas, p->config)) {
            g_critical("%s: applying config of plugin %s failed",
                    G_STRLOC, p->name);
            return -1;
        }
    }

    signal_set(&ev_sigterm, SIGTERM, sigterm_handler, NULL);
    event_base_set(chas->event_base, &ev_sigterm);
    signal_add(&ev_sigterm, NULL);

    signal_set(&ev_sigint, SIGINT, sigint_handler, NULL);
    event_base_set(chas->event_base, &ev_sigint);
    signal_add(&ev_sigint, NULL);

#ifdef SIGHUP
    signal_set(&ev_sighup, SIGHUP, sighup_handler, chas);
    event_base_set(chas->event_base, &ev_sighup);
    if (signal_add(&ev_sighup, NULL)) {
        g_critical("%s: signal_add(SIGHUP) failed", G_STRLOC);
    }
#endif

    if (chas->event_thread_count < 1) chas->event_thread_count = 1;

    /* create the event-threads
     *
     * - dup the async-queue-ping-fds
     * - setup the events notification
     * */
    for (i = 1; i <= (guint)chas->event_thread_count; i++) { /* we already have 1 event-thread running, the main-thread */
        chassis_event_thread_t *thread = chassis_event_thread_new(i);

        chassis_event_threads_init_thread(thread, chas);

        g_ptr_array_add(chas->threads, thread);
    }

    /* start the event threads */
    chassis_event_threads_start(chas->threads);

    /**
     * handle signals and all basic events into the main-thread
     *
     * block until we are asked to shutdown
     */
    chassis_mainloop_thread_loop(mainloop_thread);

    signal_del(&ev_sigterm);
    signal_del(&ev_sigint);
#ifdef SIGHUP
    signal_del(&ev_sighup);
#endif
    return 0;
}
Esempio n. 9
0
int chassis_mainloop(void *_chas) {
	chassis *chas = _chas;
	guint i;
	struct event ev_sigterm, ev_sigint;
#ifdef SIGHUP
	struct event ev_sighup;
#endif
	chassis_event_thread_t *mainloop_thread;

	/* redirect logging from libevent to glib */
	event_set_log_callback(event_log_use_glib);


	/* add a event-handler for the "main" events */
	mainloop_thread = chassis_event_thread_new();
	chassis_event_threads_init_thread(chas->threads, mainloop_thread, chas);
	chassis_event_threads_add(chas->threads, mainloop_thread);

	//add by Vinchn

	chas->event_base = mainloop_thread->event_base; /* all global events go to the 1st thread */

	g_assert(chas->event_base);


	/* setup all plugins all plugins */
	for (i = 0; i < chas->modules->len; i++) {
		chassis_plugin *p = chas->modules->pdata[i];

		g_assert(p->apply_config);
		if (0 != p->apply_config(chas, p->config)) {
			g_critical("%s: applying config of plugin %s failed",
					G_STRLOC, p->name);
			return -1;
		}
	}

	/*
	 * drop root privileges if requested
	 */
#ifndef _WIN32
	if (chas->user) {
		struct passwd *user_info;
		uid_t user_id= geteuid();

		/* Don't bother if we aren't superuser */
		if (user_id) {
			g_critical("can only use the --user switch if running as root");
			return -1;
		}

		if (NULL == (user_info = getpwnam(chas->user))) {
			g_critical("unknown user: %s", chas->user);
			return -1;
		}

		if (chas->log->log_filename) {
			/* chown logfile */
			if (-1 == chown(chas->log->log_filename, user_info->pw_uid, user_info->pw_gid)) {
				g_critical("%s.%d: chown(%s) failed: %s",
							__FILE__, __LINE__,
							chas->log->log_filename,
							g_strerror(errno) );

				return -1;
			}
		}

		setgid(user_info->pw_gid);
		setuid(user_info->pw_uid);
		g_debug("now running as user: %s (%d/%d)",
				chas->user,
				user_info->pw_uid,
				user_info->pw_gid );
	}
#endif

	signal_set(&ev_sigterm, SIGTERM, sigterm_handler, NULL);
	event_base_set(chas->event_base, &ev_sigterm);
	signal_add(&ev_sigterm, NULL);

	signal_set(&ev_sigint, SIGINT, sigterm_handler, NULL);
	event_base_set(chas->event_base, &ev_sigint);
	signal_add(&ev_sigint, NULL);

#ifdef SIGHUP
	signal_set(&ev_sighup, SIGHUP, sighup_handler, chas);
	event_base_set(chas->event_base, &ev_sighup);
	if (signal_add(&ev_sighup, NULL)) {
		g_critical("%s: signal_add(SIGHUP) failed", G_STRLOC);
	}
#endif

	if (chas->event_thread_count < 1) chas->event_thread_count = 1;

	/* create the event-threads
	 *
	 * - dup the async-queue-ping-fds
	 * - setup the events notification
	 * */
	for (i = 1; i < (guint)chas->event_thread_count; i++) { /* we already have 1 event-thread running, the main-thread */
		chassis_event_thread_t *event_thread;
	
		event_thread = chassis_event_thread_new();
		chassis_event_threads_init_thread(chas->threads, event_thread, chas);
		chassis_event_threads_add(chas->threads, event_thread);
	}

	/* start the event threads */
	if (chas->event_thread_count > 1) {
		chassis_event_threads_start(chas->threads);
	}

	/**
	 * handle signals and all basic events into the main-thread
	 *
	 * block until we are asked to shutdown
	 */
	chassis_event_thread_loop(mainloop_thread);

	signal_del(&ev_sigterm);
	signal_del(&ev_sigint);
#ifdef SIGHUP
	signal_del(&ev_sighup);
#endif
	return 0;
}
Esempio n. 10
0
void dect_event_ops_cleanup(void)
{
	signal_del(&sig_event);
	event_base_free(ev_base);
}
Esempio n. 11
0
int
ub_signal_del(struct ub_event* ev)
{
	return signal_del(AS_EVENT(ev));
}
Esempio n. 12
0
File: net.c Progetto: dolfly/nmdb
void net_loop(void)
{
	int tipc_fd = -1;
	int tcp_fd = -1;
	int udp_fd = -1;
	int sctp_fd = -1;
	struct event tipc_evt, tcp_evt, udp_evt, sctp_evt,
		     sigterm_evt, sigint_evt,
		     sighup_evt, sigusr1_evt, sigusr2_evt;

	event_init();

	/* ENABLE_* are preprocessor constants defined on the command line by
	 * make. */

	if (ENABLE_TIPC) {
		tipc_fd = tipc_init();
		if (tipc_fd < 0) {
			errlog("Error initializing TIPC");
			exit(1);
		}

		event_set(&tipc_evt, tipc_fd, EV_READ | EV_PERSIST, tipc_recv,
				&tipc_evt);
		event_add(&tipc_evt, NULL);
	}

	if (ENABLE_TCP) {
		tcp_fd = tcp_init();
		if (tcp_fd < 0) {
			errlog("Error initializing TCP");
			exit(1);
		}

		event_set(&tcp_evt, tcp_fd, EV_READ | EV_PERSIST,
				tcp_newconnection, &tcp_evt);
		event_add(&tcp_evt, NULL);
	}

	if (ENABLE_UDP) {
		udp_fd = udp_init();
		if (udp_fd < 0) {
			errlog("Error initializing UDP");
			exit(1);
		}

		event_set(&udp_evt, udp_fd, EV_READ | EV_PERSIST, udp_recv,
				&udp_evt);
		event_add(&udp_evt, NULL);
	}

	if (ENABLE_SCTP) {
		sctp_fd = sctp_init();
		if (sctp_fd < 0) {
			errlog("Error initializing SCTP");
			exit(1);
		}

		event_set(&sctp_evt, sctp_fd, EV_READ | EV_PERSIST, sctp_recv,
				&sctp_evt);
		event_add(&sctp_evt, NULL);
	}

	signal_set(&sigterm_evt, SIGTERM, exit_sighandler, &sigterm_evt);
	signal_add(&sigterm_evt, NULL);
	signal_set(&sigint_evt, SIGINT, exit_sighandler, &sigint_evt);
	signal_add(&sigint_evt, NULL);
	signal_set(&sighup_evt, SIGHUP, logfd_reopen_sighandler,
			&sighup_evt);
	signal_add(&sighup_evt, NULL);
	signal_set(&sigusr1_evt, SIGUSR1, enable_read_only_sighandler,
			&sigusr1_evt);
	signal_add(&sigusr1_evt, NULL);
	signal_set(&sigusr2_evt, SIGUSR2, passive_to_active_sighandler,
			&sigusr2_evt);
	signal_add(&sigusr2_evt, NULL);

	event_dispatch();

	if (ENABLE_TIPC)
		event_del(&tipc_evt);
	if (ENABLE_TCP)
		event_del(&tcp_evt);
	if (ENABLE_UDP)
		event_del(&udp_evt);
	if (ENABLE_SCTP)
		event_del(&sctp_evt);

	signal_del(&sigterm_evt);
	signal_del(&sigint_evt);
	signal_del(&sigusr1_evt);
	signal_del(&sigusr2_evt);

	tipc_close(tipc_fd);
	tcp_close(tcp_fd);
	udp_close(udp_fd);
	sctp_close(sctp_fd);
}
Esempio n. 13
0
int main(int argc, char *argv[])
{
	struct event event;
	struct event event2;

	char buffer[MAXRCVLEN + 1];
	int len, fd_client, fd_server, err_bind, serv;

	char connect_to[16] = "127.0.0.1";
	char nick[50] = "Anónimo";
	int port = 9999;

	int val, option_index = 0;
	static struct option long_options[] = {
		{ "conecta-con", required_argument, 0, 'c' },
		{ "nick", required_argument, 0, 'n' },
		{ "puerto", required_argument, 0, 'p' },
		{ 0 }
	};

	while ( (val = getopt_long(argc, argv, "c:n:p:", long_options,
                                   &option_index)) != -1 ) {
		switch (val) {
		case 'c':
			printf("\n La ip es %s\n", optarg);
			strncpy(connect_to, optarg, 16);
			break;
		case 'p':
			printf("\n El puerto es %d\n", atoi(optarg));
			port = atoi(optarg);
			break;
		case 'n':
			printf("\n El nick es %s\n",
                               optarg);
			strncpy(nick, optarg, 50);
			break;
		default:
			show_help();
			return 0;
		}
	}

	if (argc <= 4 && argc >=1) {
		show_help();
		return 0;
	}

	struct sockaddr_in client_sock = {
		.sin_family	= AF_INET,
		.sin_addr	= htonl(INADDR_LOOPBACK),
		.sin_port	= htons(port),
	};

	struct sockaddr_in server_sock = {
		.sin_family	= AF_INET,
		.sin_addr	= inet_addr(connect_to),
		.sin_port	= htons(port),
	};

	ev_base = event_init();
	if (ev_base == NULL)
		return EXIT_FAILURE;

	signal_set(&sigint_event, SIGINT, sigint_callback, NULL);
	signal_add(&sigint_event, NULL);

	/* Launch server */
	fd_server = socket(AF_INET, SOCK_DGRAM, 0);
	if (fd_server < 0) {
		perror("Error: Socket() -- Server\n");
		return EXIT_FAILURE;
	}

	err_bind = bind(fd_server, (struct sockaddr *)&server_sock,
                        sizeof(struct sockaddr));
	if (err_bind < 0) {
		perror("Error: Bind()\n");
		close(fd_server);
		return EXIT_FAILURE;
	}

	/* Launch client */
	fd_client = socket(AF_INET, SOCK_DGRAM, 0);
	if (fd_client < 0) {
		perror("Error: Socket() -- Client\n");
		return EXIT_FAILURE;
	}

	serv = connect(fd_client, (struct sockaddr *)&client_sock,
                       sizeof(struct sockaddr));
	if (serv < 0) {
		perror("Error: Connect()\n");
		close(fd_server);
		close(fd_client);
		return EXIT_FAILURE;
	}

	/* Create events */
	event_set(&event, fd_client, EV_WRITE | EV_PERSIST, send_msg_cb, nick);
	event_set(&event2, fd_server, EV_READ | EV_PERSIST,
                  receive_msg_cb, NULL);

	event_add(&event, NULL);
	event_add(&event2, NULL);

	while (!sigtype)
		event_loop(EVLOOP_ONCE);

	signal_del(&sigint_event);
	event_base_free(ev_base);

	close(fd_client);
	close(fd_server);

	return EXIT_SUCCESS;
}
Esempio n. 14
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;

	red_srand();
	while ((opt = getopt(argc, argv, "tc:p:")) != -1) {
		switch (opt) {
		case 't':
			conftest = true;
			break;
		case 'c':
			confname = optarg;
			break;
		case 'p':
			pidfile = optarg;
			break;
		default:
			printf(
				"Usage: %s [-t] [-c config] [-p pidfile]\n"
				"  -t           test config syntax\n"
				"  -p           write pid to pidfile\n",
				argv[0]);
			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, NULL);
	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;

	event_init();
	memset(terminators, 0, sizeof(terminators));

	FOREACH(ss, subsystems) {
		if ((*ss)->init) {
			error = (*ss)->init();
			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;
		}
	}

	log_error(LOG_NOTICE, "redsocks started");

	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(NULL);

	return !error ? EXIT_SUCCESS : EXIT_FAILURE;
}
Esempio n. 15
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;
}