From 481443d33720d14890871fd2cb3b21d9484a227a Mon Sep 17 00:00:00 2001 From: hniksic Date: Wed, 10 Aug 2005 06:50:08 -0700 Subject: [PATCH] [svn] Simplify the ip_address data union. Always use inet_ntop for printing IP addresses when IPv6 is enabled. --- src/ChangeLog | 7 ++++++ src/connect.c | 39 ++++++++++++----------------- src/ftp-basic.c | 65 +++++++++++++++++++++++-------------------------- src/ftp.c | 12 ++++----- src/host.c | 61 +++++++++++++++++++--------------------------- src/host.h | 56 +++++++++++++++--------------------------- 6 files changed, 103 insertions(+), 137 deletions(-) diff --git a/src/ChangeLog b/src/ChangeLog index 6b9f90ca..6575c255 100644 --- a/src/ChangeLog +++ b/src/ChangeLog @@ -1,3 +1,10 @@ +2005-08-10 Hrvoje Niksic + + * host.c (print_address): Always use inet_ntop when IPv6 is + enabled. + + * host.h (ip_address): Simplify the data union. + 2005-08-09 Hrvoje Niksic * mswindows.c (inet_ntop): Also handle IPv4 addresses for diff --git a/src/connect.c b/src/connect.c index dc7145f2..9cf84f22 100644 --- a/src/connect.c +++ b/src/connect.c @@ -73,27 +73,27 @@ so, delete this exception statement from your version. */ static void sockaddr_set_data (struct sockaddr *sa, const ip_address *ip, int port) { - switch (ip->type) + switch (ip->family) { - case IPV4_ADDRESS: + case AF_INET: { struct sockaddr_in *sin = (struct sockaddr_in *)sa; xzero (*sin); sin->sin_family = AF_INET; sin->sin_port = htons (port); - sin->sin_addr = ADDRESS_IPV4_IN_ADDR (ip); + sin->sin_addr = ip->data.d4; break; } #ifdef ENABLE_IPV6 - case IPV6_ADDRESS: + case AF_INET6: { struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sa; xzero (*sin6); sin6->sin6_family = AF_INET6; sin6->sin6_port = htons (port); - sin6->sin6_addr = ADDRESS_IPV6_IN6_ADDR (ip); + sin6->sin6_addr = ip->data.d6; #ifdef HAVE_SOCKADDR_IN6_SCOPE_ID - sin6->sin6_scope_id = ADDRESS_IPV6_SCOPE (ip); + sin6->sin6_scope_id = ip->ipv6_scope; #endif break; } @@ -117,8 +117,8 @@ sockaddr_get_data (const struct sockaddr *sa, ip_address *ip, int *port) struct sockaddr_in *sin = (struct sockaddr_in *)sa; if (ip) { - ip->type = IPV4_ADDRESS; - ADDRESS_IPV4_IN_ADDR (ip) = sin->sin_addr; + ip->family = AF_INET; + ip->data.d4 = sin->sin_addr; } if (port) *port = ntohs (sin->sin_port); @@ -130,10 +130,10 @@ sockaddr_get_data (const struct sockaddr *sa, ip_address *ip, int *port) struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sa; if (ip) { - ip->type = IPV6_ADDRESS; - ADDRESS_IPV6_IN6_ADDR (ip) = sin6->sin6_addr; + ip->family = AF_INET6; + ip->data.d6 = sin6->sin6_addr; #ifdef HAVE_SOCKADDR_IN6_SCOPE_ID - ADDRESS_IPV6_SCOPE (ip) = sin6->sin6_scope_id; + ip->ipv6_scope = sin6->sin6_scope_id; #endif } if (port) @@ -415,7 +415,6 @@ int bind_local (const ip_address *bind_address, int *port) { int sock; - int family = AF_INET; struct sockaddr_storage ss; struct sockaddr *sa = (struct sockaddr *)&ss; @@ -424,12 +423,7 @@ bind_local (const ip_address *bind_address, int *port) void *setopt_ptr = (void *)&setopt_val; socklen_t setopt_size = sizeof (setopt_val); -#ifdef ENABLE_IPV6 - if (bind_address->type == IPV6_ADDRESS) - family = AF_INET6; -#endif - - sock = socket (family, SOCK_STREAM, 0); + sock = socket (bind_address->family, SOCK_STREAM, 0); if (sock < 0) return -1; @@ -529,16 +523,16 @@ socket_ip_address (int sock, ip_address *ip, int endpoint) if (ret < 0) return false; + ip->family = sockaddr->sa_family; switch (sockaddr->sa_family) { #ifdef ENABLE_IPV6 case AF_INET6: { struct sockaddr_in6 *sa6 = (struct sockaddr_in6 *)&storage; - ip->type = IPV6_ADDRESS; - ADDRESS_IPV6_IN6_ADDR (ip) = sa6->sin6_addr; + ip->data.d6 = sa6->sin6_addr; #ifdef HAVE_SOCKADDR_IN6_SCOPE_ID - ADDRESS_IPV6_SCOPE (ip) = sa6->sin6_scope_id; + ip->ipv6_scope = sa6->sin6_scope_id; #endif DEBUGP (("conaddr is: %s\n", print_address (ip))); return true; @@ -547,8 +541,7 @@ socket_ip_address (int sock, ip_address *ip, int endpoint) case AF_INET: { struct sockaddr_in *sa = (struct sockaddr_in *)&storage; - ip->type = IPV4_ADDRESS; - ADDRESS_IPV4_IN_ADDR (ip) = sa->sin_addr; + ip->data.d4 = sa->sin_addr; DEBUGP (("conaddr is: %s\n", print_address (ip))); return true; } diff --git a/src/ftp-basic.c b/src/ftp-basic.c index 753566ae..dd7d7b7a 100644 --- a/src/ftp-basic.c +++ b/src/ftp-basic.c @@ -250,13 +250,11 @@ ip_address_to_port_repr (const ip_address *addr, int port, char *buf, { unsigned char *ptr; - assert (addr != NULL); - assert (addr->type == IPV4_ADDRESS); - assert (buf != NULL); + assert (addr->family == AF_INET); /* buf must contain the argument of PORT (of the form a,b,c,d,e,f). */ assert (buflen >= 6 * 4); - ptr = ADDRESS_IPV4_DATA (addr); + ptr = IP_INADDR_DATA (addr); snprintf (buf, buflen, "%d,%d,%d,%d,%d,%d", ptr[0], ptr[1], ptr[2], ptr[3], (port & 0xff00) >> 8, port & 0xff); buf[buflen - 1] = '\0'; @@ -280,7 +278,7 @@ ftp_port (int csock, int *local_sock) if (!socket_ip_address (csock, &addr, ENDPOINT_LOCAL)) return FTPSYSERR; - assert (addr.type == IPV4_ADDRESS); + assert (addr.family == AF_INET); /* Setting port to 0 lets the system choose a free port. */ port = 0; @@ -326,32 +324,29 @@ static void ip_address_to_lprt_repr (const ip_address *addr, int port, char *buf, size_t buflen) { - unsigned char *ptr; + unsigned char *ptr = IP_INADDR_DATA (addr); - assert (addr != NULL); - 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); /* Construct the argument of LPRT (of the form af,n,h1,h2,...,hn,p1,p2). */ - switch (addr->type) - { - 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, - (port & 0xff00) >> 8, port & 0xff); - buf[buflen - 1] = '\0'; - break; - 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, - (port & 0xff00) >> 8, port & 0xff); - buf[buflen - 1] = '\0'; - break; + switch (addr->family) + { + case AF_INET: + snprintf (buf, buflen, "%d,%d,%d,%d,%d,%d,%d,%d,%d", 4, 4, + ptr[0], ptr[1], ptr[2], ptr[3], 2, + (port & 0xff00) >> 8, port & 0xff); + break; + case AF_INET6: + 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, (port & 0xff00) >> 8, port & 0xff); + break; + default: + abort (); } } @@ -373,7 +368,7 @@ ftp_lprt (int csock, int *local_sock) if (!socket_ip_address (csock, &addr, ENDPOINT_LOCAL)) return FTPSYSERR; - assert (addr.type == IPV4_ADDRESS || addr.type == IPV6_ADDRESS); + assert (addr.family == AF_INET || addr.family == AF_INET6); /* Setting port to 0 lets the system choose a free port. */ port = 0; @@ -425,7 +420,7 @@ ip_address_to_eprt_repr (const ip_address *addr, int 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->family == AF_INET ? 1 : 2); snprintf (buf, buflen, "|%d|%s|%d|", afnum, print_address (addr), port); buf[buflen - 1] = '\0'; } @@ -546,8 +541,8 @@ ftp_pasv (int csock, ip_address *addr, int *port) } xfree (respline); - addr->type = IPV4_ADDRESS; - memcpy (ADDRESS_IPV4_DATA (addr), tmp, 4); + addr->family = AF_INET; + memcpy (IP_INADDR_DATA (addr), tmp, 4); *port = ((tmp[4] << 8) & 0xff00) + tmp[5]; return FTPOK; @@ -692,8 +687,8 @@ ftp_lpsv (int csock, ip_address *addr, int *port) if (af == 4) { - addr->type = IPV4_ADDRESS; - memcpy (ADDRESS_IPV4_DATA (addr), tmp, 4); + addr->family = AF_INET; + memcpy (IP_INADDR_DATA (addr), tmp, 4); *port = ((tmpprt[0] << 8) & 0xff00) + tmpprt[1]; DEBUGP (("lpsv addr is: %s\n", print_address(addr))); DEBUGP (("tmpprt[0] is: %d\n", tmpprt[0])); @@ -703,8 +698,8 @@ ftp_lpsv (int csock, ip_address *addr, int *port) else { assert (af == 6); - addr->type = IPV6_ADDRESS; - memcpy (ADDRESS_IPV6_DATA (addr), tmp, 16); + addr->family = AF_INET6; + memcpy (IP_INADDR_DATA (addr), tmp, 16); *port = ((tmpprt[0] << 8) & 0xff00) + tmpprt[1]; DEBUGP (("lpsv addr is: %s\n", print_address(addr))); DEBUGP (("tmpprt[0] is: %d\n", tmpprt[0])); @@ -735,7 +730,7 @@ ftp_epsv (int csock, ip_address *ip, int *port) /* Form the request. */ /* EPSV 1 means that we ask for IPv4 and EPSV 2 means that we ask for IPv6. */ - request = ftp_request ("EPSV", (ip->type == IPV4_ADDRESS ? "1" : "2")); + request = ftp_request ("EPSV", (ip->family == AF_INET ? "1" : "2")); /* And send it. */ nwritten = fd_write (csock, request, strlen (request), -1); diff --git a/src/ftp.c b/src/ftp.c index 7b79b8e2..9b6fc871 100644 --- a/src/ftp.c +++ b/src/ftp.c @@ -116,14 +116,14 @@ ftp_do_pasv (int csock, ip_address *addr, int *port) /* If our control connection is over IPv6, then we first try EPSV and then * LPSV if the former is not supported. If the control connection is over * IPv4, we simply issue the good old PASV request. */ - switch (addr->type) + switch (addr->family) { - case IPV4_ADDRESS: + case AF_INET: if (!opt.server_response) logputs (LOG_VERBOSE, "==> PASV ... "); err = ftp_pasv (csock, addr, port); break; - case IPV6_ADDRESS: + case AF_INET6: if (!opt.server_response) logputs (LOG_VERBOSE, "==> EPSV ... "); err = ftp_epsv (csock, addr, port); @@ -159,14 +159,14 @@ ftp_do_port (int csock, int *local_sock) /* If our control connection is over IPv6, then we first try EPRT and then * LPRT if the former is not supported. If the control connection is over * IPv4, we simply issue the good old PORT request. */ - switch (cip.type) + switch (cip.family) { - case IPV4_ADDRESS: + case AF_INET: if (!opt.server_response) logputs (LOG_VERBOSE, "==> PORT ... "); err = ftp_port (csock, local_sock); break; - case IPV6_ADDRESS: + case AF_INET6: if (!opt.server_response) logputs (LOG_VERBOSE, "==> EPRT ... "); err = ftp_eprt (csock, local_sock); diff --git a/src/host.c b/src/host.c index 745868c8..a13953b0 100644 --- a/src/host.c +++ b/src/host.c @@ -98,30 +98,27 @@ bool address_list_contains (const struct address_list *al, const ip_address *ip) { int i; - switch (ip->type) + switch (ip->family) { - case IPV4_ADDRESS: + case AF_INET: for (i = 0; i < al->count; i++) { ip_address *cur = al->addresses + i; - if (cur->type == IPV4_ADDRESS - && (ADDRESS_IPV4_IN_ADDR (cur).s_addr - == - ADDRESS_IPV4_IN_ADDR (ip).s_addr)) + if (cur->family == AF_INET + && (cur->data.d4.s_addr == ip->data.d4.s_addr)) return true; } return false; #ifdef ENABLE_IPV6 - case IPV6_ADDRESS: + case AF_INET6: for (i = 0; i < al->count; i++) { ip_address *cur = al->addresses + i; - if (cur->type == IPV6_ADDRESS + if (cur->family == AF_INET6 #ifdef HAVE_SOCKADDR_IN6_SCOPE_ID - && ADDRESS_IPV6_SCOPE (cur) == ADDRESS_IPV6_SCOPE (ip) + && cur->ipv6_scope == ip->ipv6_scope #endif - && IN6_ARE_ADDR_EQUAL (&ADDRESS_IPV6_IN6_ADDR (cur), - &ADDRESS_IPV6_IN6_ADDR (ip))) + && IN6_ARE_ADDR_EQUAL (&cur->data.d6, &ip->data.d6)) return true; } return false; @@ -199,10 +196,10 @@ address_list_from_addrinfo (const struct addrinfo *ai) { const struct sockaddr_in6 *sin6 = (const struct sockaddr_in6 *)ptr->ai_addr; - ip->type = IPV6_ADDRESS; - ADDRESS_IPV6_IN6_ADDR (ip) = sin6->sin6_addr; + ip->family = AF_INET6; + ip->data.d6 = sin6->sin6_addr; #ifdef HAVE_SOCKADDR_IN6_SCOPE_ID - ADDRESS_IPV6_SCOPE (ip) = sin6->sin6_scope_id; + ip->ipv6_scope = sin6->sin6_scope_id; #endif ++ip; } @@ -210,17 +207,17 @@ address_list_from_addrinfo (const struct addrinfo *ai) { const struct sockaddr_in *sin = (const struct sockaddr_in *)ptr->ai_addr; - ip->type = IPV4_ADDRESS; - ADDRESS_IPV4_IN_ADDR (ip) = sin->sin_addr; + ip->family = AF_INET; + ip->data.d4 = sin->sin_addr; ++ip; } assert (ip - al->addresses == cnt); return al; } -#define IS_IPV4(addr) (((const ip_address *) addr)->type == IPV4_ADDRESS) +#define IS_IPV4(addr) (((const ip_address *) addr)->family == AF_INET) -/* Compare two IP addresses by type, giving preference to the IPv4 +/* Compare two IP addresses by family, giving preference to the IPv4 address (sorting it first). In other words, return -1 if ADDR1 is IPv4 and ADDR2 is IPv6, +1 if ADDR1 is IPv6 and ADDR2 is IPv4, and 0 otherwise. @@ -234,7 +231,7 @@ cmp_prefer_ipv4 (const void *addr1, const void *addr2) return !IS_IPV4 (addr1) - !IS_IPV4 (addr2); } -#define IS_IPV6(addr) (((const ip_address *) addr)->type == IPV6_ADDRESS) +#define IS_IPV6(addr) (((const ip_address *) addr)->family == AF_INET6) /* Like the above, but give preference to the IPv6 address. */ @@ -267,7 +264,7 @@ address_list_from_ipv4_addresses (char **vec) for (i = 0; i < count; i++) { ip_address *ip = &al->addresses[i]; - ip->type = IPV4_ADDRESS; + ip->family = AF_INET; memcpy (ADDRESS_IPV4_DATA (ip), vec[i], 4); } @@ -406,26 +403,18 @@ getaddrinfo_with_timeout (const char *node, const char *service, const char * print_address (const ip_address *addr) { - switch (addr->type) - { - case IPV4_ADDRESS: - return inet_ntoa (ADDRESS_IPV4_IN_ADDR (addr)); #ifdef ENABLE_IPV6 - case IPV6_ADDRESS: - { - static char buf[64]; - if (!inet_ntop (AF_INET6, &ADDRESS_IPV6_IN6_ADDR (addr), - buf, sizeof (buf))) - snprintf (buf, sizeof buf, "", strerror (errno)); - buf[sizeof (buf) - 1] = '\0'; - return buf; - } + static char buf[64]; + if (!inet_ntop (addr->family, IP_INADDR_DATA (addr), buf, sizeof buf)) + snprintf (buf, sizeof buf, "", strerror (errno)); + return buf; +#else + return inet_ntoa (addr->data.d4); #endif - } - abort (); } -/* The following two functions were adapted from glibc. */ +/* The following two functions were adapted from glibc's + implementation of inet_pton, written by Paul Vixie. */ static bool is_valid_ipv4_address (const char *str, const char *end) diff --git a/src/host.h b/src/host.h index 6d0c553f..de71a406 100644 --- a/src/host.h +++ b/src/host.h @@ -47,48 +47,30 @@ struct address_list; /* This struct defines an IP address, tagged with family type. */ typedef struct { - /* Address type. */ - enum { - IPV4_ADDRESS -#ifdef ENABLE_IPV6 - , IPV6_ADDRESS -#endif /* ENABLE_IPV6 */ - } type; + /* Address family, one of AF_INET or AF_INET6. */ + int family; - /* Address data union: ipv6 contains IPv6-related data (address and - scope), and ipv4 contains the IPv4 address. */ + /* The actual data, in the form of struct in_addr or in6_addr: */ union { + struct in_addr d4; /* IPv4 address */ #ifdef ENABLE_IPV6 - struct { - struct in6_addr addr; -# ifdef HAVE_SOCKADDR_IN6_SCOPE_ID - unsigned int scope_id; -# endif - } ipv6; -#endif /* ENABLE_IPV6 */ - struct { - struct in_addr addr; - } ipv4; - } u; -} ip_address; - -/* Because C doesn't support anonymous unions, access to ip_address - elements is unwieldy. Hence the accessors. - - The _ADDR accessors return the address as the struct in_addr or - in6_addr. The _DATA accessor returns a pointer to the address data - -- pretty much the same as the above, but cast to void*. The - _SCOPE accessor returns the address's scope_id, and makes sense - only when IPv6 and HAVE_SOCKADDR_IN6_SCOPE_ID are both defined. */ + struct in6_addr d6; /* IPv6 address */ +#endif + } data; -#define ADDRESS_IPV4_IN_ADDR(x) ((x)->u.ipv4.addr) -/* Don't use &x->u.ipv4.addr.s_addr because it can be #defined to a - bitfield, which you can't take an address of. */ -#define ADDRESS_IPV4_DATA(x) ((void *)&(x)->u.ipv4.addr) + /* Under IPv6 getaddrinfo also returns scope_id. Since it's + IPv6-specific it strictly belongs in the above union, but we put + it here for simplicity. */ +#if defined ENABLE_IPV6 && defined HAVE_SOCKADDR_IN6_SCOPE_ID + int ipv6_scope; +#endif +} ip_address; -#define ADDRESS_IPV6_IN6_ADDR(x) ((x)->u.ipv6.addr) -#define ADDRESS_IPV6_DATA(x) ((void *)&(x)->u.ipv6.addr) -#define ADDRESS_IPV6_SCOPE(x) ((x)->u.ipv6.scope_id) +/* IP_INADDR_DATA macro returns a void pointer that can be interpreted + as a pointer to struct in_addr in IPv4 context or a pointer to + struct in6_addr in IPv4 context. This pointer can be passed to + functions that work on either, such as inet_ntop. */ +#define IP_INADDR_DATA(x) ((void *) &(x)->data) enum { LH_SILENT = 1, -- 2.39.2