[v2,13/23] nscd: Introduce __nscd_read_from_socket client function

Message ID 1b7650609687533628085fe716ac9666f5c400bd.1774037705.git.fweimer@redhat.com (mailing list archive)
State Failed CI
Headers
Series NSS, nscd updates (for group merging and more) |

Checks

Context Check Description
redhat-pt-bot/TryBot-apply_patch success Patch applied to master at the time it was sent
linaro-tcwg-bot/tcwg_glibc_build--master-arm success Build passed
linaro-tcwg-bot/tcwg_glibc_build--master-aarch64 success Build passed
linaro-tcwg-bot/tcwg_glibc_check--master-aarch64 fail Test failed
linaro-tcwg-bot/tcwg_glibc_check--master-arm fail Test failed

Commit Message

Florian Weimer March 20, 2026, 8:42 p.m. UTC
  ---
 nscd/nscd-client.h | 20 ++++++++++++++++-
 nscd/nscd_helper.c | 53 ++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 72 insertions(+), 1 deletion(-)
  

Comments

Carlos O'Donell March 24, 2026, 7:43 p.m. UTC | #1
On 3/20/26 4:42 PM, Florian Weimer wrote:

LGTM.

Reviewed-by: Carlos O'Donell <carlos@redhat.com>

> ---
>   nscd/nscd-client.h | 20 ++++++++++++++++-
>   nscd/nscd_helper.c | 53 ++++++++++++++++++++++++++++++++++++++++++++++
>   2 files changed, 72 insertions(+), 1 deletion(-)
> 
> diff --git a/nscd/nscd-client.h b/nscd/nscd-client.h
> index c507933acb..10284e8ef2 100644
> --- a/nscd/nscd-client.h
> +++ b/nscd/nscd-client.h
> @@ -366,11 +366,29 @@ struct mapped_database
>     __libc_rwlock_define (, lock);
>   };
>   
> -/* Open socket connection to nscd server.  */
> +/* Open socket connection to nscd server, send the request, and read
> +   the start of the response (update to RESPONSELEN bytes).  If the
> +   procided response buffer is exceeded, the socket is left open, so
> +   that more data can be read.  */
>   extern int __nscd_open_socket (const char *key, size_t keylen,
>   			       request_type type, void *response,
>   			       size_t responselen) attribute_hidden;
>   
> +/* Open a socket to nscd, send the request, and read the full
> +   response.  *RESPONSE is grown as necessary.
> +
> +   A non-negative return value indicates the number of response bytes
> +   stored at RESPONSE->data.  The response includes only the struct
> +   *_response_header and the data that follows it, not struct
> +   datahead.
> +
> +   On error, return a negative errno code.  */
> +struct scratch_buffer;
> +ssize_t __nscd_read_from_socket (const char *key, size_t keylen,
> +				 request_type type,
> +				 struct scratch_buffer *response)
> +  attribute_hidden;
> +
>   /* Acquire reference to the mapping for DB (see <nscd-dbtype.h>).  On
>      success, return a pointer to the mapping descriptor, and lock the
>      mapping.
> diff --git a/nscd/nscd_helper.c b/nscd/nscd_helper.c
> index 9bd0e7818e..ed2d8d09da 100644
> --- a/nscd/nscd_helper.c
> +++ b/nscd/nscd_helper.c
> @@ -37,6 +37,7 @@
>   #include <kernel-features.h>
>   #include <nss.h>
>   #include <struct___timespec64.h>
> +#include <scratch_buffer.h>
>   
>   #include "nscd-client.h"
>   #include "nscd-dbtype.h"
> @@ -612,3 +613,55 @@ __nscd_open_socket (const char *key, size_t keylen, request_type type,
>   
>     return -1;
>   }
> +
> +ssize_t
> +__nscd_read_from_socket (const char *key, size_t keylen, request_type type,
> +			 struct scratch_buffer *response)
> +{
> +  if (keylen > MAXKEYLEN)
> +    return -ENAMETOOLONG;
> +
> +  int sock = open_socket (type, key, keylen);

OK. Pass type, key and keylen to open_socket helper (used by __nscd_get_mapping,
and __nscd_open_socket).

> +  if (sock < 0)
> +    return sock;
> +
> +  /* The nscd stream protocol does not size information in a way that
> +     is independent of request type.  However, there is only one
> +     request per connection, so the code below simply reads all data
> +     that is available before end of stream.  */
> +
> +  ssize_t ret = 0;		/* Number of bytes read, or -1 on error.  */
> +  while (true)
> +    {
> +      /* Wait for data.  Give up on timeout.  */
> +      if (wait_on_socket (sock, 5 * 1000) == 0)
> +	break;
> +      size_t remaining = response->length - ret;
> +      ssize_t nbytes = TEMP_FAILURE_RETRY (__read (sock, response->data + ret,
> +						   remaining));
> +      if (nbytes < 0)
> +	{
> +	  ret = -errno;
> +	  break;
> +	}
> +      if (nbytes == 0)
> +	/* The end of the stream marks the end of packet.  We cannot
> +	   tell if the data was truncated because nscd went away
> +	   unexpectedly.  This will be recognized by the caller during
> +	   packet parsing.  */
> +	break;
> +
> +      /* Try reading more data in the next iteration after growing the
> +	 buffer.  */
> +      ret += nbytes;
> +      if (ret == response->length && !scratch_buffer_grow_preserve (response))
> +	{
> +	  ret = -ENOMEM;
> +	  break;
> +	}
> +    }
> +
> +  __close_nocancel_nostatus (sock);
> +
> +  return ret;
> +}
  

Patch

diff --git a/nscd/nscd-client.h b/nscd/nscd-client.h
index c507933acb..10284e8ef2 100644
--- a/nscd/nscd-client.h
+++ b/nscd/nscd-client.h
@@ -366,11 +366,29 @@  struct mapped_database
   __libc_rwlock_define (, lock);
 };
 
-/* Open socket connection to nscd server.  */
+/* Open socket connection to nscd server, send the request, and read
+   the start of the response (update to RESPONSELEN bytes).  If the
+   procided response buffer is exceeded, the socket is left open, so
+   that more data can be read.  */
 extern int __nscd_open_socket (const char *key, size_t keylen,
 			       request_type type, void *response,
 			       size_t responselen) attribute_hidden;
 
+/* Open a socket to nscd, send the request, and read the full
+   response.  *RESPONSE is grown as necessary.
+
+   A non-negative return value indicates the number of response bytes
+   stored at RESPONSE->data.  The response includes only the struct
+   *_response_header and the data that follows it, not struct
+   datahead.
+
+   On error, return a negative errno code.  */
+struct scratch_buffer;
+ssize_t __nscd_read_from_socket (const char *key, size_t keylen,
+				 request_type type,
+				 struct scratch_buffer *response)
+  attribute_hidden;
+
 /* Acquire reference to the mapping for DB (see <nscd-dbtype.h>).  On
    success, return a pointer to the mapping descriptor, and lock the
    mapping.
diff --git a/nscd/nscd_helper.c b/nscd/nscd_helper.c
index 9bd0e7818e..ed2d8d09da 100644
--- a/nscd/nscd_helper.c
+++ b/nscd/nscd_helper.c
@@ -37,6 +37,7 @@ 
 #include <kernel-features.h>
 #include <nss.h>
 #include <struct___timespec64.h>
+#include <scratch_buffer.h>
 
 #include "nscd-client.h"
 #include "nscd-dbtype.h"
@@ -612,3 +613,55 @@  __nscd_open_socket (const char *key, size_t keylen, request_type type,
 
   return -1;
 }
+
+ssize_t
+__nscd_read_from_socket (const char *key, size_t keylen, request_type type,
+			 struct scratch_buffer *response)
+{
+  if (keylen > MAXKEYLEN)
+    return -ENAMETOOLONG;
+
+  int sock = open_socket (type, key, keylen);
+  if (sock < 0)
+    return sock;
+
+  /* The nscd stream protocol does not size information in a way that
+     is independent of request type.  However, there is only one
+     request per connection, so the code below simply reads all data
+     that is available before end of stream.  */
+
+  ssize_t ret = 0;		/* Number of bytes read, or -1 on error.  */
+  while (true)
+    {
+      /* Wait for data.  Give up on timeout.  */
+      if (wait_on_socket (sock, 5 * 1000) == 0)
+	break;
+      size_t remaining = response->length - ret;
+      ssize_t nbytes = TEMP_FAILURE_RETRY (__read (sock, response->data + ret,
+						   remaining));
+      if (nbytes < 0)
+	{
+	  ret = -errno;
+	  break;
+	}
+      if (nbytes == 0)
+	/* The end of the stream marks the end of packet.  We cannot
+	   tell if the data was truncated because nscd went away
+	   unexpectedly.  This will be recognized by the caller during
+	   packet parsing.  */
+	break;
+
+      /* Try reading more data in the next iteration after growing the
+	 buffer.  */
+      ret += nbytes;
+      if (ret == response->length && !scratch_buffer_grow_preserve (response))
+	{
+	  ret = -ENOMEM;
+	  break;
+	}
+    }
+
+  __close_nocancel_nostatus (sock);
+
+  return ret;
+}