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.
Reviewed-by: DJ Delorie <dj@redhat.com>
.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,
}
/* 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
}
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)
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);
}
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));
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))
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
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;
}
{
/* 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)