diff options
-rw-r--r-- | ChangeLog | 11 | ||||
-rw-r--r-- | resolv/nss_dns/dns-host.c | 6 | ||||
-rw-r--r-- | sysdeps/posix/getaddrinfo.c | 106 |
3 files changed, 81 insertions, 42 deletions
diff --git a/ChangeLog b/ChangeLog index 0efdea773e..55e64af0b1 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,16 @@ 1999-09-12 Ulrich Drepper <drepper@cygnus.com> + * resolv/nss_dns/dns-host.c (_nss_dns_gethostbyname2_r): If res_search + fails don't rely on errno value. + (getanswer_r): Set *ERRNOP in error cases. + + * sysdeps/posix/getaddrinfo.c (gaih_local): Test protocol and socktype. + (gaih_inet_serv): Return EIA_NODATA if name is known but has no + associated data. Test for matching numeric address and family. + (getaddrinfo): Remember EAI_NODATA result and return this in case + everything fails. + Reported by Arkadiusz Miskiewicz <misiek@misiek.eu.org>. + * locale/programs/ld-address.c: Fix handling of non-existing definitions for this category. Correctly ignore content of this category is this is necessary. diff --git a/resolv/nss_dns/dns-host.c b/resolv/nss_dns/dns-host.c index 746bfcf313..c075961e91 100644 --- a/resolv/nss_dns/dns-host.c +++ b/resolv/nss_dns/dns-host.c @@ -163,7 +163,7 @@ _nss_dns_gethostbyname2_r (const char *name, int af, struct hostent *result, if (n < 0) { *h_errnop = h_errno; - *errnop = errno; + *errnop = *h_errnop == TRY_AGAIN ? EAGAIN : ENOENT; return errno == ECONNREFUSED ? NSS_STATUS_UNAVAIL : NSS_STATUS_NOTFOUND; } @@ -342,6 +342,7 @@ getanswer_r (const querybuf *answer, int anslen, const char *qname, int qtype, name_ok = res_dnok; break; default: + *errnop = ENOENT; return NSS_STATUS_UNAVAIL; /* XXX should be abort(); */ } @@ -356,6 +357,7 @@ getanswer_r (const querybuf *answer, int anslen, const char *qname, int qtype, if (qdcount != 1) { *h_errnop = NO_RECOVERY; + *errnop = ENOENT; return NSS_STATUS_UNAVAIL; } @@ -390,6 +392,7 @@ getanswer_r (const querybuf *answer, int anslen, const char *qname, int qtype, if (n >= MAXHOSTNAMELEN) { *h_errnop = NO_RECOVERY; + *errnop = ENOENT; return NSS_STATUS_TRYAGAIN; } result->h_name = bp; @@ -660,5 +663,6 @@ getanswer_r (const querybuf *answer, int anslen, const char *qname, int qtype, } no_recovery: *h_errnop = NO_RECOVERY; + *errnop = ENOENT; return NSS_STATUS_TRYAGAIN; } diff --git a/sysdeps/posix/getaddrinfo.c b/sysdeps/posix/getaddrinfo.c index 7f3c8aba59..ca8abc65db 100644 --- a/sysdeps/posix/getaddrinfo.c +++ b/sysdeps/posix/getaddrinfo.c @@ -120,7 +120,7 @@ gaih_local (const char *name, const struct gaih_service *service, struct utsname utsname; if ((name != NULL) || (req->ai_flags & AI_CANONNAME)) - if (uname(&utsname)) + if (uname (&utsname)) return -EAI_SYSTEM; if (name != NULL) @@ -132,7 +132,23 @@ gaih_local (const char *name, const struct gaih_service *service, return GAIH_OKIFUNSPEC | -EAI_NONAME; } - *pai = malloc (sizeof(struct addrinfo) + sizeof(struct sockaddr_un) + if (req->ai_protocol || req->ai_socktype) + { + struct gaih_typeproto *tp = gaih_inet_typeproto; + + for (tp++; tp->name && + ((req->ai_socktype != tp->socktype) || !req->ai_socktype) && + ((req->ai_protocol != tp->protocol) || !req->ai_protocol); tp++); + if (tp->name == NULL) + { + if (req->ai_socktype) + return (GAIH_OKIFUNSPEC | -EAI_SOCKTYPE); + else + return (GAIH_OKIFUNSPEC | -EAI_SERVICE); + } + } + + *pai = malloc (sizeof (struct addrinfo) + sizeof (struct sockaddr_un) + ((req->ai_flags & AI_CANONNAME) ? (strlen(utsname.nodename) + 1): 0)); if (*pai == NULL) @@ -143,8 +159,8 @@ gaih_local (const char *name, const struct gaih_service *service, (*pai)->ai_family = AF_LOCAL; (*pai)->ai_socktype = req->ai_socktype ? req->ai_socktype : SOCK_STREAM; (*pai)->ai_protocol = req->ai_protocol; - (*pai)->ai_addrlen = sizeof(struct sockaddr_un); - (*pai)->ai_addr = (void *)(*pai) + sizeof(struct addrinfo); + (*pai)->ai_addrlen = sizeof (struct sockaddr_un); + (*pai)->ai_addr = (void *) (*pai) + sizeof (struct addrinfo); #if SALEN ((struct sockaddr_un *) (*pai)->ai_addr)->sun_len = @@ -181,8 +197,9 @@ gaih_local (const char *name, const struct gaih_service *service, } if (req->ai_flags & AI_CANONNAME) - strcpy ((*pai)->ai_canonname = (char *)(*pai) + sizeof(struct addrinfo) + - sizeof(struct sockaddr_un), utsname.nodename); + (*pai)->ai_canonname = strcpy ((char *) *pai + sizeof (struct addrinfo) + + sizeof (struct sockaddr_un), + utsname.nodename); else (*pai)->ai_canonname = NULL; return 0; @@ -201,14 +218,12 @@ gaih_inet_serv (const char *servicename, struct gaih_typeproto *tp, do { tmpbuf = __alloca (tmpbuflen); - if (tmpbuf == NULL) - return -EAI_MEMORY; r = __getservbyname_r (servicename, tp->name, &ts, tmpbuf, tmpbuflen, &s); - if (r || s == NULL) + if (r != 0 || s == NULL) { - if (errno == ERANGE) + if (r == ERANGE) tmpbuflen *= 2; else return GAIH_OKIFUNSPEC | -EAI_SERVICE; @@ -234,12 +249,10 @@ gaih_inet_serv (const char *servicename, struct gaih_typeproto *tp, do { \ tmpbuflen *= 2; \ tmpbuf = __alloca (tmpbuflen); \ - if (tmpbuf == NULL) \ - return -EAI_MEMORY; \ rc = __gethostbyname2_r (name, _family, &th, tmpbuf, \ tmpbuflen, &h, &herrno); \ } while (rc == ERANGE && herrno == NETDB_INTERNAL); \ - if ((rc != 0) && (herrno == NETDB_INTERNAL)) \ + if (rc != 0 && herrno == NETDB_INTERNAL) \ { \ __set_h_errno (herrno); \ return -EAI_SYSTEM; \ @@ -249,11 +262,7 @@ gaih_inet_serv (const char *servicename, struct gaih_typeproto *tp, for (i = 0; h->h_addr_list[i]; i++) \ { \ if (*pat == NULL) \ - { \ - *pat = __alloca (sizeof(struct gaih_addrtuple)); \ - if (*pat == NULL) \ - return -EAI_MEMORY; \ - } \ + *pat = __alloca (sizeof(struct gaih_addrtuple)); \ (*pat)->next = NULL; \ (*pat)->family = _family; \ memcpy ((*pat)->addr, h->h_addr_list[i], \ @@ -261,6 +270,7 @@ gaih_inet_serv (const char *servicename, struct gaih_typeproto *tp, pat = &((*pat)->next); \ } \ } \ + no_data = rc != 0 && herrno == NO_DATA; \ } static int @@ -322,10 +332,7 @@ gaih_inet (const char *name, const struct gaih_service *service, } else { - st = __alloca (sizeof(struct gaih_servtuple)); - if (st == NULL) - return -EAI_MEMORY; - + st = __alloca (sizeof (struct gaih_servtuple)); st->next = NULL; st->socktype = tp->socktype; st->protocol = tp->protocol; @@ -335,45 +342,58 @@ gaih_inet (const char *name, const struct gaih_service *service, if (name != NULL) { - at = __alloca (sizeof(struct gaih_addrtuple)); + at = __alloca (sizeof (struct gaih_addrtuple)); - at->family = 0; + at->family = AF_UNSPEC; at->next = NULL; - if (req->ai_family == 0 || req->ai_family == AF_INET) - if (inet_pton (AF_INET, name, at->addr) > 0) - at->family = AF_INET; + if (inet_pton (AF_INET, name, at->addr) > 0) + { + if (req->ai_family == AF_UNSPEC || req->ai_family == AF_INET) + at->family = AF_INET; + else + return -EAI_ADDRFAMILY; + } - if (!at->family && (req->ai_family == 0 || req->ai_family == AF_INET6)) - if (inet_pton (AF_INET6, name, at->addr) > 0) - at->family = AF_INET6; + if (at->family == AF_UNSPEC && inet_pton (AF_INET6, name, at->addr) > 0) + { + if (req->ai_family == AF_UNSPEC || req->ai_family == AF_INET6) + at->family = AF_INET6; + else + return -EAI_ADDRFAMILY; + } if (at->family == AF_UNSPEC) { struct hostent *h; struct gaih_addrtuple **pat = &at; + int no_data = 0; if (req->ai_family == AF_UNSPEC || req->ai_family == AF_INET6) gethosts (AF_INET6, struct in6_addr); if (req->ai_family == AF_UNSPEC || req->ai_family == AF_INET) gethosts (AF_INET, struct in_addr); + + if (no_data != 0) + /* We made requests but they turned out no data. The name + is known, though. */ + return (GAIH_OKIFUNSPEC | -EAI_NODATA); } if (at->family == AF_UNSPEC) return (GAIH_OKIFUNSPEC | -EAI_NONAME); - } else { struct gaih_addrtuple *atr; - atr = at = __alloca (sizeof(struct gaih_addrtuple)); - memset (at, 0, sizeof(struct gaih_addrtuple)); + atr = at = __alloca (sizeof (struct gaih_addrtuple)); + memset (at, '\0', sizeof (struct gaih_addrtuple)); if (req->ai_family == 0) { - at->next = __alloca (sizeof(struct gaih_addrtuple)); - memset (at->next, 0, sizeof(struct gaih_addrtuple)); + at->next = __alloca (sizeof (struct gaih_addrtuple)); + memset (at->next, '\0', sizeof (struct gaih_addrtuple)); } if (req->ai_family == 0 || req->ai_family == AF_INET6) @@ -433,10 +453,9 @@ gaih_inet (const char *name, const struct gaih_service *service, &h, &herrno); } - while ((rc != 0) && (herrno == NETDB_INTERNAL) - && (errno == ERANGE)); + while (rc == errno && herrno == NETDB_INTERNAL); - if ((rc != 0) && (herrno == NETDB_INTERNAL)) + if (rc != 0 && herrno == NETDB_INTERNAL) { __set_h_errno (herrno); return -EAI_SYSTEM; @@ -527,7 +546,7 @@ int getaddrinfo (const char *name, const char *service, const struct addrinfo *hints, struct addrinfo **pai) { - int i = 0, j = 0; + int i = 0, j = 0, last_i = 0; struct addrinfo *p = NULL, **end; struct gaih *g = gaih, *pg = NULL; struct gaih_service gaih_service, *pservice; @@ -583,6 +602,11 @@ getaddrinfo (const char *name, const char *service, i = g->gaih (name, pservice, hints, end); if (i != 0) { + /* EAI_NODATA is a more specific result as it says that + we found a result but it is not usable. */ + if (last_i != (GAIH_OKIFUNSPEC | -EAI_NODATA)) + last_i = i; + if (hints->ai_family == AF_UNSPEC && (i & GAIH_OKIFUNSPEC)) continue; @@ -607,13 +631,13 @@ getaddrinfo (const char *name, const char *service, return 0; } - if (pai == NULL && i == 0) + if (pai == NULL && last_i == 0) return 0; if (p) freeaddrinfo (p); - return i ? -(i & GAIH_EAI) : EAI_NONAME; + return last_i ? -(last_i & GAIH_EAI) : EAI_NONAME; } void |