Dual-family (IPv4+IPv6) support for wget 1.9

Without this patch, IPv6 support completely disables IPv4, since dual-family
support was incomplete.  Read MODIFICATIONS.ari for details.

This patch also adds the configuration option --with-ipv4-default, which
will sort resolved addresses so that those with the AF_INET family will be
attempted first.  Remember to run autoconf in the top-level wget source
directory after patching.

NOTE:  I do not currently have an IPv6-enabled system on hand in order to
properly test IPv6 functionality.  If wget 1.9 had any problems
communicating over IPv6, it is not likely that this patch will have
corrected them.  Until this functionality is committed into wget, please
send any relevant IPv6 problems to me.


ari edelkind (10/27/2003)
last modified 10/27/2003


diff -ruN --exclude configure wget-1.9.orig/MODIFICATIONS.ari wget-1.9/MODIFICATIONS.ari
--- wget-1.9.orig/MODIFICATIONS.ari	Wed Dec 31 19:00:00 1969
+++ wget-1.9/MODIFICATIONS.ari	Mon Oct 27 04:05:34 2003
@@ -0,0 +1,40 @@
+
+- added an ip_addrset structure to host.h, containing an ip_address type and
+  a family.
+
+- Changed the address_list structure to use an array of ip_addrset types
+  instead of ip_address types.
+
+- Changed usage of ip_address type to ip_addrset type in any location where
+  it would be useful to have the family for a particular ip address or
+  connection.  Modified all dereferences accordingly, and removed
+  ip_default_family altogether.
+
+- added a family option to the sockaddr_len() function in host.c, and the
+  bindport() function in connect.c.
+
+- Added --with-ipv4-default option to configure.in.  If this option is set,
+  AF_INET will be used as the default domain, even when ipv6 is enabled.
+  This configure option defines the macro USE_IPV4_DEFAULT.
+
+- Changed the --disable-ipv6 comment in configure.in to --enable-ipv6.
+  Since ipv6 is currently enabled neither by default nor by configure
+  checks, and --enable-ipv6 must be passed in order to do so, this will make
+  the option more intuitive.  When configure is modified to check for ipv6
+  support by default, this comment should be reverted.  Be sure to run
+  autoconf to recreate the configure file.
+
+- host.c: getaddrinfo functions were conditionally included depending on
+  whether ENABLE_IPV6 was defined, yet in lookup_host(), they are called
+  depending on whether HAVE_GETADDRINFO is defined.  Switched the relevant
+  ENABLE_IPV6 conditional define to use HAVE_GETADDRINFO.
+
+- Added the function address_list_sort_family() to host.c if
+  USE_IPV4_DEFAULT is defined.  When the address list is gathered from name
+  resolution, any addresses associated with an AF_INET family will be first
+  in the al->addrsets array.  They will therefore be tried before AF_INET6
+  types.
+
+- ftp.c, getftp(): Used conaddr() to initially populate passive_addrset with
+  RBUF_FD(&con->rbuf), so that the family of the requested connection may be
+  known to other functions.
diff -ruN --exclude configure wget-1.9.orig/configure.in wget-1.9/configure.in
--- wget-1.9.orig/configure.in	Thu Oct 16 10:27:39 2003
+++ wget-1.9/configure.in	Mon Oct 27 00:24:54 2003
@@ -59,6 +59,10 @@
 [[  --with-ssl[=SSL-ROOT]   link with SSL support [default=auto]
   --without-ssl           disable SSL autodetection]])
 
+AC_ARG_WITH(ipv4-default,
+[  --with-ipv4-default     use IPv4 by default when IPv6 is enabled],
+[AC_DEFINE(USE_IPV4_DEFAULT)])
+
 AC_ARG_ENABLE(opie,
 [  --disable-opie          disable support for opie or s/key FTP login],
 USE_OPIE=$enableval, USE_OPIE=yes)
@@ -455,7 +459,7 @@
 ipv6=
 check_for_ipv6=no
 AC_ARG_ENABLE(ipv6,
-  AC_HELP_STRING([--disable-ipv6],[disable IPv6 support]),
+  AC_HELP_STRING([--enable-ipv6],[enable IPv6 support]),
   [case "${enable_ipv6}" in
   no)
     AC_MSG_NOTICE([Disabling IPv6 at user request])
diff -ruN --exclude configure wget-1.9.orig/src/config.h.in wget-1.9/src/config.h.in
--- wget-1.9.orig/src/config.h.in	Mon Oct 13 10:20:45 2003
+++ wget-1.9/src/config.h.in	Mon Oct 27 00:24:54 2003
@@ -272,6 +272,9 @@
 /* Define if you want to enable the IPv6 support.  */
 #undef ENABLE_IPV6
 
+/* Define if you want to use IPv4 by default when IPv6 is supported.  */
+#undef USE_IPV4_DEFAULT
+
 /* Defined to int or size_t on systems without socklen_t.  */
 #undef socklen_t
 
diff -ruN --exclude configure wget-1.9.orig/src/connect.c wget-1.9/src/connect.c
--- wget-1.9.orig/src/connect.c	Fri Oct 10 21:39:07 2003
+++ wget-1.9/src/connect.c	Mon Oct 27 00:24:54 2003
@@ -69,7 +69,7 @@
 static int msock = -1;
 static struct sockaddr *addr;
 
-static ip_address bind_address;
+static ip_addrset bind_address;
 static int bind_address_resolved;
 
 static void
@@ -149,17 +149,17 @@
 
 /* Connect to a remote host whose address has been resolved. */
 int
-connect_to_one (ip_address *addr, unsigned short port, int silent)
+connect_to_one (ip_addrset *addrset, unsigned short port, int silent)
 {
   wget_sockaddr sa;
   int sock, save_errno;
 
   /* Set port and protocol */
-  wget_sockaddr_set_address (&sa, ip_default_family, port, addr);
+  wget_sockaddr_set_address (&sa, addrset->family, port, &addrset->addr);
 
   if (!silent)
     {
-      char *pretty_addr = pretty_print_address (addr);
+      char *pretty_addr = pretty_print_address (&addrset->addr);
       if (connection_host_name
 	  && 0 != strcmp (connection_host_name, pretty_addr))
 	logprintf (LOG_VERBOSE, _("Connecting to %s[%s]:%hu... "),
@@ -170,7 +170,7 @@
     }
 
   /* Make an internet socket, stream type.  */
-  sock = socket (ip_default_family, SOCK_STREAM, 0);
+  sock = socket (addrset->family, SOCK_STREAM, 0);
   if (sock < 0)
     goto out;
 
@@ -196,8 +196,9 @@
     {
       /* Bind the client side to the requested address. */
       wget_sockaddr bsa;
-      wget_sockaddr_set_address (&bsa, ip_default_family, 0, &bind_address);
-      if (bind (sock, &bsa.sa, sockaddr_len ()))
+      wget_sockaddr_set_address (&bsa, bind_address.family, 0,
+              &bind_address.addr);
+      if (bind (sock, &bsa.sa, sockaddr_len (addrset->family)))
 	{
 	  CLOSE (sock);
 	  sock = -1;
@@ -206,7 +207,7 @@
     }
 
   /* Connect the socket to the remote host.  */
-  if (connect_with_timeout (sock, &sa.sa, sockaddr_len (),
+  if (connect_with_timeout (sock, &sa.sa, sockaddr_len (addrset->family),
 			    opt.connect_timeout) < 0)
     {
       CLOSE (sock);
@@ -233,20 +234,20 @@
   return sock;
 }
 
+
 /* Connect to a remote host whose address has been resolved. */
 int
 connect_to_many (struct address_list *al, unsigned short port, int silent)
 {
-  int i, start, end;
+  int i, start, end, sock;
+  ip_addrset addrset;
 
   address_list_get_bounds (al, &start, &end);
   for (i = start; i < end; i++)
     {
-      ip_address addr;
-      int sock;
-      address_list_copy_one (al, i, &addr);
+      address_list_copy_one (al, i, &addrset);
 
-      sock = connect_to_one (&addr, port, silent);
+      sock = connect_to_one (&addrset, port, silent);
       if (sock >= 0)
 	/* Success. */
 	return sock;
@@ -298,7 +299,7 @@
    internal variable MPORT is set to the value of the ensuing master
    socket.  Call acceptport() to block for and accept a connection.  */
 uerr_t
-bindport (unsigned short *port, int family)
+bindport (unsigned short *port, int ip_family)
 {
   int optval = 1;
   wget_sockaddr srv;
@@ -306,7 +307,7 @@
 
   msock = -1;
 
-  if ((msock = socket (family, SOCK_STREAM, 0)) < 0)
+  if ((msock = socket (ip_family, SOCK_STREAM, 0)) < 0)
     return CONSOCKERR;
 
 #ifdef SO_REUSEADDR
@@ -316,9 +317,9 @@
 #endif
 
   resolve_bind_address ();
-  wget_sockaddr_set_address (&srv, ip_default_family, htons (*port),
-			     bind_address_resolved ? &bind_address : NULL);
-  if (bind (msock, &srv.sa, sockaddr_len ()) < 0)
+  wget_sockaddr_set_address (&srv, ip_family, htons (*port),
+			     bind_address_resolved ? &bind_address.addr : NULL);
+  if (bind (msock, &srv.sa, sockaddr_len (ip_family)) < 0)
     {
       CLOSE (msock);
       msock = -1;
@@ -327,7 +328,7 @@
   DEBUGP (("Master socket fd %d bound.\n", msock));
   if (!*port)
     {
-      socklen_t sa_len = sockaddr_len ();
+      socklen_t sa_len = sockaddr_len (ip_family);
       if (getsockname (msock, &srv.sa, &sa_len) < 0)
 	{
 	  CLOSE (msock);
@@ -389,7 +390,13 @@
 uerr_t
 acceptport (int *sock)
 {
-  socklen_t addrlen = sockaddr_len ();
+  socklen_t addrlen;
+  ip_addrset addrset;
+
+  if (!conaddr (msock, &addrset))
+      return ACCEPTERR;
+
+  addrlen = sockaddr_len (addrset.family);
 
 #ifdef HAVE_SELECT
   if (select_fd (msock, opt.connect_timeout, 0) <= 0)
@@ -417,22 +424,22 @@
 /* Return the local IP address associated with the connection on FD.  */
 
 int
-conaddr (int fd, ip_address *ip)
+conaddr (int fd, ip_addrset *ip)
 {
   wget_sockaddr mysrv;
   socklen_t addrlen = sizeof (mysrv);	
   if (getsockname (fd, &mysrv.sa, &addrlen) < 0)
     return 0;
 
-  switch (mysrv.sa.sa_family)
+  switch (ip->family = mysrv.sa.sa_family)
     {
 #ifdef ENABLE_IPV6
     case AF_INET6:
-      memcpy (ip, &mysrv.sin6.sin6_addr, 16);
+      memcpy (&ip->addr, &mysrv.sin6.sin6_addr, 16);
       return 1;
 #endif
     case AF_INET:
-      map_ipv4_to_ip ((ip4_address *)&mysrv.sin.sin_addr, ip);
+      map_ipv4_to_ip ((ip4_address *)&mysrv.sin.sin_addr, &ip->addr);
       return 1;
     default:
       abort ();
diff -ruN --exclude configure wget-1.9.orig/src/connect.h wget-1.9/src/connect.h
--- wget-1.9.orig/src/connect.h	Sat Sep 20 19:12:18 2003
+++ wget-1.9/src/connect.h	Mon Oct 27 00:24:54 2003
@@ -34,7 +34,7 @@
 
 /* Function declarations */
 
-int connect_to_one PARAMS ((ip_address *, unsigned short, int));
+int connect_to_one PARAMS ((ip_addrset *, unsigned short, int));
 int connect_to_many PARAMS ((struct address_list *, unsigned short, int));
 void set_connection_host_name PARAMS ((const char *));
 
@@ -43,7 +43,7 @@
 uerr_t bindport PARAMS ((unsigned short *, int));
 uerr_t acceptport PARAMS ((int *));
 void closeport PARAMS ((int));
-int conaddr PARAMS ((int, ip_address *));
+int conaddr PARAMS ((int, ip_addrset *));
 
 int iread PARAMS ((int, char *, int));
 int iwrite PARAMS ((int, char *, int));
diff -ruN --exclude configure wget-1.9.orig/src/ftp-basic.c wget-1.9/src/ftp-basic.c
--- wget-1.9.orig/src/ftp-basic.c	Fri Oct 10 21:39:07 2003
+++ wget-1.9/src/ftp-basic.c	Mon Oct 27 00:24:54 2003
@@ -259,23 +259,24 @@
   uerr_t err;
 
   char *request, *respline;
-  ip_address in_addr;
+  ip_addrset in_addrset;
   unsigned short port;
 
   char ipv6 [8 * (4 * 3 + 3) + 8];
   char *bytes;
 
+  /* Get the address of this side of the connection.  */
+  if (!conaddr (RBUF_FD (rbuf), &in_addrset))
+    /* Huh?  This is not BINDERR! */
+    return BINDERR;
+
   /* Setting port to 0 lets the system choose a free port.  */
   port = 0;
-  err = bindport (&port, ip_default_family);
+  err = bindport (&port, in_addrset.family);
   if (err != BINDOK)	/* Bind the port.  */
     return err;
 
-  /* Get the address of this side of the connection.  */
-  if (!conaddr (RBUF_FD (rbuf), &in_addr))
-    /* Huh?  This is not BINDERR! */
-    return BINDERR;
-  inet_ntop (AF_INET6, &in_addr, ipv6, sizeof (ipv6));
+  inet_ntop (AF_INET6, &in_addrset.addr, ipv6, sizeof (ipv6));
 
   /* Construct the argument of EPRT (of the form |2|IPv6.ascii|PORT.ascii|). */
   bytes = alloca (3 + strlen (ipv6) + 1 + numdigit (port) + 1 + 1);
@@ -318,17 +319,27 @@
   char *request, *respline;
   char bytes[6 * 4 +1];
 
-  ip_address in_addr;
+  ip_addrset in_addrset;
   ip4_address in_addr_4;
   unsigned char *in_addr4_ptr = (unsigned char *)&in_addr_4;
 
   int nwritten;
   unsigned short port;
+
+
+  /* Get the address of this side of the connection and convert it
+     (back) to IPv4.  */
+  if (!conaddr (RBUF_FD (rbuf), &in_addrset))
+    /* Huh?  This is not BINDERR! */
+    return BINDERR;
+  if (!map_ip_to_ipv4 (&in_addrset.addr, &in_addr_4))
+    return BINDERR;
+
 #ifdef ENABLE_IPV6
   /*
     Only try the Extented Version if we actually use IPv6
   */
-  if (ip_default_family == AF_INET6)
+  if (in_addrset.family == AF_INET6)
     {
       err = ftp_eprt (rbuf);
       if (err == FTPOK)
@@ -338,18 +349,10 @@
   /* Setting port to 0 lets the system choose a free port.  */
   port = 0;
 
-  err = bindport (&port, AF_INET);
+  err = bindport (&port, in_addrset.family);
   if (err != BINDOK)
     return err;
 
-  /* Get the address of this side of the connection and convert it
-     (back) to IPv4.  */
-  if (!conaddr (RBUF_FD (rbuf), &in_addr))
-    /* Huh?  This is not BINDERR! */
-    return BINDERR;
-  if (!map_ip_to_ipv4 (&in_addr, &in_addr_4))
-    return BINDERR;
-
   /* Construct the argument of PORT (of the form a,b,c,d,e,f).  Port
      is unsigned short so (unsigned) (port & 0xff000) >> 8 is the same
      like port >> 8
@@ -384,7 +387,7 @@
 
 #ifdef ENABLE_IPV6
 uerr_t
-ftp_epsv (struct rbuf *rbuf, ip_address *addr, unsigned short *port, 
+ftp_epsv (struct rbuf *rbuf, ip_addrset *addrset, unsigned short *port, 
 	  char *typ)
 {
   int err;
@@ -423,13 +426,13 @@
     socklen_t addrlen = sizeof (remote);
     struct sockaddr_in *ipv4_sock = (struct sockaddr_in *)&remote;
     getpeername (RBUF_FD (rbuf), (struct sockaddr *)&remote, &addrlen);
-    switch(remote.sa.sa_family)
+    switch(addrset->family = remote.sa.sa_family)
       {
         case AF_INET6:
-          memcpy (addr, &remote.sin6.sin6_addr, 16);
+          memcpy (&addrset->addr, &remote.sin6.sin6_addr, 16);
 	  break;
 	case AF_INET:  
-          map_ipv4_to_ip ((ip4_address *)&ipv4_sock->sin_addr, addr);
+          map_ipv4_to_ip ((ip4_address *)&ipv4_sock->sin_addr, &addrset->addr);
 	  break;
 	default:
 	  abort();
@@ -446,7 +449,7 @@
    transfer.  Reads the response from server and parses it.  Reads the
    host and port addresses and returns them.  */
 uerr_t
-ftp_pasv (struct rbuf *rbuf, ip_address *addr, unsigned short *port)
+ftp_pasv (struct rbuf *rbuf, ip_addrset *addrset, unsigned short *port)
 {
   char *request, *respline, *s;
   int nwritten, i;
@@ -454,12 +457,12 @@
   unsigned char addr4[4];
 
 #ifdef ENABLE_IPV6
-  if (ip_default_family == AF_INET6) 
+  if (addrset->family == AF_INET6) 
     {
-      err = ftp_epsv (rbuf, addr, port, "2");	/* try IPv6 with EPSV */
+      err = ftp_epsv (rbuf, addrset, port, "2");	/* try IPv6 with EPSV */
       if (FTPOK == err) 
         return FTPOK;
-      err = ftp_epsv (rbuf, addr, port, "1");	/* try IPv4 with EPSV */
+      err = ftp_epsv (rbuf, addrset, port, "1");	/* try IPv4 with EPSV */
       if (FTPOK == err) 
         return FTPOK;
     }
@@ -507,7 +510,7 @@
     }
 
   /* Eventually make an IPv4 in IPv6 adress if needed */
-  map_ipv4_to_ip ((ip4_address *)addr4, addr);
+  map_ipv4_to_ip ((ip4_address *)addr4, &addrset->addr);
 
   *port=0;
   for (; ISDIGIT (*s); s++)
diff -ruN --exclude configure wget-1.9.orig/src/ftp.c wget-1.9/src/ftp.c
--- wget-1.9.orig/src/ftp.c	Tue Oct 14 18:52:12 2003
+++ wget-1.9/src/ftp.c	Mon Oct 27 00:24:54 2003
@@ -538,11 +538,15 @@
     {
       if (opt.ftp_pasv > 0)
 	{
-  	  ip_address     passive_addr;
+  	  ip_addrset     passive_addrset;
   	  unsigned short passive_port;
 	  if (!opt.server_response)
 	    logputs (LOG_VERBOSE, "==> PASV ... ");
-	  err = ftp_pasv (&con->rbuf, &passive_addr, &passive_port);
+
+	  if (!conaddr (RBUF_FD (&con->rbuf), &passive_addrset))
+	    return HOSTERR;
+
+	  err = ftp_pasv (&con->rbuf, &passive_addrset, &passive_port);
 	  /* FTPRERR, WRITEFAILED, FTPNOPASV, FTPINVPASV */
 	  switch (err)
 	    {
@@ -579,14 +583,14 @@
 	    }	/* switch(err) */
 	  if (err==FTPOK)
 	    {
-	      dtsock = connect_to_one (&passive_addr, passive_port, 1);
+	      dtsock = connect_to_one (&passive_addrset, passive_port, 1);
 	      if (dtsock < 0)
 		{
 		  int save_errno = errno;
 		  CLOSE (csock);
 		  rbuf_uninitialize (&con->rbuf);
 		  logprintf (LOG_VERBOSE, _("couldn't connect to %s:%hu: %s\n"),
-			     pretty_print_address (&passive_addr), passive_port,
+			     pretty_print_address (&passive_addrset.addr), passive_port,
 			     strerror (save_errno));
 		  return CONNECT_ERROR (save_errno);
 		}
diff -ruN --exclude configure wget-1.9.orig/src/ftp.h wget-1.9/src/ftp.h
--- wget-1.9.orig/src/ftp.h	Thu Sep 18 09:46:17 2003
+++ wget-1.9/src/ftp.h	Mon Oct 27 00:24:54 2003
@@ -49,9 +49,9 @@
 uerr_t ftp_response PARAMS ((struct rbuf *, char **));
 uerr_t ftp_login PARAMS ((struct rbuf *, const char *, const char *));
 uerr_t ftp_port PARAMS ((struct rbuf *));
-uerr_t ftp_pasv PARAMS ((struct rbuf *, ip_address *, unsigned short *));
+uerr_t ftp_pasv PARAMS ((struct rbuf *, ip_addrset *, unsigned short *));
 #ifdef ENABLE_IPV6
-uerr_t ftp_epsv PARAMS ((struct rbuf *, ip_address *, unsigned short *,
+uerr_t ftp_epsv PARAMS ((struct rbuf *, ip_addrset *, unsigned short *,
 			 char *));
 #endif
 uerr_t ftp_type PARAMS ((struct rbuf *, int));
diff -ruN --exclude configure wget-1.9.orig/src/host.c wget-1.9/src/host.c
--- wget-1.9.orig/src/host.c	Fri Oct 10 22:27:41 2003
+++ wget-1.9/src/host.c	Mon Oct 27 00:24:54 2003
@@ -81,11 +81,6 @@
 # endif
 #endif
 
-#ifdef ENABLE_IPV6
-int     ip_default_family = AF_INET6;
-#else
-int     ip_default_family = AF_INET;
-#endif
 
 /* Mapping between known hosts and to lists of their addresses. */
 
@@ -96,7 +91,7 @@
 
 struct address_list {
   int count;			/* number of adrresses */
-  ip_address *addresses;	/* pointer to the string of addresses */
+  ip_addrset *addrsets;		/* pointer to the string of address sets */
 
   int faulty;			/* number of addresses known not to work. */
   int refcount;			/* so we know whether to free it or not. */
@@ -114,10 +109,10 @@
 /* Copy address number INDEX to IP_STORE.  */
 
 void
-address_list_copy_one (struct address_list *al, int index, ip_address *ip_store)
+address_list_copy_one (struct address_list *al, int index, ip_addrset *ip_store)
 {
   assert (index >= al->faulty && index < al->count);
-  memcpy (ip_store, al->addresses + index, sizeof (ip_address));
+  memcpy (ip_store, al->addrsets + index, sizeof (ip_addrset));
 }
 
 /* Check whether two address lists have all their IPs in common.  */
@@ -129,8 +124,8 @@
     return 1;
   if (al1->count != al2->count)
     return 0;
-  return 0 == memcmp (al1->addresses, al2->addresses,
-		      al1->count * sizeof (ip_address));
+  return 0 == memcmp (al1->addrsets, al2->addrsets,
+		      al1->count * sizeof (ip_addrset));
 }
 
 /* Mark the INDEXth element of AL as faulty, so that the next time
@@ -153,6 +148,36 @@
     al->faulty = 0;
 }
 
+#ifdef USE_IPV4_DEFAULT
+static inline void
+address_list_sort_family (struct address_list *al, int family)
+{
+  int i, j = 0, len;
+  ip_addrset *copysets;
+
+  len = sizeof(ip_addrset) * al->count;
+
+  if (!(copysets = malloc (len))) return;
+
+  for (i = 0; i < al->count; i++)
+  {
+    if (al->addrsets[i].family == family)
+      address_list_copy_one (al, i, &copysets[j++]);
+  }
+
+  if (j < al->count) {
+    for (i = 0; i < al->count; i++)
+    {
+      if (al->addrsets[i].family != family)
+        address_list_copy_one (al, i, &copysets[j++]);
+    }
+  }
+
+  memcpy (al->addrsets, copysets, len);
+  free (copysets);
+}
+#endif
+
 #ifdef HAVE_GETADDRINFO
 /**
   * address_list_from_addrinfo
@@ -180,7 +205,7 @@
     return NULL;
 
   al = xmalloc (sizeof (struct address_list));
-  al->addresses = xmalloc (cnt * sizeof (ip_address));
+  al->addrsets = xmalloc (cnt * sizeof (ip_addrset));
   al->count     = cnt;
   al->faulty    = 0;
   al->refcount  = 1;
@@ -189,13 +214,15 @@
     if (ai->ai_family == AF_INET6) 
       {
 	struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)ai->ai_addr;
-	memcpy (al->addresses + i, &sin6->sin6_addr, 16);
+	memcpy (&al->addrsets[i].addr, &sin6->sin6_addr, 16);
+	al->addrsets[i].family = AF_INET6;
 	++i;
       } 
     else if (ai->ai_family == AF_INET)
       {
 	struct sockaddr_in *sin = (struct sockaddr_in *)ai->ai_addr;
-        map_ipv4_to_ip ((ip4_address *)&sin->sin_addr, al->addresses + i);
+	map_ipv4_to_ip ((ip4_address *)&sin->sin_addr, &al->addrsets[i].addr);
+	al->addrsets[i].family = AF_INET;
 	++i;
       }
   assert (i == cnt);
@@ -216,11 +243,13 @@
   assert (count > 0);
   al->count     = count;
   al->faulty    = 0;
-  al->addresses = xmalloc (count * sizeof (ip_address));
+  al->addrsets = xmalloc (count * sizeof (ip_addrset));
   al->refcount  = 1;
 
-  for (i = 0; i < count; i++)
-    map_ipv4_to_ip ((ip4_address *)h_addr_list[i], al->addresses + i);
+  for (i = 0; i < count; i++) {
+    al->addrsets[i].family = AF_INET;
+    map_ipv4_to_ip ((ip4_address *)h_addr_list[i], &al->addrsets[i].addr);
+  }
 
   return al;
 }
@@ -230,14 +259,15 @@
    address. */
 
 static struct address_list *
-address_list_from_single (ip_address *addr)
+address_list_from_single (ip_address *addr, int ip_family)
 {
   struct address_list *al = xmalloc (sizeof (struct address_list));
   al->count     = 1;
   al->faulty    = 0;
-  al->addresses = xmalloc (sizeof (ip_address));
+  al->addrsets = xmalloc (sizeof (ip_addrset));
   al->refcount  = 1;
-  memcpy (al->addresses, addr, sizeof (ip_address));
+  memcpy (&al->addrsets->addr, addr, sizeof (ip_address));
+  al->addrsets->family = ip_family;
 
   return al;
 }
@@ -245,7 +275,7 @@
 static void
 address_list_delete (struct address_list *al)
 {
-  xfree (al->addresses);
+  xfree (al->addrsets);
   xfree (al);
 }
 
@@ -422,12 +452,12 @@
   * socklen_t	structure length for socket options
   */
 socklen_t
-sockaddr_len () 
+sockaddr_len (int ip_family) 
 {
-  if (ip_default_family == AF_INET) 
+  if (ip_family == AF_INET) 
     return sizeof (struct sockaddr_in);
 #ifdef ENABLE_IPV6
-  if (ip_default_family == AF_INET6) 
+  if (ip_family == AF_INET6) 
     return sizeof (struct sockaddr_in6);
 #endif
   abort();
@@ -474,7 +504,7 @@
 
 /* Versions of gethostbyname and getaddrinfo that support timeout. */
 
-#ifndef ENABLE_IPV6
+#ifndef HAVE_GETADDRINFO
 
 struct ghbnwt_context {
   const char *host_name;
@@ -509,7 +539,7 @@
   return ctx.hptr;
 }
 
-#else  /* ENABLE_IPV6 */
+#else  /* HAVE_GETADDRINFO */
 
 struct gaiwt_context {
   const char *node;
@@ -548,8 +578,7 @@
     }
   return ctx.exit_code;
 }
-
-#endif /* ENABLE_IPV6 */
+#endif /* HAVE_GETADDRINFO */
 
 /* Pretty-print ADDR.  When compiled without IPv6, this is the same as
    inet_ntoa.  With IPv6, it either prints an IPv6 address or an IPv4
@@ -591,7 +620,8 @@
       int i;
       debug_logprintf ("Caching %s =>", host);
       for (i = 0; i < al->count; i++)
-	debug_logprintf (" %s", pretty_print_address (al->addresses + i));
+	debug_logprintf (" %s",
+		pretty_print_address (&al->addrsets[i].addr));
       debug_logprintf ("\n");
     }
 #endif
@@ -609,7 +639,7 @@
 
 #ifdef ENABLE_IPV6
   if (inet_pton (AF_INET6, host, &addr) > 0)
-    return address_list_from_single (&addr);
+    return address_list_from_single (&addr, AF_INET6);
 #endif
 
   addr_ipv4 = (u_int32_t)inet_addr (host);
@@ -618,7 +648,7 @@
       /* ADDR is defined to be in network byte order, which is what
 	 this returns, so we can just copy it to STORE_IP.  */
       map_ipv4_to_ip ((ip4_address *)&addr_ipv4, &addr);
-      return address_list_from_single (&addr);
+      return address_list_from_single (&addr, AF_INET6);
     }
 
   if (host_name_addresses_map)
@@ -643,11 +673,14 @@
     int err;
 
     memset (&hints, 0, sizeof (hints));
-    if (ip_default_family == AF_INET)
-      hints.ai_family   = AF_INET;
-    else
-      hints.ai_family   = PF_UNSPEC;
     hints.ai_socktype = SOCK_STREAM;
+
+# if !defined (ENABLE_IPV6)
+    hints.ai_family   = AF_INET;
+# else
+    hints.ai_family   = AF_UNSPEC;
+# endif
+
     err = getaddrinfo_with_timeout (host, NULL, &hints, &ai, opt.dns_timeout);
 
     if (err != 0 || ai == NULL)
@@ -681,6 +714,10 @@
   }
 #endif
 
+#ifdef USE_IPV4_DEFAULT
+    address_list_sort_family (al, AF_INET);
+#endif
+
   /* Print the addresses determined by DNS lookup, but no more than
      three.  */
   if (!silent)
@@ -690,7 +727,7 @@
       for (i = 0; i < printmax; i++)
 	{
 	  logprintf (LOG_VERBOSE, "%s",
-		     pretty_print_address (al->addresses + i));
+		     pretty_print_address (&al->addrsets[i].addr));
 	  if (i < printmax - 1)
 	    logputs (LOG_VERBOSE, ", ");
 	}
diff -ruN --exclude configure wget-1.9.orig/src/host.h wget-1.9/src/host.h
--- wget-1.9.orig/src/host.h	Fri Oct 10 21:39:07 2003
+++ wget-1.9/src/host.h	Mon Oct 27 03:36:52 2003
@@ -73,13 +73,18 @@
   unsigned char bytes[MAX_IP_ADDRESS_SIZE];
 } ip_address;
 
+typedef struct {
+  ip_address addr;
+  int family;
+} ip_addrset;
+
 /* Function declarations */
 struct address_list *lookup_host PARAMS ((const char *, int));
 char *herrmsg PARAMS ((int));
 
 void address_list_get_bounds PARAMS ((struct address_list *, int *, int *));
 void address_list_copy_one PARAMS ((struct address_list *, int,
-				    ip_address *));
+				    ip_addrset *));
 int address_list_match_all PARAMS ((struct address_list *,
 				    struct address_list *));
 void address_list_set_faulty PARAMS ((struct address_list *, int));
@@ -97,11 +102,9 @@
 void wget_sockaddr_set_port PARAMS((wget_sockaddr *, unsigned short));
 void *wget_sockaddr_get_addr PARAMS((wget_sockaddr *));
 unsigned short wget_sockaddr_get_port PARAMS((const wget_sockaddr *));
-socklen_t sockaddr_len PARAMS(());
+socklen_t sockaddr_len PARAMS((int));
 void map_ipv4_to_ip PARAMS((ip4_address *, ip_address *));
 int  map_ip_to_ipv4 PARAMS((ip_address *, ip4_address *));
  
-extern	int	ip_default_family;	/* defined in host.c */
-
 
 #endif /* HOST_H */
