+ sel_addtimer(&sel, &r->t, &tv, a_restimer, r);
+ bres_byname(&r->r, r->addr, a_resolved, r);
+ return;
+
+fail:
+ func(r, ARES_FAIL);
+ if (r->addr) xfree(r->addr);
+ xfree(r);
+}
+
+/*----- Adding peers ------------------------------------------------------*/
+
+/* --- @a_doadd@ --- *
+ *
+ * Arguments: @admin_resop *r@ = resolver operation
+ * @int rc@ = how it worked
+ *
+ * Returns: ---
+ *
+ * Use: Handles a completed resolution.
+ */
+
+static void a_doadd(admin_resop *r, int rc)
+{
+ admin_addop *add = (admin_addop *)r;
+
+ T( trace(T_ADMIN, "admin: done add op %s", BGTAG(add)); )
+
+ if (rc == ARES_OK) {
+ add->peer.sasz = add->r.sasz;
+ add->peer.sa = add->r.sa;
+ if (p_find(add->peer.name))
+ a_bgfail(&add->r.bg, "peer-exists", "%s", add->peer.name, A_END);
+ else if (!p_create(&add->peer))
+ a_bgfail(&add->r.bg, "peer-create-fail", "%s", add->peer.name, A_END);
+ else
+ a_bgok(&add->r.bg);
+ }
+
+ xfree(add->peer.name);
+}
+
+/* --- @acmd_add@ --- *
+ *
+ * Arguments: @admin *a@ = connection which requested the addition
+ * @unsigned ac@ = argument count
+ * @char *av[]@ = pointer to the argument list
+ *
+ * Returns: ---
+ *
+ * Use: Adds a new peer.
+ */
+
+static void acmd_add(admin *a, unsigned ac, char *av[])
+{
+ unsigned i, j;
+ const char *tag = 0;
+ admin_addop *add = 0;
+
+ /* --- Set stuff up --- */
+
+ add = xmalloc(sizeof(*add));
+ add->peer.name = xstrdup(av[0]);
+ add->peer.t_ka = 0;
+ add->peer.tops = tun_default;
+
+ /* --- Make sure someone's not got there already --- */
+
+ if (p_find(av[0])) {
+ a_fail(a, "peer-exists", "%s", av[0], A_END);
+ goto fail;
+ }
+
+ /* --- Parse options --- */
+
+ i = 1;
+ for (;;) {
+ if (!av[i])
+ goto bad_syntax;
+ if (mystrieq(av[i], "-background")) {
+ if (!av[++i]) goto bad_syntax;
+ tag = av[i];
+ } else 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], A_END);
+ goto fail;
+ }
+ if (mystrieq(av[i], tunnels[j]->name)) {
+ add->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], A_END);
+ goto fail;
+ }
+ add->peer.t_ka = t;
+ } else if (mystrieq(av[i], "--")) {
+ i++;
+ break;
+ } else
+ break;
+ i++;
+ }
+
+ /* --- Crank up the resolver --- */
+
+ a_resolve(a, &add->r, tag, a_doadd, ac - i, av + i);
+ return;
+
+ /* --- Clearing up --- */
+
+bad_syntax:
+ a_fail(a, "bad-syntax", "add", "PEER [OPTIONS] ADDR ...", A_END);
+fail:
+ xfree(add->peer.name);
+ xfree(add);
+ return;
+}
+
+/*----- Ping --------------------------------------------------------------*/
+
+/* --- @a_pingcancel@ --- *
+ *
+ * Arguments: @admin_bgop *bg@ = background operation block
+ *
+ * Returns: ---
+ *
+ * Use: Cancels a running ping.
+ */
+
+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);