Blame nscd/hstcache.c

Packit 6c4009
/* Cache handling for host lookup.
Packit 6c4009
   Copyright (C) 1998-2018 Free Software Foundation, Inc.
Packit 6c4009
   This file is part of the GNU C Library.
Packit 6c4009
   Contributed by Ulrich Drepper <drepper@cygnus.com>, 1998.
Packit 6c4009
Packit 6c4009
   This program is free software; you can redistribute it and/or modify
Packit 6c4009
   it under the terms of the GNU General Public License as published
Packit 6c4009
   by the Free Software Foundation; version 2 of the License, or
Packit 6c4009
   (at your option) any later version.
Packit 6c4009
Packit 6c4009
   This program is distributed in the hope that it will be useful,
Packit 6c4009
   but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 6c4009
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Packit 6c4009
   GNU General Public License for more details.
Packit 6c4009
Packit 6c4009
   You should have received a copy of the GNU General Public License
Packit 6c4009
   along with this program; if not, see <http://www.gnu.org/licenses/>.  */
Packit 6c4009
Packit 6c4009
#include <alloca.h>
Packit 6c4009
#include <assert.h>
Packit 6c4009
#include <errno.h>
Packit 6c4009
#include <error.h>
Packit 6c4009
#include <libintl.h>
Packit 6c4009
#include <netdb.h>
Packit 6c4009
#include <stdbool.h>
Packit 6c4009
#include <stddef.h>
Packit 6c4009
#include <stdio.h>
Packit 6c4009
#include <stdlib.h>
Packit 6c4009
#include <string.h>
Packit 6c4009
#include <time.h>
Packit 6c4009
#include <unistd.h>
Packit 6c4009
#include <stdint.h>
Packit 6c4009
#include <arpa/inet.h>
Packit 6c4009
#include <arpa/nameser.h>
Packit 6c4009
#include <sys/mman.h>
Packit 6c4009
#include <stackinfo.h>
Packit 6c4009
#include <scratch_buffer.h>
Packit 6c4009
Packit 6c4009
#include "nscd.h"
Packit 6c4009
#include "dbg_log.h"
Packit 6c4009
Packit 6c4009
Packit 6c4009
/* This is the standard reply in case the service is disabled.  */
Packit 6c4009
static const hst_response_header disabled =
Packit 6c4009
{
Packit 6c4009
  .version = NSCD_VERSION,
Packit 6c4009
  .found = -1,
Packit 6c4009
  .h_name_len = 0,
Packit 6c4009
  .h_aliases_cnt = 0,
Packit 6c4009
  .h_addrtype = -1,
Packit 6c4009
  .h_length = -1,
Packit 6c4009
  .h_addr_list_cnt = 0,
Packit 6c4009
  .error = NETDB_INTERNAL
Packit 6c4009
};
Packit 6c4009
Packit 6c4009
/* This is the struct describing how to write this record.  */
Packit 6c4009
const struct iovec hst_iov_disabled =
Packit 6c4009
{
Packit 6c4009
  .iov_base = (void *) &disabled,
Packit 6c4009
  .iov_len = sizeof (disabled)
Packit 6c4009
};
Packit 6c4009
Packit 6c4009
Packit 6c4009
/* This is the standard reply in case we haven't found the dataset.  */
Packit 6c4009
static const hst_response_header notfound =
Packit 6c4009
{
Packit 6c4009
  .version = NSCD_VERSION,
Packit 6c4009
  .found = 0,
Packit 6c4009
  .h_name_len = 0,
Packit 6c4009
  .h_aliases_cnt = 0,
Packit 6c4009
  .h_addrtype = -1,
Packit 6c4009
  .h_length = -1,
Packit 6c4009
  .h_addr_list_cnt = 0,
Packit 6c4009
  .error = HOST_NOT_FOUND
Packit 6c4009
};
Packit 6c4009
Packit 6c4009
Packit 6c4009
/* This is the standard reply in case there are temporary problems.  */
Packit 6c4009
static const hst_response_header tryagain =
Packit 6c4009
{
Packit 6c4009
  .version = NSCD_VERSION,
Packit 6c4009
  .found = 0,
Packit 6c4009
  .h_name_len = 0,
Packit 6c4009
  .h_aliases_cnt = 0,
Packit 6c4009
  .h_addrtype = -1,
Packit 6c4009
  .h_length = -1,
Packit 6c4009
  .h_addr_list_cnt = 0,
Packit 6c4009
  .error = TRY_AGAIN
Packit 6c4009
};
Packit 6c4009
Packit 6c4009
Packit 6c4009
static time_t
Packit 6c4009
cache_addhst (struct database_dyn *db, int fd, request_header *req,
Packit 6c4009
	      const void *key, struct hostent *hst, uid_t owner,
Packit 6c4009
	      struct hashentry *const he, struct datahead *dh, int errval,
Packit 6c4009
	      int32_t ttl)
Packit 6c4009
{
Packit 6c4009
  bool all_written = true;
Packit 6c4009
  time_t t = time (NULL);
Packit 6c4009
Packit 6c4009
  /* We allocate all data in one memory block: the iov vector,
Packit 6c4009
     the response header and the dataset itself.  */
Packit 6c4009
  struct dataset
Packit 6c4009
  {
Packit 6c4009
    struct datahead head;
Packit 6c4009
    hst_response_header resp;
Packit 6c4009
    char strdata[0];
Packit 6c4009
  } *dataset;
Packit 6c4009
Packit 6c4009
  assert (offsetof (struct dataset, resp) == offsetof (struct datahead, data));
Packit 6c4009
Packit 6c4009
  time_t timeout = MAX_TIMEOUT_VALUE;
Packit 6c4009
  if (hst == NULL)
Packit 6c4009
    {
Packit 6c4009
      if (he != NULL && errval == EAGAIN)
Packit 6c4009
	{
Packit 6c4009
	  /* If we have an old record available but cannot find one
Packit 6c4009
	     now because the service is not available we keep the old
Packit 6c4009
	     record and make sure it does not get removed.  */
Packit 6c4009
	  if (reload_count != UINT_MAX)
Packit 6c4009
	    /* Do not reset the value if we never not reload the record.  */
Packit 6c4009
	    dh->nreloads = reload_count - 1;
Packit 6c4009
Packit 6c4009
	  /* Reload with the same time-to-live value.  */
Packit 6c4009
	  timeout = dh->timeout = t + dh->ttl;
Packit 6c4009
	}
Packit 6c4009
      else
Packit 6c4009
	{
Packit 6c4009
	  /* We have no data.  This means we send the standard reply for this
Packit 6c4009
	     case.  Possibly this is only temporary.  */
Packit 6c4009
	  ssize_t total = sizeof (notfound);
Packit 6c4009
	  assert (sizeof (notfound) == sizeof (tryagain));
Packit 6c4009
Packit 6c4009
	  const hst_response_header *resp = (errval == EAGAIN
Packit 6c4009
					     ? &tryagain : &notfound);
Packit 6c4009
Packit 6c4009
	  if (fd != -1 &&
Packit 6c4009
	      TEMP_FAILURE_RETRY (send (fd, resp, total,
Packit 6c4009
					MSG_NOSIGNAL)) != total)
Packit 6c4009
	    all_written = false;
Packit 6c4009
Packit 6c4009
	  /* If we have a transient error or cannot permanently store
Packit 6c4009
	     the result, so be it.  */
Packit 6c4009
	  if (errval == EAGAIN || __builtin_expect (db->negtimeout == 0, 0))
Packit 6c4009
	    {
Packit 6c4009
	      /* Mark the old entry as obsolete.  */
Packit 6c4009
	      if (dh != NULL)
Packit 6c4009
		dh->usable = false;
Packit 6c4009
	    }
Packit 6c4009
	  else if ((dataset = mempool_alloc (db, (sizeof (struct dataset)
Packit 6c4009
						  + req->key_len), 1)) != NULL)
Packit 6c4009
	    {
Packit 6c4009
	      timeout = datahead_init_neg (&dataset->head,
Packit 6c4009
					   (sizeof (struct dataset)
Packit 6c4009
					    + req->key_len), total,
Packit 6c4009
					   (ttl == INT32_MAX
Packit 6c4009
					    ? db->negtimeout : ttl));
Packit 6c4009
Packit 6c4009
	      /* This is the reply.  */
Packit 6c4009
	      memcpy (&dataset->resp, resp, total);
Packit 6c4009
Packit 6c4009
	      /* Copy the key data.  */
Packit 6c4009
	      memcpy (dataset->strdata, key, req->key_len);
Packit 6c4009
Packit 6c4009
	      /* If necessary, we also propagate the data to disk.  */
Packit 6c4009
	      if (db->persistent)
Packit 6c4009
		{
Packit 6c4009
		  // XXX async OK?
Packit 6c4009
		  uintptr_t pval = (uintptr_t) dataset & ~pagesize_m1;
Packit 6c4009
		  msync ((void *) pval,
Packit 6c4009
			 ((uintptr_t) dataset & pagesize_m1)
Packit 6c4009
			 + sizeof (struct dataset) + req->key_len, MS_ASYNC);
Packit 6c4009
		}
Packit 6c4009
Packit 6c4009
	      (void) cache_add (req->type, &dataset->strdata, req->key_len,
Packit 6c4009
				&dataset->head, true, db, owner, he == NULL);
Packit 6c4009
Packit 6c4009
	      pthread_rwlock_unlock (&db->lock);
Packit 6c4009
Packit 6c4009
	      /* Mark the old entry as obsolete.  */
Packit 6c4009
	      if (dh != NULL)
Packit 6c4009
		dh->usable = false;
Packit 6c4009
	    }
Packit 6c4009
	}
Packit 6c4009
    }
Packit 6c4009
  else
Packit 6c4009
    {
Packit 6c4009
      /* Determine the I/O structure.  */
Packit 6c4009
      size_t h_name_len = strlen (hst->h_name) + 1;
Packit 6c4009
      size_t h_aliases_cnt;
Packit 6c4009
      uint32_t *h_aliases_len;
Packit 6c4009
      size_t h_addr_list_cnt;
Packit 6c4009
      char *addresses;
Packit 6c4009
      char *aliases;
Packit 6c4009
      char *key_copy = NULL;
Packit 6c4009
      char *cp;
Packit 6c4009
      size_t cnt;
Packit 6c4009
      ssize_t total;
Packit 6c4009
Packit 6c4009
      /* Determine the number of aliases.  */
Packit 6c4009
      h_aliases_cnt = 0;
Packit 6c4009
      for (cnt = 0; hst->h_aliases[cnt] != NULL; ++cnt)
Packit 6c4009
	++h_aliases_cnt;
Packit 6c4009
      /* Determine the length of all aliases.  */
Packit 6c4009
      h_aliases_len = (uint32_t *) alloca (h_aliases_cnt * sizeof (uint32_t));
Packit 6c4009
      total = 0;
Packit 6c4009
      for (cnt = 0; cnt < h_aliases_cnt; ++cnt)
Packit 6c4009
	{
Packit 6c4009
	  h_aliases_len[cnt] = strlen (hst->h_aliases[cnt]) + 1;
Packit 6c4009
	  total += h_aliases_len[cnt];
Packit 6c4009
	}
Packit 6c4009
Packit 6c4009
      /* Determine the number of addresses.  */
Packit 6c4009
      h_addr_list_cnt = 0;
Packit 6c4009
      while (hst->h_addr_list[h_addr_list_cnt] != NULL)
Packit 6c4009
	++h_addr_list_cnt;
Packit 6c4009
Packit 6c4009
      if (h_addr_list_cnt == 0)
Packit 6c4009
	/* Invalid entry.  */
Packit 6c4009
	return MAX_TIMEOUT_VALUE;
Packit 6c4009
Packit 6c4009
      total += (sizeof (struct dataset)
Packit 6c4009
		+ h_name_len
Packit 6c4009
		+ h_aliases_cnt * sizeof (uint32_t)
Packit 6c4009
		+ h_addr_list_cnt * hst->h_length);
Packit 6c4009
Packit 6c4009
      /* If we refill the cache, first assume the reconrd did not
Packit 6c4009
	 change.  Allocate memory on the cache since it is likely
Packit 6c4009
	 discarded anyway.  If it turns out to be necessary to have a
Packit 6c4009
	 new record we can still allocate real memory.  */
Packit 6c4009
      bool alloca_used = false;
Packit 6c4009
      dataset = NULL;
Packit 6c4009
Packit 6c4009
      /* If the record contains more than one IP address (used for
Packit 6c4009
	 load balancing etc) don't cache the entry.  This is something
Packit 6c4009
	 the current cache handling cannot handle and it is more than
Packit 6c4009
	 questionable whether it is worthwhile complicating the cache
Packit 6c4009
	 handling just for handling such a special case. */
Packit 6c4009
      if (he == NULL && h_addr_list_cnt == 1)
Packit 6c4009
	dataset = (struct dataset *) mempool_alloc (db, total + req->key_len,
Packit 6c4009
						    1);
Packit 6c4009
Packit 6c4009
      if (dataset == NULL)
Packit 6c4009
	{
Packit 6c4009
	  /* We cannot permanently add the result in the moment.  But
Packit 6c4009
	     we can provide the result as is.  Store the data in some
Packit 6c4009
	     temporary memory.  */
Packit 6c4009
	  dataset = (struct dataset *) alloca (total + req->key_len);
Packit 6c4009
Packit 6c4009
	  /* We cannot add this record to the permanent database.  */
Packit 6c4009
	  alloca_used = true;
Packit 6c4009
	}
Packit 6c4009
Packit 6c4009
      timeout = datahead_init_pos (&dataset->head, total + req->key_len,
Packit 6c4009
				   total - offsetof (struct dataset, resp),
Packit 6c4009
				   he == NULL ? 0 : dh->nreloads + 1,
Packit 6c4009
				   ttl == INT32_MAX ? db->postimeout : ttl);
Packit 6c4009
Packit 6c4009
      dataset->resp.version = NSCD_VERSION;
Packit 6c4009
      dataset->resp.found = 1;
Packit 6c4009
      dataset->resp.h_name_len = h_name_len;
Packit 6c4009
      dataset->resp.h_aliases_cnt = h_aliases_cnt;
Packit 6c4009
      dataset->resp.h_addrtype = hst->h_addrtype;
Packit 6c4009
      dataset->resp.h_length = hst->h_length;
Packit 6c4009
      dataset->resp.h_addr_list_cnt = h_addr_list_cnt;
Packit 6c4009
      dataset->resp.error = NETDB_SUCCESS;
Packit 6c4009
Packit 6c4009
      /* Make sure there is no gap.  */
Packit 6c4009
      assert ((char *) (&dataset->resp.error + 1) == dataset->strdata);
Packit 6c4009
Packit 6c4009
      cp = dataset->strdata;
Packit 6c4009
Packit 6c4009
      cp = mempcpy (cp, hst->h_name, h_name_len);
Packit 6c4009
      cp = mempcpy (cp, h_aliases_len, h_aliases_cnt * sizeof (uint32_t));
Packit 6c4009
Packit 6c4009
      /* The normal addresses first.  */
Packit 6c4009
      addresses = cp;
Packit 6c4009
      for (cnt = 0; cnt < h_addr_list_cnt; ++cnt)
Packit 6c4009
	cp = mempcpy (cp, hst->h_addr_list[cnt], hst->h_length);
Packit 6c4009
Packit 6c4009
      /* Then the aliases.  */
Packit 6c4009
      aliases = cp;
Packit 6c4009
      for (cnt = 0; cnt < h_aliases_cnt; ++cnt)
Packit 6c4009
	cp = mempcpy (cp, hst->h_aliases[cnt], h_aliases_len[cnt]);
Packit 6c4009
Packit 6c4009
      assert (cp
Packit 6c4009
	      == dataset->strdata + total - offsetof (struct dataset,
Packit 6c4009
						      strdata));
Packit 6c4009
Packit 6c4009
      /* If we are adding a GETHOSTBYNAME{,v6} entry we must be prepared
Packit 6c4009
	 that the answer we get from the NSS does not contain the key
Packit 6c4009
	 itself.  This is the case if the resolver is used and the name
Packit 6c4009
	 is extended by the domainnames from /etc/resolv.conf.  Therefore
Packit 6c4009
	 we explicitly add the name here.  */
Packit 6c4009
      key_copy = memcpy (cp, key, req->key_len);
Packit 6c4009
Packit 6c4009
      assert ((char *) &dataset->resp + dataset->head.recsize == cp);
Packit 6c4009
Packit 6c4009
      /* Now we can determine whether on refill we have to create a new
Packit 6c4009
	 record or not.  */
Packit 6c4009
      if (he != NULL)
Packit 6c4009
	{
Packit 6c4009
	  assert (fd == -1);
Packit 6c4009
Packit 6c4009
	  if (total + req->key_len == dh->allocsize
Packit 6c4009
	      && total - offsetof (struct dataset, resp) == dh->recsize
Packit 6c4009
	      && memcmp (&dataset->resp, dh->data,
Packit 6c4009
			 dh->allocsize - offsetof (struct dataset, resp)) == 0)
Packit 6c4009
	    {
Packit 6c4009
	      /* The data has not changed.  We will just bump the
Packit 6c4009
		 timeout value.  Note that the new record has been
Packit 6c4009
		 allocated on the stack and need not be freed.  */
Packit 6c4009
	      assert (h_addr_list_cnt == 1);
Packit 6c4009
	      dh->ttl = dataset->head.ttl;
Packit 6c4009
	      dh->timeout = dataset->head.timeout;
Packit 6c4009
	      ++dh->nreloads;
Packit 6c4009
	    }
Packit 6c4009
	  else
Packit 6c4009
	    {
Packit 6c4009
	      if (h_addr_list_cnt == 1)
Packit 6c4009
		{
Packit 6c4009
		  /* We have to create a new record.  Just allocate
Packit 6c4009
		     appropriate memory and copy it.  */
Packit 6c4009
		  struct dataset *newp
Packit 6c4009
		    = (struct dataset *) mempool_alloc (db,
Packit 6c4009
							total + req->key_len,
Packit 6c4009
							1);
Packit 6c4009
		  if (newp != NULL)
Packit 6c4009
		    {
Packit 6c4009
		      /* Adjust pointers into the memory block.  */
Packit 6c4009
		      addresses = (char *) newp + (addresses
Packit 6c4009
						   - (char *) dataset);
Packit 6c4009
		      aliases = (char *) newp + (aliases - (char *) dataset);
Packit 6c4009
		      assert (key_copy != NULL);
Packit 6c4009
		      key_copy = (char *) newp + (key_copy - (char *) dataset);
Packit 6c4009
Packit 6c4009
		      dataset = memcpy (newp, dataset, total + req->key_len);
Packit 6c4009
		      alloca_used = false;
Packit 6c4009
		    }
Packit 6c4009
		}
Packit 6c4009
Packit 6c4009
	      /* Mark the old record as obsolete.  */
Packit 6c4009
	      dh->usable = false;
Packit 6c4009
	    }
Packit 6c4009
	}
Packit 6c4009
      else
Packit 6c4009
	{
Packit 6c4009
	  /* We write the dataset before inserting it to the database
Packit 6c4009
	     since while inserting this thread might block and so would
Packit 6c4009
	     unnecessarily keep the receiver waiting.  */
Packit 6c4009
	  assert (fd != -1);
Packit 6c4009
Packit 6c4009
	  if (writeall (fd, &dataset->resp, dataset->head.recsize)
Packit 6c4009
	      != dataset->head.recsize)
Packit 6c4009
	    all_written = false;
Packit 6c4009
	}
Packit 6c4009
Packit 6c4009
      /* Add the record to the database.  But only if it has not been
Packit 6c4009
	 stored on the stack.
Packit 6c4009
Packit 6c4009
	 If the record contains more than one IP address (used for
Packit 6c4009
	 load balancing etc) don't cache the entry.  This is something
Packit 6c4009
	 the current cache handling cannot handle and it is more than
Packit 6c4009
	 questionable whether it is worthwhile complicating the cache
Packit 6c4009
	 handling just for handling such a special case. */
Packit 6c4009
      if (! alloca_used)
Packit 6c4009
	{
Packit 6c4009
	  /* If necessary, we also propagate the data to disk.  */
Packit 6c4009
	  if (db->persistent)
Packit 6c4009
	    {
Packit 6c4009
	      // XXX async OK?
Packit 6c4009
	      uintptr_t pval = (uintptr_t) dataset & ~pagesize_m1;
Packit 6c4009
	      msync ((void *) pval,
Packit 6c4009
		     ((uintptr_t) dataset & pagesize_m1)
Packit 6c4009
		     + total + req->key_len, MS_ASYNC);
Packit 6c4009
	    }
Packit 6c4009
Packit 6c4009
	  /* NB: the following code is really complicated.  It has
Packit 6c4009
	     seemlingly duplicated code paths which do the same.  The
Packit 6c4009
	     problem is that we always must add the hash table entry
Packit 6c4009
	     with the FIRST flag set first.  Otherwise we get dangling
Packit 6c4009
	     pointers in case memory allocation fails.  */
Packit 6c4009
	  assert (hst->h_addr_list[1] == NULL);
Packit 6c4009
Packit 6c4009
	  /* Avoid adding names if more than one address is available.  See
Packit 6c4009
	     above for more info.  */
Packit 6c4009
	  assert (req->type == GETHOSTBYNAME
Packit 6c4009
		  || req->type == GETHOSTBYNAMEv6
Packit 6c4009
		  || req->type == GETHOSTBYADDR
Packit 6c4009
		  || req->type == GETHOSTBYADDRv6);
Packit 6c4009
Packit 6c4009
	  (void) cache_add (req->type, key_copy, req->key_len,
Packit 6c4009
			    &dataset->head, true, db, owner, he == NULL);
Packit 6c4009
Packit 6c4009
	  pthread_rwlock_unlock (&db->lock);
Packit 6c4009
	}
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  if (__builtin_expect (!all_written, 0) && debug_level > 0)
Packit 6c4009
    {
Packit 6c4009
      char buf[256];
Packit 6c4009
      dbg_log (_("short write in %s: %s"),  __FUNCTION__,
Packit 6c4009
	       strerror_r (errno, buf, sizeof (buf)));
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  return timeout;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
Packit 6c4009
static int
Packit 6c4009
lookup (int type, void *key, struct hostent *resultbufp, char *buffer,
Packit 6c4009
	size_t buflen, struct hostent **hst, int32_t *ttlp)
Packit 6c4009
{
Packit 6c4009
  if (type == GETHOSTBYNAME)
Packit 6c4009
    return __gethostbyname3_r (key, AF_INET, resultbufp, buffer, buflen, hst,
Packit 6c4009
			       &h_errno, ttlp, NULL);
Packit 6c4009
  if (type == GETHOSTBYNAMEv6)
Packit 6c4009
    return __gethostbyname3_r (key, AF_INET6, resultbufp, buffer, buflen, hst,
Packit 6c4009
			       &h_errno, ttlp, NULL);
Packit 6c4009
  if (type == GETHOSTBYADDR)
Packit 6c4009
    return __gethostbyaddr2_r (key, NS_INADDRSZ, AF_INET, resultbufp, buffer,
Packit 6c4009
			       buflen, hst, &h_errno, ttlp);
Packit 6c4009
  return __gethostbyaddr2_r (key, NS_IN6ADDRSZ, AF_INET6, resultbufp, buffer,
Packit 6c4009
			     buflen, hst, &h_errno, ttlp);
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
Packit 6c4009
static time_t
Packit 6c4009
addhstbyX (struct database_dyn *db, int fd, request_header *req,
Packit 6c4009
	   void *key, uid_t uid, struct hashentry *he, struct datahead *dh)
Packit 6c4009
{
Packit 6c4009
  /* Search for the entry matching the key.  Please note that we don't
Packit 6c4009
     look again in the table whether the dataset is now available.  We
Packit 6c4009
     simply insert it.  It does not matter if it is in there twice.  The
Packit 6c4009
     pruning function only will look at the timestamp.  */
Packit 6c4009
  struct hostent resultbuf;
Packit 6c4009
  struct hostent *hst;
Packit 6c4009
  int errval = 0;
Packit 6c4009
  int32_t ttl = INT32_MAX;
Packit 6c4009
Packit 6c4009
  if (__glibc_unlikely (debug_level > 0))
Packit 6c4009
    {
Packit 6c4009
      const char *str;
Packit 6c4009
      char buf[INET6_ADDRSTRLEN + 1];
Packit 6c4009
      if (req->type == GETHOSTBYNAME || req->type == GETHOSTBYNAMEv6)
Packit 6c4009
	str = key;
Packit 6c4009
      else
Packit 6c4009
	str = inet_ntop (req->type == GETHOSTBYADDR ? AF_INET : AF_INET6,
Packit 6c4009
			 key, buf, sizeof (buf));
Packit 6c4009
Packit 6c4009
      if (he == NULL)
Packit 6c4009
	dbg_log (_("Haven't found \"%s\" in hosts cache!"), (char *) str);
Packit 6c4009
      else
Packit 6c4009
	dbg_log (_("Reloading \"%s\" in hosts cache!"), (char *) str);
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  struct scratch_buffer tmpbuf;
Packit 6c4009
  scratch_buffer_init (&tmpbuf);
Packit 6c4009
Packit 6c4009
  while (lookup (req->type, key, &resultbuf,
Packit 6c4009
		 tmpbuf.data, tmpbuf.length, &hst, &ttl) != 0
Packit 6c4009
	 && h_errno == NETDB_INTERNAL
Packit 6c4009
	 && (errval = errno) == ERANGE)
Packit 6c4009
    if (!scratch_buffer_grow (&tmpbuf))
Packit 6c4009
      {
Packit 6c4009
	/* We ran out of memory.  We cannot do anything but sending a
Packit 6c4009
	   negative response.  In reality this should never
Packit 6c4009
	   happen.  */
Packit 6c4009
	hst = NULL;
Packit 6c4009
	/* We set the error to indicate this is (possibly) a temporary
Packit 6c4009
	   error and that it does not mean the entry is not
Packit 6c4009
	   available at all.  */
Packit 6c4009
	h_errno = TRY_AGAIN;
Packit 6c4009
	errval = EAGAIN;
Packit 6c4009
	break;
Packit 6c4009
      }
Packit 6c4009
Packit 6c4009
  time_t timeout = cache_addhst (db, fd, req, key, hst, uid, he, dh,
Packit 6c4009
				 h_errno == TRY_AGAIN ? errval : 0, ttl);
Packit 6c4009
  scratch_buffer_free (&tmpbuf);
Packit 6c4009
  return timeout;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
Packit 6c4009
void
Packit 6c4009
addhstbyname (struct database_dyn *db, int fd, request_header *req,
Packit 6c4009
	      void *key, uid_t uid)
Packit 6c4009
{
Packit 6c4009
  addhstbyX (db, fd, req, key, uid, NULL, NULL);
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
Packit 6c4009
time_t
Packit 6c4009
readdhstbyname (struct database_dyn *db, struct hashentry *he,
Packit 6c4009
		struct datahead *dh)
Packit 6c4009
{
Packit 6c4009
  request_header req =
Packit 6c4009
    {
Packit 6c4009
      .type = GETHOSTBYNAME,
Packit 6c4009
      .key_len = he->len
Packit 6c4009
    };
Packit 6c4009
Packit 6c4009
  return addhstbyX (db, -1, &req, db->data + he->key, he->owner, he, dh);
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
Packit 6c4009
void
Packit 6c4009
addhstbyaddr (struct database_dyn *db, int fd, request_header *req,
Packit 6c4009
	      void *key, uid_t uid)
Packit 6c4009
{
Packit 6c4009
  addhstbyX (db, fd, req, key, uid, NULL, NULL);
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
Packit 6c4009
time_t
Packit 6c4009
readdhstbyaddr (struct database_dyn *db, struct hashentry *he,
Packit 6c4009
		struct datahead *dh)
Packit 6c4009
{
Packit 6c4009
  request_header req =
Packit 6c4009
    {
Packit 6c4009
      .type = GETHOSTBYADDR,
Packit 6c4009
      .key_len = he->len
Packit 6c4009
    };
Packit 6c4009
Packit 6c4009
  return addhstbyX (db, -1, &req, db->data + he->key, he->owner, he, dh);
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
Packit 6c4009
void
Packit 6c4009
addhstbynamev6 (struct database_dyn *db, int fd, request_header *req,
Packit 6c4009
		void *key, uid_t uid)
Packit 6c4009
{
Packit 6c4009
  addhstbyX (db, fd, req, key, uid, NULL, NULL);
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
Packit 6c4009
time_t
Packit 6c4009
readdhstbynamev6 (struct database_dyn *db, struct hashentry *he,
Packit 6c4009
		  struct datahead *dh)
Packit 6c4009
{
Packit 6c4009
  request_header req =
Packit 6c4009
    {
Packit 6c4009
      .type = GETHOSTBYNAMEv6,
Packit 6c4009
      .key_len = he->len
Packit 6c4009
    };
Packit 6c4009
Packit 6c4009
  return addhstbyX (db, -1, &req, db->data + he->key, he->owner, he, dh);
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
Packit 6c4009
void
Packit 6c4009
addhstbyaddrv6 (struct database_dyn *db, int fd, request_header *req,
Packit 6c4009
		void *key, uid_t uid)
Packit 6c4009
{
Packit 6c4009
  addhstbyX (db, fd, req, key, uid, NULL, NULL);
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
Packit 6c4009
time_t
Packit 6c4009
readdhstbyaddrv6 (struct database_dyn *db, struct hashentry *he,
Packit 6c4009
		  struct datahead *dh)
Packit 6c4009
{
Packit 6c4009
  request_header req =
Packit 6c4009
    {
Packit 6c4009
      .type = GETHOSTBYADDRv6,
Packit 6c4009
      .key_len = he->len
Packit 6c4009
    };
Packit 6c4009
Packit 6c4009
  return addhstbyX (db, -1, &req, db->data + he->key, he->owner, he, dh);
Packit 6c4009
}