server/: Institute `address family table'; contemplate multiple sockets.
authorMark Wooding <mdw@distorted.org.uk>
Sat, 16 Sep 2017 14:30:42 +0000 (15:30 +0100)
committerMark Wooding <mdw@distorted.org.uk>
Thu, 28 Jun 2018 23:26:40 +0000 (00:26 +0100)
This is a slightly oddly-shaped change which lays important groundwork
for the future.

  * Firstly, it creates a table of address families, currently not very
    interestingly since there's only one, but this will be an essential
    tool for adding IPv6 support later.

  * Secondly, it turns the peer module's `sock' into a global vector
    `udpsock' of UDP sockets, possibly one for each of the supported
    address families.  There's no real change here, because there's only
    one address family known, but the `port' command has grown an
    address-family argument in case they have different ports.  To make
    this work, each peer now keeps track of the index of the socket it
    should use for transmitting messages.

py/tripe.py.in
server/admin.c
server/peer.c
server/servutil.c
server/tripe-admin.5.in
server/tripe.h

index 5562d7b..29911b0 100644 (file)
@@ -878,8 +878,10 @@ class TripeCommandDispatcher (TripeConnection):
                                *['PING'] +
                                _kwopts(kw, ['timeout']) +
                                [peer]))
                                *['PING'] +
                                _kwopts(kw, ['timeout']) +
                                [peer]))
-  def port(me):
-    return _oneline(me.command('PORT', filter = _tokenjoin))
+  def port(me, af = None):
+    return _oneline(me.command('PORT',
+                               *((af is not None) and [af] or []),
+                               filter = _tokenjoin))
   def quit(me):
     return _simple(me.command('QUIT'))
   def reload(me):
   def quit(me):
     return _simple(me.command('QUIT'))
   def reload(me):
index 46a7348..3b99848 100644 (file)
@@ -1666,7 +1666,24 @@ static void acmd_warn(admin *a, unsigned ac, char *av[])
   { alertcmd(a, AF_WARN, AF_WARN, "WARN", av); }
 
 static void acmd_port(admin *a, unsigned ac, char *av[])
   { alertcmd(a, AF_WARN, AF_WARN, "WARN", av); }
 
 static void acmd_port(admin *a, unsigned ac, char *av[])
-  { a_info(a, "%u", p_port(), A_END); a_ok(a); }
+{
+  int i;
+
+  if (ac) {
+    for (i = 0; i < NADDRFAM; i++)
+      if (mystrieq(av[0], aftab[i].name)) goto found;
+    a_fail(a, "unknown-address-family", "%s", av[0], A_END);
+    return;
+  found:
+    assert(udpsock[i].fd >= 0);
+  } else {
+    for (i = 0; i < NADDRFAM; i++)
+      if (udpsock[i].fd >= 0) goto found;
+    abort();
+  }
+  a_info(a, "%u", p_port(i), A_END);
+  a_ok(a);
+}
 
 static void acmd_daemon(admin *a, unsigned ac, char *av[])
 {
 
 static void acmd_daemon(admin *a, unsigned ac, char *av[])
 {
@@ -1977,7 +1994,7 @@ static const acmd acmdtab[] = {
   { "notify",  "MESSAGE ...",          1,      0xffff, acmd_notify },
   { "peerinfo",        "PEER",                 1,      1,      acmd_peerinfo },
   { "ping",    "[OPTIONS] PEER",       1,      0xffff, acmd_ping },
   { "notify",  "MESSAGE ...",          1,      0xffff, acmd_notify },
   { "peerinfo",        "PEER",                 1,      1,      acmd_peerinfo },
   { "ping",    "[OPTIONS] PEER",       1,      0xffff, acmd_ping },
-  { "port",    0,                      0,      0,      acmd_port },
+  { "port",    "[FAMILY]",             0,      1,      acmd_port },
   { "quit",    0,                      0,      0,      acmd_quit },
   { "reload",  0,                      0,      0,      acmd_reload },
   { "servinfo",        0,                      0,      0,      acmd_servinfo },
   { "quit",    0,                      0,      0,      acmd_quit },
   { "reload",  0,                      0,      0,      acmd_reload },
   { "servinfo",        0,                      0,      0,      acmd_servinfo },
index 03ed2ae..ba8d7ba 100644 (file)
 
 #include "tripe.h"
 
 
 #include "tripe.h"
 
+/*----- Global state ------------------------------------------------------*/
+
+sel_file udpsock[NADDRFAM];
+
 /*----- Static variables --------------------------------------------------*/
 
 static sym_table byname;
 static addrmap byaddr;
 /*----- Static variables --------------------------------------------------*/
 
 static sym_table byname;
 static addrmap byaddr;
-static sel_file sock;
 static unsigned nmobile;
 
 /*----- Tunnel table ------------------------------------------------------*/
 static unsigned nmobile;
 
 /*----- Tunnel table ------------------------------------------------------*/
@@ -181,6 +184,7 @@ int p_updateaddr(peer *p, const addr *a)
 {
   peer *q;
   peer_byaddr *pa, *qa;
 {
   peer *q;
   peer_byaddr *pa, *qa;
+  int ix;
   unsigned f;
 
   /* --- Figure out how to proceed --- *
   unsigned f;
 
   /* --- Figure out how to proceed --- *
@@ -197,6 +201,7 @@ int p_updateaddr(peer *p, const addr *a)
     T( trace(T_PEER, "peer: updating address for `%s'", p_name(p)); )
     am_remove(&byaddr, p->byaddr);
     p->byaddr = pa; p->spec.sa = *a; pa->p = p;
     T( trace(T_PEER, "peer: updating address for `%s'", p_name(p)); )
     am_remove(&byaddr, p->byaddr);
     p->byaddr = pa; p->spec.sa = *a; pa->p = p;
+    p->afix = afix(p->spec.sa.sa.sa_family); assert(p->afix >= 0);
     a_notify("NEWADDR", "?PEER", p, "?ADDR", a, A_END);
     return (0);
   } else {
     a_notify("NEWADDR", "?PEER", p, "?ADDR", a, A_END);
     return (0);
   } else {
@@ -205,6 +210,7 @@ int p_updateaddr(peer *p, const addr *a)
             p_name(p), p_name(q)); )
     q->byaddr = qa; qa->p = q; q->spec.sa = p->spec.sa;
     p->byaddr = pa; pa->p = p; p->spec.sa = *a;
             p_name(p), p_name(q)); )
     q->byaddr = qa; qa->p = q; q->spec.sa = p->spec.sa;
     p->byaddr = pa; pa->p = p; p->spec.sa = *a;
+    ix = p->afix; p->afix = q->afix; q->afix = ix;
     a_notify("NEWADDR", "?PEER", p, "?ADDR", a, A_END);
     a_notify("NEWADDR", "?PEER", q, "?ADDR", &q->spec.sa, A_END);
     return (0);
     a_notify("NEWADDR", "?PEER", p, "?ADDR", a, A_END);
     a_notify("NEWADDR", "?PEER", q, "?ADDR", &q->spec.sa, A_END);
     return (0);
@@ -510,7 +516,7 @@ static int p_dotxend(peer *p)
   }
   IF_TRACING(T_PEER, trace_block(T_PACKET, "peer: sending packet",
                                 BBASE(&p->b), BLEN(&p->b)); )
   }
   IF_TRACING(T_PEER, trace_block(T_PACKET, "peer: sending packet",
                                 BBASE(&p->b), BLEN(&p->b)); )
-  if (sendto(sock.fd, BBASE(&p->b), BLEN(&p->b),
+  if (sendto(udpsock[p->afix].fd, BBASE(&p->b), BLEN(&p->b),
             0, &p->spec.sa.sa, sasz) < 0) {
     a_warn("PEER", "?PEER", p, "socket-write-error", "?ERRNO", A_END);
     return (0);
             0, &p->spec.sa.sa, sasz) < 0) {
     a_warn("PEER", "?PEER", p, "socket-write-error", "?ERRNO", A_END);
     return (0);
@@ -802,8 +808,8 @@ void p_init(struct in_addr addr, unsigned port)
        strerror(errno));
   }
   fdflags(fd, O_NONBLOCK, O_NONBLOCK, FD_CLOEXEC, FD_CLOEXEC);
        strerror(errno));
   }
   fdflags(fd, O_NONBLOCK, O_NONBLOCK, FD_CLOEXEC, FD_CLOEXEC);
-  sel_initfile(&sel, &sock, fd, SEL_READ, p_read, 0);
-  sel_addfile(&sock);
+  sel_initfile(&sel, &udpsock[AFIX_INET], fd, SEL_READ, p_read, 0);
+  sel_addfile(&udpsock[AFIX_INET]);
   T( trace(T_PEER, "peer: created socket"); )
 
   sym_create(&byname);
   T( trace(T_PEER, "peer: created socket"); )
 
   sym_create(&byname);
@@ -812,17 +818,17 @@ void p_init(struct in_addr addr, unsigned port)
 
 /* --- @p_port@ --- *
  *
 
 /* --- @p_port@ --- *
  *
- * Arguments:  ---
+ * Arguments:  @int i@ = address family index to retrieve
  *
  * Returns:    Port number used for socket.
  */
 
  *
  * Returns:    Port number used for socket.
  */
 
-unsigned p_port(void)
+unsigned p_port(int i)
 {
   addr a;
   socklen_t sz = sizeof(addr);
 
 {
   addr a;
   socklen_t sz = sizeof(addr);
 
-  if (getsockname(sock.fd, &a.sa, &sz))
+  if (getsockname(udpsock[i].fd, &a.sa, &sz))
     die(EXIT_FAILURE, "couldn't read port number: %s", strerror(errno));
   assert(a.sa.sa_family == AF_INET);
   return (ntohs(a.sin.sin_port));
     die(EXIT_FAILURE, "couldn't read port number: %s", strerror(errno));
   assert(a.sa.sa_family == AF_INET);
   return (ntohs(a.sin.sin_port));
@@ -898,6 +904,7 @@ peer *p_create(peerspec *spec)
   p->ks = 0;
   p->pings = 0;
   p->ifname = 0;
   p->ks = 0;
   p->pings = 0;
   p->ifname = 0;
+  p->afix = afix(p->spec.sa.sa.sa_family); assert(p->afix >= 0);
   memset(&p->st, 0, sizeof(stats));
   p->st.t_start = time(0);
   if (!(tops->flags & TUNF_PRIVOPEN))
   memset(&p->st, 0, sizeof(stats));
   p->st.t_start = time(0);
   if (!(tops->flags & TUNF_PRIVOPEN))
index 7072139..70776dd 100644 (file)
@@ -121,6 +121,30 @@ int mystrieq(const char *x, const char *y)
   }
 }
 
   }
 }
 
+/*----- Address handling --------------------------------------------------*/
+
+const struct addrfam aftab[] = {
+#define DEF(af) { AF_##af, #af },
+  ADDRFAM(DEF)
+#undef DEF
+};
+
+/* --- @afix@ --- *
+ *
+ * Arguments:  @int af@ = an address family code
+ *
+ * Returns:    The index of the address family's record in @aftab@, or @-1@.
+ */
+
+int afix(int af)
+{
+  int i;
+
+  for (i = 0; i < NADDRFAM; i++)
+    if (af == aftab[i].af) return (i);
+  return (-1);
+}
+
 /* --- @addrsz@ --- *
  *
  * Arguments:  @const addr *a@ = a network address
 /* --- @addrsz@ --- *
  *
  * Arguments:  @const addr *a@ = a network address
index 5836eea..43f7725 100644 (file)
@@ -663,12 +663,18 @@ given, seconds are assumed.
 .RE
 .SP
 .B "PORT"
 .RE
 .SP
 .B "PORT"
+.RI [ family ]
 Emits an
 .B INFO
 line containing just the number of the UDP port used by the
 .B tripe
 Emits an
 .B INFO
 line containing just the number of the UDP port used by the
 .B tripe
-server.  If you've allowed your server to allocate a port dynamically,
-this is how to find out which one it chose.
+server, for the given address
+.I family
+(or one chosen arbitrarily if omitted -- though
+.B tripe
+tries to use the same port number consistently so this is not a likely
+problem in practice).  If you've allowed your server to allocate a port
+dynamically, this is how to find out which one it chose.
 .SP
 .B "RELOAD"
 Instructs the server to recheck its keyring files.  The server checks
 .SP
 .B "RELOAD"
 Instructs the server to recheck its keyring files.  The server checks
@@ -1079,6 +1085,13 @@ is available, which does not meet the stated requirements.
 .I tag
 is already the tag of an outstanding job.
 .SP
 .I tag
 is already the tag of an outstanding job.
 .SP
+.BI "unknown-address-family " afam
+(For
+.BR PORT .)
+The address family
+.I afam
+is unrecognized.
+.SP
 .BI "unknown-command " token
 The command
 .I token
 .BI "unknown-command " token
 The command
 .I token
index 4b6c710..0eae8dc 100644 (file)
@@ -410,6 +410,23 @@ extern const bulkops bulktab[];
 
 /*----- Data structures ---------------------------------------------------*/
 
 
 /*----- Data structures ---------------------------------------------------*/
 
+/* --- The address-family table --- */
+
+#define ADDRFAM(_)                                                     \
+  _(INET)
+
+enum {
+#define ENUM(af) AFIX_##af,
+  ADDRFAM(ENUM)
+#undef ENUM
+  NADDRFAM
+};
+
+extern const struct addrfam {
+  int af;
+  const char *name;
+} aftab[NADDRFAM];
+
 /* --- Socket addresses --- *
  *
  * A magic union of supported socket addresses.
 /* --- Socket addresses --- *
  *
  * A magic union of supported socket addresses.
@@ -615,6 +632,7 @@ typedef struct peer {
   peer_byaddr *byaddr;                 /* Lookup-by-address block */
   struct ping *pings;                  /* Pings we're waiting for */
   peerspec spec;                       /* Specifications for this peer */
   peer_byaddr *byaddr;                 /* Lookup-by-address block */
   struct ping *pings;                  /* Pings we're waiting for */
   peerspec spec;                       /* Specifications for this peer */
+  int afix;                            /* Index of address family */
   tunnel *t;                           /* Tunnel for local packets */
   char *ifname;                                /* Interface name for tunnel */
   keyset *ks;                          /* List head for keysets */
   tunnel *t;                           /* Tunnel for local packets */
   char *ifname;                                /* Interface name for tunnel */
   keyset *ks;                          /* List head for keysets */
@@ -757,6 +775,7 @@ 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 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 sel_file udpsock[NADDRFAM];     /* The master UDP sockets */
 extern kdata *master;                  /* Default private key */
 extern const char *tag_priv;           /* Default private key tag */
 
 extern kdata *master;                  /* Default private key */
 extern const char *tag_priv;           /* Default private key tag */
 
@@ -1577,12 +1596,12 @@ extern void p_init(struct in_addr /*addr*/, unsigned /*port*/);
 
 /* --- @p_port@ --- *
  *
 
 /* --- @p_port@ --- *
  *
- * Arguments:  ---
+ * Arguments:  @int i@ = address family index to retrieve
  *
  * Returns:    Port number used for socket.
  */
 
  *
  * Returns:    Port number used for socket.
  */
 
-unsigned p_port(void);
+extern unsigned p_port(int /*i*/);
 
 /* --- @p_create@ --- *
  *
 
 /* --- @p_create@ --- *
  *
@@ -1742,6 +1761,15 @@ extern const char *timestr(time_t /*t*/);
 
 extern int mystrieq(const char */*x*/, const char */*y*/);
 
 
 extern int mystrieq(const char */*x*/, const char */*y*/);
 
+/* --- @afix@ --- *
+ *
+ * Arguments:  @int af@ = an address family code
+ *
+ * Returns:    The index of the address family's record in @aftab@, or @-1@.
+ */
+
+extern int afix(int af);
+
 /* --- @addrsz@ --- *
  *
  * Arguments:  @const addr *a@ = a network address
 /* --- @addrsz@ --- *
  *
  * Arguments:  @const addr *a@ = a network address