X-Git-Url: http://nsz.repo.hu/git/?a=blobdiff_plain;f=src%2Fnetwork%2Fgetaddrinfo.c;h=64ad259acae870fada78af1ea4d1731929e56209;hb=c87d75f2aa6fde49a99cf3287e535a14f354f781;hp=d991344598165d3c5ecd6a942b5625a8c743cf8c;hpb=bdad2fefb206d9727d4a3254f7883b8455452d89;p=musl diff --git a/src/network/getaddrinfo.c b/src/network/getaddrinfo.c index d9913445..64ad259a 100644 --- a/src/network/getaddrinfo.c +++ b/src/network/getaddrinfo.c @@ -3,6 +3,10 @@ #include #include #include +#include +#include +#include +#include #include "lookup.h" int getaddrinfo(const char *restrict host, const char *restrict serv, const struct addrinfo *restrict hint, struct addrinfo **restrict res) @@ -11,19 +15,17 @@ int getaddrinfo(const char *restrict host, const char *restrict serv, const stru struct address addrs[MAXADDRS]; char canon[256], *outcanon; int nservs, naddrs, nais, canon_len, i, j, k; - int family = AF_UNSPEC, flags = 0, proto = 0; - struct aibuf { - struct addrinfo ai; - union sa { - struct sockaddr_in sin; - struct sockaddr_in6 sin6; - } sa; - } *out; + int family = AF_UNSPEC, flags = 0, proto = 0, socktype = 0; + int no_family = 0; + struct aibuf *out; + + if (!host && !serv) return EAI_NONAME; if (hint) { family = hint->ai_family; flags = hint->ai_flags; proto = hint->ai_protocol; + socktype = hint->ai_socktype; const int mask = AI_PASSIVE | AI_CANONNAME | AI_NUMERICHOST | AI_V4MAPPED | AI_ALL | AI_ADDRCONFIG | AI_NUMERICSERV; @@ -38,40 +40,62 @@ int getaddrinfo(const char *restrict host, const char *restrict serv, const stru default: return EAI_FAMILY; } + } - switch (hint->ai_socktype) { - case SOCK_STREAM: - switch (proto) { - case 0: - proto = IPPROTO_TCP; - case IPPROTO_TCP: - break; - default: - return EAI_SERVICE; + if (flags & AI_ADDRCONFIG) { + /* Define the "an address is configured" condition for address + * families via ability to create a socket for the family plus + * routability of the loopback address for the family. */ + static const struct sockaddr_in lo4 = { + .sin_family = AF_INET, .sin_port = 65535, + .sin_addr.s_addr = __BYTE_ORDER == __BIG_ENDIAN + ? 0x7f000001 : 0x0100007f + }; + static const struct sockaddr_in6 lo6 = { + .sin6_family = AF_INET6, .sin6_port = 65535, + .sin6_addr = IN6ADDR_LOOPBACK_INIT + }; + int tf[2] = { AF_INET, AF_INET6 }; + const void *ta[2] = { &lo4, &lo6 }; + socklen_t tl[2] = { sizeof lo4, sizeof lo6 }; + for (i=0; i<2; i++) { + if (family==tf[1-i]) continue; + int s = socket(tf[i], SOCK_CLOEXEC|SOCK_DGRAM, + IPPROTO_UDP); + if (s>=0) { + int cs; + pthread_setcancelstate( + PTHREAD_CANCEL_DISABLE, &cs); + int r = connect(s, ta[i], tl[i]); + int saved_errno = errno; + pthread_setcancelstate(cs, 0); + close(s); + if (!r) continue; + errno = saved_errno; } - break; - case SOCK_DGRAM: - switch (proto) { - case 0: - proto = IPPROTO_UDP; - case IPPROTO_UDP: + switch (errno) { + case EADDRNOTAVAIL: + case EAFNOSUPPORT: + case EHOSTUNREACH: + case ENETDOWN: + case ENETUNREACH: break; default: - return EAI_SERVICE; + return EAI_SYSTEM; } - case 0: - break; - default: - return EAI_SOCKTYPE; + if (family == tf[i]) no_family = 1; + family = tf[1-i]; } } - nservs = __lookup_serv(ports, serv, proto, flags); + nservs = __lookup_serv(ports, serv, proto, socktype, flags); if (nservs < 0) return nservs; naddrs = __lookup_name(addrs, canon, host, family, flags); if (naddrs < 0) return naddrs; + if (no_family) return EAI_NODATA; + nais = nservs * naddrs; canon_len = strlen(canon); out = calloc(1, nais * sizeof(*out) + canon_len + 1); @@ -85,17 +109,17 @@ int getaddrinfo(const char *restrict host, const char *restrict serv, const stru } for (k=i=0; iai; return 0; }