public inbox for glibc-cvs@sourceware.org
help / color / mirror / Atom feed
From: Siddhesh Poyarekar <siddhesh@sourceware.org>
To: glibc-cvs@sourceware.org
Subject: [glibc/siddhesh/gai-cleanup2] gaih_inet: make numeric lookup a separate routine
Date: Wed, 23 Feb 2022 10:06:55 +0000 (GMT)	[thread overview]
Message-ID: <20220223100655.B33A239484A1@sourceware.org> (raw)

https://sourceware.org/git/gitweb.cgi?p=glibc.git;h=c0f8dce131bd1951663495f4dcf78718cd24efd6

commit c0f8dce131bd1951663495f4dcf78718cd24efd6
Author: Siddhesh Poyarekar <siddhesh@sourceware.org>
Date:   Wed Feb 16 23:36:32 2022 +0530

    gaih_inet: make numeric lookup a separate routine
    
    Split numeric lookup into a separate function to make the control flow
    clearer.  Also fail right there if AI_NUMERICHOST is request and
    get_numeric_res does not return a result, which is indicated by a NULL
    AT and a zero RC.
    
    NSS modules (especially nss_files) seem to depend on AT being backed by
    at least one tuple, so allocate it later to keep it working.  Subsequent
    patches will drop this too.
    
    A `git diff -b` will get a better idea of the changes since much of the
    diff is whitespace changes.
    
    Signed-off-by: Siddhesh Poyarekar <siddhesh@sourceware.org>

Diff:
---
 sysdeps/posix/getaddrinfo.c | 803 ++++++++++++++++++++++++--------------------
 1 file changed, 433 insertions(+), 370 deletions(-)

diff --git a/sysdeps/posix/getaddrinfo.c b/sysdeps/posix/getaddrinfo.c
index 3b6c106b0d..528dc6e7b0 100644
--- a/sysdeps/posix/getaddrinfo.c
+++ b/sysdeps/posix/getaddrinfo.c
@@ -409,6 +409,130 @@ get_servtuples (const struct gaih_service *service, const struct addrinfo *req,
   return 0;
 }
 
+/* Return a numeric result in a dynamically allocated address tuple to be freed
+   by the caller. Also set *CANONP if successful.  On failure, set RETP to the
+   error code, except when AI_NUMERICHOST is not requested, where NULL is
+   returned, but RETP is set to 0.  */
+
+static struct gaih_addrtuple *
+get_numeric_res (const char *name, const struct addrinfo *req, int *retp)
+{
+  uint32_t addr[4] = {0};
+
+  if (__inet_aton_exact (name, (struct in_addr *) addr) != 0)
+    {
+      if (req->ai_family != AF_UNSPEC && req->ai_family != AF_INET
+	  && (req->ai_family != AF_INET6 || !(req->ai_flags & AI_V4MAPPED)))
+	{
+	  *retp = -EAI_ADDRFAMILY;
+	  return NULL;
+	}
+
+      struct gaih_addrtuple *at = calloc (1, sizeof (*at));
+      if (at == NULL)
+	{
+	  *retp = EAI_MEMORY;
+	  return NULL;
+	}
+      memcpy (at->addr, addr, sizeof (addr));
+
+      if (req->ai_family == AF_UNSPEC || req->ai_family == AF_INET)
+	at->family = AF_INET;
+      else
+	{
+	  at->addr[3] = at->addr[0];
+	  at->addr[2] = htonl (0xffff);
+	  at->addr[1] = 0;
+	  at->addr[0] = 0;
+	  at->family = AF_INET6;
+	}
+
+      if (req->ai_flags & AI_CANONNAME)
+	{
+	  char *canonbuf = __strdup (name);
+	  if (canonbuf == NULL)
+	    {
+	      free (at);
+	      *retp = -EAI_MEMORY;
+	      return NULL;
+	    }
+	  at->name = canonbuf;
+	}
+
+      *retp = 0;
+      return at;
+    }
+
+  char *scope_delim = strchr (name, SCOPE_DELIMITER);
+  int e;
+
+  if (scope_delim == NULL)
+    e = inet_pton (AF_INET6, name, addr);
+  else
+    e = __inet_pton_length (AF_INET6, name, scope_delim - name, addr);
+
+  if (e > 0)
+    {
+      if (req->ai_family != AF_UNSPEC && req->ai_family != AF_INET6
+	  && (req->ai_family != AF_INET || !IN6_IS_ADDR_V4MAPPED (addr)))
+	{
+	  *retp = -EAI_ADDRFAMILY;
+	  return NULL;
+	}
+
+      uint32_t scopeid = 0;
+
+      if (scope_delim != NULL
+	  && __inet6_scopeid_pton ((struct in6_addr *) addr, scope_delim + 1,
+				   &scopeid) != 0)
+	{
+	  *retp = -EAI_NONAME;
+	  return NULL;
+	}
+
+      struct gaih_addrtuple *at = calloc (1, sizeof (*at));
+      if (at == NULL)
+	{
+	  *retp = EAI_MEMORY;
+	  return NULL;
+	}
+      memcpy (at->addr, addr, sizeof (addr));
+      at->scopeid = scopeid;
+
+      if (req->ai_family == AF_UNSPEC || req->ai_family == AF_INET6)
+	at->family = AF_INET6;
+      else
+	{
+	  at->addr[0] = at->addr[3];
+	  at->family = AF_INET;
+	}
+
+      if (req->ai_flags & AI_CANONNAME)
+	{
+	  char *canonbuf = __strdup (name);
+	  if (canonbuf == NULL)
+	    {
+	      free (at);
+	      *retp = -EAI_MEMORY;
+	      return NULL;
+	    }
+	  at->name = canonbuf;
+	}
+
+      *retp = 0;
+      return at;
+    }
+
+  if (req->ai_flags & AI_NUMERICHOST)
+    {
+      *retp = -EAI_NONAME;
+      return NULL;
+    }
+
+  *retp = 0;
+  return NULL;
+}
+
 static int
 gaih_inet (const char *name, const struct gaih_service *service,
 	   const struct addrinfo *req, struct addrinfo **pai,
@@ -437,11 +561,6 @@ gaih_inet (const char *name, const struct gaih_service *service,
 
   if (name != NULL)
     {
-      at = alloca_account (sizeof (struct gaih_addrtuple), alloca_used);
-      at->family = AF_UNSPEC;
-      at->scopeid = 0;
-      at->next = NULL;
-
       if (req->ai_flags & AI_IDN)
 	{
 	  char *out;
@@ -452,464 +571,408 @@ gaih_inet (const char *name, const struct gaih_service *service,
 	  malloc_name = true;
 	}
 
-      if (__inet_aton_exact (name, (struct in_addr *) at->addr) != 0)
+      if ((at = get_numeric_res (name, req, &result)) != NULL)
 	{
-	  if (req->ai_family == AF_UNSPEC || req->ai_family == AF_INET)
-	    at->family = AF_INET;
-	  else if (req->ai_family == AF_INET6 && (req->ai_flags & AI_V4MAPPED))
-	    {
-	      at->addr[3] = at->addr[0];
-	      at->addr[2] = htonl (0xffff);
-	      at->addr[1] = 0;
-	      at->addr[0] = 0;
-	      at->family = AF_INET6;
-	    }
-	  else
-	    {
-	      result = -EAI_ADDRFAMILY;
-	      goto free_and_return;
-	    }
-
-	  if (req->ai_flags & AI_CANONNAME)
-	    canon = name;
+	  addrmem = at;
+	  canon = canonbuf = at->name;
+	  goto process_list;
 	}
-      else if (at->family == AF_UNSPEC)
+      else if (result != 0)
+	goto free_and_return;
+
+      struct gaih_addrtuple **pat = &at;
+      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;
+
+      /* If we do not have to look for IPv6 addresses or the canonical
+	 name, use the simple, old functions, which do not support
+	 IPv6 scope ids, nor retrieving the canonical name.  */
+      if (req->ai_family == AF_INET
+	  && (req->ai_flags & AI_CANONNAME) == 0)
 	{
-	  char *scope_delim = strchr (name, SCOPE_DELIMITER);
-	  int e;
-	  if (scope_delim == NULL)
-	    e = inet_pton (AF_INET6, name, at->addr);
-	  else
-	    e = __inet_pton_length (AF_INET6, name, scope_delim - name,
-				    at->addr);
-	  if (e > 0)
+	  int rc;
+	  struct hostent th;
+	  struct hostent *h;
+
+	  while (1)
 	    {
-	      if (req->ai_family == AF_UNSPEC || req->ai_family == AF_INET6)
-		at->family = AF_INET6;
-	      else if (req->ai_family == AF_INET
-		       && IN6_IS_ADDR_V4MAPPED (at->addr))
-		{
-		  at->addr[0] = at->addr[3];
-		  at->family = AF_INET;
-		}
-	      else
+	      rc = __gethostbyname2_r (name, AF_INET, &th,
+				       tmpbuf->data, tmpbuf->length,
+				       &h, &h_errno);
+	      if (rc != ERANGE || h_errno != NETDB_INTERNAL)
+		break;
+	      if (!scratch_buffer_grow (tmpbuf))
 		{
-		  result = -EAI_ADDRFAMILY;
+		  result = -EAI_MEMORY;
 		  goto free_and_return;
 		}
+	    }
 
-	      if (scope_delim != NULL
-		  && __inet6_scopeid_pton ((struct in6_addr *) at->addr,
-					   scope_delim + 1,
-					   &at->scopeid) != 0)
+	  if (rc == 0)
+	    {
+	      if (h != NULL)
+		{
+		  /* We found data, convert it.  */
+		  if (!convert_hostent_to_gaih_addrtuple
+		      (req, AF_INET, h, &addrmem))
+		    {
+		      result = -EAI_MEMORY;
+		      goto free_and_return;
+		    }
+		  *pat = addrmem;
+		}
+	      else
 		{
-		  result = -EAI_NONAME;
+		  if (h_errno == NO_DATA)
+		    result = -EAI_NODATA;
+		  else
+		    result = -EAI_NONAME;
 		  goto free_and_return;
 		}
+	    }
+	  else
+	    {
+	      if (h_errno == NETDB_INTERNAL)
+		result = -EAI_SYSTEM;
+	      else if (h_errno == TRY_AGAIN)
+		result = -EAI_AGAIN;
+	      else
+		/* We made requests but they turned out no data.
+		   The name is known, though.  */
+		result = -EAI_NODATA;
 
-	      if (req->ai_flags & AI_CANONNAME)
-		canon = name;
+	      goto free_and_return;
 	    }
+
+	  goto process_list;
 	}
 
-      if (at->family == AF_UNSPEC && (req->ai_flags & AI_NUMERICHOST) == 0)
+#ifdef USE_NSCD
+      if (__nss_not_use_nscd_hosts > 0
+	  && ++__nss_not_use_nscd_hosts > NSS_NSCD_RETRY)
+	__nss_not_use_nscd_hosts = 0;
+
+      if (!__nss_not_use_nscd_hosts
+	  && !__nss_database_custom[NSS_DBSIDX_hosts])
 	{
-	  struct gaih_addrtuple **pat = &at;
-	  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;
-
-	  /* If we do not have to look for IPv6 addresses or the canonical
-	     name, use the simple, old functions, which do not support
-	     IPv6 scope ids, nor retrieving the canonical name.  */
-	  if (req->ai_family == AF_INET
-	      && (req->ai_flags & AI_CANONNAME) == 0)
+	  /* Try to use nscd.  */
+	  struct nscd_ai_result *air = NULL;
+	  int err = __nscd_getai (name, &air, &h_errno);
+	  if (air != NULL)
 	    {
-	      int rc;
-	      struct hostent th;
-	      struct hostent *h;
+	      /* Transform into gaih_addrtuple list.  */
+	      bool added_canon = (req->ai_flags & AI_CANONNAME) == 0;
+	      char *addrs = air->addrs;
 
-	      while (1)
+	      addrmem = calloc (air->naddrs, sizeof (*addrmem));
+	      if (addrmem == NULL)
 		{
-		  rc = __gethostbyname2_r (name, AF_INET, &th,
-					   tmpbuf->data, tmpbuf->length,
-					   &h, &h_errno);
-		  if (rc != ERANGE || h_errno != NETDB_INTERNAL)
-		    break;
-		  if (!scratch_buffer_grow (tmpbuf))
-		    {
-		      result = -EAI_MEMORY;
-		      goto free_and_return;
-		    }
+		  result = -EAI_MEMORY;
+		  goto free_and_return;
 		}
 
-	      if (rc == 0)
+	      struct gaih_addrtuple *addrfree = addrmem;
+	      for (int i = 0; i < air->naddrs; ++i)
 		{
-		  if (h != NULL)
+		  socklen_t size = (air->family[i] == AF_INET
+				    ? INADDRSZ : IN6ADDRSZ);
+
+		  if (!((air->family[i] == AF_INET
+			 && req->ai_family == AF_INET6
+			 && (req->ai_flags & AI_V4MAPPED) != 0)
+			|| req->ai_family == AF_UNSPEC
+			|| air->family[i] == req->ai_family))
+		    {
+		      /* Skip over non-matching result.  */
+		      addrs += size;
+		      continue;
+		    }
+
+		  if (*pat == NULL)
+		    {
+		      *pat = addrfree++;
+		      (*pat)->scopeid = 0;
+		    }
+		  uint32_t *pataddr = (*pat)->addr;
+		  (*pat)->next = NULL;
+		  if (added_canon || air->canon == NULL)
+		    (*pat)->name = NULL;
+		  else if (canonbuf == NULL)
 		    {
-		      /* We found data, convert it.  */
-		      if (!convert_hostent_to_gaih_addrtuple
-			  (req, AF_INET, h, &addrmem))
+		      canonbuf = __strdup (air->canon);
+		      if (canonbuf == NULL)
 			{
 			  result = -EAI_MEMORY;
 			  goto free_and_return;
 			}
-		      *pat = addrmem;
+		      canon = (*pat)->name = canonbuf;
 		    }
-		  else
+
+		  if (air->family[i] == AF_INET
+		      && req->ai_family == AF_INET6
+		      && (req->ai_flags & AI_V4MAPPED))
 		    {
-		      if (h_errno == NO_DATA)
-			result = -EAI_NODATA;
-		      else
-			result = -EAI_NONAME;
-		      goto free_and_return;
+		      (*pat)->family = AF_INET6;
+		      pataddr[3] = *(uint32_t *) addrs;
+		      pataddr[2] = htonl (0xffff);
+		      pataddr[1] = 0;
+		      pataddr[0] = 0;
+		      pat = &((*pat)->next);
+		      added_canon = true;
+		    }
+		  else if (req->ai_family == AF_UNSPEC
+			   || air->family[i] == req->ai_family)
+		    {
+		      (*pat)->family = air->family[i];
+		      memcpy (pataddr, addrs, size);
+		      pat = &((*pat)->next);
+		      added_canon = true;
+		      if (air->family[i] == AF_INET6)
+			got_ipv6 = true;
 		    }
+		  addrs += size;
 		}
-	      else
-		{
-		  if (h_errno == NETDB_INTERNAL)
-		    result = -EAI_SYSTEM;
-		  else if (h_errno == TRY_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;
-		}
+	      free (air);
 
 	      goto process_list;
 	    }
+	  else if (err == 0)
+	    /* The database contains a negative entry.  */
+	    goto free_and_return;
+	  else if (__nss_not_use_nscd_hosts == 0)
+	    {
+	      if (h_errno == NETDB_INTERNAL && errno == ENOMEM)
+		result = -EAI_MEMORY;
+	      else if (h_errno == TRY_AGAIN)
+		result = -EAI_AGAIN;
+	      else
+		result = -EAI_SYSTEM;
 
-#ifdef USE_NSCD
-	  if (__nss_not_use_nscd_hosts > 0
-	      && ++__nss_not_use_nscd_hosts > NSS_NSCD_RETRY)
-	    __nss_not_use_nscd_hosts = 0;
+	      goto free_and_return;
+	    }
+	}
+#endif
+
+      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;
+
+      at = __alloca (sizeof (*at));
+      at->next = NULL;
+      at->family = AF_UNSPEC;
+
+      while (!no_more)
+	{
+	  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 (!__nss_not_use_nscd_hosts
-	      && !__nss_database_custom[NSS_DBSIDX_hosts])
+	  if (fct4 != NULL)
 	    {
-	      /* Try to use nscd.  */
-	      struct nscd_ai_result *air = NULL;
-	      int err = __nscd_getai (name, &air, &h_errno);
-	      if (air != NULL)
+	      while (1)
 		{
-		  /* Transform into gaih_addrtuple list.  */
-		  bool added_canon = (req->ai_flags & AI_CANONNAME) == 0;
-		  char *addrs = air->addrs;
+		  status = DL_CALL_FCT (fct4, (name, pat,
+					       tmpbuf->data, tmpbuf->length,
+					       &errno, &h_errno,
+					       NULL));
+		  if (status == NSS_STATUS_SUCCESS)
+		    break;
+		  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;
+		    }
 
-		  addrmem = calloc (air->naddrs, sizeof (*addrmem));
-		  if (addrmem == NULL)
+		  if (!scratch_buffer_grow (tmpbuf))
 		    {
+		      __resolv_context_put (res_ctx);
 		      result = -EAI_MEMORY;
 		      goto free_and_return;
 		    }
+		}
 
-		  struct gaih_addrtuple *addrfree = addrmem;
-		  for (int i = 0; i < air->naddrs; ++i)
-		    {
-		      socklen_t size = (air->family[i] == AF_INET
-					? INADDRSZ : IN6ADDRSZ);
-
-		      if (!((air->family[i] == AF_INET
-			     && req->ai_family == AF_INET6
-			     && (req->ai_flags & AI_V4MAPPED) != 0)
-			    || req->ai_family == AF_UNSPEC
-			    || air->family[i] == req->ai_family))
-			{
-			  /* Skip over non-matching result.  */
-			  addrs += size;
-			  continue;
-			}
+	      if (status == NSS_STATUS_SUCCESS)
+		{
+		  assert (!no_data);
+		  no_data = 1;
 
-		      if (*pat == NULL)
-			{
-			  *pat = addrfree++;
-			  (*pat)->scopeid = 0;
-			}
-		      uint32_t *pataddr = (*pat)->addr;
-		      (*pat)->next = NULL;
-		      if (added_canon || air->canon == NULL)
-			(*pat)->name = NULL;
-		      else if (canonbuf == NULL)
-			{
-			  canonbuf = __strdup (air->canon);
-			  if (canonbuf == NULL)
-			    {
-			      result = -EAI_MEMORY;
-			      goto free_and_return;
-			    }
-			  canon = (*pat)->name = canonbuf;
-			}
+		  if ((req->ai_flags & AI_CANONNAME) != 0 && canon == NULL)
+		    canon = (*pat)->name;
 
-		      if (air->family[i] == AF_INET
+		  while (*pat != NULL)
+		    {
+		      if ((*pat)->family == AF_INET
 			  && req->ai_family == AF_INET6
-			  && (req->ai_flags & AI_V4MAPPED))
+			  && (req->ai_flags & AI_V4MAPPED) != 0)
 			{
+			  uint32_t *pataddr = (*pat)->addr;
 			  (*pat)->family = AF_INET6;
-			  pataddr[3] = *(uint32_t *) addrs;
+			  pataddr[3] = pataddr[0];
 			  pataddr[2] = htonl (0xffff);
 			  pataddr[1] = 0;
 			  pataddr[0] = 0;
 			  pat = &((*pat)->next);
-			  added_canon = true;
+			  no_data = 0;
 			}
 		      else if (req->ai_family == AF_UNSPEC
-			       || air->family[i] == req->ai_family)
+			       || (*pat)->family == req->ai_family)
 			{
-			  (*pat)->family = air->family[i];
-			  memcpy (pataddr, addrs, size);
 			  pat = &((*pat)->next);
-			  added_canon = true;
-			  if (air->family[i] == AF_INET6)
+
+			  no_data = 0;
+			  if (req->ai_family == AF_INET6)
 			    got_ipv6 = true;
 			}
-		      addrs += size;
-		    }
-
-		  free (air);
-
-		  if (at->family == AF_UNSPEC)
-		    {
-		      result = -EAI_NONAME;
-		      goto free_and_return;
+		      else
+			*pat = ((*pat)->next);
 		    }
-
-		  goto process_list;
 		}
-	      else if (err == 0)
-		/* The database contains a negative entry.  */
-		goto free_and_return;
-	      else if (__nss_not_use_nscd_hosts == 0)
-		{
-		  if (h_errno == NETDB_INTERNAL && errno == ENOMEM)
-		    result = -EAI_MEMORY;
-		  else if (h_errno == TRY_AGAIN)
-		    result = -EAI_AGAIN;
-		  else
-		    result = -EAI_SYSTEM;
 
-		  goto free_and_return;
-		}
+	      no_inet6_data = no_data;
 	    }
-#endif
-
-	  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)
+	  else
 	    {
-	      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)
+	      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)
 		{
-		  while (1)
+		  if (req->ai_family == AF_INET6
+		      || req->ai_family == AF_UNSPEC)
 		    {
-		      status = DL_CALL_FCT (fct4, (name, pat,
-						   tmpbuf->data, tmpbuf->length,
-						   &errno, &h_errno,
-						   NULL));
-		      if (status == NSS_STATUS_SUCCESS)
-			break;
-		      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;
-			}
+		      gethosts (AF_INET6);
+		      no_inet6_data = no_data;
+		      inet6_status = status;
 		    }
-
-		  if (status == NSS_STATUS_SUCCESS)
+		  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) || !got_ipv6)))
 		    {
-		      assert (!no_data);
-		      no_data = 1;
-
-		      if ((req->ai_flags & AI_CANONNAME) != 0 && canon == NULL)
-			canon = (*pat)->name;
-
-		      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);
+		      gethosts (AF_INET);
 
-			      no_data = 0;
-			      if (req->ai_family == AF_INET6)
-				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)
+		      if (req->ai_family == AF_INET)
 			{
-			  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) || !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 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
+			  && canon == NULL)
 			{
-			  if ((req->ai_flags & AI_CANONNAME) != 0
-			      && canon == NULL)
+			  canonbuf = getcanonname (nip, at, name);
+			  if (canonbuf == NULL)
 			    {
-			      canonbuf = getcanonname (nip, at, name);
-			      if (canonbuf == NULL)
-				{
-				  __resolv_context_put (res_ctx);
-				  result = -EAI_MEMORY;
-				  goto free_and_return;
-				}
-			      canon = canonbuf;
+			      __resolv_context_put (res_ctx);
+			      result = -EAI_MEMORY;
+			      goto free_and_return;
 			    }
-			  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;
+			  canon = canonbuf;
 			}
+		      status = NSS_STATUS_SUCCESS;
 		    }
 		  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);
+		      /* 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;
+	  if (nss_next_action (nip, status) == NSS_ACTION_RETURN)
+	    break;
 
-	      nip++;
-	      if (nip->module == NULL)
-		no_more = -1;
-	    }
+	  nip++;
+	  if (nip->module == NULL)
+	    no_more = -1;
+	}
 
-	  __resolv_context_put (res_ctx);
+      __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 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;
+      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;
-	    }
+	  goto free_and_return;
 	}
 
     process_list:
-      if (at->family == AF_UNSPEC)
+      if (at == NULL || at->family == AF_UNSPEC)
 	{
 	  result = -EAI_NONAME;
 	  goto free_and_return;


             reply	other threads:[~2022-02-23 10:06 UTC|newest]

Thread overview: 7+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2022-02-23 10:06 Siddhesh Poyarekar [this message]
  -- strict thread matches above, loose matches on Subject: below --
2022-03-14 14:16 Siddhesh Poyarekar
2022-03-08 14:09 Siddhesh Poyarekar
2022-03-07 16:56 Siddhesh Poyarekar
2022-03-01  2:40 Siddhesh Poyarekar
2022-02-23  9:02 Siddhesh Poyarekar
2022-02-22 13:51 Siddhesh Poyarekar

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20220223100655.B33A239484A1@sourceware.org \
    --to=siddhesh@sourceware.org \
    --cc=glibc-cvs@sourceware.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).