+int cht_do_adns_lookup(ClientData cd, Tcl_Interp *ip,
+ const AdnsTclRRTypeInfo *rrtype,
+ const char *domain,
+ int objc, Tcl_Obj *const *objv,
+ Tcl_Obj **result) {
+ int rc;
+ adns_answer *answer;
+
+ rc= synch(ip,rrtype,domain,objc,objv,&answer); if (rc) return rc;
+
+ if (answer->status) {
+ Tcl_Obj *problem[RESULTSTATUS_LLEN];
+ make_resultstatus(ip, answer->status, problem);
+ *result= Tcl_NewListObj(RESULTSTATUS_LLEN, problem);
+ } else {
+ *result= make_resultrdata(ip, answer);
+ }
+ free(answer);
+ return TCL_OK;
+}
+
+int cht_do_adns_synch(ClientData cd, Tcl_Interp *ip,
+ const AdnsTclRRTypeInfo *rrtype,
+ const char *domain,
+ int objc, Tcl_Obj *const *objv,
+ Tcl_Obj **result) {
+ int rc;
+ adns_answer *answer;
+ Tcl_Obj *results[RESULTLIST_LLEN];
+
+ rc= synch(ip,rrtype,domain,objc,objv,&answer); if (rc) return rc;
+ make_resultlist(ip,answer,results);
+ free(answer);
+ *result= Tcl_NewListObj(RESULTLIST_LLEN, results);
+ return TCL_OK;
+}
+
+/*---------- asynchronous query handling ----------*/
+
+struct Query {
+ int ix; /* first! */
+ Resolver *res;
+ adns_query aqu;
+ ScriptToInvoke on_yes, on_no, on_fail;
+ Tcl_Obj *xargs;
+};
+
+static void asynch_check_now(Resolver *res);
+
+static void asynch_timerhandler(void *res_v) {
+ Resolver *res= res_v;
+ res->timertoken= 0;
+ adns_processtimeouts(res->ads,0);
+ asynch_check_now(res);
+}
+
+static void asynch_filehandler(void *res_v, int mask) {
+ Resolver *res= res_v;
+ int ec;
+
+ ec= adns_processany(res->ads);
+ if (ec) adns_globalsystemfailure(res->ads);
+ asynch_check_now(res);
+}
+
+static void asynch_sethandlers_generic(Resolver *res,
+ int shutdown /*from _cancelhandlers*/,
+ int immediate /*from _perturbed*/) {
+ fd_set want[3];
+ int maxfd;
+ struct timeval tv_buf, *timeout;
+ int i, fd;
+
+ timeout= 0;
+ maxfd= 0;
+ for (i=0; i<3; i++) FD_ZERO(&want[i]);
+
+ if (!shutdown)
+ adns_beforeselect(res->ads,&maxfd,&want[0],&want[1],&want[2],
+ &timeout,&tv_buf,0);
+
+ for (fd= 0; fd < maxfd || fd < res->maxfd; fd++)
+ for (i=0; i<3; i++)
+ if (!!FD_ISSET(fd, &res->handling[i])
+ != !!FD_ISSET(fd, &want[i])) {
+ int mask=0;
+ if (FD_ISSET(fd, &want[0])) mask |= TCL_READABLE;
+ if (FD_ISSET(fd, &want[1])) mask |= TCL_WRITABLE;
+ if (FD_ISSET(fd, &want[2])) mask |= TCL_EXCEPTION;
+ if (mask) {
+ Tcl_CreateFileHandler(fd,mask,asynch_filehandler,res);
+ FD_SET(fd, &res->handling[i]);
+ } else {
+ Tcl_DeleteFileHandler(fd);
+ FD_CLR(fd, &res->handling[i]);
+ }
+ }
+ res->maxfd= maxfd;
+
+ Tcl_DeleteTimerHandler(res->timertoken);
+
+ if (immediate) {
+ res->timertoken= Tcl_CreateTimerHandler(0,asynch_timerhandler,res);
+ } else if (timeout) {
+ int milliseconds;
+
+ if (timeout->tv_sec >= INT_MAX/1000 - 1)
+ milliseconds= INT_MAX;
+ else
+ milliseconds= timeout->tv_sec * 1000 +
+ (timeout->tv_usec + 999) / 1000;
+
+ res->timertoken=
+ Tcl_CreateTimerHandler(milliseconds,asynch_timerhandler,res);
+ }
+}
+
+static void asynch_sethandlers(Resolver *res) {
+ asynch_sethandlers_generic(res,0,0);
+}
+static void asynch_cancelhandlers(Resolver *res) {
+ asynch_sethandlers_generic(res,1,0);
+}
+static void asynch_perturbed(Resolver *res) {
+ asynch_sethandlers_generic(res,0,1);
+}
+
+static void asynch_check_now(Resolver *res) {