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: separate nss lookup loop into its own function
Date: Tue,  1 Mar 2022 02:41:12 +0000 (GMT)	[thread overview]
Message-ID: <20220301024112.5DA323858408@sourceware.org> (raw)

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

commit 98f728a01610bb31622c2ccff18795853dd849d1
Author: Siddhesh Poyarekar <siddhesh@sourceware.org>
Date:   Mon Feb 28 20:20:41 2022 +0530

    gaih_inet: separate nss lookup loop into its own function
    
    Signed-off-by: Siddhesh Poyarekar <siddhesh@sourceware.org>

Diff:
---
 sysdeps/posix/getaddrinfo.c | 529 +++++++++++++++++++++++---------------------
 1 file changed, 274 insertions(+), 255 deletions(-)

diff --git a/sysdeps/posix/getaddrinfo.c b/sysdeps/posix/getaddrinfo.c
index ea3fa76748..59109d0a35 100644
--- a/sysdeps/posix/getaddrinfo.c
+++ b/sysdeps/posix/getaddrinfo.c
@@ -297,7 +297,6 @@ convert_hostent_to_gaih_addrtuple (const struct addrinfo *req,
 	break;								      \
       if (!scratch_buffer_grow (tmpbuf))				      \
 	{								      \
-	  __resolv_context_put (res_ctx);				      \
 	  result = -EAI_MEMORY;						      \
 	  goto free_and_return;						      \
 	}								      \
@@ -307,7 +306,6 @@ convert_hostent_to_gaih_addrtuple (const struct addrinfo *req,
     {									      \
       if (h_errno == NETDB_INTERNAL)					      \
 	{								      \
-	  __resolv_context_put (res_ctx);				      \
 	  result = -EAI_SYSTEM;						      \
 	  goto free_and_return;						      \
 	}								      \
@@ -321,11 +319,10 @@ convert_hostent_to_gaih_addrtuple (const struct addrinfo *req,
       struct gaih_addrtuple *addrmem = NULL;				      \
       if (!convert_hostent_to_gaih_addrtuple (req, _family, &th, &addrmem))   \
 	{								      \
-	  __resolv_context_put (res_ctx);				      \
 	  result = -EAI_SYSTEM;						      \
 	  goto free_and_return;						      \
 	}								      \
-      if (addrmem && !gaih_lookup_result_push_alloc (&res, addrmem))	      \
+      if (addrmem && !gaih_lookup_result_push_alloc (res, addrmem))	      \
 	{								      \
 	  free (addrmem);						      \
 	  result = -EAI_MEMORY;						      \
@@ -339,14 +336,13 @@ convert_hostent_to_gaih_addrtuple (const struct addrinfo *req,
 	  char *canonbuf = __strdup (localcanon);			      \
 	  if (canonbuf == NULL)						      \
 	    {								      \
-	      __resolv_context_put (res_ctx);				      \
 	      result = -EAI_SYSTEM;					      \
 	      goto free_and_return;					      \
 	    }								      \
 	  canon = canonbuf;						      \
 	}								      \
       if (_family == AF_INET6 && addrmem != NULL)			      \
-	got_ipv6 = true;						      \
+	res->got_ipv6 = true;						      \
     }									      \
  }
 
@@ -768,6 +764,271 @@ simple_gethostbyname (const char *name, const struct addrinfo *req,
   return -EAI_NODATA;
 }
 
+static int
+get_nss_addresses (const char *name, const struct addrinfo *req,
+		   struct scratch_buffer *tmpbuf,
+		   struct gaih_lookup_result *res)
+{
+  struct gaih_addrtuple *at = NULL;
+
+  /* Use PAT to track the end of the tuple list so that multiple lookups append
+     to the end of the latest list.  */
+  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;
+  char *canon = NULL;
+  int result = 0;
+
+  res->at = NULL;
+
+  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)
+    {
+      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)
+	{
+	  size_t length = 1024;
+	  char *buf = malloc (length);
+
+	  while (1)
+	    {
+	      *pat = NULL;
+	      status = DL_CALL_FCT (fct4, (name, pat, buf, 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;
+		}
+
+	      length *= 2;
+	      free (buf);
+	      if ((buf = malloc (length)) == NULL)
+		{
+		  result = -EAI_MEMORY;
+		  goto free_and_return;
+		}
+	    }
+
+	  if (!gaih_lookup_result_push_alloc (res, buf))
+	    {
+	      free (buf);
+	      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 && canon == NULL)
+		{
+		  char *canonbuf = __strdup ((*pat)->name);
+		  if (canonbuf == NULL)
+		    {
+		      result = -EAI_MEMORY;
+		      goto free_and_return;
+		    }
+		  canon = canonbuf;
+		}
+
+	      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 && canon == NULL)
+		    {
+		      char *canonbuf = getcanonname (nip, at, name);
+		      if (canonbuf == NULL)
+			{
+			  result = -EAI_MEMORY;
+			  goto free_and_return;
+			}
+		      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;
+
+      /* Discard all previous results on CONTINUE.  Allocations will get
+	 freed at the end of gaih_cleanup, so only adjust PAT and free
+	 CANONBUF if it was allocated.  */
+      if (nss_next_action (nip, status) == NSS_ACTION_CONTINUE)
+	{
+	  at = NULL;
+	  pat = &at;
+	  free (canon);
+	  canon = NULL;
+	}
+
+      nip++;
+      if (nip->module == NULL)
+	no_more = -1;
+    }
+
+  /* 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;
+    }
+
+free_and_return:
+  __resolv_context_put (res_ctx);
+
+  if (result != 0)
+    at = NULL;
+
+  if (at == NULL)
+    free (canon);
+  else
+    at->name = canon;
+
+  res->at = at;
+  return result;
+}
+
 static int
 process_canonname (const struct addrinfo *req, const char *orig_name,
 		   char **canonp)
@@ -876,259 +1137,17 @@ gaih_inet (const char *name, const struct gaih_service *service,
 	}
 #endif
 
-      /* For NSS lookups, use PAT to track the end of the tuple list so that
-	 multiple lookups append to the end of the latest list.  */
-      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;
-
-      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)
-	{
-	  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)
-	    {
-	      size_t length = 1024;
-	      char *buf = malloc (length);
-
-	      while (1)
-		{
-		  *pat = NULL;
-		  status = DL_CALL_FCT (fct4, (name, pat,
-					       buf, 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;
-		    }
-
-		  length *= 2;
-		  free (buf);
-		  if ((buf = malloc (length)) == NULL)
-		    {
-		      __resolv_context_put (res_ctx);
-		      result = -EAI_MEMORY;
-		      goto free_and_return;
-		    }
-		}
-
-	      if (!gaih_lookup_result_push_alloc (&res, buf))
-		{
-		  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 && canon == NULL)
-		    {
-		      char *canonbuf = __strdup ((*pat)->name);
-		      if (canonbuf == NULL)
-			{
-			  __resolv_context_put (res_ctx);
-			  result = -EAI_MEMORY;
-			  goto free_and_return;
-			}
-		      canon = canonbuf;
-		    }
-
-		  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)
-			    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) || !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
-			  && canon == NULL)
-			{
-			  char *canonbuf = getcanonname (nip, at, name);
-			  if (canonbuf == NULL)
-			    {
-			      __resolv_context_put (res_ctx);
-			      result = -EAI_MEMORY;
-			      goto free_and_return;
-			    }
-			  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;
-
-	  /* Discard the previous result on CONTINUE.  Allocations will get
-	     freed at the end with func_cleanup, so only adjust PAT and free
-	     CANONBUF if it was allocated.  */
-	  if (nss_next_action (nip, status) == NSS_ACTION_CONTINUE)
-	    {
-	      at = NULL;
-	      pat = &at;
-	      free (canon);
-	      canon = NULL;
-	    }
-
-	  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 ((result = get_nss_addresses (name, req, tmpbuf, &res)) != 0)
+	goto free_and_return;
+      else if (res.at != NULL)
 	{
-	  /* 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;
+	  at = res.at;
+	  canon = at->name;
+	  got_ipv6 = res.got_ipv6;
 	}
 
     process_list:
-      if (at == NULL || at->family == AF_UNSPEC)
+      if (at == NULL)
 	{
 	  result = -EAI_NONAME;
 	  goto free_and_return;


             reply	other threads:[~2022-03-01  2:41 UTC|newest]

Thread overview: 4+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2022-03-01  2:41 Siddhesh Poyarekar [this message]
2022-03-07 16:56 Siddhesh Poyarekar
2022-03-08 14:10 Siddhesh Poyarekar
2022-03-14 14:17 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=20220301024112.5DA323858408@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).