Pretty printing.
[kopensolaris-gnu/glibc.git] / nscd / nscd_getai.c
1 /* Copyright (C) 2004 Free Software Foundation, Inc.
2    This file is part of the GNU C Library.
3    Contributed by Ulrich Drepper <drepper@redhat.com>, 2004.
4
5    The GNU C Library is free software; you can redistribute it and/or
6    modify it under the terms of the GNU Lesser General Public
7    License as published by the Free Software Foundation; either
8    version 2.1 of the License, or (at your option) any later version.
9
10    The GNU C Library is distributed in the hope that it will be useful,
11    but WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13    Lesser General Public License for more details.
14
15    You should have received a copy of the GNU Lesser General Public
16    License along with the GNU C Library; if not, write to the Free
17    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
18    02111-1307 USA.  */
19
20 #include <assert.h>
21 #include <errno.h>
22 #include <netdb.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <unistd.h>
26 #include <not-cancel.h>
27
28 #include "nscd-client.h"
29 #include "nscd_proto.h"
30
31
32 /* Define in nscd_gethst_r.c.  */
33 extern int __nss_not_use_nscd_hosts;
34
35
36 libc_locked_map_ptr (map_handle);
37 /* Note that we only free the structure if necessary.  The memory
38    mapping is not removed since it is not visible to the malloc
39    handling.  */
40 libc_freeres_fn (ai_map_free)
41 {
42   if (map_handle.mapped != NO_MAPPING)
43     free (map_handle.mapped);
44 }
45
46
47 int
48 __nscd_getai (const char *key, struct nscd_ai_result **result, int *h_errnop)
49 {
50   size_t keylen = strlen (key) + 1;
51   int gc_cycle;
52
53   /* If the mapping is available, try to search there instead of
54      communicating with the nscd.  */
55   struct mapped_database *mapped;
56   mapped = __nscd_get_map_ref (GETFDHST, "hosts", &map_handle, &gc_cycle);
57
58  retry:;
59   const ai_response_header *ai_resp = NULL;
60   struct nscd_ai_result *resultbuf = NULL;
61   const char *recend = (const char *) ~UINTMAX_C (0);
62   char *respdata = NULL;
63   int retval = -1;
64   int sock = -1;
65
66   if (mapped != NO_MAPPING)
67     {
68       const struct datahead *found = __nscd_cache_search (GETAI, key, keylen,
69                                                           mapped);
70       if (found != NULL)
71         {
72           ai_resp = &found->data[0].aidata;
73           respdata = (char *) (ai_resp + 1);
74           recend = (const char *) found->data + found->recsize;
75         }
76     }
77
78   /* If we do not have the cache mapped, try to get the data over the
79      socket.  */
80   ai_response_header ai_resp_mem;
81   if (ai_resp == NULL)
82     {
83       sock = __nscd_open_socket (key, keylen, GETAI, &ai_resp_mem,
84                                  sizeof (ai_resp_mem));
85       if (sock == -1)
86         {
87           /* nscd not running or wrong version or hosts caching disabled.  */
88           __nss_not_use_nscd_hosts = 1;
89           goto out;
90         }
91
92       ai_resp = &ai_resp_mem;
93     }
94
95   if (ai_resp->found == 1)
96     {
97       size_t datalen = ai_resp->naddrs + ai_resp->addrslen + ai_resp->canonlen;
98
99       /* This check is really only affects the case where the data
100          comes from the mapped cache.  */
101       if ((char *) (ai_resp + 1) + datalen > recend)
102         {
103           assert (sock == -1);
104           goto out;
105         }
106
107       /* Create result.  */
108       resultbuf = (struct nscd_ai_result *) malloc (sizeof (*resultbuf)
109                                                     + datalen);
110       if (resultbuf == NULL)
111         {
112           *h_errnop = NETDB_INTERNAL;
113           return -1;
114         }
115
116       /* Set up the data structure, including pointers.  */
117       resultbuf->naddrs = ai_resp->naddrs;
118       resultbuf->addrs = (char *) (resultbuf + 1);
119       resultbuf->family = (uint8_t *) (resultbuf->addrs + ai_resp->addrslen);
120       if (ai_resp->canonlen != 0)
121         resultbuf->canon = (char *) (resultbuf->family + resultbuf->naddrs);
122       else
123         resultbuf->canon = NULL;
124
125       if (respdata == NULL)
126         {
127           /* Read the data from the socket.  */
128           if ((size_t) TEMP_FAILURE_RETRY (__read (sock, resultbuf + 1,
129                                                    datalen)) == datalen)
130             {
131               retval = 0;
132               *result = resultbuf;
133             }
134           else
135             {
136               free (resultbuf);
137               *h_errnop = NETDB_INTERNAL;
138             }
139         }
140       else
141         {
142           /* Copy the data in the block.  */
143           memcpy (resultbuf + 1, respdata, datalen);
144
145           retval = 0;
146           *result = resultbuf;
147         }
148     }
149   else
150     {
151       /* Store the error number.  */
152       *h_errnop = ai_resp->error;
153
154       /* The `errno' to some value != ERANGE.  */
155       __set_errno (ENOENT);
156       /* Even though we have not found anything, the result is zero.  */
157       retval = 0;
158     }
159
160   if (sock != -1)
161     close_not_cancel_no_status (sock);
162  out:
163   if (__nscd_drop_map_ref (mapped, &gc_cycle) != 0 && retval != -1)
164     {
165       /* When we come here this means there has been a GC cycle while we
166          were looking for the data.  This means the data might have been
167          inconsistent.  Retry if possible.  */
168       if ((gc_cycle & 1) != 0)
169         {
170           /* nscd is just running gc now.  Disable using the mapping.  */
171           __nscd_unmap (mapped);
172           mapped = NO_MAPPING;
173         }
174
175       free (resultbuf);
176
177       goto retry;
178     }
179
180   return retval;
181 }