You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
673 lines
20 KiB
673 lines
20 KiB
commit ec71cb961121760f81e55af5489e658dc89e96e6 |
|
Author: Siddhesh Poyarekar <siddhesh@sourceware.org> |
|
Date: Mon Mar 7 15:56:22 2022 +0530 |
|
|
|
gaih_inet: separate nss lookup loop into its own function |
|
|
|
Signed-off-by: Siddhesh Poyarekar <siddhesh@sourceware.org> |
|
Reviewed-by: DJ Delorie <dj@redhat.com> |
|
(cherry picked from commit 906cecbe0889e601c91d9aba738049c73ebe4dd2) |
|
|
|
diff --git a/sysdeps/posix/getaddrinfo.c b/sysdeps/posix/getaddrinfo.c |
|
index 7c497a88f8b5b9f8..145ea6fa381ad14b 100644 |
|
--- a/sysdeps/posix/getaddrinfo.c |
|
+++ b/sysdeps/posix/getaddrinfo.c |
|
@@ -159,6 +159,14 @@ static const struct addrinfo default_hints = |
|
.ai_next = NULL |
|
}; |
|
|
|
+static void |
|
+gaih_result_reset (struct gaih_result *res) |
|
+{ |
|
+ if (res->free_at) |
|
+ free (res->at); |
|
+ free (res->canon); |
|
+ memset (res, 0, sizeof (*res)); |
|
+} |
|
|
|
static int |
|
gaih_inet_serv (const char *servicename, const struct gaih_typeproto *tp, |
|
@@ -197,13 +205,10 @@ gaih_inet_serv (const char *servicename, const struct gaih_typeproto *tp, |
|
|
|
/* Convert struct hostent to a list of struct gaih_addrtuple objects. h_name |
|
is not copied, and the struct hostent object must not be deallocated |
|
- prematurely. The new addresses are appended to the tuple array in |
|
- RESULT. */ |
|
+ prematurely. The new addresses are appended to the tuple array in RES. */ |
|
static bool |
|
-convert_hostent_to_gaih_addrtuple (const struct addrinfo *req, |
|
- int family, |
|
- struct hostent *h, |
|
- struct gaih_addrtuple **result) |
|
+convert_hostent_to_gaih_addrtuple (const struct addrinfo *req, int family, |
|
+ struct hostent *h, struct gaih_result *res) |
|
{ |
|
/* Count the number of addresses in h->h_addr_list. */ |
|
size_t count = 0; |
|
@@ -215,7 +220,7 @@ convert_hostent_to_gaih_addrtuple (const struct addrinfo *req, |
|
if (count == 0 || h->h_length > sizeof (((struct gaih_addrtuple) {}).addr)) |
|
return true; |
|
|
|
- struct gaih_addrtuple *array = *result; |
|
+ struct gaih_addrtuple *array = res->at; |
|
size_t old = 0; |
|
|
|
while (array != NULL) |
|
@@ -224,12 +229,14 @@ convert_hostent_to_gaih_addrtuple (const struct addrinfo *req, |
|
array = array->next; |
|
} |
|
|
|
- array = realloc (*result, (old + count) * sizeof (*array)); |
|
+ array = realloc (res->at, (old + count) * sizeof (*array)); |
|
|
|
if (array == NULL) |
|
return false; |
|
|
|
- *result = array; |
|
+ res->got_ipv6 = family == AF_INET6; |
|
+ res->at = array; |
|
+ res->free_at = true; |
|
|
|
/* Update the next pointers on reallocation. */ |
|
for (size_t i = 0; i < old; i++) |
|
@@ -278,7 +285,7 @@ convert_hostent_to_gaih_addrtuple (const struct addrinfo *req, |
|
{ \ |
|
__resolv_context_put (res_ctx); \ |
|
result = -EAI_MEMORY; \ |
|
- goto free_and_return; \ |
|
+ goto out; \ |
|
} \ |
|
} \ |
|
if (status == NSS_STATUS_NOTFOUND \ |
|
@@ -288,7 +295,7 @@ convert_hostent_to_gaih_addrtuple (const struct addrinfo *req, |
|
{ \ |
|
__resolv_context_put (res_ctx); \ |
|
result = -EAI_SYSTEM; \ |
|
- goto free_and_return; \ |
|
+ goto out; \ |
|
} \ |
|
if (h_errno == TRY_AGAIN) \ |
|
no_data = EAI_AGAIN; \ |
|
@@ -297,27 +304,24 @@ convert_hostent_to_gaih_addrtuple (const struct addrinfo *req, |
|
} \ |
|
else if (status == NSS_STATUS_SUCCESS) \ |
|
{ \ |
|
- if (!convert_hostent_to_gaih_addrtuple (req, _family, &th, &addrmem)) \ |
|
+ if (!convert_hostent_to_gaih_addrtuple (req, _family, &th, res)) \ |
|
{ \ |
|
__resolv_context_put (res_ctx); \ |
|
result = -EAI_SYSTEM; \ |
|
- goto free_and_return; \ |
|
+ goto out; \ |
|
} \ |
|
- *pat = addrmem; \ |
|
\ |
|
- if (localcanon != NULL && res.canon == NULL) \ |
|
+ if (localcanon != NULL && res->canon == NULL) \ |
|
{ \ |
|
char *canonbuf = __strdup (localcanon); \ |
|
if (canonbuf == NULL) \ |
|
{ \ |
|
__resolv_context_put (res_ctx); \ |
|
result = -EAI_SYSTEM; \ |
|
- goto free_and_return; \ |
|
+ goto out; \ |
|
} \ |
|
- res.canon = canonbuf; \ |
|
+ res->canon = canonbuf; \ |
|
} \ |
|
- if (_family == AF_INET6 && *pat != NULL) \ |
|
- res.got_ipv6 = true; \ |
|
} \ |
|
} |
|
|
|
@@ -590,6 +594,260 @@ out: |
|
} |
|
#endif |
|
|
|
+static int |
|
+get_nss_addresses (const char *name, const struct addrinfo *req, |
|
+ struct scratch_buffer *tmpbuf, struct gaih_result *res) |
|
+{ |
|
+ int no_data = 0; |
|
+ int no_inet6_data = 0; |
|
+ nss_action_list nip; |
|
+ enum nss_status inet6_status = NSS_STATUS_UNAVAIL; |
|
+ enum nss_status status = NSS_STATUS_UNAVAIL; |
|
+ int no_more; |
|
+ struct resolv_context *res_ctx = NULL; |
|
+ bool do_merge = false; |
|
+ int result = 0; |
|
+ |
|
+ no_more = !__nss_database_get (nss_database_hosts, &nip); |
|
+ |
|
+ /* If we are looking for both IPv4 and IPv6 address we don't |
|
+ want the lookup functions to automatically promote IPv4 |
|
+ addresses to IPv6 addresses, so we use the no_inet6 |
|
+ function variant. */ |
|
+ res_ctx = __resolv_context_get (); |
|
+ if (res_ctx == NULL) |
|
+ no_more = 1; |
|
+ |
|
+ while (!no_more) |
|
+ { |
|
+ /* Always start afresh; continue should discard previous results |
|
+ and the hosts database does not support merge. */ |
|
+ gaih_result_reset (res); |
|
+ |
|
+ if (do_merge) |
|
+ { |
|
+ __set_h_errno (NETDB_INTERNAL); |
|
+ __set_errno (EBUSY); |
|
+ break; |
|
+ } |
|
+ |
|
+ no_data = 0; |
|
+ nss_gethostbyname4_r *fct4 = NULL; |
|
+ |
|
+ /* gethostbyname4_r sends out parallel A and AAAA queries and |
|
+ is thus only suitable for PF_UNSPEC. */ |
|
+ if (req->ai_family == PF_UNSPEC) |
|
+ fct4 = __nss_lookup_function (nip, "gethostbyname4_r"); |
|
+ |
|
+ if (fct4 != NULL) |
|
+ { |
|
+ while (1) |
|
+ { |
|
+ status = DL_CALL_FCT (fct4, (name, &res->at, |
|
+ tmpbuf->data, tmpbuf->length, |
|
+ &errno, &h_errno, |
|
+ NULL)); |
|
+ if (status == NSS_STATUS_SUCCESS) |
|
+ break; |
|
+ /* gethostbyname4_r may write into AT, so reset it. */ |
|
+ res->at = NULL; |
|
+ if (status != NSS_STATUS_TRYAGAIN |
|
+ || errno != ERANGE || h_errno != NETDB_INTERNAL) |
|
+ { |
|
+ if (h_errno == TRY_AGAIN) |
|
+ no_data = EAI_AGAIN; |
|
+ else |
|
+ no_data = h_errno == NO_DATA; |
|
+ break; |
|
+ } |
|
+ |
|
+ if (!scratch_buffer_grow (tmpbuf)) |
|
+ { |
|
+ __resolv_context_put (res_ctx); |
|
+ result = -EAI_MEMORY; |
|
+ goto out; |
|
+ } |
|
+ } |
|
+ |
|
+ if (status == NSS_STATUS_SUCCESS) |
|
+ { |
|
+ assert (!no_data); |
|
+ no_data = 1; |
|
+ |
|
+ if ((req->ai_flags & AI_CANONNAME) != 0 && res->canon == NULL) |
|
+ { |
|
+ char *canonbuf = __strdup (res->at->name); |
|
+ if (canonbuf == NULL) |
|
+ { |
|
+ __resolv_context_put (res_ctx); |
|
+ result = -EAI_MEMORY; |
|
+ goto out; |
|
+ } |
|
+ res->canon = canonbuf; |
|
+ } |
|
+ |
|
+ struct gaih_addrtuple **pat = &res->at; |
|
+ |
|
+ while (*pat != NULL) |
|
+ { |
|
+ if ((*pat)->family == AF_INET |
|
+ && req->ai_family == AF_INET6 |
|
+ && (req->ai_flags & AI_V4MAPPED) != 0) |
|
+ { |
|
+ uint32_t *pataddr = (*pat)->addr; |
|
+ (*pat)->family = AF_INET6; |
|
+ pataddr[3] = pataddr[0]; |
|
+ pataddr[2] = htonl (0xffff); |
|
+ pataddr[1] = 0; |
|
+ pataddr[0] = 0; |
|
+ pat = &((*pat)->next); |
|
+ no_data = 0; |
|
+ } |
|
+ else if (req->ai_family == AF_UNSPEC |
|
+ || (*pat)->family == req->ai_family) |
|
+ { |
|
+ pat = &((*pat)->next); |
|
+ |
|
+ no_data = 0; |
|
+ if (req->ai_family == AF_INET6) |
|
+ res->got_ipv6 = true; |
|
+ } |
|
+ else |
|
+ *pat = ((*pat)->next); |
|
+ } |
|
+ } |
|
+ |
|
+ no_inet6_data = no_data; |
|
+ } |
|
+ else |
|
+ { |
|
+ nss_gethostbyname3_r *fct = NULL; |
|
+ if (req->ai_flags & AI_CANONNAME) |
|
+ /* No need to use this function if we do not look for |
|
+ the canonical name. The function does not exist in |
|
+ all NSS modules and therefore the lookup would |
|
+ often fail. */ |
|
+ fct = __nss_lookup_function (nip, "gethostbyname3_r"); |
|
+ if (fct == NULL) |
|
+ /* We are cheating here. The gethostbyname2_r |
|
+ function does not have the same interface as |
|
+ gethostbyname3_r but the extra arguments the |
|
+ latter takes are added at the end. So the |
|
+ gethostbyname2_r code will just ignore them. */ |
|
+ fct = __nss_lookup_function (nip, "gethostbyname2_r"); |
|
+ |
|
+ if (fct != NULL) |
|
+ { |
|
+ if (req->ai_family == AF_INET6 |
|
+ || req->ai_family == AF_UNSPEC) |
|
+ { |
|
+ gethosts (AF_INET6); |
|
+ no_inet6_data = no_data; |
|
+ inet6_status = status; |
|
+ } |
|
+ if (req->ai_family == AF_INET |
|
+ || req->ai_family == AF_UNSPEC |
|
+ || (req->ai_family == AF_INET6 |
|
+ && (req->ai_flags & AI_V4MAPPED) |
|
+ /* Avoid generating the mapped addresses if we |
|
+ know we are not going to need them. */ |
|
+ && ((req->ai_flags & AI_ALL) || !res->got_ipv6))) |
|
+ { |
|
+ gethosts (AF_INET); |
|
+ |
|
+ if (req->ai_family == AF_INET) |
|
+ { |
|
+ no_inet6_data = no_data; |
|
+ inet6_status = status; |
|
+ } |
|
+ } |
|
+ |
|
+ /* If we found one address for AF_INET or AF_INET6, |
|
+ don't continue the search. */ |
|
+ if (inet6_status == NSS_STATUS_SUCCESS |
|
+ || status == NSS_STATUS_SUCCESS) |
|
+ { |
|
+ if ((req->ai_flags & AI_CANONNAME) != 0 |
|
+ && res->canon == NULL) |
|
+ { |
|
+ char *canonbuf = getcanonname (nip, res->at, name); |
|
+ if (canonbuf == NULL) |
|
+ { |
|
+ __resolv_context_put (res_ctx); |
|
+ result = -EAI_MEMORY; |
|
+ goto out; |
|
+ } |
|
+ res->canon = canonbuf; |
|
+ } |
|
+ status = NSS_STATUS_SUCCESS; |
|
+ } |
|
+ else |
|
+ { |
|
+ /* We can have different states for AF_INET and |
|
+ AF_INET6. Try to find a useful one for both. */ |
|
+ if (inet6_status == NSS_STATUS_TRYAGAIN) |
|
+ status = NSS_STATUS_TRYAGAIN; |
|
+ else if (status == NSS_STATUS_UNAVAIL |
|
+ && inet6_status != NSS_STATUS_UNAVAIL) |
|
+ status = inet6_status; |
|
+ } |
|
+ } |
|
+ else |
|
+ { |
|
+ /* Could not locate any of the lookup functions. |
|
+ The NSS lookup code does not consistently set |
|
+ errno, so we need to supply our own error |
|
+ code here. The root cause could either be a |
|
+ resource allocation failure, or a missing |
|
+ service function in the DSO (so it should not |
|
+ be listed in /etc/nsswitch.conf). Assume the |
|
+ former, and return EBUSY. */ |
|
+ status = NSS_STATUS_UNAVAIL; |
|
+ __set_h_errno (NETDB_INTERNAL); |
|
+ __set_errno (EBUSY); |
|
+ } |
|
+ } |
|
+ |
|
+ if (nss_next_action (nip, status) == NSS_ACTION_RETURN) |
|
+ break; |
|
+ |
|
+ /* The hosts database does not support MERGE. */ |
|
+ if (nss_next_action (nip, status) == NSS_ACTION_MERGE) |
|
+ do_merge = true; |
|
+ |
|
+ nip++; |
|
+ if (nip->module == NULL) |
|
+ no_more = -1; |
|
+ } |
|
+ |
|
+ __resolv_context_put (res_ctx); |
|
+ |
|
+ /* If we have a failure which sets errno, report it using |
|
+ EAI_SYSTEM. */ |
|
+ if ((status == NSS_STATUS_TRYAGAIN || status == NSS_STATUS_UNAVAIL) |
|
+ && h_errno == NETDB_INTERNAL) |
|
+ { |
|
+ result = -EAI_SYSTEM; |
|
+ goto out; |
|
+ } |
|
+ |
|
+ if (no_data != 0 && no_inet6_data != 0) |
|
+ { |
|
+ /* If both requests timed out report this. */ |
|
+ if (no_data == EAI_AGAIN && no_inet6_data == EAI_AGAIN) |
|
+ result = -EAI_AGAIN; |
|
+ else |
|
+ /* We made requests but they turned out no data. The name |
|
+ is known, though. */ |
|
+ result = -EAI_NODATA; |
|
+ } |
|
+ |
|
+out: |
|
+ if (result != 0) |
|
+ gaih_result_reset (res); |
|
+ return result; |
|
+} |
|
+ |
|
/* Convert numeric addresses to binary into RES. On failure, RES->AT is set to |
|
NULL and an error code is returned. If AI_NUMERIC_HOST is not requested and |
|
the function cannot determine a result, RES->AT is set to NULL and 0 |
|
@@ -723,7 +981,7 @@ try_simple_gethostbyname (const char *name, const struct addrinfo *req, |
|
/* We found data, convert it. RES->AT from the conversion will |
|
either be an allocated block or NULL, both of which are safe to |
|
pass to free (). */ |
|
- if (!convert_hostent_to_gaih_addrtuple (req, AF_INET, h, &res->at)) |
|
+ if (!convert_hostent_to_gaih_addrtuple (req, AF_INET, h, res)) |
|
return -EAI_MEMORY; |
|
|
|
res->free_at = true; |
|
@@ -801,264 +1059,14 @@ gaih_inet (const char *name, const struct gaih_service *service, |
|
goto process_list; |
|
#endif |
|
|
|
- int no_data = 0; |
|
- int no_inet6_data = 0; |
|
- nss_action_list nip; |
|
- enum nss_status inet6_status = NSS_STATUS_UNAVAIL; |
|
- enum nss_status status = NSS_STATUS_UNAVAIL; |
|
- int no_more; |
|
- struct resolv_context *res_ctx = NULL; |
|
- bool do_merge = false; |
|
- |
|
- no_more = !__nss_database_get (nss_database_hosts, &nip); |
|
- |
|
- /* If we are looking for both IPv4 and IPv6 address we don't |
|
- want the lookup functions to automatically promote IPv4 |
|
- addresses to IPv6 addresses, so we use the no_inet6 |
|
- function variant. */ |
|
- res_ctx = __resolv_context_get (); |
|
- if (res_ctx == NULL) |
|
- no_more = 1; |
|
- |
|
- while (!no_more) |
|
- { |
|
- /* Always start afresh; continue should discard previous results |
|
- and the hosts database does not support merge. */ |
|
- res.at = NULL; |
|
- free (res.canon); |
|
- free (addrmem); |
|
- res.canon = NULL; |
|
- addrmem = NULL; |
|
- got_ipv6 = false; |
|
- |
|
- if (do_merge) |
|
- { |
|
- __set_h_errno (NETDB_INTERNAL); |
|
- __set_errno (EBUSY); |
|
- break; |
|
- } |
|
- |
|
- no_data = 0; |
|
- nss_gethostbyname4_r *fct4 = NULL; |
|
- |
|
- /* gethostbyname4_r sends out parallel A and AAAA queries and |
|
- is thus only suitable for PF_UNSPEC. */ |
|
- if (req->ai_family == PF_UNSPEC) |
|
- fct4 = __nss_lookup_function (nip, "gethostbyname4_r"); |
|
- |
|
- if (fct4 != NULL) |
|
- { |
|
- while (1) |
|
- { |
|
- status = DL_CALL_FCT (fct4, (name, &res.at, |
|
- tmpbuf->data, tmpbuf->length, |
|
- &errno, &h_errno, |
|
- NULL)); |
|
- if (status == NSS_STATUS_SUCCESS) |
|
- break; |
|
- /* gethostbyname4_r may write into AT, so reset it. */ |
|
- res.at = NULL; |
|
- if (status != NSS_STATUS_TRYAGAIN |
|
- || errno != ERANGE || h_errno != NETDB_INTERNAL) |
|
- { |
|
- if (h_errno == TRY_AGAIN) |
|
- no_data = EAI_AGAIN; |
|
- else |
|
- no_data = h_errno == NO_DATA; |
|
- break; |
|
- } |
|
- |
|
- if (!scratch_buffer_grow (tmpbuf)) |
|
- { |
|
- __resolv_context_put (res_ctx); |
|
- result = -EAI_MEMORY; |
|
- goto free_and_return; |
|
- } |
|
- } |
|
- |
|
- if (status == NSS_STATUS_SUCCESS) |
|
- { |
|
- assert (!no_data); |
|
- no_data = 1; |
|
- |
|
- if ((req->ai_flags & AI_CANONNAME) != 0 && res.canon == NULL) |
|
- { |
|
- char *canonbuf = __strdup (res.at->name); |
|
- if (canonbuf == NULL) |
|
- { |
|
- __resolv_context_put (res_ctx); |
|
- result = -EAI_MEMORY; |
|
- goto free_and_return; |
|
- } |
|
- res.canon = canonbuf; |
|
- } |
|
- |
|
- struct gaih_addrtuple **pat = &res.at; |
|
- |
|
- while (*pat != NULL) |
|
- { |
|
- if ((*pat)->family == AF_INET |
|
- && req->ai_family == AF_INET6 |
|
- && (req->ai_flags & AI_V4MAPPED) != 0) |
|
- { |
|
- uint32_t *pataddr = (*pat)->addr; |
|
- (*pat)->family = AF_INET6; |
|
- pataddr[3] = pataddr[0]; |
|
- pataddr[2] = htonl (0xffff); |
|
- pataddr[1] = 0; |
|
- pataddr[0] = 0; |
|
- pat = &((*pat)->next); |
|
- no_data = 0; |
|
- } |
|
- else if (req->ai_family == AF_UNSPEC |
|
- || (*pat)->family == req->ai_family) |
|
- { |
|
- pat = &((*pat)->next); |
|
- |
|
- no_data = 0; |
|
- if (req->ai_family == AF_INET6) |
|
- res.got_ipv6 = true; |
|
- } |
|
- else |
|
- *pat = ((*pat)->next); |
|
- } |
|
- } |
|
- |
|
- no_inet6_data = no_data; |
|
- } |
|
- else |
|
- { |
|
- nss_gethostbyname3_r *fct = NULL; |
|
- if (req->ai_flags & AI_CANONNAME) |
|
- /* No need to use this function if we do not look for |
|
- the canonical name. The function does not exist in |
|
- all NSS modules and therefore the lookup would |
|
- often fail. */ |
|
- fct = __nss_lookup_function (nip, "gethostbyname3_r"); |
|
- if (fct == NULL) |
|
- /* We are cheating here. The gethostbyname2_r |
|
- function does not have the same interface as |
|
- gethostbyname3_r but the extra arguments the |
|
- latter takes are added at the end. So the |
|
- gethostbyname2_r code will just ignore them. */ |
|
- fct = __nss_lookup_function (nip, "gethostbyname2_r"); |
|
- |
|
- if (fct != NULL) |
|
- { |
|
- struct gaih_addrtuple **pat = &res.at; |
|
- |
|
- if (req->ai_family == AF_INET6 |
|
- || req->ai_family == AF_UNSPEC) |
|
- { |
|
- gethosts (AF_INET6); |
|
- no_inet6_data = no_data; |
|
- inet6_status = status; |
|
- } |
|
- if (req->ai_family == AF_INET |
|
- || req->ai_family == AF_UNSPEC |
|
- || (req->ai_family == AF_INET6 |
|
- && (req->ai_flags & AI_V4MAPPED) |
|
- /* Avoid generating the mapped addresses if we |
|
- know we are not going to need them. */ |
|
- && ((req->ai_flags & AI_ALL) || !res.got_ipv6))) |
|
- { |
|
- gethosts (AF_INET); |
|
- |
|
- if (req->ai_family == AF_INET) |
|
- { |
|
- no_inet6_data = no_data; |
|
- inet6_status = status; |
|
- } |
|
- } |
|
- |
|
- /* If we found one address for AF_INET or AF_INET6, |
|
- don't continue the search. */ |
|
- if (inet6_status == NSS_STATUS_SUCCESS |
|
- || status == NSS_STATUS_SUCCESS) |
|
- { |
|
- if ((req->ai_flags & AI_CANONNAME) != 0 |
|
- && res.canon == NULL) |
|
- { |
|
- char *canonbuf = getcanonname (nip, res.at, name); |
|
- if (canonbuf == NULL) |
|
- { |
|
- __resolv_context_put (res_ctx); |
|
- result = -EAI_MEMORY; |
|
- goto free_and_return; |
|
- } |
|
- res.canon = canonbuf; |
|
- } |
|
- status = NSS_STATUS_SUCCESS; |
|
- } |
|
- else |
|
- { |
|
- /* We can have different states for AF_INET and |
|
- AF_INET6. Try to find a useful one for both. */ |
|
- if (inet6_status == NSS_STATUS_TRYAGAIN) |
|
- status = NSS_STATUS_TRYAGAIN; |
|
- else if (status == NSS_STATUS_UNAVAIL |
|
- && inet6_status != NSS_STATUS_UNAVAIL) |
|
- status = inet6_status; |
|
- } |
|
- } |
|
- else |
|
- { |
|
- /* Could not locate any of the lookup functions. |
|
- The NSS lookup code does not consistently set |
|
- errno, so we need to supply our own error |
|
- code here. The root cause could either be a |
|
- resource allocation failure, or a missing |
|
- service function in the DSO (so it should not |
|
- be listed in /etc/nsswitch.conf). Assume the |
|
- former, and return EBUSY. */ |
|
- status = NSS_STATUS_UNAVAIL; |
|
- __set_h_errno (NETDB_INTERNAL); |
|
- __set_errno (EBUSY); |
|
- } |
|
- } |
|
- |
|
- if (nss_next_action (nip, status) == NSS_ACTION_RETURN) |
|
- break; |
|
- |
|
- /* The hosts database does not support MERGE. */ |
|
- if (nss_next_action (nip, status) == NSS_ACTION_MERGE) |
|
- do_merge = true; |
|
- |
|
- nip++; |
|
- if (nip->module == NULL) |
|
- no_more = -1; |
|
- } |
|
- |
|
- __resolv_context_put (res_ctx); |
|
- |
|
- /* If we have a failure which sets errno, report it using |
|
- EAI_SYSTEM. */ |
|
- if ((status == NSS_STATUS_TRYAGAIN || status == NSS_STATUS_UNAVAIL) |
|
- && h_errno == NETDB_INTERNAL) |
|
- { |
|
- result = -EAI_SYSTEM; |
|
- goto free_and_return; |
|
- } |
|
- |
|
- if (no_data != 0 && no_inet6_data != 0) |
|
- { |
|
- /* If both requests timed out report this. */ |
|
- if (no_data == EAI_AGAIN && no_inet6_data == EAI_AGAIN) |
|
- result = -EAI_AGAIN; |
|
- else |
|
- /* We made requests but they turned out no data. The name |
|
- is known, though. */ |
|
- result = -EAI_NODATA; |
|
- |
|
- goto free_and_return; |
|
- } |
|
+ if ((result = get_nss_addresses (name, req, tmpbuf, &res)) != 0) |
|
+ goto free_and_return; |
|
+ else if (res.at != NULL) |
|
+ goto process_list; |
|
|
|
- process_list: |
|
- if (res.at == NULL) |
|
- { |
|
- result = -EAI_NONAME; |
|
- goto free_and_return; |
|
- } |
|
+ /* None of the lookups worked, so name not found. */ |
|
+ result = -EAI_NONAME; |
|
+ goto free_and_return; |
|
} |
|
else |
|
{ |
|
@@ -1089,6 +1097,7 @@ gaih_inet (const char *name, const struct gaih_service *service, |
|
} |
|
} |
|
|
|
+process_list: |
|
{ |
|
/* Set up the canonical name if we need it. */ |
|
if ((result = process_canonname (req, orig_name, &res)) != 0)
|
|
|