static sel_timer it;
#define T_INTERVAL MIN(1)
-/*----- Main code ---------------------------------------------------------*/
+static unsigned iv_nreasons = 0;
+static struct timeval iv_next = { 0, 0 };
+static int lpdone = 0;
+
+/*----- The interval timer ------------------------------------------------*/
/* --- @interval@ --- *
*
static void interval(struct timeval *tv, void *v)
{
- struct timeval tvv;
T( trace(T_PEER, "peer: interval timer"); )
+ iv_next = *tv;
rand_seed(RAND_GLOBAL, MAXHASHSZ);
p_interval();
- tvv = *tv;
- tvv.tv_sec += T_INTERVAL;
- sel_addtimer(&sel, &it, &tvv, interval, v);
+ iv_next.tv_sec += T_INTERVAL;
+ sel_addtimer(&sel, &it, &iv_next, interval, v);
+}
+
+/* --- @iv_addreason@ --- *
+ *
+ * Arguments: ---
+ *
+ * Returns: ---
+ *
+ * Use: Adds an `interval timer reason'; if there are no others, the
+ * interval timer is engaged.
+ */
+
+void iv_addreason(void)
+{
+ struct timeval tv;
+
+ if (!iv_nreasons) {
+ gettimeofday(&tv, 0);
+ if (TV_CMP(&tv, >=, &iv_next)) interval(&tv, 0);
+ else sel_addtimer(&sel, &it, &iv_next, interval, 0);
+ }
+ iv_nreasons++;
+}
+
+/* --- @iv_rmreason@ --- *
+ *
+ * Arguments: ---
+ *
+ * Returns: ---
+ *
+ * Use: Removes an interval timer reason; if there are none left, the
+ * interval timer is disengaged.
+ */
+
+void iv_rmreason(void)
+{
+ assert(iv_nreasons); iv_nreasons--;
+ if (!iv_nreasons) sel_rmtimer(&it);
+}
+
+/*----- The main loop -----------------------------------------------------*/
+
+/* --- @lp_init@ --- *
+ *
+ * Arguments: ---
+ *
+ * Returns: ---
+ *
+ * Use: Initializes the main loop. Most importantly, this sets up
+ * the select multiplexor that everything else hooks onto.
+ */
+
+void lp_init(void)
+{
+ rand_noisesrc(RAND_GLOBAL, &noise_source);
+ rand_seed(RAND_GLOBAL, MAXHASHSZ);
+ gettimeofday(&iv_next, 0); iv_next.tv_sec += T_INTERVAL;
+ signal(SIGPIPE, SIG_IGN);
+ sel_init(&sel);
+ sig_init(&sel);
}
+/* --- @lp_end@ --- *
+ *
+ * Arguments: ---
+ *
+ * Returns: ---
+ *
+ * Use: Requests an exit from the main loop.
+ */
+
+void lp_end(void) { lpdone = 1; }
+
+/* --- @lp_run@ --- *
+ *
+ * Arguments: ---
+ *
+ * Returns: Zero on successful termination; @-1@ if things went wrong.
+ *
+ * Use: Cranks the main loop until it should be cranked no more.
+ */
+
+int lp_run(void)
+{
+ int nerr = 0;
+
+ for (;;) {
+ a_preselect();
+ if (lpdone) break;
+ if (!sel_select(&sel)) nerr = 0;
+ else if (errno != EINTR && errno != EAGAIN) {
+ a_warn("SERVER", "select-error", "?ERRNO", A_END);
+ nerr++;
+ if (nerr > 8) {
+ a_warn("ABORT", "repeated-select-errors", A_END);
+ abort();
+ }
+ }
+ }
+ lpdone = 0;
+ return (0);
+}
+
+/*----- Tunnel table ------------------------------------------------------*/
+
+static const tunnel_ops *tunnels[] = {
+#ifdef TUN_LINUX
+ &tun_linux,
+#endif
+#ifdef TUN_BSD
+ &tun_bsd,
+#endif
+#ifdef TUN_UNET
+ &tun_unet,
+#endif
+ &tun_slip,
+};
+
+/*----- Main code ---------------------------------------------------------*/
+
/* --- @main@ --- *
*
* Arguments: @int argc@ = number of command line arguments
const char *p;
const char *bindhost = 0, *bindsvc = STR(TRIPE_PORT);
struct addrinfo aihint = { 0 }, *ailist;
+ const tunnel_ops *dflt = 0;
unsigned f = 0;
int i;
- int err, selerr = 0;
+ int err;
unsigned af;
- struct timeval tv;
uid_t u = -1;
gid_t g = -1;
dir = p;
if ((p = getenv("TRIPESOCK")) != 0)
csock = p;
- tun_default = tunnels[0];
aihint.ai_family = AF_UNSPEC;
for (;;) {
break;
case 'n': {
int i;
- for (i = 0;; i++) {
- if (!tunnels[i])
- die(EXIT_FAILURE, "unknown tunnel `%s'", optarg);
+ for (i = 0; i < N(tunnels); i++)
if (mystrieq(optarg, tunnels[i]->name))
- break;
- }
- tun_default = tunnels[i];
+ { dflt = tunnels[i]; goto found_tun; }
+ die(EXIT_FAILURE, "unknown tunnel `%s'", optarg);
+ found_tun:;
} break;
case 'd':
dir = optarg;
#endif
case '0': {
int i;
- for (i = 0; tunnels[i]; i++)
+ for (i = 0; i < N(tunnels); i++)
puts(tunnels[i]->name);
exit(0);
} break;
dir, strerror(errno));
}
- sel_init(&sel);
- sig_init(&sel);
- rand_noisesrc(RAND_GLOBAL, &noise_source);
- rand_seed(RAND_GLOBAL, MAXHASHSZ);
- signal(SIGPIPE, SIG_IGN);
- for (i = 0; tunnels[i]; i++)
- tunnels[i]->init();
- p_init(ailist); freeaddrinfo(ailist);
+ lp_init();
+
if (!(f & f_daemon)) {
af = AF_WARN;
#ifndef NTRACE
if (f & f_foreground)
af |= AF_FOREGROUND;
a_create(STDIN_FILENO, STDOUT_FILENO, af);
+ a_switcherr();
}
- ps_split(f & f_daemon);
- a_init(csock, u, g, csockmode);
+
+ p_init();
+ for (i = 0; i < N(tunnels); i++)
+ p_addtun(tunnels[i]);
+ if (dflt) p_setdflttun(dflt);
+ p_bind(ailist); freeaddrinfo(ailist);
+
+ for (i = 0; tunnels[i]; i++) {
+ if (tunnels[i]->flags&TUNF_PRIVOPEN) {
+ ps_split(f & f_daemon);
+ break;
+ }
+ }
+
+ a_init();
+ a_signals();
+ a_listen(csock, u, g, csockmode);
u_setugid(u, g);
km_init(kr_priv, kr_pub, tag_priv);
kx_init();
if (f & f_daemon) {
- if (daemonize())
- die(EXIT_FAILURE, "couldn't become a daemon: %s", strerror(errno));
+ if (daemonize()) {
+ a_warn("SERVER", "daemon-error", "?ERRNO", A_END);
+ exit(EXIT_FAILURE);
+ }
a_daemon();
+ a_switcherr();
}
- tv.tv_sec = time(0) + T_INTERVAL;
- tv.tv_usec = 0;
- sel_addtimer(&sel, &it, &tv, interval, 0);
-
- for (;;) {
- a_preselect();
- if (!sel_select(&sel))
- selerr = 0;
- else if (errno != EINTR && errno != EAGAIN) {
- a_warn("SERVER", "select-error", "?ERRNO", A_END);
- selerr++;
- if (selerr > 8) {
- a_warn("ABORT", "repeated-select-errors", A_END);
- abort();
- }
- }
- }
+ lp_run();
+ p_destroyall();
+ p_unbind();
+ a_unlisten();
+ km_clear();
+ ps_quit();
return (0);
}