server/: Build a proper interface for handling tunnel classes.
[tripe] / server / tripe.c
index aa225da..637400a 100644 (file)
@@ -36,7 +36,11 @@ sel_state sel;
 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@ --- *
  *
@@ -50,15 +54,132 @@ static sel_timer it;
 
 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
@@ -123,11 +244,11 @@ int main(int argc, char *argv[])
   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;
 
@@ -142,7 +263,6 @@ int main(int argc, char *argv[])
     dir = p;
   if ((p = getenv("TRIPESOCK")) != 0)
     csock = p;
-  tun_default = tunnels[0];
   aihint.ai_family = AF_UNSPEC;
 
   for (;;) {
@@ -218,13 +338,11 @@ int main(int argc, char *argv[])
        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;
@@ -254,7 +372,7 @@ int main(int argc, char *argv[])
 #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;
@@ -287,11 +405,7 @@ int main(int argc, char *argv[])
        dir, strerror(errno));
   }
 
-  sel_init(&sel);
-  sig_init(&sel);
-  rand_noisesrc(RAND_GLOBAL, &noise_source);
-  rand_seed(RAND_GLOBAL, MAXHASHSZ);
-  signal(SIGPIPE, SIG_IGN);
+  lp_init();
 
   if (!(f & f_daemon)) {
     af = AF_WARN;
@@ -305,8 +419,9 @@ int main(int argc, char *argv[])
   }
 
   p_init();
-  for (i = 0; tunnels[i]; i++)
-    tunnels[i]->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++) {
@@ -323,30 +438,21 @@ int main(int argc, char *argv[])
   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);
 }