Make the query callbacks return the number of timeouts that happened during the execu...
authorSteinar H. Gunderson <sesse@google.com>
Fri, 28 Sep 2007 14:46:51 +0000 (14:46 +0000)
committerSteinar H. Gunderson <sesse@google.com>
Fri, 28 Sep 2007 14:46:51 +0000 (14:46 +0000)
19 files changed:
adig.c
ahost.c
ares.h
ares_cancel.c
ares_destroy.c
ares_gethostbyaddr.3
ares_gethostbyaddr.c
ares_gethostbyname.3
ares_gethostbyname.c
ares_getnameinfo.3
ares_getnameinfo.c
ares_private.h
ares_process.c
ares_query.3
ares_query.c
ares_search.3
ares_search.c
ares_send.3
ares_send.c

diff --git a/adig.c b/adig.c
index 1eea3df..b4fd205 100644 (file)
--- a/adig.c
+++ b/adig.c
@@ -127,7 +127,8 @@ static const char *rcodes[] = {
   "(unknown)", "(unknown)", "(unknown)", "(unknown)", "NOCHANGE"
 };
 
-static void callback(void *arg, int status, unsigned char *abuf, int alen);
+static void callback(void *arg, int status, int timeouts,
+                     unsigned char *abuf, int alen);
 static const unsigned char *display_question(const unsigned char *aptr,
                                              const unsigned char *abuf,
                                              int alen);
@@ -294,7 +295,8 @@ int main(int argc, char **argv)
   return 0;
 }
 
-static void callback(void *arg, int status, unsigned char *abuf, int alen)
+static void callback(void *arg, int status, int timeouts,
+                     unsigned char *abuf, int alen)
 {
   char *name = (char *) arg;
   int id, qr, opcode, aa, tc, rd, ra, rcode;
diff --git a/ahost.c b/ahost.c
index e381c19..1e6cc8b 100644 (file)
--- a/ahost.c
+++ b/ahost.c
@@ -47,7 +47,7 @@ struct in6_addr
 };
 #endif
 
-static void callback(void *arg, int status, struct hostent *host);
+static void callback(void *arg, int status, int timeouts, struct hostent *host);
 static void usage(void);
 
 int main(int argc, char **argv)
@@ -142,7 +142,7 @@ int main(int argc, char **argv)
   return 0;
 }
 
-static void callback(void *arg, int status, struct hostent *host)
+static void callback(void *arg, int status, int timeouts, struct hostent *host)
 {
   char **p;
 
diff --git a/ares.h b/ares.h
index 61d5a56..50ce7f8 100644 (file)
--- a/ares.h
+++ b/ares.h
@@ -193,11 +193,11 @@ struct timeval;
 struct sockaddr;
 struct ares_channeldata;
 typedef struct ares_channeldata *ares_channel;
-typedef void (*ares_callback)(void *arg, int status, unsigned char *abuf,
-                              int alen);
-typedef void (*ares_host_callback)(void *arg, int status,
+typedef void (*ares_callback)(void *arg, int status, int timeouts,
+                              unsigned char *abuf, int alen);
+typedef void (*ares_host_callback)(void *arg, int status, int timeouts,
                                    struct hostent *hostent);
-typedef void (*ares_nameinfo_callback)(void *arg, int status,
+typedef void (*ares_nameinfo_callback)(void *arg, int status, int timeouts,
                                        char *node, char *service);
 
 int ares_init(ares_channel *channelptr);
index 65f86b9..c3d668e 100644 (file)
@@ -31,7 +31,7 @@ void ares_cancel(ares_channel channel)
   for (query = channel->queries; query; query = next)
   {
     next = query->next;
-    query->callback(query->arg, ARES_ETIMEOUT, NULL, 0);
+    query->callback(query->arg, ARES_ETIMEOUT, 0, NULL, 0);
     free(query->tcpbuf);
     free(query->server_info);
     free(query);
index e844ea6..d1f82bd 100644 (file)
@@ -62,7 +62,7 @@ void ares_destroy(ares_channel channel)
   while (channel->queries) {
     query = channel->queries;
     channel->queries = query->next;
-    query->callback(query->arg, ARES_EDESTRUCTION, NULL, 0);
+    query->callback(query->arg, ARES_EDESTRUCTION, 0, NULL, 0);
     if (query->tcpbuf)
       free(query->tcpbuf);
     if (query->server_info)
index e3fc3c5..3782d4a 100644 (file)
@@ -22,7 +22,7 @@ ares_gethostbyaddr \- Initiate a host query by address
 .B #include <ares.h>
 .PP
 .B typedef void (*ares_host_callback)(void *\fIarg\fP, int \fIstatus\fP,
-.B     struct hostent *\fIhostent\fP)
+.B     int \fItimeouts\fP, struct hostent *\fIhostent\fP)
 .PP
 .B void ares_gethostbyaddr(ares_channel \fIchannel\fP, const void *\fIaddr\fP,
 .B     int \fIaddrlen\fP, int \fIfamily\fP, ares_host_callback \fIcallback\fP,
@@ -76,6 +76,11 @@ The name service channel
 .I channel
 is being destroyed; the query will not be completed.
 .PP
+The callback argument
+.I timeouts
+reports how many times a query timed out during the execution of the
+given request.
+.PP
 On successful completion of the query, the callback argument
 .I hostent
 points to a
index 7ea7ebb..b3abc09 100644 (file)
@@ -49,11 +49,12 @@ struct addr_query {
   void *arg;
 
   const char *remaining_lookups;
+  int timeouts;
 };
 
 static void next_lookup(struct addr_query *aquery);
-static void addr_callback(void *arg, int status, unsigned char *abuf,
-                          int alen);
+static void addr_callback(void *arg, int status, int timeouts,
+                          unsigned char *abuf, int alen);
 static void end_aquery(struct addr_query *aquery, int status,
                        struct hostent *host);
 static int file_lookup(union ares_addr *addr, int family, struct hostent **host);
@@ -65,21 +66,21 @@ void ares_gethostbyaddr(ares_channel channel, const void *addr, int addrlen,
 
   if (family != AF_INET && family != AF_INET6)
     {
-      callback(arg, ARES_ENOTIMP, NULL);
+      callback(arg, ARES_ENOTIMP, 0, NULL);
       return;
     }
 
   if ((family == AF_INET && addrlen != sizeof(struct in_addr)) ||
       (family == AF_INET6 && addrlen != sizeof(struct in6_addr)))
     {
-      callback(arg, ARES_ENOTIMP, NULL);
+      callback(arg, ARES_ENOTIMP, 0, NULL);
       return;
     }
 
   aquery = malloc(sizeof(struct addr_query));
   if (!aquery)
     {
-      callback(arg, ARES_ENOMEM, NULL);
+      callback(arg, ARES_ENOMEM, 0, NULL);
       return;
     }
   aquery->channel = channel;
@@ -91,6 +92,7 @@ void ares_gethostbyaddr(ares_channel channel, const void *addr, int addrlen,
   aquery->callback = callback;
   aquery->arg = arg;
   aquery->remaining_lookups = channel->lookups;
+  aquery->timeouts = 0;
 
   next_lookup(aquery);
 }
@@ -151,11 +153,13 @@ static void next_lookup(struct addr_query *aquery)
   end_aquery(aquery, ARES_ENOTFOUND, NULL);
 }
 
-static void addr_callback(void *arg, int status, unsigned char *abuf, int alen)
+static void addr_callback(void *arg, int status, int timeouts,
+                          unsigned char *abuf, int alen)
 {
   struct addr_query *aquery = (struct addr_query *) arg;
   struct hostent *host;
 
+  aquery->timeouts += timeouts;
   if (status == ARES_SUCCESS)
     {
       if (aquery->family == AF_INET)
@@ -175,7 +179,7 @@ static void addr_callback(void *arg, int status, unsigned char *abuf, int alen)
 static void end_aquery(struct addr_query *aquery, int status,
                        struct hostent *host)
 {
-  aquery->callback(aquery->arg, status, host);
+  aquery->callback(aquery->arg, status, aquery->timeouts, host);
   if (host)
     ares_free_hostent(host);
   free(aquery);
index 680b213..c59c038 100644 (file)
@@ -22,7 +22,7 @@ ares_gethostbyname \- Initiate a host query by name
 .B #include <ares.h>
 .PP
 .B typedef void (*ares_host_callback)(void *\fIarg\fP, int \fIstatus\fP,
-.B     struct hostent *\fIhostent\fP)
+.B     int \fItimeouts\fP, struct hostent *\fIhostent\fP)
 .PP
 .B void ares_gethostbyname(ares_channel \fIchannel\fP, const char *\fIname\fP,
 .B     int \fIfamily\fP, ares_host_callback \fIcallback\fP, void *\fIarg\fP)
@@ -80,6 +80,11 @@ The name service channel
 .I channel
 is being destroyed; the query will not be completed.
 .PP
+The callback argument
+.I timeouts
+reports how many times a query timed out during the execution of the
+given request.
+.PP
 On successful completion of the query, the callback argument
 .I hostent
 points to a
index c0fa474..49ae53e 100644 (file)
@@ -54,11 +54,12 @@ struct host_query {
   void *arg;
   int family;
   const char *remaining_lookups;
+  int timeouts;
 };
 
 static void next_lookup(struct host_query *hquery);
-static void host_callback(void *arg, int status, unsigned char *abuf,
-                          int alen);
+static void host_callback(void *arg, int status, int timeouts,
+                          unsigned char *abuf, int alen);
 static void end_hquery(struct host_query *hquery, int status,
                        struct hostent *host);
 static int fake_hostent(const char *name, int family, ares_host_callback callback,
@@ -81,7 +82,7 @@ void ares_gethostbyname(ares_channel channel, const char *name, int family,
   /* Right now we only know how to look up Internet addresses. */
   if (family != AF_INET && family != AF_INET6)
     {
-      callback(arg, ARES_ENOTIMP, NULL);
+      callback(arg, ARES_ENOTIMP, 0, NULL);
       return;
     }
 
@@ -92,7 +93,7 @@ void ares_gethostbyname(ares_channel channel, const char *name, int family,
   hquery = malloc(sizeof(struct host_query));
   if (!hquery)
     {
-      callback(arg, ARES_ENOMEM, NULL);
+      callback(arg, ARES_ENOMEM, 0, NULL);
       return;
     }
   hquery->channel = channel;
@@ -101,12 +102,13 @@ void ares_gethostbyname(ares_channel channel, const char *name, int family,
   if (!hquery->name)
     {
       free(hquery);
-      callback(arg, ARES_ENOMEM, NULL);
+      callback(arg, ARES_ENOMEM, 0, NULL);
       return;
     }
   hquery->callback = callback;
   hquery->arg = arg;
   hquery->remaining_lookups = channel->lookups;
+  hquery->timeouts = 0;
 
   /* Start performing lookups according to channel->lookups. */
   next_lookup(hquery);
@@ -144,15 +146,16 @@ static void next_lookup(struct host_query *hquery)
           break;
         }
     }
-  end_hquery(hquery, ARES_ENOTFOUND, NULL);
 }
 
-static void host_callback(void *arg, int status, unsigned char *abuf, int alen)
+static void host_callback(void *arg, int status, int timeouts,
+                          unsigned char *abuf, int alen)
 {
   struct host_query *hquery = (struct host_query *) arg;
   ares_channel channel = hquery->channel;
   struct hostent *host;
 
+  hquery->timeouts += timeouts;
   if (status == ARES_SUCCESS)
     {
       if (hquery->family == AF_INET)
@@ -185,7 +188,7 @@ static void host_callback(void *arg, int status, unsigned char *abuf, int alen)
 static void end_hquery(struct host_query *hquery, int status,
                        struct hostent *host)
 {
-  hquery->callback(hquery->arg, status, host);
+  hquery->callback(hquery->arg, status, hquery->timeouts, host);
   if (host)
     ares_free_hostent(host);
   free(hquery->name);
@@ -227,7 +230,7 @@ static int fake_hostent(const char *name, int family, ares_host_callback callbac
   hostent.h_name = strdup(name);
   if (!hostent.h_name)
     {
-      callback(arg, ARES_ENOMEM, NULL);
+      callback(arg, ARES_ENOMEM, 0, NULL);
       return 1;
     }
 
@@ -236,7 +239,7 @@ static int fake_hostent(const char *name, int family, ares_host_callback callbac
   hostent.h_aliases = aliases;
   hostent.h_addrtype = family;
   hostent.h_addr_list = addrs;
-  callback(arg, ARES_SUCCESS, &hostent);
+  callback(arg, ARES_SUCCESS, 0, &hostent);
 
   free((char *)(hostent.h_name));
   return 1;
@@ -416,4 +419,3 @@ static int get6_address_index(struct in6_addr *addr, struct apattern *sortlist,
     }
   return i;
 }
-
index 9b6bd73..55918ff 100644 (file)
@@ -22,7 +22,7 @@ ares_getnameinfo \- Address-to-nodename translation in protocol-independent mann
 .B #include <ares.h>\r
 .PP\r
 .B typedef void (*ares_nameinfo_callback)(void *\fIarg\fP, int \fIstatus\fP,\r
-.B     char *\fInode\fP, char *\fIservice\fP)\r
+.B     int \fItimeouts\fP, char *\fInode\fP, char *\fIservice\fP)\r
 .PP\r
 .B void ares_getnameinfo(ares_channel \fIchannel\fP, const struct sockaddr *\fIsa\fP,\r
 .B     socklen_t \fIsalen\fP, int \fIflags\fP, ares_nameinfo_callback \fIcallback\fP,\r
@@ -120,6 +120,11 @@ The
 .I flags\r
 parameter contains an illegal value.\r
 .PP\r
+The callback argument\r
+.I timeouts\r
+reports how many times a query timed out during the execution of the\r
+given request.\r
+.PP\r
 On successful completion of the query, the callback argument\r
 .I node\r
 contains a string representing the hostname (assuming \r
index 2c28ceb..4f690f9 100644 (file)
@@ -59,6 +59,7 @@ struct nameinfo_query {
   } addr;
   int family;
   int flags;
+  int timeouts;
 };
 
 #ifdef HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID
@@ -67,7 +68,7 @@ struct nameinfo_query {
 #define IPBUFSIZ 40
 #endif
 
-static void nameinfo_callback(void *arg, int status, struct hostent *host);
+static void nameinfo_callback(void *arg, int status, int timeouts, struct hostent *host);
 static char *lookup_service(unsigned short port, int flags,
                             char *buf, size_t buflen);
 #ifdef HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID
@@ -90,7 +91,7 @@ void ares_getnameinfo(ares_channel channel, const struct sockaddr *sa, socklen_t
     addr6 = (struct sockaddr_in6 *)sa;
   else
     {
-      callback(arg, ARES_ENOTIMP, NULL, NULL);
+      callback(arg, ARES_ENOTIMP, 0, NULL, NULL);
       return;
     }
 
@@ -110,7 +111,7 @@ void ares_getnameinfo(ares_channel channel, const struct sockaddr *sa, socklen_t
         port = addr6->sin6_port;
       service = lookup_service((unsigned short)(port & 0xffff),
                                flags, buf, sizeof(buf));
-      callback(arg, ARES_SUCCESS, NULL, service);
+      callback(arg, ARES_SUCCESS, 0, NULL, service);
       return;
     }
 
@@ -131,7 +132,7 @@ void ares_getnameinfo(ares_channel channel, const struct sockaddr *sa, socklen_t
          */
         if (flags & ARES_NI_NAMEREQD)
           {
-            callback(arg, ARES_EBADFLAGS, NULL, NULL);
+            callback(arg, ARES_EBADFLAGS, 0, NULL, NULL);
             return;
           }
         if (salen == sizeof(struct sockaddr_in6))
@@ -152,7 +153,7 @@ void ares_getnameinfo(ares_channel channel, const struct sockaddr *sa, socklen_t
         if (flags & ARES_NI_LOOKUPSERVICE)
           service = lookup_service((unsigned short)(port & 0xffff),
                                    flags, srvbuf, sizeof(srvbuf));
-        callback(arg, ARES_SUCCESS, ipbuf, service);
+        callback(arg, ARES_SUCCESS, 0, ipbuf, service);
         return;
       }
     /* This is where a DNS lookup becomes necessary */
@@ -161,12 +162,13 @@ void ares_getnameinfo(ares_channel channel, const struct sockaddr *sa, socklen_t
         niquery = malloc(sizeof(struct nameinfo_query));
         if (!niquery)
           {
-            callback(arg, ARES_ENOMEM, NULL, NULL);
+            callback(arg, ARES_ENOMEM, 0, NULL, NULL);
             return;
           }
         niquery->callback = callback;
         niquery->arg = arg;
         niquery->flags = flags;
+        niquery->timeouts = 0;
         if (sa->sa_family == AF_INET)
           {
             niquery->family = AF_INET;
@@ -185,13 +187,13 @@ void ares_getnameinfo(ares_channel channel, const struct sockaddr *sa, socklen_t
     }
 }
 
-static void nameinfo_callback(void *arg, int status, struct hostent *host)
+static void nameinfo_callback(void *arg, int status, int timeouts, struct hostent *host)
 {
   struct nameinfo_query *niquery = (struct nameinfo_query *) arg;
   char srvbuf[33];
   char *service = NULL;
 
-
+  niquery->timeouts += timeouts;
   if (status == ARES_SUCCESS)
     {
       /* They want a service too */
@@ -220,7 +222,7 @@ static void nameinfo_callback(void *arg, int status, struct hostent *host)
                  *end = 0;
              }
         }
-      niquery->callback(niquery->arg, ARES_SUCCESS, (char *)(host->h_name),
+      niquery->callback(niquery->arg, ARES_SUCCESS, niquery->timeouts, (char *)(host->h_name),
                         service);
       return;
     }
@@ -247,10 +249,10 @@ static void nameinfo_callback(void *arg, int status, struct hostent *host)
             service = lookup_service(niquery->addr.addr6.sin6_port,
                                      niquery->flags, srvbuf, sizeof(srvbuf));
         }
-      niquery->callback(niquery->arg, ARES_SUCCESS, ipbuf, service);
+      niquery->callback(niquery->arg, ARES_SUCCESS, 0, ipbuf, service);
       return;
     }
-  niquery->callback(niquery->arg, status, NULL, NULL);
+  niquery->callback(niquery->arg, status, 0, NULL, NULL);
   free(niquery);
 }
 
index dd9070a..e6ecaa2 100644 (file)
@@ -152,6 +152,7 @@ struct query {
 
   /* Next query in chain */
   struct query *next;
+  int timeouts; /* number of timeouts we saw for this request */
 };
 
 /* Per-server state for a query */
@@ -195,6 +196,8 @@ struct ares_channeldata {
   int ndots;
   int udp_port;
   int tcp_port;
+  int socket_send_buffer_size;
+  int socket_receive_buffer_size;
   char **domains;
   int ndomains;
   struct apattern *sortlist;
index 15aa06e..d359b11 100644 (file)
@@ -936,7 +936,7 @@ static struct query *end_query (ares_channel channel, struct query *query, int s
     }
  
   /* Invoke the callback */ 
-  query->callback(query->arg, status, abuf, alen);
+  query->callback(query->arg, status, query->timeouts, abuf, alen);
   for (q = &channel->queries; *q; q = &(*q)->next)
     {
       if (*q == query)
index 4bd8b68..93f64b2 100644 (file)
@@ -22,7 +22,7 @@ ares_query \- Initiate a single-question DNS query
 .B #include <ares.h>
 .PP
 .B typedef void (*ares_callback)(void *\fIarg\fP, int \fIstatus\fP,
-.B     unsigned char *\fIabuf\fP, int \fIalen\fP)
+.B     int \fItimeouts\fP, unsigned char *\fIabuf\fP, int \fIalen\fP)
 .PP
 .B void ares_query(ares_channel \fIchannel\fP, const char *\fIname\fP,
 .B     int \fIdnsclass\fP, int \fItype\fP, ares_callback \fIcallback\fP,
@@ -124,6 +124,11 @@ The name service channel
 .I channel
 is being destroyed; the query will not be completed.
 .PP
+The callback argument
+.I timeouts
+reports how many times a query timed out during the execution of the
+given request.
+.PP
 If the query completed (even if there was something wrong with it, as
 indicated by some of the above error codes), the callback argument
 .I abuf
index 0cd6557..c5fc124 100644 (file)
@@ -37,7 +37,7 @@ struct qquery {
   void *arg;
 };
 
-static void qcallback(void *arg, int status, unsigned char *abuf, int alen);
+static void qcallback(void *arg, int status, int timeouts, unsigned char *abuf, int alen);
 
 void ares__rc4(rc4_key* key, unsigned char *buffer_ptr, int buffer_len)
 {
@@ -110,7 +110,8 @@ void ares_query(ares_channel channel, const char *name, int dnsclass,
                         &qlen);
   if (status != ARES_SUCCESS)
     {
-      callback(arg, status, NULL, 0);
+      if (qbuf != NULL) free(qbuf);
+      callback(arg, status, 0, NULL, 0);
       return;
     }
 
@@ -121,7 +122,7 @@ void ares_query(ares_channel channel, const char *name, int dnsclass,
   if (!qquery)
     {
       ares_free_string(qbuf);
-      callback(arg, ARES_ENOMEM, NULL, 0);
+      callback(arg, ARES_ENOMEM, 0, NULL, 0);
       return;
     }
   qquery->callback = callback;
@@ -132,14 +133,14 @@ void ares_query(ares_channel channel, const char *name, int dnsclass,
   ares_free_string(qbuf);
 }
 
-static void qcallback(void *arg, int status, unsigned char *abuf, int alen)
+static void qcallback(void *arg, int status, int timeouts, unsigned char *abuf, int alen)
 {
   struct qquery *qquery = (struct qquery *) arg;
   unsigned int ancount;
   int rcode;
 
   if (status != ARES_SUCCESS)
-    qquery->callback(qquery->arg, status, abuf, alen);
+    qquery->callback(qquery->arg, status, timeouts, abuf, alen);
   else
     {
       /* Pull the response code and answer count from the packet. */
@@ -168,7 +169,7 @@ static void qcallback(void *arg, int status, unsigned char *abuf, int alen)
           status = ARES_EREFUSED;
           break;
         }
-      qquery->callback(qquery->arg, status, abuf, alen);
+      qquery->callback(qquery->arg, status, timeouts, abuf, alen);
     }
   free(qquery);
 }
index 2e93ba3..f5bf80d 100644 (file)
@@ -22,7 +22,7 @@ ares_search \- Initiate a DNS query with domain search
 .B #include <ares.h>
 .PP
 .B typedef void (*ares_callback)(void *\fIarg\fP, int \fIstatus\fP,
-.B     unsigned char *\fIabuf\fP, int \fIalen\fP)
+.B     int \fItimeouts\fP, unsigned char *\fIabuf\fP, int \fIalen\fP)
 .PP
 .B void ares_search(ares_channel \fIchannel\fP, const char *\fIname\fP,
 .B     int \fIdnsclass\fP, int \fItype\fP, ares_callback \fIcallback\fP,
@@ -125,6 +125,11 @@ The name service channel
 .I channel
 is being destroyed; the query will not be completed.
 .PP
+The callback argument
+.I timeouts
+reports how many times a query timed out during the execution of the
+given request.
+.PP
 If a query completed successfully, the callback argument
 .I abuf
 points to a result buffer of length
index 4ff5453..ca703a3 100644 (file)
@@ -41,10 +41,11 @@ struct search_query {
   int status_as_is;             /* error status from trying as-is */
   int next_domain;              /* next search domain to try */
   int trying_as_is;             /* current query is for name as-is */
+  int timeouts;                 /* number of timeouts we saw for this request */
 };
 
-static void search_callback(void *arg, int status, unsigned char *abuf,
-                            int alen);
+static void search_callback(void *arg, int status, int timeouts,
+                            unsigned char *abuf, int alen);
 static void end_squery(struct search_query *squery, int status,
                        unsigned char *abuf, int alen);
 static int cat_domain(const char *name, const char *domain, char **s);
@@ -64,7 +65,7 @@ void ares_search(ares_channel channel, const char *name, int dnsclass,
   status = single_domain(channel, name, &s);
   if (status != ARES_SUCCESS)
     {
-      callback(arg, status, NULL, 0);
+      callback(arg, status, 0, NULL, 0);
       return;
     }
   if (s)
@@ -80,7 +81,7 @@ void ares_search(ares_channel channel, const char *name, int dnsclass,
   squery = malloc(sizeof(struct search_query));
   if (!squery)
     {
-      callback(arg, ARES_ENOMEM, NULL, 0);
+      callback(arg, ARES_ENOMEM, 0, NULL, 0);
       return;
     }
   squery->channel = channel;
@@ -88,7 +89,7 @@ void ares_search(ares_channel channel, const char *name, int dnsclass,
   if (!squery->name)
     {
       free(squery);
-      callback(arg, ARES_ENOMEM, NULL, 0);
+      callback(arg, ARES_ENOMEM, 0, NULL, 0);
       return;
     }
   squery->dnsclass = dnsclass;
@@ -96,6 +97,7 @@ void ares_search(ares_channel channel, const char *name, int dnsclass,
   squery->status_as_is = -1;
   squery->callback = callback;
   squery->arg = arg;
+  squery->timeouts = 0;
 
   /* Count the number of dots in name. */
   ndots = 0;
@@ -132,18 +134,20 @@ void ares_search(ares_channel channel, const char *name, int dnsclass,
         /* failed, free the malloc()ed memory */
         free(squery->name);
         free(squery);
-        callback(arg, status, NULL, 0);
+        callback(arg, status, 0, NULL, 0);
       }
     }
 }
 
-static void search_callback(void *arg, int status, unsigned char *abuf,
-                            int alen)
+static void search_callback(void *arg, int status, int timeouts,
+                            unsigned char *abuf, int alen)
 {
   struct search_query *squery = (struct search_query *) arg;
   ares_channel channel = squery->channel;
   char *s;
 
+  squery->timeouts += timeouts;
+
   /* Stop searching unless we got a non-fatal error. */
   if (status != ARES_ENODATA && status != ARES_ESERVFAIL
       && status != ARES_ENOTFOUND)
@@ -184,7 +188,7 @@ static void search_callback(void *arg, int status, unsigned char *abuf,
 static void end_squery(struct search_query *squery, int status,
                        unsigned char *abuf, int alen)
 {
-  squery->callback(squery->arg, status, abuf, alen);
+  squery->callback(squery->arg, status, squery->timeouts, abuf, alen);
   free(squery->name);
   free(squery);
 }
index 2627b17..e8a2404 100644 (file)
@@ -22,7 +22,7 @@ ares_send \- Initiate a DNS query
 .B #include <ares.h>
 .PP
 .B typedef void (*ares_callback)(void *\fIarg\fP, int \fIstatus\fP,
-.B     unsigned char *\fIabuf\fP, int \fIalen\fP)
+.B     int \fItimeouts\fP, unsigned char *\fIabuf\fP, int \fIalen\fP)
 .PP
 .B void ares_send(ares_channel \fIchannel\fP, const unsigned char *\fIqbuf\fP,
 .B     int \fIqlen\fP, ares_callback \fIcallback\fP, void *\fIarg\fP)
@@ -79,6 +79,11 @@ The name service channel
 .I channel
 is being destroyed; the query will not be completed.
 .PP
+The callback argument
+.I timeouts
+reports how many times a query timed out during the execution of the
+given request.
+.PP
 If the query completed, the callback argument
 .I abuf
 points to a result buffer of length
index fd1450b..c801580 100644 (file)
@@ -44,7 +44,7 @@ void ares_send(ares_channel channel, const unsigned char *qbuf, int qlen,
   /* Verify that the query is at least long enough to hold the header. */
   if (qlen < HFIXEDSZ || qlen >= (1 << 16))
     {
-      callback(arg, ARES_EBADQUERY, NULL, 0);
+      callback(arg, ARES_EBADQUERY, 0, NULL, 0);
       return;
     }
 
@@ -52,14 +52,14 @@ void ares_send(ares_channel channel, const unsigned char *qbuf, int qlen,
   query = malloc(sizeof(struct query));
   if (!query)
     {
-      callback(arg, ARES_ENOMEM, NULL, 0);
+      callback(arg, ARES_ENOMEM, 0, NULL, 0);
       return;
     }
   query->tcpbuf = malloc(qlen + 2);
   if (!query->tcpbuf)
     {
       free(query);
-      callback(arg, ARES_ENOMEM, NULL, 0);
+      callback(arg, ARES_ENOMEM, 0, NULL, 0);
       return;
     }
   query->server_info = malloc(channel->nservers *
@@ -68,7 +68,7 @@ void ares_send(ares_channel channel, const unsigned char *qbuf, int qlen,
     {
       free(query->tcpbuf);
       free(query);
-      callback(arg, ARES_ENOMEM, NULL, 0);
+      callback(arg, ARES_ENOMEM, 0, NULL, 0);
       return;
     }
 
@@ -100,6 +100,7 @@ void ares_send(ares_channel channel, const unsigned char *qbuf, int qlen,
     }
   query->using_tcp = (channel->flags & ARES_FLAG_USEVC) || qlen > PACKETSZ;
   query->error_status = ARES_ECONNREFUSED;
+  query->timeouts = 0;
 
   /* Chain the query into this channel's query list. */
   query->next = channel->queries;