static void a_lock(admin */*a*/);
static void a_unlock(admin */*a*/);
+#define BOOL(x) ((x) ? "t" : "nil")
+
/*----- Output functions --------------------------------------------------*/
/* --- @trywrite@ --- *
/*----- Backgrounded operations -------------------------------------------*/
+#define BGTAG(bg) \
+ (((admin_bgop *)(bg))->tag ? ((admin_bgop *)(bg))->tag : "<foreground>")
+
/* --- @a_bgrelease@ --- *
*
* Arguments: @admin_bgop *bg@ = backgrounded operation
{
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@ --- *
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);
}
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);
}
{
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);
{
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);
sel_rmtimer(&add->t);
a_addfree(add);
a_bgrelease(&add->bg);
- a_unlock(add->bg.a);
}
/* --- @a_addtimer@ --- *
{
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@ --- *
*/
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);
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:
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);
}
struct timeval tv;
double millis;
- a_lock(pg->bg.a);
switch (rc) {
case PING_OK:
gettimeofday(&tv, 0);
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@ --- *
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);
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;
}
}
+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[])
{ "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 },
* 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); )
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
/* --- 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@ --- *