X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~mdw/git/tripe/blobdiff_plain/7d6ec3708e83ad0f9fe52360512df995cda06007..0ba8de86535cf6025076f5034b76ab753e4dde08:/admin.c diff --git a/admin.c b/admin.c index bbfc0ed6..e081bdf6 100644 --- 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)) + 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;