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]))
-  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):
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[])
-  { 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[])
 {
@@ -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 },
-  { "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 },
index 03ed2ae..ba8d7ba 100644 (file)
 
 #include "tripe.h"
 
+/*----- Global state ------------------------------------------------------*/
+
+sel_file udpsock[NADDRFAM];
+
 /*----- Static variables --------------------------------------------------*/
 
 static sym_table byname;
 static addrmap byaddr;
-static sel_file sock;
 static unsigned nmobile;
 
 /*----- Tunnel table ------------------------------------------------------*/
@@ -181,6 +184,7 @@ int p_updateaddr(peer *p, const addr *a)
 {
   peer *q;
   peer_byaddr *pa, *qa;
+  int ix;
   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;
+    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 {
@@ -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;
+    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);
@@ -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 (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);
@@ -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);
-  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);
@@ -812,17 +818,17 @@ void p_init(struct in_addr addr, unsigned port)
 
 /* --- @p_port@ --- *
  *
- * Arguments:  ---
+ * Arguments:  @int i@ = address family index to retrieve
  *
  * Returns:    Port number used for socket.
  */
 
-unsigned p_port(void)
+unsigned p_port(int i)
 {
   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));
@@ -898,6 +904,7 @@ peer *p_create(peerspec *spec)
   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))
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
index 5836eea..43f7725 100644 (file)
@@ -663,12 +663,18 @@ given, seconds are assumed.
 .RE
 .SP
 .B "PORT"
+.RI [ family ]
 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
@@ -1079,6 +1085,13 @@ is available, which does not meet the stated requirements.
 .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
index 4b6c710..0eae8dc 100644 (file)
@@ -410,6 +410,23 @@ extern const bulkops bulktab[];
 
 /*----- 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.
@@ -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 */
+  int afix;                            /* Index of address family */
   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 sel_file udpsock[NADDRFAM];     /* The master UDP sockets */
 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@ --- *
  *
- * Arguments:  ---
+ * Arguments:  @int i@ = address family index to retrieve
  *
  * Returns:    Port number used for socket.
  */
 
-unsigned p_port(void);
+extern unsigned p_port(int /*i*/);
 
 /* --- @p_create@ --- *
  *
@@ -1742,6 +1761,15 @@ extern const char *timestr(time_t /*t*/);
 
 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