server/: Build a proper interface for handling tunnel classes.
authorMark Wooding <mdw@distorted.org.uk>
Sat, 19 May 2018 20:39:53 +0000 (21:39 +0100)
committerMark Wooding <mdw@distorted.org.uk>
Thu, 5 Sep 2019 12:05:24 +0000 (13:05 +0100)
  * Introduce functions for enumerating the available tunnel types,
    looking one up by name, and returning a default tunnel.  This
    eliminates the direct access previously used by the admin code.

  * Introduce a registration interface.  This isn't necessary for our
    purposes, but, in case it's not been obvious enough, the recent
    changes have been directed towards making the server code suitable
    as a library, and a user of this library might well need a custom
    tunnel class.

server/admin.c
server/peer.c
server/tripe.c
server/tripe.h

index 0432b8a..78188f5 100644 (file)
@@ -1428,6 +1428,7 @@ static void acmd_add(admin *a, unsigned ac, char *av[])
 {
   const char *tag = 0;
   admin_addop *add;
+  const tunnel_ops *tops;
 
   /* --- Set stuff up --- */
 
@@ -1437,7 +1438,7 @@ static void acmd_add(admin *a, unsigned ac, char *av[])
   add->peer.privtag = 0;
   add->peer.knock = 0;
   add->peer.t_ka = 0;
-  add->peer.tops = tun_default;
+  add->peer.tops = p_dflttun();
   add->peer.f = 0;
 
   /* --- Parse options --- */
@@ -1445,17 +1446,9 @@ static void acmd_add(admin *a, unsigned ac, char *av[])
   OPTIONS(ac, av, {
     OPTARG("-background", arg, { tag = arg; })
     OPTARG("-tunnel", arg, {
-      unsigned i;
-      for (i = 0;; i++) {
-       if (!tunnels[i]) {
-         a_fail(a, "unknown-tunnel", "%s", arg, A_END);
-         goto fail;
-       }
-       if (mystrieq(arg, tunnels[i]->name)) {
-         add->peer.tops = tunnels[i];
-         break;
-       }
-      }
+      if ((tops = p_findtun(arg)) == 0)
+       { a_fail(a, "unknown-tunnel", "%s", arg, A_END); goto fail; }
+      add->peer.tops = tops;
     })
     OPTTIME("-keepalive", t, { add->peer.t_ka = t; })
     OPT("-cork", { add->peer.f |= KXF_CORK; })
@@ -2144,10 +2137,7 @@ static void acmd_version(admin *a, unsigned ac, char *av[])
 
 static void acmd_tunnels(admin *a, unsigned ac, char *av[])
 {
-  int i;
-
-  for (i = 0; tunnels[i]; i++)
-    a_info(a, "%s", tunnels[i]->name, A_END);
+  FOREACH_TUN(tops, { a_info(a, "%s", tops->name, A_END); });
   a_ok(a);
 }
 
index f723ccc..278a6b2 100644 (file)
@@ -36,22 +36,11 @@ udpsocket udpsock[NADDRFAM];
 static sym_table byname;
 static addrmap byaddr;
 static unsigned nmobile;
-
-/*----- Tunnel table ------------------------------------------------------*/
-
-const tunnel_ops *tunnels[] = {
-#ifdef TUN_LINUX
-  &tun_linux,
-#endif
-#ifdef TUN_BSD
-  &tun_bsd,
-#endif
-#ifdef TUN_UNET
-  &tun_unet,
-#endif
-  &tun_slip,
-  0
-}, *tun_default;
+static struct tunnel_node {
+  struct tunnel_node *next;
+  const tunnel_ops *tops;
+} *tunnels, **tunnels_tail = &tunnels;
+const tunnel_ops *dflttun;
 
 /*----- Main code ---------------------------------------------------------*/
 
@@ -935,6 +924,101 @@ void p_init(void)
   am_create(&byaddr);
 }
 
+/* --- @p_addtun@ --- *
+ *
+ * Arguments:  @const tunnel_ops *tops@ = tunnel ops to add
+ *
+ * Returns:    ---
+ *
+ * Use:                Adds a tunnel class to the list of known classes.  If there
+ *             is no current default tunnel, then this one is made the
+ *             default.
+ *
+ *             Does nothing if the tunnel class is already known.  So adding
+ *             a bunch of tunnels takes quadratic time, but there will be
+ *             too few to care about.
+ */
+
+void p_addtun(const tunnel_ops *tops)
+{
+  struct tunnel_node *tn;
+
+  for (tn = tunnels; tn; tn = tn->next)
+    if (tn->tops == tops) return;
+  tops->init();
+  tn = CREATE(struct tunnel_node);
+  tn->next = 0; tn->tops = tops;
+  *tunnels_tail = tn; tunnels_tail = &tn->next;
+  if (!dflttun) dflttun = tops;
+}
+
+/* --- @p_setdflttun@ --- *
+ *
+ * Arguments:  @const tunnel_ops *tops@ = tunnel ops to set
+ *
+ * Returns:    ---
+ *
+ * Use:                Sets the default tunnel.  It must already be registered.  The
+ *             old default is forgotten.
+ */
+
+void p_setdflttun(const tunnel_ops *tops)
+  { dflttun = tops; }
+
+/* --- @p_dflttun@ --- *
+ *
+ * Arguments:  ---
+ *
+ * Returns:    A pointer to the current default tunnel operations, or null
+ *             if no tunnels are defined.
+ */
+
+const tunnel_ops *p_dflttun(void) { return (dflttun); }
+
+/* --- @p_findtun@ --- *
+ *
+ * Arguments:  @const char *name@ = tunnel name
+ *
+ * Returns:    Pointer to the tunnel operations, or null.
+ *
+ * Use:                Finds the operations for a named tunnel class.
+ */
+
+const tunnel_ops *p_findtun(const char *name)
+{
+  const struct tunnel_node *tn;
+
+  for (tn = tunnels; tn; tn = tn->next)
+    if (mystrieq(tn->tops->name, name) == 0) return (tn->tops);
+  return (0);
+}
+
+/* --- @p_mktuniter@ --- *
+ *
+ * Arguments:  @tuniter *i@ = pointer to iterator to initialize
+ *
+ * Returns:    ---
+ *
+ * Use:                Initializes a tunnel iterator.
+ */
+
+void p_mktuniter(tun_iter *i) { i->next = tunnels; }
+
+/* --- @p_nexttun@ --- *
+ *
+ * Arguments:  @tuniter *i@ = pointer to iterator
+ *
+ * Returns:    Pointer to the next tunnel's operations, or null.
+ */
+
+const tunnel_ops *p_nexttun(tun_iter *i)
+{
+  const struct tunnel_node *tn = i->next;
+
+  if (!tn) return (0);
+  else { i->next = tn->next; return (tn->tops); }
+}
+
 /* --- @p_keepalive@ --- *
  *
  * Arguments:  @struct timeval *now@ = the current time
index fb1d337..637400a 100644 (file)
@@ -163,6 +163,21 @@ int lp_run(void)
   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@ --- *
@@ -229,6 +244,7 @@ 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;
@@ -247,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 (;;) {
@@ -323,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;
@@ -359,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;
@@ -406,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++) {
index bf75b45..fd0f44e 100644 (file)
@@ -611,6 +611,10 @@ typedef struct tunnel_ops {
 struct tunnel { const tunnel_ops *ops; };
 #endif
 
+typedef struct tun_iter {
+  const struct tunnel_node *next;
+} tun_iter;
+
 /* --- Peer statistics --- *
  *
  * Contains various interesting and not-so-interesting statistics about a
@@ -815,8 +819,6 @@ struct admin {
 
 extern sel_state sel;                  /* Global I/O event state */
 extern octet buf_i[PKBUFSZ], buf_o[PKBUFSZ], buf_t[PKBUFSZ], buf_u[PKBUFSZ];
-extern const tunnel_ops *tunnels[];    /* Table of tunnels (0-term) */
-extern const tunnel_ops *tun_default;  /* Default tunnel to use */
 extern udpsocket udpsock[NADDRFAM];    /* The master UDP sockets */
 extern kdata *master;                  /* Default private key */
 extern char *tag_priv;                 /* Default private key tag */
@@ -1735,6 +1737,90 @@ extern void p_unbind(void);
 
 extern void p_init(void);
 
+/* --- @p_addtun@ --- *
+ *
+ * Arguments:  @const tunnel_ops *tops@ = tunnel ops to add
+ *
+ * Returns:    ---
+ *
+ * Use:                Adds a tunnel class to the list of known classes.  If there
+ *             is no current default tunnel, then this one is made the
+ *             default.
+ *
+ *             Does nothing if the tunnel class is already known.  So adding
+ *             a bunch of tunnels takes quadratic time, but there will be
+ *             too few to care about.
+ */
+
+extern void p_addtun(const tunnel_ops */*tops*/);
+
+/* --- @p_setdflttun@ --- *
+ *
+ * Arguments:  @const tunnel_ops *tops@ = tunnel ops to set
+ *
+ * Returns:    ---
+ *
+ * Use:                Sets the default tunnel.  It must already be registered.  The
+ *             old default is forgotten.
+ */
+
+extern void p_setdflttun(const tunnel_ops */*tops*/);
+
+/* --- @p_dflttun@ --- *
+ *
+ * Arguments:  ---
+ *
+ * Returns:    A pointer to the current default tunnel operations, or null
+ *             if no tunnels are defined.
+ */
+
+extern const tunnel_ops *p_dflttun(void);
+
+/* --- @p_findtun@ --- *
+ *
+ * Arguments:  @const char *name@ = tunnel name
+ *
+ * Returns:    Pointer to the tunnel operations, or null.
+ *
+ * Use:                Finds the operations for a named tunnel class.
+ */
+
+extern const tunnel_ops *p_findtun(const char */*name*/);
+
+/* --- @p_mktuniter@ --- *
+ *
+ * Arguments:  @tuniter *i@ = pointer to iterator to initialize
+ *
+ * Returns:    ---
+ *
+ * Use:                Initializes a tunnel iterator.
+ */
+
+extern void p_mktuniter(tun_iter */*i*/);
+
+/* --- @p_nexttun@ --- *
+ *
+ * Arguments:  @tuniter *i@ = pointer to iterator
+ *
+ * Returns:    Pointer to the next tunnel's operations, or null.
+ */
+
+extern const tunnel_ops *p_nexttun(tun_iter */*i*/);
+
+/* --- @FOREACH_TUN@ --- *
+ *
+ * Arguments:  @tops@ = name to bind to each tunnel
+ *             @stuff@ = thing to do for each item
+ *
+ * Use:                Does something for each known tunnel class.
+ */
+
+#define FOREACH_TUN(tops, stuff) do {                                  \
+  tun_iter i_;                                                         \
+  const tunnel_ops *tops;                                              \
+  for (p_mktuniter(&i_); (tops = p_nexttun(&i_)) != 0; ) stuff;                \
+} while (0)
+
 /* --- @p_create@ --- *
  *
  * Arguments:  @peerspec *spec@ = information about this peer