From 6f1250b1c6a9e9a01cc378e668e38b65739e3e8f Mon Sep 17 00:00:00 2001 From: hniksic Date: Wed, 29 Oct 2003 15:13:25 -0800 Subject: [PATCH] [svn] Updated IPv6 code. --- src/ChangeLog | 9 +++ src/connect.c | 48 +++++++------ src/connect.h | 8 +-- src/ftp-basic.c | 39 +++++------ src/ftp.c | 2 +- src/host.c | 182 ++++++++++++++++++++++++++++-------------------- src/host.h | 34 ++++++--- src/http.c | 2 +- src/wget.h | 14 +++- 9 files changed, 200 insertions(+), 138 deletions(-) diff --git a/src/ChangeLog b/src/ChangeLog index ec0db660..0863de3a 100644 --- a/src/ChangeLog +++ b/src/ChangeLog @@ -1,3 +1,12 @@ +2003-10-29 Hrvoje Niksic + + * 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 * host.c, connect.c, ftp.c, ...: Added support for dual-family diff --git a/src/connect.c b/src/connect.c index 252cf512..7e52b691 100644 --- a/src/connect.c +++ b/src/connect.c @@ -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; } 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 (); } diff --git a/src/connect.h b/src/connect.h index f85fe6a6..a020bf25 100644 --- a/src/connect.h +++ b/src/connect.h @@ -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 */ diff --git a/src/ftp-basic.c b/src/ftp-basic.c index 39d98fd1..84095793 100644 --- a/src/ftp-basic.c +++ b/src/ftp-basic.c @@ -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])); diff --git a/src/ftp.c b/src/ftp.c index 7c0bee7b..8c3b4869 100644 --- 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; diff --git a/src/host.c b/src/host.c index d0fd7e7c..62088aef 100644 --- a/src/host.c +++ b/src/host.c @@ -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 diff --git a/src/host.h b/src/host.h index 46acacb1..d2293dac 100644 --- a/src/host.h +++ b/src/host.h @@ -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)); diff --git a/src/http.c b/src/http.c index d4ee74c0..a3a40d4d 100644 --- a/src/http.c +++ b/src/http.c @@ -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); diff --git a/src/wget.h b/src/wget.h index e742d47a..496078fe 100644 --- a/src/wget.h +++ b/src/wget.h @@ -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 */ -- 2.39.2