[Author Prev][Author Next][Thread Prev][Thread Next][Author Index][Thread Index]

[or-cvs] bugfix: we were caching transient dns failures



Update of /home/or/cvsroot/src/or
In directory moria.mit.edu:/home2/arma/work/onion/cvs/src/or

Modified Files:
	dns.c 
Log Message:
bugfix: we were caching transient dns failures


Index: dns.c
===================================================================
RCS file: /home/or/cvsroot/src/or/dns.c,v
retrieving revision 1.65
retrieving revision 1.66
diff -u -d -r1.65 -r1.66
--- dns.c	11 Mar 2004 06:35:03 -0000	1.65
+++ dns.c	12 Mar 2004 18:45:42 -0000	1.66
@@ -16,16 +16,13 @@
 #define MIN_DNSWORKERS 3
 #define MAX_IDLE_DNSWORKERS 10
 
+#define DNS_RESOLVE_FAILED_TRANSIENT 1
+#define DNS_RESOLVE_FAILED_PERMANENT 2
+#define DNS_RESOLVE_SUCCEEDED 3
+
 int num_dnsworkers=0;
 int num_dnsworkers_busy=0;
 
-static void purge_expired_resolves(uint32_t now);
-static int assign_to_dnsworker(connection_t *exitconn);
-static void dns_found_answer(char *address, uint32_t addr);
-int dnsworker_main(void *data);
-static int spawn_dnsworker(void);
-static void spawn_enough_dnsworkers(void);
-
 struct pending_connection_t {
   struct connection_t *conn;
   struct pending_connection_t *next;
@@ -44,6 +41,14 @@
   struct cached_resolve *next;
 };
 
+static void purge_expired_resolves(uint32_t now);
+static int assign_to_dnsworker(connection_t *exitconn);
+static void dns_purge_resolve(struct cached_resolve *resolve);
+static void dns_found_answer(char *address, uint32_t addr, char outcome);
+int dnsworker_main(void *data);
+static int spawn_dnsworker(void);
+static void spawn_enough_dnsworkers(void);
+
 static SPLAY_HEAD(cache_tree, cached_resolve) cache_root;
 
 static int compare_cached_resolves(struct cached_resolve *a,
@@ -238,7 +243,7 @@
 void dns_cancel_pending_resolve(char *address) {
   struct pending_connection_t *pend;
   struct cached_resolve search;
-  struct cached_resolve *resolve, *tmp;
+  struct cached_resolve *resolve;
   connection_t *pendconn;
 
   strncpy(search.address, address, MAX_ADDRESSLEN);
@@ -266,6 +271,12 @@
     tor_free(pend);
   }
 
+  dns_purge_resolve(resolve);
+}
+
+static void dns_purge_resolve(struct cached_resolve *resolve) {
+  struct cached_resolve *tmp;
+
   /* remove resolve from the linked list */
   if(resolve == oldest_cached_resolve) {
     oldest_cached_resolve = resolve->next;
@@ -287,7 +298,7 @@
   tor_free(resolve);
 }
 
-static void dns_found_answer(char *address, uint32_t addr) {
+static void dns_found_answer(char *address, uint32_t addr, char outcome) {
   struct pending_connection_t *pend;
   struct cached_resolve search;
   struct cached_resolve *resolve;
@@ -316,7 +327,7 @@
   /* assert(resolve->state == CACHE_STATE_PENDING); */
 
   resolve->addr = ntohl(addr);
-  if(resolve->addr)
+  if(outcome == DNS_RESOLVE_SUCCEEDED)
     resolve->state = CACHE_STATE_VALID;
   else
     resolve->state = CACHE_STATE_FAILED;
@@ -337,6 +348,10 @@
     resolve->pending_connections = pend->next;
     tor_free(pend);
   }
+
+  if(outcome == DNS_RESOLVE_FAILED_TRANSIENT) { /* remove from cache */
+    dns_purge_resolve(resolve);
+  }
 }
 
 /******************************************************************/
@@ -348,6 +363,7 @@
 }
 
 int connection_dns_process_inbuf(connection_t *conn) {
+  char answer[5];
   uint32_t addr;
 
   assert(conn && conn->type == CONN_TYPE_DNSWORKER);
@@ -364,16 +380,19 @@
   }
 
   assert(conn->state == DNSWORKER_STATE_BUSY);
-  if(buf_datalen(conn->inbuf) < 4) /* entire answer available? */
+  if(buf_datalen(conn->inbuf) < 5) /* entire answer available? */
     return 0; /* not yet */
-  assert(buf_datalen(conn->inbuf) == 4);
+  assert(buf_datalen(conn->inbuf) == 5);
 
-  connection_fetch_from_buf((char*)&addr,sizeof(addr),conn);
+  connection_fetch_from_buf(answer,sizeof(answer),conn);
+  addr = *(uint32_t*)(answer+1);
 
   log_fn(LOG_DEBUG, "DNSWorker (fd %d) returned answer for '%s'",
          conn->s, conn->address);
 
-  dns_found_answer(conn->address, addr);
+  assert(answer[0] >= DNS_RESOLVE_FAILED_TRANSIENT);
+  assert(answer[0] <= DNS_RESOLVE_SUCCEEDED);
+  dns_found_answer(conn->address, addr, answer[0]);
 
   tor_free(conn->address);
   conn->address = tor_strdup("<idle>");
@@ -386,6 +405,7 @@
 int dnsworker_main(void *data) {
   char address[MAX_ADDRESSLEN];
   unsigned char address_len;
+  char answer[5];
   struct hostent *rent;
   int *fdarray = data;
   int fd;
@@ -398,7 +418,6 @@
   for(;;) {
 
     if(recv(fd, &address_len, 1, 0) != 1) {
-//      log_fn(LOG_INFO,"read length failed. Child exiting.");
       log_fn(LOG_INFO,"dnsworker exiting because tor process died.");
       spawn_exit();
     }
@@ -412,19 +431,24 @@
 
     rent = gethostbyname(address);
     if (!rent) {
-      log_fn(LOG_INFO,"Could not resolve dest addr %s. Returning nulls.",address);
-      if(write_all(fd, "\0\0\0\0", 4, 1) != 4) {
-        log_fn(LOG_ERR,"writing nulls failed. Child exiting.");
-        spawn_exit();
+      if(h_errno == TRY_AGAIN) { /* transient error -- don't cache it */
+        log_fn(LOG_INFO,"Could not resolve dest addr %s (transient).",address);
+        answer[0] = DNS_RESOLVE_FAILED_TRANSIENT;
+      } else { /* permanent error, can be cached */
+        log_fn(LOG_INFO,"Could not resolve dest addr %s (permanent).",address);
+        answer[0] = DNS_RESOLVE_FAILED_PERMANENT;
       }
+      memset(answer+1,0,4);
     } else {
       assert(rent->h_length == 4); /* break to remind us if we move away from ipv4 */
-      if(write_all(fd, rent->h_addr, 4, 1) != 4) {
-        log_fn(LOG_INFO,"writing answer failed. Child exiting.");
-        spawn_exit();
-      }
+      answer[0] = DNS_RESOLVE_SUCCEEDED;
+      memcpy(answer+1, rent->h_addr, 4);
       log_fn(LOG_INFO,"Resolved address '%s'.",address);
     }
+    if(write_all(fd, answer, 5, 1) != 5) {
+      log_fn(LOG_ERR,"writing answer failed. Child exiting.");
+      spawn_exit();
+    }
   }
   return 0; /* windows wants this function to return an int */
 }