chiark / gitweb /
Fix for new key-data interface.
[tripe] / admin.c
diff --git a/admin.c b/admin.c
index 24d86c64ac40dcf7a33e61c84d6ccb2eac48ae6a..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*/);
@@ -467,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@ --- *
@@ -489,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->tops, &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);
 }
@@ -523,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);
 }
@@ -546,7 +570,6 @@ static void acmd_add(admin *a, unsigned ac, char *av[])
   unsigned long pt;
   struct timeval tv;
   unsigned i, j;
-  const tunnel_ops *tops = tun_default;
   char *p;
 
   /* --- Make sure someone's not got there already --- */
@@ -556,6 +579,12 @@ static void acmd_add(admin *a, unsigned ac, char *av[])
     return;
   }
 
+  /* --- Set stuff up --- */
+
+  a->peer.name = av[0];
+  a->peer.t_ka = 0;
+  a->peer.tops = tun_default;
+
   /* --- Parse options --- */
 
   i = 1;
@@ -563,37 +592,42 @@ static void acmd_add(admin *a, unsigned ac, char *av[])
     if (!av[i])
       goto bad_syntax;
     if (mystrieq(av[i], "-tunnel")) {
-      i++;
-      if (!av[i])
-       goto bad_syntax;
+      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)) {
-         tops = tunnels[j];
+         a->peer.tops = tunnels[j];
          break;
        }
       }
-      i++;
+    } 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 --- */
 
-  BURN(a->peer);
   if (mystrieq(av[i], "inet")) i++;
   if (ac - i != 2) {
-    a_fail(a, "bad-syntax -- add PEER [-tunnel TUN] [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");
@@ -607,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], tops, &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;
   }
 
@@ -626,9 +661,8 @@ 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]);
-  a->tops = tops;
   selbuf_disable(&a->b);
   gettimeofday(&tv, 0);
   tv.tv_sec += T_RESOLVE;
@@ -639,10 +673,108 @@ static void acmd_add(admin *a, unsigned ac, char *av[])
   return;
 
 bad_syntax:
-  a_fail(a, "bad-syntax -- add PEER [-tunnel TUN] ADDR ...");
+  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 --- */
@@ -856,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");
@@ -903,8 +1046,11 @@ 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 [-tunnel TUN] ADDR ...",
+  { "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 },
@@ -955,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);
@@ -1081,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;