IP addresses when IPv6 is enabled.
+2005-08-10 Hrvoje Niksic <hniksic@xemacs.org>
+
+ * 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 <hniksic@xemacs.org>
* mswindows.c (inet_ntop): Also handle IPv4 addresses for
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;
}
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);
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)
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;
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;
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;
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;
}
{
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';
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;
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 ();
}
}
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;
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';
}
}
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;
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]));
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]));
/* 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);
/* 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);
/* 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);
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;
{
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;
}
{
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.
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. */
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);
}
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, "<error: %s>", 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, "<error: %s>", 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)
/* 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,