chiark / gitweb /
many improvements: use Get/SetAssocData for idtables to avoid globals, and adns bindi...
[chiark-tcl.git] / adns / adns.c
index 34ca06ce1e72055693299202c22603a5a9643104..1ecb6729c19b635e343554beec29ee1211fc1c86 100644 (file)
 
 /*---------- important types and forward declarations ----------*/
 
+typedef struct Query Query;
 typedef struct Resolver Resolver;
 typedef struct OptionInfo OptionInfo;
 static void asynch_check(Resolver *res);
 static void asynch_sethandlers(Resolver *res, int shutdown);
+static void asynch_query_dispose(Tcl_Interp *interp, Query *query);
 
 /*---------- common resolver/query option processing ----------*/
 
@@ -144,8 +146,6 @@ static int parse_options(Tcl_Interp *ip, int objc, Tcl_Obj *const *objv,
 
 /*---------- resolver management ----------*/
 
-IdDataTable adnstcl_resolvers= { "adns-res" };
-
 struct Resolver {
   int ix; /* first! */
   Tcl_Interp *interp;
@@ -202,15 +202,33 @@ static void adnslogfn_callback(adns_state ads, void *logfndata,
   abort(); /* fixme implement adns_logcallbackfn */
 }
 
-int do_adns_destroy_resolver(ClientData cd, Tcl_Interp *ip, void *res_v) {
-  Resolver *res= res_v;
-  tabledataid_disposing(res,&adnstcl_resolvers);
-  if (res->ads) adns_finish(res->ads);
+static void destroy_resolver(Tcl_Interp *ip, Resolver *res) {
+  void *query_v;
+  adns_query aqu;
+  
+  if (res->ads) {
+    /* although adns would throw these away for us, we need to
+     * destroy our own data too and only adns has a list of them */
+    for (;;) {
+      adns_forallqueries_begin(res->ads);
+      aqu= adns_forallqueries_next(res->ads, &query_v);
+      if (!aqu) break;
+      asynch_query_dispose(ip, query_v);
+    }
+    adns_finish(res->ads);
+  }
   asynch_sethandlers(res,1);
   TFREE(res);
-  /* fixme what about outstanding queries */
   /* fixme what about the default resolver */
-  /* fixme what if the tcl interpreter gets deleted */
+}
+
+static void destroy_resolver_idtabcb(Tcl_Interp *ip, void *resolver_v) {
+  destroy_resolver(ip,resolver_v);
+}
+
+int do_adns_destroy_resolver(ClientData cd, Tcl_Interp *ip, void *res_v) {
+  destroy_resolver(ip,res_v);
+  tabledataid_disposing(ip,res_v,&adnstcl_resolvers);
   return TCL_OK;
 }
 
@@ -262,6 +280,10 @@ int do_adns_new_resolver(ClientData cd, Tcl_Interp *ip,
   return rc;
 }
 
+const IdDataSpec adnstcl_resolvers= {
+  "adns-res", "adns-resolvers-table", destroy_resolver_idtabcb
+};
+
 /*---------- query, query option and answers - common stuff ----------*/
 
 #define RRTYPE_EXACTLY(t) { #t, adns_r_##t }
@@ -316,7 +338,7 @@ static const OptionInfo query_optioninfos[]= {
 static int query_submit(Tcl_Interp *ip,
                        const AdnsTclRRTypeInfo *type, const char *domain,
                        int queryopts_objc, Tcl_Obj *const *queryopts_objv,
-                       adns_query *aqu_r, OptionParse *op) {
+                       adns_query *aqu_r, void *context, OptionParse *op) {
   struct sockaddr sa;
   static const int aftry[]= { AF_INET, AF_INET6 };
   int rc, r, ec;
@@ -324,7 +346,8 @@ static int query_submit(Tcl_Interp *ip,
   
   op->aflags= adns_qf_owner;
   op->sflags= 0;
-  op->resolver= 0;
+  op->resolver= 0; /* fixme default */
+  op->reverseany= 0;
   rc= parse_options(ip, queryopts_objc,queryopts_objv, query_optioninfos,op);
   if (rc) return rc;
 
@@ -344,13 +367,13 @@ static int query_submit(Tcl_Interp *ip,
 
   if (op->reverseany) {
     ec= adns_submit_reverse_any(ads, &sa, op->reverseany,
-                               type->number, op->aflags, 0, aqu_r);
+                               type->number, op->aflags, context, aqu_r);
   } else if (op->sflags & oisf_reverse) {
     ec= adns_submit_reverse(ads, &sa,
-                           type->number, op->aflags, 0, aqu_r);
+                           type->number, op->aflags, context, aqu_r);
   } else {
     ec= adns_submit(ads, domain,
-                   type->number, op->aflags, 0, aqu_r);
+                   type->number, op->aflags, context, aqu_r);
   }
   if (ec)
     return posixerr(ip,ec,"submit adns query");
@@ -370,7 +393,7 @@ static void make_resultstatus(Tcl_Interp *ip, adns_status status,
 }
 
 static Tcl_Obj *make_resultrdata(Tcl_Interp *ip, adns_answer *answer) {
-  Tcl_Obj **rdata;
+  Tcl_Obj **rdata, *rl;
   int i, rrsz;
   adns_status st;
   char *datap, *rdatastring;
@@ -384,8 +407,9 @@ static Tcl_Obj *make_resultrdata(Tcl_Interp *ip, adns_answer *answer) {
     rdata[i]= ret_string(ip, rdatastring);
     free(rdatastring);
   }
+  rl= Tcl_NewListObj(answer->nrrs, rdata);
   TFREE(rdata);
-  return Tcl_NewListObj(answer->nrrs, rdata);
+  return rl;
 }
 
 static void make_resultlist(Tcl_Interp *ip, adns_answer *answer,
@@ -408,7 +432,7 @@ static int synch(Tcl_Interp *ip, const AdnsTclRRTypeInfo *rrtype,
   Resolver *res;
   int rc, ec;
   
-  rc= query_submit(ip,rrtype,domain,objc,objv,&aqu,&op);
+  rc= query_submit(ip,rrtype,domain,objc,objv,&aqu,0,&op);
   if (rc) return rc;
 
   res= op.resolver;
@@ -458,15 +482,13 @@ int do_adns_synch(ClientData cd, Tcl_Interp *ip,
 
 /*---------- asynchronous query handling ----------*/
 
-typedef struct {
+struct Query {
   int ix; /* first! */
   Resolver *res;
   adns_query aqu;
   ScriptToInvoke on_yes, on_no, on_fail;
   Tcl_Obj *xargs;
-} Query;
-
-IdDataTable adnstcl_queries= { "adns" };
+};
 
 static void asynch_timerhandler(void *res_v) {
   Resolver *res= res_v;
@@ -526,16 +548,6 @@ static void asynch_sethandlers(Resolver *res, int shutdown) {
   }
 }
 
-static void asynch_query_dispose(Query *query) {
-  tabledataid_disposing(query, &adnstcl_queries);
-  scriptinv_cancel(&query->on_yes);
-  scriptinv_cancel(&query->on_no);
-  scriptinv_cancel(&query->on_fail);
-  if (query->xargs) Tcl_DecrRefCount(query->xargs);
-  if (query->aqu) adns_cancel(query->aqu);
-  TFREE(query);
-}
-
 static void asynch_check(Resolver *res) {
   Tcl_Interp *interp= res->interp;
   adns_query aqu;
@@ -553,7 +565,7 @@ static void asynch_check(Resolver *res) {
     query= query_v;
 
     query->aqu= 0;
-    tabledataid_disposing(query, &adnstcl_queries);
+    tabledataid_disposing(interp, query, &adnstcl_queries);
 
     si= (!answer->status ? si= &query->on_yes
         : answer->status > adns_s_max_tempfail ? &query->on_no
@@ -562,7 +574,7 @@ static void asynch_check(Resolver *res) {
     make_resultlist(interp, answer, results);
     free(answer);
     scriptinv_invoke(si, RESULTLIST_LLEN, results);
-    asynch_query_dispose(query);
+    asynch_query_dispose(interp, query);
   }
 
   asynch_sethandlers(res,0);
@@ -586,7 +598,7 @@ int do_adns_asynch(ClientData cd, Tcl_Interp *ip,
   scriptinv_init(&query->on_fail);
   query->xargs= 0;
 
-  rc= query_submit(ip,rrtype,domain,objc,objv,&query->aqu,&op);
+  rc= query_submit(ip,rrtype,domain,objc,objv,&query->aqu,query,&op);
   if (rc) goto x_rc;
 
   res= op.resolver;
@@ -601,7 +613,7 @@ int do_adns_asynch(ClientData cd, Tcl_Interp *ip,
   return TCL_OK;
 
  x_rc:
-  if (query) asynch_query_dispose(query);
+  if (query) asynch_query_dispose(ip, query);
   if (res) asynch_sethandlers(res,0);
   return rc;
 }
@@ -609,8 +621,25 @@ int do_adns_asynch(ClientData cd, Tcl_Interp *ip,
 int do_adns_asynch_cancel(ClientData cd, Tcl_Interp *ip, void *query_v) {
   Query *query= query_v;
   Resolver *res= query->res;
-  
-  asynch_query_dispose(query);
+  asynch_query_dispose(ip, query);
   asynch_sethandlers(res,0);
   return TCL_OK;
 }
+
+static void asynch_query_dispose(Tcl_Interp *interp, Query *query) {
+  tabledataid_disposing(interp, query, &adnstcl_queries);
+  scriptinv_cancel(&query->on_yes);
+  scriptinv_cancel(&query->on_no);
+  scriptinv_cancel(&query->on_fail);
+  if (query->xargs) Tcl_DecrRefCount(query->xargs);
+  if (query->aqu) adns_cancel(query->aqu);
+  TFREE(query);
+}
+
+static void destroy_query_idtabcb(Tcl_Interp *interp, void *query_v) {
+  asynch_query_dispose(interp, query_v);
+}
+
+const IdDataSpec adnstcl_queries= {
+  "adns", "adns-query-table", destroy_query_idtabcb
+};