[PATCH 5/7] nscd: Pass TRY_AGAIN errors in the hosts cache to clients
Florian Weimer
fweimer@redhat.com
Fri Jan 30 16:05:35 GMT 2026
This is the minimal set of changes to get the upcoming test to pass.
The TTL extension logic is somewhat iffy. There is a trade-off here:
correct operation under the DNS specification (no TTL extensions), or
reducing loading the infrastructure if TRY_AGAIN is the result of
overload from this client.
---
nscd/aicache.c | 26 ++++++++++++++++++++------
nscd/hstcache.c | 15 +++++++++------
nss/getaddrinfo.c | 7 ++++++-
3 files changed, 35 insertions(+), 13 deletions(-)
diff --git a/nscd/aicache.c b/nscd/aicache.c
index 91ec09af7b..ef15c373f5 100644
--- a/nscd/aicache.c
+++ b/nscd/aicache.c
@@ -42,6 +42,15 @@ static const ai_response_header notfound =
.error = 0
};
+static const ai_response_header tryagain =
+{
+ .version = NSCD_VERSION,
+ .found = 0,
+ .naddrs = 0,
+ .addrslen = 0,
+ .canonlen = 0,
+ .error = TRY_AGAIN
+};
static time_t
addhstaiX (struct database_dyn *db, int fd, request_header *req,
@@ -440,7 +449,7 @@ next_nip:
}
/* No result found. Create a negative result record. */
- if (he != NULL && rc4 == EAGAIN)
+ if (he != NULL && herrno == TRY_AGAIN)
{
/* If we have an old record available but cannot find one now
because the service is not available we keep the old record
@@ -454,16 +463,21 @@ next_nip:
}
else
{
- /* We have no data. This means we send the standard reply for
- this case. */
+ /* We have no data. This means we send the standard reply
+ for this case. Possibly this is only temporary due to
+ networking errors or memory allocation failures. */
total = sizeof (notfound);
+ assert (sizeof (notfound) == sizeof (tryagain));
+
+ const ai_response_header *resp = (herrno == TRY_AGAIN
+ ? &tryagain : ¬found);
if (fd != -1)
- TEMP_FAILURE_RETRY (send (fd, ¬found, total, MSG_NOSIGNAL));
+ TEMP_FAILURE_RETRY (send (fd, resp, total, MSG_NOSIGNAL));
/* If we have a transient error or cannot permanently store the
result, so be it. */
- if (rc4 == EAGAIN || __builtin_expect (db->negtimeout == 0, 0))
+ if (herrno == TRY_AGAIN || __builtin_expect (db->negtimeout == 0, 0))
{
/* Mark the old entry as obsolete. */
if (dh != NULL)
@@ -478,7 +492,7 @@ next_nip:
total, db->negtimeout);
/* This is the reply. */
- memcpy (&dataset->resp, ¬found, total);
+ memcpy (&dataset->resp, resp, total);
/* Copy the key data. */
key_copy = memcpy (dataset->strdata, key, req->key_len);
diff --git a/nscd/hstcache.c b/nscd/hstcache.c
index e9272000a3..78485fbac3 100644
--- a/nscd/hstcache.c
+++ b/nscd/hstcache.c
@@ -125,8 +125,9 @@ cache_addhst (struct database_dyn *db, int fd, request_header *req,
}
else
{
- /* We have no data. This means we send the standard reply for this
- case. Possibly this is only temporary. */
+ /* We have no data. This means we send the standard reply
+ for this case. Possibly this is only temporary due to
+ networking errors or memory allocation failures. */
ssize_t total = sizeof (notfound);
assert (sizeof (notfound) == sizeof (tryagain));
@@ -434,7 +435,6 @@ addhstbyX (struct database_dyn *db, int fd, request_header *req,
pruning function only will look at the timestamp. */
struct hostent resultbuf;
struct hostent *hst;
- int errval = 0;
int32_t ttl = INT32_MAX;
if (__glibc_unlikely (debug_level > 0))
@@ -459,7 +459,7 @@ addhstbyX (struct database_dyn *db, int fd, request_header *req,
while (lookup (req->type, key, &resultbuf,
tmpbuf.data, tmpbuf.length, &hst, &ttl) != 0
&& h_errno == NETDB_INTERNAL
- && (errval = errno) == ERANGE)
+ && errno == ERANGE)
if (!scratch_buffer_grow (&tmpbuf))
{
/* We ran out of memory. We cannot do anything but sending a
@@ -470,12 +470,15 @@ addhstbyX (struct database_dyn *db, int fd, request_header *req,
error and that it does not mean the entry is not
available at all. */
h_errno = TRY_AGAIN;
- errval = EAGAIN;
break;
}
+ /* On out-of-memory or without a network connection, pass EAGAIN as
+ an error code. This will be translated back to TRY_AGAIN in the
+ client. Other errors with hst == NULL and error code 0 are
+ treated as HOST_NOT_FOUND. */
time_t timeout = cache_addhst (db, fd, req, key, hst, uid, he, dh,
- h_errno == TRY_AGAIN ? errval : 0, ttl);
+ h_errno == TRY_AGAIN ? EAGAIN : 0, ttl);
scratch_buffer_free (&tmpbuf);
return timeout;
}
diff --git a/nss/getaddrinfo.c b/nss/getaddrinfo.c
index c0f496f96c..4f6ac3358a 100644
--- a/nss/getaddrinfo.c
+++ b/nss/getaddrinfo.c
@@ -502,7 +502,12 @@ get_nscd_addresses (const char *name, const struct addrinfo *req,
{
/* The database contains a negative entry. */
if (err == 0)
- return -EAI_NONAME;
+ {
+ /* h_errno contains the error from nscd. */
+ if (h_errno == TRY_AGAIN)
+ return -EAI_AGAIN;
+ return -EAI_NONAME;
+ }
if (__nss_not_use_nscd_hosts == 0)
{
if (h_errno == NETDB_INTERNAL && errno == ENOMEM)
--
2.52.0
More information about the Libc-alpha
mailing list