chiark / gitweb /
Fix for new key-data interface.
[tripe] / admin.c
diff --git a/admin.c b/admin.c
index 0213996a45fe27d58f916b2190cec659da57de8f..e081bdf6106ffd6faf982b6b54a88b3cbdf4bc41 100644 (file)
--- a/admin.c
+++ b/admin.c
@@ -71,6 +71,7 @@ static sig s_term, s_int, s_hup;
 #define F_INIT 2u
 
 #define T_RESOLVE SEC(30)
+#define T_PING SEC(5)
 
 static void a_destroy(admin */*a*/);
 static void a_lock(admin */*a*/);
@@ -78,23 +79,6 @@ static void a_unlock(admin */*a*/);
 
 /*----- Output functions --------------------------------------------------*/
 
-/* --- @mystrieq@ --- *
- *
- * Arguments:  @const char *x, *y@ = two strings
- *
- * Returns:    True if @x@ and @y are equal, up to case.
- */
-
-static int mystrieq(const char *x, const char *y)
-{
-  for (;;) {
-    if (!*x && !*y) return (1);
-    if (tolower((unsigned char)*x) != tolower((unsigned char)*y))
-      return (0);
-    x++; y++;
-  }
-}
-
 /* --- @trywrite@ --- *
  *
  * Arguments:  @admin *a@ = pointer to an admin block
@@ -433,6 +417,10 @@ void a_notify(const char *fmt, ...)
 
 void a_quit(void)
 {
+  peer *p;
+
+  while ((p = p_first()) != 0)
+    p_destroy(p);
   close(sock.fd);
   unlink(sockname);
   exit(0);
@@ -480,6 +468,29 @@ static void a_sighup(int sig, void *v)
   a_warn("SERVER ignore signal SIGHUP");
 }
 
+/* --- @a_parsetime@ --- *
+ *
+ * Arguments;  @const char *p@ = time string to parse
+ *
+ * Returns:    Time in seconds, or @< 0@ on error.
+ */
+
+static long a_parsetime(const char *p)
+{
+  char *q;
+  long t = strtol(p, &q, 0);
+
+  switch (*q) {
+    case 'd': t *= 24;
+    case 'h': t *= 60;
+    case 'm': t *= 60;
+    case 's': if (q[1] != 0)
+    default:    t = -1;
+    case 0:   break;
+  }
+  return (t);    
+}
+
 /*----- Adding peers ------------------------------------------------------*/
  
 /* --- @a_resolve@ --- *
@@ -502,18 +513,18 @@ static void a_resolve(struct hostent *h, void *v)
   sel_rmtimer(&a->t);
   if (!h)
     a_fail(a, "resolve-error %s", a->paddr);
-  else if (p_find(a->pname))
-    a_fail(a, "peer-exists %s", a->pname);
+  else if (p_find(a->peer.name))
+    a_fail(a, "peer-exists %s", a->peer.name);
   else {
-    memcpy(&a->peer.sin.sin_addr, h->h_addr, sizeof(struct in_addr));
-    if (!p_create(a->pname, &a->peer.sa, a->sasz))
-      a_fail(a, "peer-create-fail %s" a->pname);
+    memcpy(&a->peer.sa.sin.sin_addr, h->h_addr, sizeof(struct in_addr));
+    if (!p_create(&a->peer))
+      a_fail(a, "peer-create-fail %s", a->peer.name);
     else
       a_ok(a);
   }
-  xfree(a->pname);
+  xfree(a->peer.name);
   xfree(a->paddr);
-  a->pname = 0;
+  a->peer.name = 0;
   selbuf_enable(&a->b);
   a_unlock(a);
 }
@@ -536,9 +547,9 @@ static void a_timer(struct timeval *tv, void *v)
   T( trace(T_ADMIN, "admin: %u resolver timeout", a->seq); )
   bres_abort(&a->r);
   a_fail(a, "resolver-timeout %s\n", a->paddr);
-  xfree(a->pname);
+  xfree(a->peer.name);
   xfree(a->paddr);
-  a->pname = 0;
+  a->peer.name = 0;
   selbuf_enable(&a->b);
   a_unlock(a);
 }
@@ -558,7 +569,7 @@ static void acmd_add(admin *a, unsigned ac, char *av[])
 {
   unsigned long pt;
   struct timeval tv;
-  unsigned i;
+  unsigned i, j;
   char *p;
 
   /* --- Make sure someone's not got there already --- */
@@ -568,17 +579,55 @@ static void acmd_add(admin *a, unsigned ac, char *av[])
     return;
   }
 
-  /* --- Fill in the easy bits of address --- */
+  /* --- Set stuff up --- */
+
+  a->peer.name = av[0];
+  a->peer.t_ka = 0;
+  a->peer.tops = tun_default;
+
+  /* --- Parse options --- */
 
-  BURN(a->peer);
   i = 1;
+  for (;;) {
+    if (!av[i])
+      goto bad_syntax;
+    if (mystrieq(av[i], "-tunnel")) {
+      if (!av[++i]) goto bad_syntax;
+      for (j = 0;; j++) {
+       if (!tunnels[j]) {
+         a_fail(a, "unknown-tunnel %s", av[i]);
+         return;
+       }
+       if (mystrieq(av[i], tunnels[j]->name)) {
+         a->peer.tops = tunnels[j];
+         break;
+       }
+      }
+    } else if (mystrieq(av[i], "-keepalive")) {
+      long t;
+      if (!av[++i]) goto bad_syntax;
+      if ((t = a_parsetime(av[i])) < 0) {
+       a_fail(a, "bad-time-spec %s", av[i]);
+       return;
+      }
+      a->peer.t_ka = t;
+    } else if (mystrieq(av[i], "--")) {
+      i++;
+      break;
+    } else
+      break;
+    i++;
+  }
+
+  /* --- Fill in the easy bits of address --- */
+
   if (mystrieq(av[i], "inet")) i++;
   if (ac - i != 2) {
-    a_fail(a, "bad-syntax -- add PEER [inet] ADDRESS PORT");
+    a_fail(a, "bad-syntax -- add PEER [OPTIONS] [inet] ADDRESS PORT");
     return;
   }
-  a->peer.sin.sin_family = AF_INET;
-  a->sasz = sizeof(a->peer.sin);
+  a->peer.sa.sin.sin_family = AF_INET;
+  a->peer.sasz = sizeof(a->peer.sa.sin);
   pt = strtoul(av[i + 1], &p, 0);
   if (*p) {
     struct servent *s = getservbyname(av[i + 1], "udp");
@@ -592,15 +641,16 @@ static void acmd_add(admin *a, unsigned ac, char *av[])
     a_fail(a, "invalid-port %lu", pt);
     return;
   }
-  a->peer.sin.sin_port = htons(pt);
+  a->peer.sa.sin.sin_port = htons(pt);
 
   /* --- If the name is numeric, do it the easy way --- */
   
-  if (inet_aton(av[i], &a->peer.sin.sin_addr)) {
-    if (!p_create(av[0], &a->peer.sa, a->sasz))
-      a_fail(a, "peer-create-fail %s", a->pname);
+  if (inet_aton(av[i], &a->peer.sa.sin.sin_addr)) {
+    if (!p_create(&a->peer))
+      a_fail(a, "peer-create-fail %s", av[0]);
     else
       a_ok(a);
+    a->peer.name = 0;
     return;
   }
 
@@ -611,7 +661,7 @@ static void acmd_add(admin *a, unsigned ac, char *av[])
    * the system continues regardless), but makes life simpler for the client.
    */
 
-  a->pname = xstrdup(av[0]);
+  a->peer.name = xstrdup(av[0]);
   a->paddr = xstrdup(av[i]);
   selbuf_disable(&a->b);
   gettimeofday(&tv, 0);
@@ -620,8 +670,111 @@ static void acmd_add(admin *a, unsigned ac, char *av[])
   bres_byname(&a->r, a->paddr, a_resolve, a);
   T( trace(T_ADMIN, "admin: %u resolving hostname `%s'",
           a->seq, a->paddr); )
+  return;
+
+bad_syntax:
+  a_fail(a, "bad-syntax -- add PEER [OPTIONS] ADDR ...");
+  return;
 }
 
+/*----- Ping --------------------------------------------------------------*/
+
+/* --- @a_pong@ --- *
+ *
+ * Arguments:  @int rc@ = return code
+ *             @void *av@ = admin connection which requested the ping
+ *
+ * Returns:    ---
+ *
+ * Use:                Collects what happened to a ping message.
+ */
+
+static void a_pong(int rc, void *av)
+{
+  admin *a = av;
+  struct timeval tv;
+  double millis;
+
+  a_lock(a);
+  switch (rc) {
+    case PING_OK:
+      gettimeofday(&tv, 0);
+      tv_sub(&tv, &tv, &a->pingtime);
+      millis = (double)tv.tv_sec * 1000 + (double)tv.tv_usec/1000;
+      a_info(a, "ping-ok %.1f", millis);
+      a_ok(a);
+      break;
+    case PING_TIMEOUT:
+      a_info(a, "ping-timeout");
+      a_ok(a);
+      break;
+    case PING_PEERDIED:
+      a_info(a, "ping-peer-died");
+      a_ok(a);
+      break;
+    default:
+      abort();
+  }
+  a_unlock(a);
+}
+
+/* --- @acmd_ping@, @acmd_eping@ --- *
+ *
+ * Arguments:  @admin *a@ = connection which requested the ping
+ *             @unsigned ac@ = argument count
+ *             @char *av[]@ = pointer to the argument list
+ *
+ * Returns:    ---
+ *
+ * Use:                Pings a peer.
+ */
+
+static void a_ping(admin *a, unsigned ac, char *av[],
+                  const char *cmd, unsigned msg)
+{
+  long t = T_PING;
+  int i;
+  peer *p;
+
+  i = 0;
+  for (;;) {
+    if (!av[i])
+      goto bad_syntax;
+    if (mystrieq(av[i], "-timeout")) {
+      if (!av[++i]) goto bad_syntax;
+      if ((t = a_parsetime(av[i])) < 0) {
+       a_fail(a, "bad-time-spec %s", av[i]);
+       return;
+      }
+    } else if (mystrieq(av[i], "--")) {
+      i++;
+      break;
+    } else
+      break;
+    i++;
+  }
+
+  if (!av[i]) goto bad_syntax;
+  if ((p = p_find(av[i])) == 0) {
+    a_fail(a, "unknown-peer %s", av[i]);
+    return;
+  }
+  gettimeofday(&a->pingtime, 0);
+  if (p_pingsend(p, &a->ping, msg, t, a_pong, a))
+    a_fail(a, "ping-send-failed");
+  return;
+    
+bad_syntax:
+  a_fail(a, "bad-syntax -- %s [OPTIONS] PEER", cmd);
+  return;
+}
+
+static void acmd_ping(admin *a, unsigned ac, char *av[])
+  { a_ping(a, ac, av, "ping", MISC_PING); }
+static void acmd_eping(admin *a, unsigned ac, char *av[])
+  { a_ping(a, ac, av, "eping", MISC_EPING); }
+  
+
 /*----- Administration commands -------------------------------------------*/
 
 /* --- Miscellaneous commands --- */
@@ -835,6 +988,17 @@ static void acmd_kill(admin *a, unsigned ac, char *av[])
   }
 }
 
+static void acmd_forcekx(admin *a, unsigned ac, char *av[])
+{
+  peer *p;
+  if ((p = p_find(av[0])) == 0)
+    a_fail(a, "unknown-peer %s", av[0]);
+  else {
+    kx_start(&p->kx);
+    a_ok(a);
+  }
+}
+
 static void acmd_quit(admin *a, unsigned ac, char *av[])
 {
   a_warn("SERVER quit admin-request");
@@ -848,6 +1012,14 @@ static void acmd_version(admin *a, unsigned ac, char *av[])
   a_ok(a);
 }
 
+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_ok(a);
+}
+
 /* --- The command table and help --- */
 
 typedef struct acmd {
@@ -874,8 +1046,13 @@ static const acmd acmdtab[] = {
   { "ifname",  "ifname PEER",          1,      1,      acmd_ifname },
   { "addr",    "addr PEER",            1,      1,      acmd_addr },
   { "stats",   "stats PEER",           1,      1,      acmd_stats },
+  { "ping",    "ping [OPTIONS] PEER",  1,      0xffff, acmd_ping },
+  { "eping",   "eping [OPTIONS] PEER", 1,      0xffff, acmd_eping },
   { "kill",    "kill PEER",            1,      1,      acmd_kill },
-  { "add",     "add PEER ADDR ...",    2,      0xffff, acmd_add },
+  { "forcekx", "forcekx PEER",         1,      1,      acmd_forcekx },
+  { "add",     "add PEER [OPTIONS] ADDR ...",
+                                       2,      0xffff, acmd_add },
+  { "tunnels", "tunnels",              0,      0,      acmd_tunnels },
   { "quit",    "quit",                 0,      0,      acmd_quit },
   { 0,         0,                      0,      0,      0 }
 };
@@ -924,12 +1101,14 @@ static void a_unlock(admin *a)
           a->seq); )
 
   selbuf_destroy(&a->b);
-  if (a->pname) {
-    xfree(a->pname);
+  if (a->peer.name) {
+    xfree(a->peer.name);
     xfree(a->paddr);
     bres_abort(&a->r);
     sel_rmtimer(&a->t);
   }
+  if (a->ping.p)
+    p_pingdone(&a->ping, PING_NONOTIFY);
   if (a->b.reader.fd != a->w.fd)
     close(a->b.reader.fd);
   close(a->w.fd);
@@ -1050,7 +1229,8 @@ void a_create(int fd_in, int fd_out, unsigned f)
   T( static unsigned seq = 0;
      a->seq = seq++; )
   T( trace(T_ADMIN, "admin: accepted connection %u", a->seq); )
-  a->pname = 0;
+  a->peer.name = 0;
+  a->ping.p = 0;
   a->f = f;
   if (fd_in == STDIN_FILENO)
     a_stdin = a;