+/* --- @a_rescancel@ --- *
+ *
+ * Arguments: @admin_bgop *bg@ = background operation
+ *
+ * Returns: ---
+ *
+ * Use: Cancels an add operation.
+ */
+
+static void a_rescancel(admin_bgop *bg)
+{
+ admin_resop *r = (admin_resop *)bg;
+
+ T( trace(T_ADMIN, "admin: cancel resop %s", BGTAG(r)); )
+ r->func(r, ARES_FAIL);
+ sel_rmtimer(&r->t);
+ xfree(r->addr);
+ bres_abort(&r->r);
+}
+
+/* --- @a_resolve@ --- *
+ *
+ * Arguments: @admin *a@ = administration connection
+ * @admin_resop *r@ = resolver operation to run
+ * @const char *tag@ = background operation tag
+ * @void (*func)(struct admin_resop *, int@ = handler function
+ * @unsigned ac@ = number of remaining arguments
+ * @char *av[]@ = pointer to remaining arguments
+ *
+ * Returns: ---
+ *
+ * Use: Cranks up a resolver job.
+ */
+
+static void a_resolve(admin *a, admin_resop *r, const char *tag,
+ void (*func)(struct admin_resop *, int),
+ unsigned ac, char *av[])
+{
+ struct timeval tv;
+ unsigned long pt;
+ char *p;
+ int i = 0;
+
+ /* --- Fill in the easy bits of address --- */
+
+ r->bg.tag = "<starting>";
+ r->addr = 0;
+ r->func = func;
+ if (mystrieq(av[i], "inet")) i++;
+ if (ac - i != 2) {
+ a_fail(a, "bad-addr-syntax", "[inet] ADDRESS PORT", A_END);
+ goto fail;
+ }
+ r->sa.sin.sin_family = AF_INET;
+ r->sasz = sizeof(r->sa.sin);
+ r->addr = xstrdup(av[i]);
+ pt = strtoul(av[i + 1], &p, 0);
+ if (*p) {
+ struct servent *s = getservbyname(av[i + 1], "udp");
+ if (!s) {
+ a_fail(a, "unknown-service", "%s", av[i + 1], A_END);
+ goto fail;
+ }
+ pt = ntohs(s->s_port);
+ }
+ if (pt == 0 || pt >= 65536) {
+ a_fail(a, "invalid-port", "%lu", pt, A_END);
+ goto fail;
+ }
+ r->sa.sin.sin_port = htons(pt);
+
+ /* --- Report backgrounding --- *
+ *
+ * Do this for consistency of interface, even if we're going to get the
+ * answer straight away.
+ */
+
+ a_bgadd(a, &r->bg, tag, a_rescancel);
+ T( trace(T_ADMIN, "admin: %u, resop %s, hostname `%s'",
+ a->seq, BGTAG(r), r->addr); )
+
+ /* --- If the name is numeric, do it the easy way --- */
+
+ if (inet_aton(av[i], &r->sa.sin.sin_addr)) {
+ T( trace(T_ADMIN, "admin: resop %s done the easy way", BGTAG(r)); )
+ func(r, ARES_OK);
+ xfree(r->addr);
+ a_bgrelease(&r->bg);
+ return;
+ }
+
+ /* --- Store everything for later and crank up the resolver --- */
+
+ gettimeofday(&tv, 0);
+ tv.tv_sec += T_RESOLVE;
+ 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);