]> sjero.net Git - wget/commitdiff
[svn] Updated IPv6 code.
authorhniksic <devnull@localhost>
Wed, 29 Oct 2003 23:13:25 +0000 (15:13 -0800)
committerhniksic <devnull@localhost>
Wed, 29 Oct 2003 23:13:25 +0000 (15:13 -0800)
src/ChangeLog
src/connect.c
src/connect.h
src/ftp-basic.c
src/ftp.c
src/host.c
src/host.h
src/http.c
src/wget.h

index ec0db660c12f159e6fc927ca2ebefadae791d28c..0863de3afd4544eb361e1998cc47ec667eea7411 100644 (file)
@@ -1,3 +1,12 @@
+2003-10-29  Hrvoje Niksic  <hniksic@xemacs.org>
+
+       * host.h: Defined accessors for elements of ip_address.  Updated
+       all callers.
+       (address_list_match_all): Use memcmp in the non-IPv6 case.
+
+       * wget.h (CONNECT_ERROR): Don't retry connecting if connect()
+       returned EAFNOSUPPORT.
+
 2003-10-27  Mauro Tortonesi <mauro@deepspace6.net>
 
        * host.c, connect.c, ftp.c, ...: Added support for dual-family
index 252cf5126942ef622c8aa356901d0c494865a111..7e52b691c103c1cee3736b28d40bf36151196038 100644 (file)
@@ -73,12 +73,11 @@ static int
 resolve_bind_address (int flags, ip_address *addr)
 {
   struct address_list *al = NULL;
-  int bind_address_resolved = 0;
+  int resolved = 0;
 
   if (opt.bind_address != NULL)
     {
       al = lookup_host (opt.bind_address, flags | LH_SILENT | LH_PASSIVE);
-
       if (al == NULL)
         {
           logprintf (LOG_NOTQUIET,
@@ -86,11 +85,14 @@ resolve_bind_address (int flags, ip_address *addr)
                     opt.bind_address);
        }
       else 
-        bind_address_resolved = 1;
+        resolved = 1;
     }
 
   if (al == NULL)
     {
+      /* #### Is there really a need for this?  Shouldn't we simply
+        return 0 and have the caller use sockaddr_set_address to
+        specify INADDR_ANY/in6addr_any?  */
       const char *unspecified_address = "0.0.0.0";
 #ifdef ENABLE_IPV6
       if (flags & BIND_ON_IPV6_ONLY)
@@ -104,7 +106,7 @@ resolve_bind_address (int flags, ip_address *addr)
   address_list_copy_one (al, 0, addr);
   address_list_release (al);
 
-  return bind_address_resolved;
+  return resolved;
 }
 \f
 struct cwt_context {
@@ -182,7 +184,7 @@ connect_to_one (ip_address *addr, unsigned short port, int silent)
                   pretty_addr, port);
     }
 
-  /* Make an internet socket, stream type.  */
+  /* Create the socket of the family appropriate for the address.  */
   sock = socket (sa->sa_family, SOCK_STREAM, 0);
   if (sock < 0)
     goto out;
@@ -327,7 +329,7 @@ bindport (const ip_address *bind_address, unsigned short *port)
   msock = -1;
 
 #ifdef ENABLE_IPV6
-  if (bind_address->type == IPv6_ADDRESS) 
+  if (bind_address->type == IPV6_ADDRESS) 
     family = AF_INET6;
 #endif
   
@@ -458,30 +460,36 @@ closeport (int sock)
 int
 conaddr (int fd, ip_address *ip)
 {
-  struct sockaddr_storage ss;
-  struct sockaddr *sa = (struct sockaddr *)&ss;
-  socklen_t addrlen = sizeof (ss);     
+  struct sockaddr_storage storage;
+  struct sockaddr *sockaddr = (struct sockaddr *)&storage;
+  socklen_t addrlen = sizeof (storage);
 
-  if (getsockname (fd, sa, &addrlen) < 0)
+  if (getsockname (fd, sockaddr, &addrlen) < 0)
     return 0;
 
-  switch (sa->sa_family)
+  switch (sockaddr->sa_family)
     {
 #ifdef ENABLE_IPV6
     case AF_INET6:
-      ip->type = IPv6_ADDRESS;
-      ip->addr.ipv6.addr = ((struct sockaddr_in6 *)sa)->sin6_addr;
+      {
+       struct sockaddr_in6 *sa6 = (struct sockaddr_in6 *)&storage;
+       ip->type = IPV6_ADDRESS;
+       ADDRESS_IPV6_IN6_ADDR (ip) = sa6->sin6_addr;
 #ifdef HAVE_SOCKADDR_IN6_SCOPE_ID
-      ip->addr.ipv6.scope_id = ((struct sockaddr_in6 *)sa)->sin6_scope_id;
+       ADDRESS_IPV6_SCOPE (ip) = sa6->sin6_scope_id;
 #endif
-      DEBUGP (("conaddr is: %s\n", pretty_print_address (ip)));
-      return 1;
+       DEBUGP (("conaddr is: %s\n", pretty_print_address (ip)));
+       return 1;
+      }
 #endif
     case AF_INET:
-      ip->type = IPv4_ADDRESS;
-      ip->addr.ipv4.addr = ((struct sockaddr_in *)sa)->sin_addr;
-      DEBUGP (("conaddr is: %s\n", pretty_print_address (ip)));
-      return 1;
+      {
+       struct sockaddr_in *sa = (struct sockaddr_in *)&storage;
+       ip->type = IPV4_ADDRESS;
+       ADDRESS_IPV4_IN_ADDR (ip) = sa->sin_addr;
+       DEBUGP (("conaddr is: %s\n", pretty_print_address (ip)));
+       return 1;
+      }
     default:
       abort ();
     }
index f85fe6a61615575eda63b0bb5f9227abde49dec8..a020bf253a63f77c82cf41019e6c92a91c5430e4 100644 (file)
@@ -30,13 +30,11 @@ so, delete this exception statement from your version.  */
 #ifndef CONNECT_H
 #define CONNECT_H
 
-#include "host.h"
+#include "host.h"              /* for definition of ip_address */
 
 /* bindport flags */
-#define BIND_ON_IPV4_ONLY LH_IPv4_ONLY
-#ifdef ENABLE_IPV6
-#define BIND_ON_IPV6_ONLY LH_IPv6_ONLY
-#endif /* ENABLE_IPV6 */
+#define BIND_ON_IPV4_ONLY LH_IPV4_ONLY
+#define BIND_ON_IPV6_ONLY LH_IPV6_ONLY
 
 /* Function declarations */
 
index 39d98fd19fe4c32f6cc0d98a6b811630b75fb7cc..8409579394b57ec4654e8739fd9f73ca0227bcb1 100644 (file)
@@ -260,12 +260,12 @@ ip_address_to_port_repr (const ip_address *addr, unsigned short port, char *buf,
   unsigned char *ptr;
 
   assert (addr != NULL);
-  assert (addr->type == IPv4_ADDRESS);
+  assert (addr->type == IPV4_ADDRESS);
   assert (buf != NULL);
   /* buf must contain the argument of PORT (of the form a,b,c,d,e,f). */
   assert (buflen >= 6 * 4);
 
-  ptr = (unsigned char *)(&addr->addr.ipv4.addr.s_addr);
+  ptr = ADDRESS_IPV4_DATA (addr);
   snprintf (buf, buflen, "%d,%d,%d,%d,%d,%d", ptr[0], ptr[1],
             ptr[2], ptr[3], (unsigned) (port & 0xff00) >> 8, port & 0xff);
   buf[buflen - 1] = '\0';
@@ -292,7 +292,7 @@ ftp_port (struct rbuf *rbuf)
   if (!conaddr (RBUF_FD (rbuf), &addr))
     return BINDERR;
 
-  assert (addr.type == IPv4_ADDRESS);
+  assert (addr.type == IPV4_ADDRESS);
 
   /* Setting port to 0 lets the system choose a free port.  */
   port = 0;
@@ -342,7 +342,7 @@ ip_address_to_lprt_repr (const ip_address *addr, unsigned short port, char *buf,
   unsigned char *ptr;
 
   assert (addr != NULL);
-  assert (addr->type == IPv4_ADDRESS || addr->type == IPv6_ADDRESS);
+  assert (addr->type == IPV4_ADDRESS || addr->type == IPV6_ADDRESS);
   assert (buf != NULL);
   /* buf must contain the argument of LPRT (of the form af,n,h1,h2,...,hn,p1,p2). */
   assert (buflen >= 21 * 4);
@@ -350,15 +350,15 @@ ip_address_to_lprt_repr (const ip_address *addr, unsigned short port, char *buf,
   /* Construct the argument of LPRT (of the form af,n,h1,h2,...,hn,p1,p2). */
   switch (addr->type) 
     {
-      case IPv4_ADDRESS: 
-       ptr = (unsigned char *)(&addr->addr.ipv4.addr);
+      case IPV4_ADDRESS: 
+       ptr = ADDRESS_IPV4_DATA (addr);
         snprintf (buf, buflen, "%d,%d,%d,%d,%d,%d,%d,%d,%d", 4, 4, 
                   ptr[0], ptr[1], ptr[2], ptr[3], 2,
                   (unsigned) (port & 0xff00) >> 8, port & 0xff);
         buf[buflen - 1] = '\0';
         break;
-      case IPv6_ADDRESS: 
-       ptr = (unsigned char *)(&addr->addr.ipv6.addr);
+      case IPV6_ADDRESS: 
+       ptr = ADDRESS_IPV6_DATA (addr);
        snprintf (buf, buflen, "%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d",
                  6, 16, ptr[0], ptr[1], ptr[2], ptr[3], ptr[4], ptr[5], ptr[6], ptr[7], 
                  ptr[8], ptr[9], ptr[10], ptr[11], ptr[12], ptr[13], ptr[14], ptr[15], 2,
@@ -389,7 +389,7 @@ ftp_lprt (struct rbuf *rbuf)
   if (!conaddr (RBUF_FD (rbuf), &addr))
     return BINDERR;
 
-  assert (addr.type == IPv4_ADDRESS || addr.type == IPv6_ADDRESS);
+  assert (addr.type == IPV4_ADDRESS || addr.type == IPV6_ADDRESS);
 
   /* Setting port to 0 lets the system choose a free port.  */
   port = 0;
@@ -437,7 +437,7 @@ ip_address_to_eprt_repr (const ip_address *addr, unsigned short port, char *buf,
   int afnum;
 
   assert (addr != NULL);
-  assert (addr->type == IPv4_ADDRESS || addr->type == IPv6_ADDRESS);
+  assert (addr->type == IPV4_ADDRESS || addr->type == IPV6_ADDRESS);
   assert (buf != NULL);
   /* buf must contain the argument of EPRT (of the form |af|addr|port|). 
    * 4 chars for the | separators, INET6_ADDRSTRLEN chars for addr  
@@ -445,7 +445,7 @@ ip_address_to_eprt_repr (const ip_address *addr, unsigned short port, char *buf,
   assert (buflen >= 4 + INET6_ADDRSTRLEN + 1 + 5); 
 
   /* Construct the argument of EPRT (of the form |af|addr|port|). */
-  afnum = (addr->type == IPv4_ADDRESS ? 1 : 2);
+  afnum = (addr->type == IPV4_ADDRESS ? 1 : 2);
   snprintf (buf, buflen, "|%d|%s|%d|", afnum, pretty_print_address (addr), port);
   buf[buflen - 1] = '\0';
 }
@@ -473,7 +473,7 @@ ftp_eprt (struct rbuf *rbuf)
   if (!conaddr (RBUF_FD (rbuf), &addr))
     return BINDERR;
 
-  assert (addr.type == IPv4_ADDRESS || addr.type == IPv6_ADDRESS);
+  assert (addr.type == IPV4_ADDRESS || addr.type == IPV6_ADDRESS);
 
   /* Setting port to 0 lets the system choose a free port.  */
   port = 0;
@@ -527,7 +527,7 @@ ftp_pasv (struct rbuf *rbuf, ip_address *addr, unsigned short *port)
   unsigned char tmp[6];
 
   assert (rbuf != NULL);
-  assert (rbuf_initialized_p(rbuf));
+  assert (rbuf_initialized_p (rbuf));
   assert (addr != NULL);
   assert (port != NULL);
 
@@ -576,9 +576,8 @@ ftp_pasv (struct rbuf *rbuf, ip_address *addr, unsigned short *port)
     }
   xfree (respline);
 
-  addr->type = IPv4_ADDRESS;
-  /* Mauro Tortonesi: is this safe and/or elegant enough? */
-  memcpy (&addr->addr.ipv4.addr, tmp, 4);
+  addr->type = IPV4_ADDRESS;
+  memcpy (ADDRESS_IPV4_DATA (addr), tmp, 4);
   *port = ((tmp[4] << 8) & 0xff00) + tmp[5];
 
   return FTPOK;
@@ -727,8 +726,8 @@ ftp_lpsv (struct rbuf *rbuf, ip_address *addr, unsigned short *port)
 
   if (af == 4)
     {
-      addr->type = IPv4_ADDRESS;
-      memcpy (&addr->addr.ipv4.addr, tmp, 4);
+      addr->type = IPV4_ADDRESS;
+      memcpy (ADDRESS_IPV4_DATA (addr), tmp, 4);
       *port = ((tmpprt[0] << 8) & 0xff00) + tmpprt[1];
       DEBUGP (("lpsv addr is: %s\n", pretty_print_address(addr)));
       DEBUGP (("tmpprt[0] is: %d\n", tmpprt[0]));
@@ -738,8 +737,8 @@ ftp_lpsv (struct rbuf *rbuf, ip_address *addr, unsigned short *port)
   else
     {
       assert (af == 6);
-      addr->type = IPv6_ADDRESS;
-      memcpy (&addr->addr.ipv6.addr, tmp, 16);
+      addr->type = IPV6_ADDRESS;
+      memcpy (ADDRESS_IPV6_DATA (addr), tmp, 16);
       *port = ((tmpprt[0] << 8) & 0xff00) + tmpprt[1];
       DEBUGP (("lpsv addr is: %s\n", pretty_print_address(addr)));
       DEBUGP (("tmpprt[0] is: %d\n", tmpprt[0]));
index 7c0bee7b3e873fedcf809e42bd8e9758a7c9efce..8c3b4869e66d348f741751792908fecd03262fcd 100644 (file)
--- a/src/ftp.c
+++ b/src/ftp.c
@@ -1242,7 +1242,7 @@ ftp_loop_internal (struct url *u, struct fileinfo *f, ccon *con)
 
       switch (err)
        {
-       case HOSTERR: case CONREFUSED: case FWRITEERR: case FOPENERR:
+       case HOSTERR: case CONIMPOSSIBLE: case FWRITEERR: case FOPENERR:
        case FTPNSFOD: case FTPLOGINC: case FTPNOPASV: case CONTNOTSUPPORTED:
          /* Fatal errors, give up.  */
          return err;
index d0fd7e7c948e849c71dbfef4d3f6bcd57dc9f989..62088aefd657ab336a14b8b4ba39cdbe88063829 100644 (file)
@@ -114,7 +114,8 @@ address_list_get_bounds (const struct address_list *al, int *start, int *end)
 /* Copy address number INDEX to IP_STORE.  */
 
 void
-address_list_copy_one (const struct address_list *al, int index, ip_address *ip_store)
+address_list_copy_one (const struct address_list *al, int index,
+                      ip_address *ip_store)
 {
   assert (index >= al->faulty && index < al->count);
   memcpy (ip_store, al->addresses + index, sizeof (ip_address));
@@ -123,43 +124,57 @@ address_list_copy_one (const struct address_list *al, int index, ip_address *ip_
 /* Check whether two address lists have all their IPs in common.  */
 
 int
-address_list_match_all (const struct address_list *al1, const struct address_list *al2)
+address_list_match_all (const struct address_list *al1,
+                       const struct address_list *al2)
 {
+#ifdef ENABLE_IPV6
   int i;
+#endif
   if (al1 == al2)
     return 1;
   if (al1->count != al2->count)
     return 0;
+
+  /* For the comparison to be complete, we'd need to sort the IP
+     addresses first.  But that's not necessary because this is only
+     used as an optimization.  */
+
+#ifndef ENABLE_IPV6
+  /* In the non-IPv6 case, there is only one address type, so we can
+     compare the whole array with memcmp.  */
+  return 0 == memcmp (al1->addresses, al2->addresses,
+                     al1->count * sizeof (ip_address));
+#else  /* ENABLE_IPV6 */
   for (i = 0; i < al1->count; ++i) 
     {
-#ifdef ENABLE_IPv6
-      if (al1->addresses[i].type != al2->addresses[i].type) 
+      const ip_address *ip1 = &al1->addresses[i];
+      const ip_address *ip2 = &al2->addresses[i];
+
+      if (ip1->type != ip2->type)
        return 0;
-      if (al1->addresses[i].type == IPv6_ADDRESS)
-       {
-         const struct in6_addr *addr1 = &al1->addresses[i].addr.ipv6.addr;
-         const struct in6_addr *addr2 = &al2->addresses[i].addr.ipv6.addr;
 
+      switch (ip1->type)
+       {
+       case IPV4_ADDRESS:
+         if (ADDRESS_IPV4_IN_ADDR (ip1).s_addr
+             != ADDRESS_IPV4_IN_ADDR (ip2).s_addr)
+           return 0;
+         break;
+       case IPV6_ADDRESS:
 #ifdef HAVE_SOCKADDR_IN6_SCOPE_ID
-         if ((al1->addresses[i].address.scope_id
-              != al2->addresses[i].address.scope_id)
-             || !IN6_ARE_ADDR_EQUAL (addr1, addr2))
-#else
-         if (!IN6_ARE_ADDR_EQUAL (addr1, addr2))
-#endif
+         if (ADDRESS_IPV6_SCOPE (ip1) != ADDRESS_IPV6_SCOPE (ip2))
            return 0;
-       }
-      else
-#endif
-       {
-         const struct in_addr *addr1 = (const struct in_addr *)&al1->addresses[i].addr.ipv4.addr;
-         const struct in_addr *addr2 = (const struct in_addr *)&al2->addresses[i].addr.ipv4.addr;
-         
-         if (addr1->s_addr != addr2->s_addr)
+#endif /* HAVE_SOCKADDR_IN6_SCOPE_ID */
+         if (!IN6_ARE_ADDR_EQUAL (&ADDRESS_IPV6_IN6_ADDR (ip1),
+                                  &ADDRESS_IPV6_IN6_ADDR (ip2)))
            return 0;
+         break;
+       default:
+         abort ();
        }
     }
   return 1;
+#endif /* ENABLE_IPV6 */
 }
 
 /* Mark the INDEXth element of AL as faulty, so that the next time
@@ -199,9 +214,10 @@ address_list_from_addrinfo (const struct addrinfo *ai)
 {
   struct address_list *al;
   const struct addrinfo *ptr;
-  int cnt = 0;
-  int i;
+  int cnt;
+  ip_address *ip;
 
+  cnt = 0;
   for (ptr = ai; ptr != NULL ; ptr = ptr->ai_next)
     if (ptr->ai_family == AF_INET || ptr->ai_family == AF_INET6)
       ++cnt;
@@ -214,27 +230,28 @@ address_list_from_addrinfo (const struct addrinfo *ai)
   al->faulty    = 0;
   al->refcount  = 1;
 
-  for (i = 0, ptr = ai; ptr != NULL; ptr = ptr->ai_next)
+  ip = al->addresses;
+  for (ptr = ai; ptr != NULL; ptr = ptr->ai_next)
     if (ptr->ai_family == AF_INET6) 
       {
        const struct sockaddr_in6 *sin6 =
          (const struct sockaddr_in6 *)ptr->ai_addr;
-       al->addresses[i].addr.ipv6.addr = sin6->sin6_addr;
-       al->addresses[i].type = IPv6_ADDRESS;
+       ip->type = IPV6_ADDRESS;
+       ADDRESS_IPV6_IN6_ADDR (ip) = sin6->sin6_addr;
 #ifdef HAVE_SOCKADDR_IN6_SCOPE_ID
-       al->addresses[i].addr.ipv6.scope_id = sin6->sin6_scope_id;
+       ADDRESS_IPV6_SCOPE (ip) = sin6->sin6_scope_id;
 #endif
-       ++i;
+       ++ip;
       } 
     else if (ptr->ai_family == AF_INET)
       {
        const struct sockaddr_in *sin =
          (const struct sockaddr_in *)ptr->ai_addr;
-       al->addresses[i].addr.ipv4.addr = sin->sin_addr;
-       al->addresses[i].type = IPv4_ADDRESS;
-       ++i;
+       ip->type = IPV4_ADDRESS;
+       ADDRESS_IPV4_IN_ADDR (ip) = sin->sin_addr;
+       ++ip;
       }
-  assert (i == cnt);
+  assert (ip - al->addresses == cnt);
   return al;
 }
 #else
@@ -243,23 +260,25 @@ address_list_from_addrinfo (const struct addrinfo *ai)
 static struct address_list *
 address_list_from_vector (char **h_addr_list)
 {
-  int count = 0, i;
-
+  int count, i;
   struct address_list *al = xmalloc (sizeof (struct address_list));
 
+  count = 0;
   while (h_addr_list[count])
     ++count;
   assert (count > 0);
+
   al->count     = count;
   al->faulty    = 0;
   al->addresses = xmalloc (count * sizeof (ip_address));
   al->refcount  = 1;
 
-  for (i = 0; i < count; i++) {
-    /* Mauro Tortonesi: is this safe? */
-    memcpy (&((al->addresses + i)->addr.ipv4.addr.s_addr), h_addr_list[i], 4);
-    (al->addresses + i)->type = IPv4_ADDRESS;
-  }
+  for (i = 0; i < count; i++)
+    {
+      ip_address *ip = &al->addresses[i];
+      ip->type = IPV4_ADDRESS;
+      memcpy (ADDRESS_IPV4_DATA (ip), h_addr_list[i], 4);
+    }
 
   return al;
 }
@@ -323,31 +342,38 @@ void
 sockaddr_set_address (struct sockaddr *sa, unsigned short port, 
                      const ip_address *addr)
 {
-  if (addr->type == IPv4_ADDRESS)
+  if (addr->type == IPV4_ADDRESS)
     {
       struct sockaddr_in *sin = (struct sockaddr_in *)sa;
 
       sin->sin_family = AF_INET;
       sin->sin_port = htons (port);
-      if (addr == NULL) 
+      if (addr == NULL)
        sin->sin_addr.s_addr = INADDR_ANY;
       else
-       sin->sin_addr = addr->addr.ipv4.addr;
+       sin->sin_addr = ADDRESS_IPV4_IN_ADDR (addr);
     }
 #ifdef ENABLE_IPV6
-  else if (addr->type == IPv6_ADDRESS) 
+  else if (addr->type == IPV6_ADDRESS) 
     {
       struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sa;
 
       sin6->sin6_family = AF_INET6;
       sin6->sin6_port = htons (port);
-      if (addr == NULL) 
-       sin6->sin6_addr = in6addr_any;
+      /* #### How can ADDR be NULL?  We have dereferenced it above by
+        accessing addr->type!  */
+      if (addr == NULL)
+       {
+         sin6->sin6_addr = in6addr_any;
+         /* #### Should we set the scope_id here? */
+       }
       else
-       sin6->sin6_addr = addr->addr.ipv6.addr;
+       {
+         sin6->sin6_addr = ADDRESS_IPV6_IN6_ADDR (addr);
 #ifdef HAVE_SOCKADDR_IN6_SCOPE_ID
-      sin6->sin6_scope_id = addr->addr.ipv6.scope_id;
-#endif /* HAVE_SOCKADDR_IN6_SCOPE_ID */
+         sin6->sin6_scope_id = ADDRESS_IPV6_SCOPE (addr);
+#endif
+       }
     }
 #endif /* ENABLE_IPV6 */
   else
@@ -362,8 +388,8 @@ sockaddr_get_address (const struct sockaddr *sa, unsigned short *port,
     {
       struct sockaddr_in *sin = (struct sockaddr_in *)sa;
 
-      addr->type = IPv4_ADDRESS;
-      addr->addr.ipv4.addr = sin->sin_addr;
+      addr->type = IPV4_ADDRESS;
+      ADDRESS_IPV4_IN_ADDR (addr) = sin->sin_addr;
       if (port != NULL) 
        *port = ntohs (sin->sin_port);
     }
@@ -372,10 +398,10 @@ sockaddr_get_address (const struct sockaddr *sa, unsigned short *port,
     {
       struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sa;
 
-      addr->type = IPv6_ADDRESS;
-      addr->addr.ipv6.addr = sin6->sin6_addr;
+      addr->type = IPV6_ADDRESS;
+      ADDRESS_IPV6_IN6_ADDR (addr) = sin6->sin6_addr;
 #ifdef HAVE_SOCKADDR_IN6_SCOPE_ID
-      addr->addr.ipv6.scope_id = sin6->sin6_scope_id;
+      ADDRESS_IPV6_SCOPE (addr) = sin6->sin6_scope_id;
 #endif  
       if (port != NULL) 
        *port = ntohs (sin6->sin6_port);
@@ -578,21 +604,23 @@ pretty_print_address (const ip_address *addr)
 {
   switch (addr->type) 
     {
-    case IPv4_ADDRESS:
-      return inet_ntoa (addr->addr.ipv4.addr);
+    case IPV4_ADDRESS:
+      return inet_ntoa (ADDRESS_IPV4_IN_ADDR (addr));
 #ifdef ENABLE_IPV6
-    case IPv6_ADDRESS:
+    case IPV6_ADDRESS:
       {
-        int len;
         static char buf[128];
-       inet_ntop (AF_INET6, &addr->addr.ipv6.addr, buf, sizeof (buf));
+       inet_ntop (AF_INET6, &ADDRESS_IPV6_IN6_ADDR (addr), buf, sizeof (buf));
 #if 0
 #ifdef HAVE_SOCKADDR_IN6_SCOPE_ID
-        /* print also scope_id for all ?non-global? addresses */
-        snprintf (buf + len, sizeof (buf) - len, "%%%d", addr->addr.ipv6.scope_id);
+       {
+         /* append "%SCOPE_ID" for all ?non-global? addresses */
+         char *p = buf + strlen (buf);
+         *p++ = '%';
+         number_to_string (p, ADDRESS_IPV6_SCOPE (addr));
+       }
 #endif
 #endif
-        len = strlen (buf);
         buf[sizeof (buf) - 1] = '\0';
         return buf;
       }
@@ -636,20 +664,23 @@ lookup_host (const char *host, int flags)
   int err, family;
   struct addrinfo hints, *res;
 
-  /* This ip_default_family+flags business looks like bad design to
-     me.  This function should rather accept a FAMILY argument.  */
-  if (flags & LH_IPv4_ONLY)
+  /* Is this necessary?  Should this function be changed to accept a
+     FAMILY argument?  */
+  if (flags & LH_IPV4_ONLY)
     family = AF_INET;
-  else if (flags & LH_IPv6_ONLY)
+  else if (flags & LH_IPV6_ONLY)
     family = AF_INET6;
   else
     family = ip_default_family;
 #endif
          
   /* First, try to check whether the address is already a numeric
-     address.  Where getaddrinfo is available, we do it using the
-     AI_NUMERICHOST flag.  Without IPv6, we check whether inet_addr
-     succeeds.  */
+     address, in which case we don't need to cache it or bother with
+     setting up timeouts.  Plus, if memory serves me right, Ultrix's
+     gethostbyname can't handle numeric addresses (!).
+
+     Where getaddrinfo is available, we do it using the AI_NUMERICHOST
+     flag.  Without IPv6, we use inet_addr succeeds.  */
 
 #ifdef ENABLE_IPV6
   memset (&hints, 0, sizeof (hints));
@@ -675,14 +706,11 @@ lookup_host (const char *host, int flags)
     if (addr_ipv4 != (uint32_t) -1)
       {
        /* The return value of inet_addr is in network byte order, so
-          we can just copy it to ADDR.  */
-       ip_address addr;
-       /* This has a huge number of dereferences because C doesn't
-          support anonymous unions and because struct in_addr adds a
-          cast.  */
-       addr.addr.ipv4.addr.s_addr = addr_ipv4;
-       addr.type = IPv4_ADDRESS;
-       return address_list_from_single (&addr);
+          we can just copy it to IP.  */
+       ip_address ip;
+       ip.type = IPV4_ADDRESS;
+       memcpy (ADDRESS_IPV4_DATA (&ip), &addr_ipv4, 4);
+       return address_list_from_single (&ip);
       }
   }
 #endif
index 46acacb18dbca748e321521829df962a0f67ff40..d2293dacfae079e88197e24bfb1f22cd322a1cf3 100644 (file)
@@ -46,13 +46,19 @@ struct address_list;
 
 extern int ip_default_family;  /* defined in host.c */
 
+/* This struct defines an IP address, tagged with family type.  */
+
 typedef struct {
+  /* Address type. */
   enum { 
-    IPv4_ADDRESS, 
+    IPV4_ADDRESS, 
 #ifdef ENABLE_IPV6
-    IPv6_ADDRESS 
+    IPV6_ADDRESS 
 #endif /* ENABLE_IPV6 */
   } type;
+
+  /* Address data union: ipv6 contains IPv6-related data (address and
+     scope), and ipv4 contains IPv4 address.  */
   union {
 #ifdef ENABLE_IPV6
     struct {
@@ -65,24 +71,30 @@ typedef struct {
     struct {
       struct in_addr addr;
     } ipv4;
-  } addr;
+  } u;
 } ip_address;
 
-#ifndef ENABLE_IPV6
+/* Because C doesn't support anonymous unions, access to ip_address
+   elements is clunky.  Hence the accessors.  */
 
-#ifndef HAVE_SOCKADDR_STORAGE
-#define sockaddr_storage sockaddr_in
-#endif
+#define ADDRESS_IPV6_IN6_ADDR(x) ((x)->u.ipv6.addr)
+#define ADDRESS_IPV6_DATA(x) ((void *)&(x)->u.ipv6.addr.s6_addr)
+#define ADDRESS_IPV6_SCOPE(x) ((x)->u.ipv6.scope_id)
 
+#define ADDRESS_IPV4_IN_ADDR(x) ((x)->u.ipv4.addr)
+#define ADDRESS_IPV4_DATA(x) ((void *)&(x)->u.ipv4.addr.s_addr)
+
+#ifndef ENABLE_IPV6
+# ifndef HAVE_SOCKADDR_STORAGE
+#  define sockaddr_storage sockaddr_in
+# endif
 #endif /* ENABLE_IPV6 */
 
 /* Flags for lookup_host */
 #define LH_SILENT    0x0001
 #define LH_PASSIVE   0x0002
-#define LH_IPv4_ONLY 0x0004
-#ifdef ENABLE_IPV6
-#define LH_IPv6_ONLY 0x0008
-#endif /* ENABLE_IPV6 */
+#define LH_IPV4_ONLY 0x0004
+#define LH_IPV6_ONLY 0x0008
 
 /* Function declarations */
 struct address_list *lookup_host PARAMS ((const char *, int));
index d4ee74c063f871f3f6480408f0279447ad50e66b..a3a40d4d7180861651bbce4d5b83513605f8abc7 100644 (file)
@@ -1789,7 +1789,7 @@ File `%s' already there, will not retrieve.\n"), *hstat.local_file);
          printwhat (count, opt.ntry);
          continue;
          break;
-       case HOSTERR: case CONREFUSED: case PROXERR: case AUTHFAILED: 
+       case HOSTERR: case CONIMPOSSIBLE: case PROXERR: case AUTHFAILED: 
        case SSLERRCTXCREATE: case CONTNOTSUPPORTED:
          /* Fatal errors just return from the function.  */
          free_hstat (&hstat);
index e742d47abffe09848e239a2a4ffe893a89a1cd39..496078fe175ffb4f06940f0649e3a1268deec692 100644 (file)
@@ -276,7 +276,7 @@ enum
 typedef enum
 {
   NOCONERROR, HOSTERR, CONSOCKERR, CONERROR, CONSSLERR,
-  CONREFUSED, NEWLOCATION, NOTENOUGHMEM, CONPORTERR,
+  CONIMPOSSIBLE, NEWLOCATION, NOTENOUGHMEM, CONPORTERR,
   BINDERR, BINDOK, LISTENERR, ACCEPTERR, ACCEPTOK,
   CONCLOSED, FTPOK, FTPLOGINC, FTPLOGREFUSED, FTPPORTERR,
   FTPNSFOD, FTPRETROK, FTPUNKNOWNTYPE, FTPRERR,
@@ -310,7 +310,15 @@ typedef unsigned char  boolean;
    retrieve the requisites of a single document. */
 #define INFINITE_RECURSION -1
 
-#define CONNECT_ERROR(x) ((x) == ECONNREFUSED && !opt.retry_connrefused        \
-                         ? CONREFUSED : CONERROR)
+/* In case old systems don't have EAFNOSUPPORT, which we use below. */
+#ifndef EAFNOSUPPORT
+# define EAFNOSUPPORT EINVAL
+#endif
+
+#define CONNECT_ERROR(err) ((   (err) == EAFNOSUPPORT          \
+                            || (err) == EINVAL                 \
+                            || ((err) == ECONNREFUSED          \
+                                && !opt.retry_connrefused))    \
+                           ? CONIMPOSSIBLE : CONERROR)
 
 #endif /* WGET_H */