From 62beba6902f315a14113c26ed3e068342e101399 Mon Sep 17 00:00:00 2001 From: Jakub Jelinek Date: Thu, 20 Sep 2007 00:11:37 +0000 Subject: Updated to fedora-glibc-20070920T0007 --- sysdeps/posix/getaddrinfo.c | 47 +++++++++++++++++++++++++++++++++++++++------ 1 file changed, 41 insertions(+), 6 deletions(-) (limited to 'sysdeps/posix/getaddrinfo.c') diff --git a/sysdeps/posix/getaddrinfo.c b/sysdeps/posix/getaddrinfo.c index adb3c4f96a..b668936095 100644 --- a/sysdeps/posix/getaddrinfo.c +++ b/sysdeps/posix/getaddrinfo.c @@ -1944,6 +1944,9 @@ getaddrinfo (const char *name, const char *service, if (in6ai != NULL) qsort (in6ai, in6ailen, sizeof (*in6ai), in6aicmp); + int fd = -1; + int af = AF_UNSPEC; + for (i = 0, q = p; q != NULL; ++i, last = q, q = q->ai_next) { results[i].dest_addr = q; @@ -1968,7 +1971,21 @@ getaddrinfo (const char *name, const char *service, want connect() to connect to the other side. If we cannot determine the source address remember this fact. */ - int fd = __socket (q->ai_family, SOCK_DGRAM, IPPROTO_IP); + if (fd == -1 || (af == AF_INET && q->ai_family == AF_INET6)) + { + if (fd != -1) + close_retry: + close (fd); + af = q->ai_family; + fd = __socket (af, SOCK_DGRAM, IPPROTO_IP); + } + else + { + /* Reset the connection. */ + struct sockaddr sa = { .sa_family = AF_UNSPEC }; + __connect (fd, &sa, sizeof (sa)); + } + socklen_t sl = sizeof (results[i].source_addr); if (fd != -1 && __connect (fd, q->ai_addr, q->ai_addrlen) == 0 @@ -1979,9 +1996,9 @@ getaddrinfo (const char *name, const char *service, results[i].source_addr_len = sl; results[i].got_source_addr = true; - if (q->ai_family == PF_INET6 && in6ai != NULL) + if (q->ai_family == AF_INET6 && in6ai != NULL) { - /* See whether the source address is the list of + /* See whether the source address is on the list of deprecated or temporary addresses. */ struct in6addrinfo tmp; struct sockaddr_in6 *sin6p @@ -1994,14 +2011,29 @@ getaddrinfo (const char *name, const char *service, if (found != NULL) results[i].source_addr_flags = found->flags; } + else if (q->ai_family == AF_INET && af == AF_INET6) + { + /* We have to convert the address. The socket is + IPv6 and the request is for IPv4. */ + struct sockaddr_in6 *sin6 + = (struct sockaddr_in6 *) &results[i].source_addr; + struct sockaddr_in *sin + = (struct sockaddr_in *) &results[i].source_addr; + assert (IN6_IS_ADDR_V4MAPPED (sin6->sin6_addr.s6_addr32)); + memcpy (&sin->sin_addr, + &sin6->sin6_addr.s6_addr32[3], INADDRSZ); + results[i].source_addr_len = INADDRSZ; + sin->sin_family = AF_INET; + } } + else if (errno == EAFNOSUPPORT && af == AF_INET6 + && q->ai_family == AF_INET) + /* This could mean IPv6 sockets are IPv6-only. */ + goto close_retry; else /* Just make sure that if we have to process the same address again we do not copy any memory. */ results[i].source_addr_len = 0; - - if (fd != -1) - close_not_cancel_no_status (fd); } /* Remember the canonical name. */ @@ -2013,6 +2045,9 @@ getaddrinfo (const char *name, const char *service, } } + if (fd != -1) + close_not_cancel_no_status (fd); + /* We got all the source addresses we can get, now sort using the information. */ qsort (results, nresults, sizeof (results[0]), rfc3484_sort); -- cgit v1.2.3