chiark / gitweb /
More support scripts and other cool stuff.
[tripe] / admin.c
diff --git a/admin.c b/admin.c
index 92ea0a6..987de7a 100644 (file)
--- a/admin.c
+++ b/admin.c
@@ -77,6 +77,8 @@ static void a_destroy(admin */*a*/);
 static void a_lock(admin */*a*/);
 static void a_unlock(admin */*a*/);
 
+#define BOOL(x) ((x) ? "t" : "nil")
+
 /*----- Output functions --------------------------------------------------*/
 
 /* --- @trywrite@ --- *
@@ -512,6 +514,9 @@ static long a_parsetime(const char *p)
 
 /*----- Backgrounded operations -------------------------------------------*/
 
+#define BGTAG(bg)                                                      \
+  (((admin_bgop *)(bg))->tag ? ((admin_bgop *)(bg))->tag : "<foreground>")
+
 /* --- @a_bgrelease@ --- *
  *
  * Arguments:  @admin_bgop *bg@ = backgrounded operation
@@ -526,19 +531,15 @@ static void a_bgrelease(admin_bgop *bg)
 {
   admin *a = bg->a;
 
-  if (bg->tag)
-    xfree(bg->tag);
-  else
-    selbuf_enable(&a->b);
-  if (bg->next)
-    bg->next->prev = bg->prev;
-  if (bg->prev)
-    bg->prev->next = bg->next;
-  else
-    a->bg = bg->next;
+  T( trace(T_ADMIN, "admin: release bgop %s", BGTAG(bg)); )
+  if (bg->tag) xfree(bg->tag);
+  else selbuf_enable(&a->b);
+  if (bg->next) bg->next->prev = bg->prev;
+  if (bg->prev) bg->prev->next = bg->next;
+  else a->bg = bg->next;
   xfree(bg);
-  if (a->f & AF_CLOSE)
-    a_destroy(a);
+  if (a->f & AF_CLOSE) a_destroy(a);
+  a_unlock(a);
 }
 
 /* --- @a_bgok@, @a_bginfo@, @a_bgfail@ --- *
@@ -596,7 +597,10 @@ static void a_bgadd(admin *a, admin_bgop *bg, const char *tag,
   bg->cancel = cancel;
   bg->next = a->bg;
   bg->prev = 0;
+  if (a->bg) a->bg->prev = bg;
   a->bg = bg;
+  a_lock(a);
+  T( trace(T_ADMIN, "admin: add bgop %s", BGTAG(bg)); )
   if (tag) a_write(a, "DETACH", tag, 0);
 }
 
@@ -613,6 +617,7 @@ static void a_bgadd(admin *a, admin_bgop *bg, const char *tag,
 
 static void a_addfree(admin_addop *add)
 {
+  T( trace(T_ADMIN, "admin: free add op %s", BGTAG(add)); )
   if (add->peer.name) xfree(add->peer.name);
   if (add->paddr) xfree(add->paddr);
 }
@@ -630,6 +635,7 @@ static void a_addcancel(admin_bgop *bg)
 {
   admin_addop *add = (admin_addop *)bg;
 
+  T( trace(T_ADMIN, "admin: cancel add op %s", BGTAG(add)); )
   sel_rmtimer(&add->t);
   bres_abort(&add->r);
   a_addfree(add);
@@ -668,8 +674,7 @@ static void a_addresolve(struct hostent *h, void *v)
 {
   admin_addop *add = v;
 
-  a_lock(add->bg.a);
-  T( trace(T_ADMIN, "admin: %u resolved", add->bg.a->seq); )
+  T( trace(T_ADMIN, "admin: add op %s resolved", BGTAG(add)); )
   TIMER;
   if (!h)
     a_bgfail(&add->bg, "resolve-error %s", add->paddr);
@@ -680,7 +685,6 @@ static void a_addresolve(struct hostent *h, void *v)
   sel_rmtimer(&add->t);
   a_addfree(add);
   a_bgrelease(&add->bg);
-  a_unlock(add->bg.a);
 }
 
 /* --- @a_addtimer@ --- *
@@ -697,13 +701,11 @@ static void a_addtimer(struct timeval *tv, void *v)
 {
   admin_addop *add = v;
 
-  a_lock(add->bg.a);
-  T( trace(T_ADMIN, "admin: %u resolver timeout", add->bg.a->seq); )
+  T( trace(T_ADMIN, "admin: add op %s timeout", BGTAG(add)); )
   a_bgfail(&add->bg, "resolver-timeout %s\n", add->paddr);
   bres_abort(&add->r);
   a_addfree(add);
   a_bgrelease(&add->bg);
-  a_unlock(add->bg.a);
 }
 
 /* --- @acmd_add@ --- *
@@ -810,10 +812,13 @@ static void acmd_add(admin *a, unsigned ac, char *av[])
    */
 
   a_bgadd(a, &add->bg, tag, a_addcancel);
+  T( trace(T_ADMIN, "admin: %u, add op %s resolving hostname `%s'",
+          a->seq, BGTAG(add), add->paddr); )
 
   /* --- If the name is numeric, do it the easy way --- */
   
   if (inet_aton(av[i], &add->peer.sa.sin.sin_addr)) {
+    T( trace(T_ADMIN, "admin: add op %s done the easy way", BGTAG(add)); )
     a_doadd(add);
     a_addfree(add);
     a_bgrelease(&add->bg);
@@ -826,8 +831,6 @@ static void acmd_add(admin *a, unsigned ac, char *av[])
   tv.tv_sec += T_RESOLVE;
   sel_addtimer(&sel, &add->t, &tv, a_addtimer, add);
   bres_byname(&add->r, add->paddr, a_addresolve, add);
-  T( trace(T_ADMIN, "admin: %u resolving hostname `%s'",
-          a->seq, add->paddr); )
   return;
 
 bad_syntax:
@@ -854,6 +857,7 @@ fail:
 static void a_pingcancel(admin_bgop *bg)
 {
   admin_pingop *pg = (admin_pingop *)bg;
+  T( trace(T_ADMIN, "admin: cancel ping op %s", BGTAG(pg)); )
   p_pingdone(&pg->ping, PING_NONOTIFY);
 }
 
@@ -873,7 +877,6 @@ static void a_pong(int rc, void *v)
   struct timeval tv;
   double millis;
 
-  a_lock(pg->bg.a);
   switch (rc) {
     case PING_OK:
       gettimeofday(&tv, 0);
@@ -893,8 +896,8 @@ static void a_pong(int rc, void *v)
     default:
       abort();
   }
+  T( trace(T_ADMIN, "admin: ponged ping op %s", BGTAG(pg)); )
   a_bgrelease(&pg->bg);
-  a_unlock(pg->bg.a);
 }
 
 /* --- @acmd_ping@, @acmd_eping@ --- *
@@ -946,6 +949,8 @@ static void a_ping(admin *a, unsigned ac, char *av[],
   pg = xmalloc(sizeof(*pg));
   gettimeofday(&pg->pingtime, 0);
   a_bgadd(a, &pg->bg, tag, a_pingcancel);
+  T( trace(T_ADMIN, "admin: ping op %s: %s to %s",
+          BGTAG(pg), cmd, p_name(p)); )
   if (p_pingsend(p, &pg->ping, msg, t, a_pong, pg)) {
     a_bgfail(&pg->bg, "ping-send-failed");
     a_bgrelease(&pg->bg);
@@ -987,10 +992,9 @@ static int traceish(admin *a, unsigned ac, char *av[],
 
   if (!ac || strcmp(av[0], "?") == 0) {
     const trace_opt *t;
-    a_info(a, "Current %s status:", what);
     for (t = tt; t->ch; t++) {
-      a_info(a, "%c %c  %s",
-            t->ch, (*ff & t->f) == t->f ? '*' : ' ', t->help);
+      a_info(a, "%c%c %s",
+            t->ch, (*ff & t->f) == t->f ? '+' : ' ', t->help);
     }
   } else {
     unsigned sense = 1;
@@ -1136,32 +1140,57 @@ static void acmd_addr(admin *a, unsigned ac, char *av[])
   }
 }
 
+static void acmd_peerinfo(admin *a, unsigned ac, char *av[])
+{
+  peer *p;
+  const peerspec *ps;
+
+  if ((p = p_find(av[0])) == 0) {
+    a_fail(a, "unknown-peer %s", av[0]);
+    return;
+  }
+
+  ps = p_spec(p);
+  a_info(a, "tunnel=%s", ps->tops->name);
+  a_info(a, "keepalive=%lu", ps->t_ka);
+  a_ok(a);
+}
+
+static void acmd_servinfo(admin *a, unsigned ac, char *av[])
+{
+  a_info(a, "implementation=edgeware-tripe");
+  a_info(a, "version=%s", VERSION);
+  a_info(a, "daemon=%s", BOOL(flags & F_DAEMON));
+  a_ok(a);
+}
+
 static void acmd_stats(admin *a, unsigned ac, char *av[])
 {
   peer *p;
   stats *st;
 
-  if ((p = p_find(av[0])) == 0)
+  if ((p = p_find(av[0])) == 0) {
     a_fail(a, "unknown-peer %s", av[0]);
-  else {
-    st = p_stats(p);
-    a_info(a, "start-time=%s", timestr(st->t_start));
-    a_info(a, "last-packet-time=%s", timestr(st->t_last));
-    a_info(a, "last-keyexch-time=%s", timestr(st->t_kx));
-    a_info(a, "packets-in=%lu bytes-in=%lu", st->n_in, st->sz_in);
-    a_info(a, "packets-out=%lu bytes-out=%lu",
-           st->n_out, st->sz_out);
-    a_info(a, "keyexch-packets-in=%lu keyexch-bytes-in=%lu",
-           st->n_kxin, st->sz_kxin);
-    a_info(a, "keyexch-packets-out=%lu keyexch-bytes-out=%lu",
-           st->n_kxout, st->sz_kxout);
-    a_info(a, "ip-packets-in=%lu ip-bytes-in=%lu",
-           st->n_ipin, st->sz_ipin);
-    a_info(a, "ip-packets-out=%lu ip-bytes-out=%lu",
-           st->n_ipout, st->sz_ipout);
-    a_info(a, "rejected-packets=%lu", st->n_reject);
-    a_ok(a);
+    return;
   }
+
+  st = p_stats(p);
+  a_info(a, "start-time=%s", timestr(st->t_start));
+  a_info(a, "last-packet-time=%s", timestr(st->t_last));
+  a_info(a, "last-keyexch-time=%s", timestr(st->t_kx));
+  a_info(a, "packets-in=%lu bytes-in=%lu", st->n_in, st->sz_in);
+  a_info(a, "packets-out=%lu bytes-out=%lu",
+        st->n_out, st->sz_out);
+  a_info(a, "keyexch-packets-in=%lu keyexch-bytes-in=%lu",
+        st->n_kxin, st->sz_kxin);
+  a_info(a, "keyexch-packets-out=%lu keyexch-bytes-out=%lu",
+        st->n_kxout, st->sz_kxout);
+  a_info(a, "ip-packets-in=%lu ip-bytes-in=%lu",
+        st->n_ipin, st->sz_ipin);
+  a_info(a, "ip-packets-out=%lu ip-bytes-out=%lu",
+        st->n_ipout, st->sz_ipout);
+  a_info(a, "rejected-packets=%lu", st->n_reject);
+  a_ok(a);
 }
 
 static void acmd_kill(admin *a, unsigned ac, char *av[])
@@ -1234,10 +1263,12 @@ static const acmd acmdtab[] = {
   { "kill",    "kill PEER",            1,      1,      acmd_kill },
   { "list",    "list",                 0,      0,      acmd_list },
   { "notify",  "notify MESSAGE ...",   1,      0xffff, acmd_notify },
+  { "peerinfo",        "peerinfo PEER",        1,      1,      acmd_peerinfo },
   { "ping",    "ping [OPTIONS] PEER",  1,      0xffff, acmd_ping },
   { "port",    "port",                 0,      0,      acmd_port },
   { "quit",    "quit",                 0,      0,      acmd_quit },
   { "reload",  "reload",               0,      0,      acmd_reload },
+  { "servinfo",        "servinfo",             0,      0,      acmd_servinfo },
   { "stats",   "stats PEER",           1,      1,      acmd_stats },
 #ifndef NTRACE
   { "trace",   "trace [OPTIONS]",      0,      1,      acmd_trace },
@@ -1269,32 +1300,20 @@ static void acmd_help(admin *a, unsigned ac, char *av[])
  *             immediately.
  */
 
-static void a_lock(admin *a) { assert(!(a->f & AF_LOCK)); a->f |= AF_LOCK; }
+static void a_lock(admin *a) { a->ref++; }
 
-/* --- @a_unlock@ --- *
+/* --- @a_dodestroy@ --- *
  *
  * Arguments:  @admin *a@ = pointer to an admin block
  *
  * Returns:    ---
  *
- * Use:                Unlocks an admin block, allowing its destruction.  This is
- *             also the second half of @a_destroy@.
+ * Use:                Actually does the legwork of destroying an admin block.
  */
 
-static void a_unlock(admin *a)
+static void a_dodestroy(admin *a)
 {
   admin_bgop *bg, *bbg;
-  
-  assert(a->f & AF_LOCK);
-
-  /* --- If we're not dead, that's fine --- */
-
-  if (!(a->f & AF_DEAD)) {
-    a->f &= ~AF_LOCK;
-    return;
-  }
-
-  /* --- If we are, then destroy the rest of the block --- */
 
   T( trace(T_ADMIN, "admin: completing destruction of connection %u",
           a->seq); )
@@ -1320,6 +1339,23 @@ static void a_unlock(admin *a)
   DESTROY(a);
 }
 
+/* --- @a_unlock@ --- *
+ *
+ * Arguments:  @admin *a@ = pointer to an admin block
+ *
+ * Returns:    ---
+ *
+ * Use:                Unlocks an admin block, allowing its destruction.  This is
+ *             also the second half of @a_destroy@.
+ */
+
+static void a_unlock(admin *a)
+{
+  assert(a->ref);
+  if (!--a->ref && (a->f & AF_DEAD))
+    a_dodestroy(a);
+}
+
 /* --- @a_destroy@ --- *
  *
  * Arguments:  @admin *a@ = pointer to an admin block
@@ -1361,12 +1397,10 @@ static void a_destroy(admin *a)
 
   /* --- If the block is locked, that's all we can manage --- */
 
-  if (a->f & AF_LOCK) {
-    T( trace(T_ADMIN, "admin: deferring destruction..."); )
-    return;
-  }
-  a->f |= AF_LOCK;
-  a_unlock(a);
+  if (!a->ref)
+    a_dodestroy(a);
+  T( else 
+     trace(T_ADMIN, "admin: deferring destruction..."); )
 }
 
 /* --- @a_line@ --- *