diff --git a/winsup/cygwin/ChangeLog b/winsup/cygwin/ChangeLog index bf45c600f..2873a6b4d 100644 --- a/winsup/cygwin/ChangeLog +++ b/winsup/cygwin/ChangeLog @@ -1,3 +1,21 @@ +2007-02-01 Corinna Vinschen + + * net.cc (ga_dup): New function, taken from ga_clone with v4-in-v6 + mapping addition. + (ga_clone): Just call ga_dup from here. + (ga_duplist): New function to duplicate list of struct addrinfo. + (ga_echeck): Don't check a_flags, it already happened in + cygwin_getaddrinfo. + (cygwin_freeaddrinfo): Always call ipv4_freeaddrinfo. + (cygwin_getaddrinfo): Use new wincap.supports_all_posix_ai_flags + flag rather than wincap.has_gaa_on_link_prefix. Always duplicate + WinSock's addrinfo list to a self-allocated list. Handle AI_V4MAPPED + for pre-Vista platforms supporting getaddrinfo. + * wincap.h (wincapc::supports_all_posix_ai_flags): New element. + * wincap.cc: Implement above element throughout. + * include/netdb.h: Note how AI_ADDRCONFIG is not supported pre-Vista. + Remove superfluous comment. + 2007-02-01 Corinna Vinschen * include/cygwin/socket.h: Add IPv6 socket options. diff --git a/winsup/cygwin/include/netdb.h b/winsup/cygwin/include/netdb.h index 4f2ead1ae..ffa2f8792 100644 --- a/winsup/cygwin/include/netdb.h +++ b/winsup/cygwin/include/netdb.h @@ -148,9 +148,9 @@ extern __declspec(dllimport) int h_errno; #define AI_CANONNAME 2 #define AI_NUMERICHOST 4 #define AI_NUMERICSERV 8 -/* Only available since Vista. Ignored on older systems. */ #define AI_ALL 256 -#define AI_ADDRCONFIG 1024 +#define AI_ADDRCONFIG 1024 /* Only available on Vista. Unchangable default + on older systems. */ #define AI_V4MAPPED 2048 #define NI_NOFQDN 1 diff --git a/winsup/cygwin/net.cc b/winsup/cygwin/net.cc index ad99bc277..ddd9a88ac 100644 --- a/winsup/cygwin/net.cc +++ b/winsup/cygwin/net.cc @@ -3013,28 +3013,92 @@ ga_aistruct (struct addrinfo ***paipnext, const struct addrinfo *hintsp, */ /* include ga_clone */ + +/* Cygwin specific: The ga_clone function is split up to allow an easy + duplication of addrinfo structs. This is used to duplicate the + structures from Winsock, so that we have the allocation of the structs + returned to the application under control. This is especially helpful + for the AI_V4MAPPED case prior to Vista. */ static struct addrinfo * -ga_clone (struct addrinfo *ai) +ga_dup (struct addrinfo *ai, bool v4mapped) { struct addrinfo *nai; if ((nai = (struct addrinfo *) calloc (1, sizeof (struct addrinfo))) == NULL) return (NULL); - nai->ai_next = ai->ai_next; - ai->ai_next = nai; - nai->ai_flags = 0; /* make sure AI_CLONE is off */ - nai->ai_family = ai->ai_family; + nai->ai_family = v4mapped ? AF_INET6 : ai->ai_family; nai->ai_socktype = ai->ai_socktype; nai->ai_protocol = ai->ai_protocol; nai->ai_canonname = NULL; - nai->ai_addrlen = ai->ai_addrlen; - if ((nai->ai_addr = (struct sockaddr *) malloc (ai->ai_addrlen)) == NULL) - return (NULL); - memcpy (nai->ai_addr, ai->ai_addr, ai->ai_addrlen); + if (!(ai->ai_flags & AI_CLONE) && ai->ai_canonname + && !(nai->ai_canonname = strdup (ai->ai_canonname))) + { + free (nai); + return NULL; + } + nai->ai_addrlen = v4mapped ? sizeof (struct sockaddr_in6) : ai->ai_addrlen; + if ((nai->ai_addr = (struct sockaddr *) malloc (v4mapped + ? sizeof (struct sockaddr_in6) + : ai->ai_addrlen)) == NULL) + { + if (nai->ai_canonname) + free (nai->ai_canonname); + free (nai); + return NULL; + } + if (v4mapped) + { + struct sockaddr_in6 *in = (struct sockaddr_in6 *) nai->ai_addr; + in->sin6_family = AF_INET6; + in->sin6_port = ((struct sockaddr_in *) ai->ai_addr)->sin_port; + in->sin6_flowinfo = 0; + in->sin6_addr.s6_addr32[0] = 0; + in->sin6_addr.s6_addr32[1] = 0; + in->sin6_addr.s6_addr32[2] = htonl (0xffff); + in->sin6_addr.s6_addr32[3] = ((struct sockaddr_in *) ai->ai_addr)->sin_addr.s_addr; + in->sin6_scope_id = 0; + } + else + memcpy (nai->ai_addr, ai->ai_addr, ai->ai_addrlen); - return (nai); + return nai; +} + +static struct addrinfo * +ga_clone (struct addrinfo *ai) +{ + struct addrinfo *nai; + + if ((nai = ga_dup (ai, false))) + { + nai->ai_next = ai->ai_next; + ai->ai_next = nai; + } + return nai; +} + +static struct addrinfo * +ga_duplist (struct addrinfo *ai, bool v4mapped) +{ + void ipv4_freeaddrinfo (struct addrinfo *aihead); + struct addrinfo *tmp, *nai = NULL, *nai0 = NULL; + + for (; ai; ai = ai->ai_next, nai = tmp) + { + if (!(tmp = ga_dup (ai, v4mapped))) + goto bad; + if (!nai0) + nai0 = tmp; + if (nai) + nai->ai_next = tmp; + } + return nai0; + +bad: + ipv4_freeaddrinfo (nai0); + return NULL; } /* end ga_clone */ @@ -3048,9 +3112,10 @@ static int ga_echeck (const char *hostname, const char *servname, int flags, int family, int socktype, int protocol) { +#if 0 if (flags & ~(AI_PASSIVE | AI_CANONNAME)) return (EAI_BADFLAGS); /* unknown flag bits */ - +#endif if (hostname == NULL || hostname[0] == '\0') { if (servname == NULL || servname[0] == '\0') @@ -3861,11 +3926,7 @@ cygwin_freeaddrinfo (struct addrinfo *addr) myfault efault; if (efault.faulted (EFAULT)) return; - load_ipv6 (); - if (freeaddrinfo) - freeaddrinfo (addr); - else - ipv4_freeaddrinfo (addr); + ipv4_freeaddrinfo (addr); } extern "C" int @@ -3894,21 +3955,71 @@ cygwin_getaddrinfo (const char *hostname, const char *servname, load_ipv6 (); if (getaddrinfo) { - struct addrinfo nhints; + struct addrinfo nhints, *dupres; /* AI_ADDRCONFIG is not supported prior to Vista. Rather it's the default and only possible setting. On Vista, the default behaviour is as if AI_ADDRCONFIG is set, apparently for performance reasons. To get the POSIX default behaviour, the AI_ALL flag has to be set. */ - if (wincap.has_gaa_on_link_prefix () + if (wincap.supports_all_posix_ai_flags () && hints && hints->ai_family == PF_UNSPEC) { nhints = *hints; hints = &nhints; nhints.ai_flags |= AI_ALL; } - return w32_to_gai_err (getaddrinfo (hostname, servname, hints, res)); + int ret = w32_to_gai_err (getaddrinfo (hostname, servname, hints, res)); + /* Always copy over to self-allocated memory. */ + if (!ret) + { + dupres = ga_duplist (*res, false); + freeaddrinfo (*res); + *res = dupres; + if (!dupres) + return EAI_MEMORY; + } + /* AI_V4MAPPED and AI_ALL are not supported prior to Vista. So, what + we do here is to emulate AI_V4MAPPED. If no IPv6 addresses are + returned, or the AI_ALL flag is set, we try with AF_INET again, and + convert the returned IPv4 addresses into v4-in-v6 entries. This + is done in ga_dup if the v4mapped flag is set. */ + if (!wincap.supports_all_posix_ai_flags () + && hints->ai_family == AF_INET6 + && (hints->ai_flags & AI_V4MAPPED) + && (ret == EAI_NODATA || ret == EAI_NONAME + || (hints->ai_flags & AI_ALL))) + { + struct addrinfo *v4res; + nhints = *hints; + nhints.ai_family = AF_INET; + int ret2 = w32_to_gai_err (getaddrinfo (hostname, servname, + &nhints, &v4res)); + if (!ret2) + { + dupres = ga_duplist (v4res, true); + freeaddrinfo (v4res); + if (!dupres) + { + if (!ret) + ipv4_freeaddrinfo (*res); + return EAI_MEMORY; + } + /* If a list of v6 addresses exists, append the v4-in-v6 address + list. Otherwise just return the v4-in-v6 address list. */ + if (!ret) + { + struct addrinfo *ptr; + for (ptr = *res; ptr->ai_next; ptr = ptr->ai_next) + ; + ptr->ai_next = dupres; + } + else + *res = dupres; + ret = 0; + } + } + return ret; } return ipv4_getaddrinfo (hostname, servname, hints, res); } diff --git a/winsup/cygwin/wincap.cc b/winsup/cygwin/wincap.cc index 7e9f71069..b26c78f84 100644 --- a/winsup/cygwin/wincap.cc +++ b/winsup/cygwin/wincap.cc @@ -74,6 +74,7 @@ static NO_COPY wincaps wincap_unknown = { has_recycle_dot_bin:false, has_gaa_prefixes:false, has_gaa_on_link_prefix:false, + supports_all_posix_ai_flags:false, }; static NO_COPY wincaps wincap_95 = { @@ -139,6 +140,7 @@ static NO_COPY wincaps wincap_95 = { has_recycle_dot_bin:false, has_gaa_prefixes:false, has_gaa_on_link_prefix:false, + supports_all_posix_ai_flags:false, }; static NO_COPY wincaps wincap_95osr2 = { @@ -204,6 +206,7 @@ static NO_COPY wincaps wincap_95osr2 = { has_recycle_dot_bin:false, has_gaa_prefixes:false, has_gaa_on_link_prefix:false, + supports_all_posix_ai_flags:false, }; static NO_COPY wincaps wincap_98 = { @@ -269,6 +272,7 @@ static NO_COPY wincaps wincap_98 = { has_recycle_dot_bin:false, has_gaa_prefixes:false, has_gaa_on_link_prefix:false, + supports_all_posix_ai_flags:false, }; static NO_COPY wincaps wincap_98se = { @@ -334,6 +338,7 @@ static NO_COPY wincaps wincap_98se = { has_recycle_dot_bin:false, has_gaa_prefixes:false, has_gaa_on_link_prefix:false, + supports_all_posix_ai_flags:false, }; static NO_COPY wincaps wincap_me = { @@ -399,6 +404,7 @@ static NO_COPY wincaps wincap_me = { has_recycle_dot_bin:false, has_gaa_prefixes:false, has_gaa_on_link_prefix:false, + supports_all_posix_ai_flags:false, }; static NO_COPY wincaps wincap_nt3 = { @@ -464,6 +470,7 @@ static NO_COPY wincaps wincap_nt3 = { has_recycle_dot_bin:false, has_gaa_prefixes:false, has_gaa_on_link_prefix:false, + supports_all_posix_ai_flags:false, }; static NO_COPY wincaps wincap_nt4 = { @@ -529,6 +536,7 @@ static NO_COPY wincaps wincap_nt4 = { has_recycle_dot_bin:false, has_gaa_prefixes:false, has_gaa_on_link_prefix:false, + supports_all_posix_ai_flags:false, }; static NO_COPY wincaps wincap_nt4sp4 = { @@ -594,6 +602,7 @@ static NO_COPY wincaps wincap_nt4sp4 = { has_recycle_dot_bin:false, has_gaa_prefixes:false, has_gaa_on_link_prefix:false, + supports_all_posix_ai_flags:false, }; static NO_COPY wincaps wincap_2000 = { @@ -659,6 +668,7 @@ static NO_COPY wincaps wincap_2000 = { has_recycle_dot_bin:false, has_gaa_prefixes:false, has_gaa_on_link_prefix:false, + supports_all_posix_ai_flags:false, }; static NO_COPY wincaps wincap_xp = { @@ -724,6 +734,7 @@ static NO_COPY wincaps wincap_xp = { has_recycle_dot_bin:false, has_gaa_prefixes:true, has_gaa_on_link_prefix:false, + supports_all_posix_ai_flags:false, }; static NO_COPY wincaps wincap_2003 = { @@ -789,6 +800,7 @@ static NO_COPY wincaps wincap_2003 = { has_recycle_dot_bin:false, has_gaa_prefixes:true, has_gaa_on_link_prefix:false, + supports_all_posix_ai_flags:false, }; static NO_COPY wincaps wincap_vista = { @@ -854,6 +866,7 @@ static NO_COPY wincaps wincap_vista = { has_recycle_dot_bin:true, has_gaa_prefixes:true, has_gaa_on_link_prefix:true, + supports_all_posix_ai_flags:true, }; wincapc wincap __attribute__((section (".cygwin_dll_common"), shared)); diff --git a/winsup/cygwin/wincap.h b/winsup/cygwin/wincap.h index de5d9a8d4..381a0c209 100644 --- a/winsup/cygwin/wincap.h +++ b/winsup/cygwin/wincap.h @@ -75,6 +75,7 @@ struct wincaps unsigned has_recycle_dot_bin : 1; unsigned has_gaa_prefixes : 1; unsigned has_gaa_on_link_prefix : 1; + unsigned supports_all_posix_ai_flags : 1; }; class wincapc @@ -156,6 +157,7 @@ public: bool IMPLEMENT (has_recycle_dot_bin) bool IMPLEMENT (has_gaa_prefixes) bool IMPLEMENT (has_gaa_on_link_prefix) + bool IMPLEMENT (supports_all_posix_ai_flags) #undef IMPLEMENT };