Back to index

glibc  2.9
Functions | Variables
nscd_getai.c File Reference
#include <assert.h>
#include <errno.h>
#include <netdb.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <not-cancel.h>
#include "nscd-client.h"
#include "nscd_proto.h"

Go to the source code of this file.

Functions

 libc_locked_map_ptr (extern, __hst_map_handle)

Variables

int __nss_not_use_nscd_hosts

Function Documentation

libc_locked_map_ptr ( extern  ,
__hst_map_handle   
)

Definition at line 37 of file nscd_getai.c.

{
  size_t keylen = strlen (key) + 1;
  int gc_cycle;
  int nretries = 0;

  /* If the mapping is available, try to search there instead of
     communicating with the nscd.  */
  struct mapped_database *mapped;
  mapped = __nscd_get_map_ref (GETFDHST, "hosts", &__hst_map_handle,
                            &gc_cycle);

 retry:;
  struct nscd_ai_result *resultbuf = NULL;
  const char *recend = (const char *) ~UINTMAX_C (0);
  char *respdata = NULL;
  int retval = -1;
  int sock = -1;
  ai_response_header ai_resp;

  if (mapped != NO_MAPPING)
    {
      struct datahead *found = __nscd_cache_search (GETAI, key, keylen,
                                              mapped);
      if (found != NULL)
       {
         respdata = (char *) (&found->data[0].aidata + 1);
         ai_resp = found->data[0].aidata;
         recend = (const char *) found->data + found->recsize;
         /* Now check if we can trust ai_resp fields.  If GC is
            in progress, it can contain anything.  */
         if (mapped->head->gc_cycle != gc_cycle)
           {
             retval = -2;
             goto out;
           }
       }
    }

  /* If we do not have the cache mapped, try to get the data over the
     socket.  */
  if (respdata == NULL)
    {
      sock = __nscd_open_socket (key, keylen, GETAI, &ai_resp,
                             sizeof (ai_resp));
      if (sock == -1)
       {
         /* nscd not running or wrong version.  */
         __nss_not_use_nscd_hosts = 1;
         goto out;
       }
    }

  if (ai_resp.found == 1)
    {
      size_t datalen = ai_resp.naddrs + ai_resp.addrslen + ai_resp.canonlen;

      /* This check really only affects the case where the data
        comes from the mapped cache.  */
      if (respdata + datalen > recend)
       {
         assert (sock == -1);
         goto out;
       }

      /* Create result.  */
      resultbuf = (struct nscd_ai_result *) malloc (sizeof (*resultbuf)
                                              + datalen);
      if (resultbuf == NULL)
       {
         *h_errnop = NETDB_INTERNAL;
         goto out_close;
       }

      /* Set up the data structure, including pointers.  */
      resultbuf->naddrs = ai_resp.naddrs;
      resultbuf->addrs = (char *) (resultbuf + 1);
      resultbuf->family = (uint8_t *) (resultbuf->addrs + ai_resp.addrslen);
      if (ai_resp.canonlen != 0)
       resultbuf->canon = (char *) (resultbuf->family + resultbuf->naddrs);
      else
       resultbuf->canon = NULL;

      if (respdata == NULL)
       {
         /* Read the data from the socket.  */
         if ((size_t) __readall (sock, resultbuf + 1, datalen) == datalen)
           {
             retval = 0;
             *result = resultbuf;
           }
         else
           {
             free (resultbuf);
             *h_errnop = NETDB_INTERNAL;
           }
       }
      else
       {
         /* Copy the data in the block.  */
         memcpy (resultbuf + 1, respdata, datalen);

         /* Try to detect corrupt databases.  */
         if (resultbuf->canon != NULL
             && resultbuf->canon[ai_resp.canonlen - 1] != '\0')
           /* We cannot use the database.  */
           {
             if (mapped->head->gc_cycle != gc_cycle)
              retval = -2;
             else
              free (resultbuf);
             goto out_close;
           }

         retval = 0;
         *result = resultbuf;
       }
    }
  else
    {
      if (__builtin_expect (ai_resp.found == -1, 0))
       {
         /* The daemon does not cache this database.  */
         __nss_not_use_nscd_hosts = 1;
         goto out_close;
       }

      /* Store the error number.  */
      *h_errnop = ai_resp.error;

      /* Set errno to 0 to indicate no error, just no found record.  */
      __set_errno (0);
      /* Even though we have not found anything, the result is zero.  */
      retval = 0;
    }

 out_close:
  if (sock != -1)
    close_not_cancel_no_status (sock);
 out:
  if (__nscd_drop_map_ref (mapped, &gc_cycle) != 0)
    {
      /* When we come here this means there has been a GC cycle while we
        were looking for the data.  This means the data might have been
        inconsistent.  Retry if possible.  */
      if ((gc_cycle & 1) != 0 || ++nretries == 5 || retval == -1)
       {
         /* nscd is just running gc now.  Disable using the mapping.  */
         if (atomic_decrement_val (&mapped->counter) == 0)
           __nscd_unmap (mapped);
         mapped = NO_MAPPING;
       }

      if (retval != -1)
       {
         *result = NULL;
         free (resultbuf);
         goto retry;
       }
    }

  return retval;
}

Here is the call graph for this function:


Variable Documentation

Definition at line 30 of file nscd_gethst_r.c.