chiark / gitweb /
reassemble adns log messages
authorian <ian>
Sun, 19 Dec 2004 20:35:08 +0000 (20:35 +0000)
committerian <ian>
Sun, 19 Dec 2004 20:35:08 +0000 (20:35 +0000)
adns/adns.c

index e768cd6..01f0dc6 100644 (file)
  *        cancels outstanding queries
  */
 
+#define _GNU_SOURCE
+
+#include <stdio.h>
+
 #include "tables.h"
 #include "hbytes.h"
 
@@ -125,7 +129,7 @@ static int oifn_reverse_any(Tcl_Interp *ip, const OptionInfo *oi,
 
 static void optparse_blank(OptionParse *op) {
   memset(op,0,sizeof(*op));
-  op->errfile= 0;
+  op->errfile= stderr;
   op->errcallback= 0;
   op->config_string= 0;
 }
@@ -170,6 +174,7 @@ struct Resolver {
   int maxfd;
   fd_set handling[3];
   ScriptToInvoke errcallback;
+  Tcl_Obj *errstring_accum;
 };
 
 /* The default resolver is recorded using Tcl_SetAssocData with key
@@ -220,9 +225,36 @@ static const OptionInfo resolver_optioninfos[]= {
   { 0 }
 };
 
+static void adnslogfn_flushmessage(Resolver *res) {
+  scriptinv_invoke(&res->errcallback, 1, &res->errstring_accum);
+  Tcl_SetObjLength(res->errstring_accum, 0);
+}
+
 static void adnslogfn_callback(adns_state ads, void *logfndata,
                               const char *fmt, va_list al) {
-  abort(); /* fixme implement adns_logcallbackfn */
+  Resolver *res= logfndata;
+  int l, newline;
+  char *str;
+
+  l= vasprintf(&str,fmt,al);
+  if (l<0) {
+    posixerr(res->interp,errno,"construct adns log callback string");
+    Tcl_BackgroundError(res->interp);
+  }
+
+  if (l==0) { free(str); return; }
+  if ((newline= l>0 && str[l-1]=='\n')) l--;
+
+  if (!res->errstring_accum) {
+    res->errstring_accum= Tcl_NewStringObj(str,l);
+    Tcl_IncrRefCount(res->errstring_accum);
+  } else {
+    Tcl_AppendToObj(res->errstring_accum,str,l);
+  }
+  free(str);
+
+  if (newline)
+    adnslogfn_flushmessage(res);
 }
 
 static Resolver *default_resolver(Tcl_Interp *ip) {
@@ -231,11 +263,20 @@ static Resolver *default_resolver(Tcl_Interp *ip) {
 
 static void destroy_resolver(Tcl_Interp *ip, Resolver *res) {
   void *query_v;
+  int logstring_len;
+  char *rstr;
   adns_query aqu;
  
   if (res == default_resolver(ip))
     Tcl_DeleteAssocData(ip,ASSOC_DEFAULTRES);
  
+  if (res->errstring_accum) {
+    rstr= Tcl_GetStringFromObj(res->errstring_accum, &logstring_len);
+    assert(rstr);
+    if (logstring_len)
+      adnslogfn_flushmessage(res);
+  }
+
   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 */
@@ -248,6 +289,7 @@ static void destroy_resolver(Tcl_Interp *ip, Resolver *res) {
     adns_finish(res->ads);
   }
   asynch_cancelhandlers(res);
+  scriptinv_cancel(&res->errcallback);
   TFREE(res);
 }
 
@@ -275,20 +317,20 @@ static int create_resolver(Tcl_Interp *ip, const OptionParse *op,
   res->ads= 0;
   res->timertoken= 0;
   res->maxfd= 0;
-  scriptinv_init(&res->errcallback);
   for (i=0; i<3; i++) FD_ZERO(&res->handling[i]);
+  scriptinv_init(&res->errcallback);
+  res->errstring_accum= 0;
+
+  if (op->errcallback)
+    scriptinv_set(&res->errcallback, ip, op->errcallback, 0);
 
   ec= adns_init_logfn(&res->ads,
                      op->aflags | adns_if_noautosys,
                      op->config_string,
                      op->errcallback ? adnslogfn_callback : 0,
-                     op->errcallback ? (void*)op->errcallback
-                     : (void*)op->errfile);
+                     op->errcallback ? (void*)res : (void*)op->errfile);
   if (ec) { rc= posixerr(ip,ec,"create adns resolver"); goto x_rc; }
 
-  if (op->errcallback)
-    scriptinv_set(&res->errcallback, ip, op->errcallback, 0);
-
   *res_r= res;
   return TCL_OK;