wget 1.10.x: New option --random to randomize the dns result

Jerry Lundström <[email protected]> Tue, 18 Apr 2006 14:28:12 +0200
Newsgroups gmane.comp.web.wget.patches
Message-ID <[email protected]>
This is a multi-part message in MIME format.
--------------060005040708080500000808
Content-Type: text/plain; charset=ISO-8859-1
Content-Transfer-Encoding: 8bit

Hi all,

Here is a patch that adds '--random' (rename at will). What it does is
to run address_list_randomize() after getting the dns result.
Reason I made this was because of IPv6 and RFC 3484 the dns result for
multi record hosts are sorted leaving round robins mirrors useless.
It can be argued that rfc 3484 sorting might be good most of the time
but since getaddrinfo() doesnt have a flag to turn off sorting one might
want a random result sometimes.

I have subscribe to this list so please comment the patch.

Regards,
Jerry

-- 
Jerry Lundström, System Developer
The Division of IT and media, Stockholm University, Sweden
+46 (0)8 16 19 99 / http://www.it.su.se

--------------060005040708080500000808
Content-Type: text/plain;
 name="wget-1.10-random_dns_result.patch"
Content-Transfer-Encoding: 7bit
Content-Disposition: inline;
 filename="wget-1.10-random_dns_result.patch"

Index: src/options.h
===================================================================
--- src/options.h	(revision 2139)
+++ src/options.h	(working copy)
@@ -216,6 +216,7 @@
     prefer_none
   } prefer_family;		/* preferred address family when more
 				   than one type is available */
+  int random;
 };
 
 extern struct options opt;
Index: src/init.c
===================================================================
--- src/init.c	(revision 2139)
+++ src/init.c	(working copy)
@@ -210,6 +210,7 @@
   { "proxyuser",	&opt.proxy_user,	cmd_string },
   { "quiet",		&opt.quiet,		cmd_boolean },
   { "quota",		&opt.quota,		cmd_bytes_sum },
+  { "random",       &opt.random,    cmd_boolean },
 #ifdef HAVE_SSL
   { "randomfile",	&opt.random_file,	cmd_file },
 #endif
Index: src/host.c
===================================================================
--- src/host.c	(revision 2139)
+++ src/host.c	(working copy)
@@ -31,6 +31,7 @@
 
 #include <stdio.h>
 #include <stdlib.h>
+#include <time.h>
 #ifdef HAVE_STRING_H
 # include <string.h>
 #else
@@ -183,6 +184,49 @@
   return al->connected;
 }
 
+/* random al
+   Why?
+   Because of RFC 3484 breaks dns round robins wetsites/mirrors ... etc
+   [email protected]
+*/
+struct address_list *
+address_list_randomize (struct address_list *al)
+{
+  if (opt.random && al->count > 1) {
+    int *tbl = xnew0_array(int, al->count);
+    ip_address *ip = xnew0_array(ip_address, al->count);
+    int i = 0;
+
+    /* fast init */
+    srandom(al->count*time(0));
+    while(i < al->count)
+    {
+        int r = random() % al->count;
+        int rs = r;
+        /* find first free from random place */
+        while(tbl[r]) {
+            r++;
+            if(r>=al->count) r=0;
+            if(r == rs) {
+                /* we looped the table, something is broken, skip random */
+                xfree(ip);
+                xfree(tbl);
+                return al;
+            }
+        }
+        /* reserve the place in the table and copy the address */
+        tbl[r] = 1;
+        memcpy(&ip[r], &al->addresses[i], sizeof(ip_address));
+        i++;
+    }
+    /* replace the old addresses */
+    xfree(al->addresses);
+    xfree(tbl);
+    al->addresses = ip;
+  }
+  return al;
+}
+
 #ifdef ENABLE_IPV6
 
 /* Create an address_list from the addresses in the given struct
@@ -739,7 +783,7 @@
 	{
 	  al = cache_query (host);
 	  if (al)
-	    return al;
+	    return address_list_randomize(al);
 	}
       else
 	cache_remove (host);
@@ -827,6 +871,8 @@
   }
 #endif /* not ENABLE_IPV6 */
 
+  al = address_list_randomize(al);
+
   /* Print the addresses determined by DNS lookup, but no more than
      three.  */
   if (!silent && !numeric_address)
Index: src/host.h
===================================================================
--- src/host.h	(revision 2139)
+++ src/host.h	(working copy)
@@ -105,6 +105,7 @@
 void address_list_set_faulty PARAMS ((struct address_list *, int));
 void address_list_set_connected PARAMS ((struct address_list *));
 int address_list_connected_p PARAMS ((const struct address_list *));
+struct address_list *address_list_randomize PARAMS ((struct address_list *));
 void address_list_release PARAMS ((struct address_list *));
 
 const char *pretty_print_address PARAMS ((const ip_address *));
Index: src/main.c
===================================================================
--- src/main.c	(revision 2139)
+++ src/main.c	(working copy)
@@ -237,6 +237,7 @@
     { "proxy-user", 0, OPT_VALUE, "proxyuser", -1 },
     { "quiet", 'q', OPT_BOOLEAN, "quiet", -1 },
     { "quota", 'Q', OPT_VALUE, "quota", -1 },
+    { "random", 0, OPT_BOOLEAN, "random", -1 },
     { "random-file", 0, OPT_VALUE, "randomfile", -1 },
     { "random-wait", 0, OPT_BOOLEAN, "randomwait", -1 },
     { "read-timeout", 0, OPT_VALUE, "readtimeout", -1 },
@@ -457,6 +458,8 @@
     N_("\
        --waitretry=SECONDS       wait 1..SECONDS between retries of a retrieval.\n"),
     N_("\
+       --random                  random dns result (only affect if ipv6 inuse).\n"),
+    N_("\
        --random-wait             wait from 0...2*WAIT secs between retrievals.\n"),
     N_("\
   -Y,  --proxy                   explicitly turn on proxy.\n"),

--------------060005040708080500000808--