]>
Commit | Line | Data |
---|---|---|
11bf311e | 1 | /* Copyright (C) 2004, 2005, 2006 Free Software Foundation, Inc. |
d19687d6 UD |
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> | |
d19687d6 UD |
26 | #include <not-cancel.h> |
27 | ||
28 | #include "nscd-client.h" | |
62417d7e | 29 | #include "nscd_proto.h" |
d19687d6 UD |
30 | |
31 | ||
32 | /* Define in nscd_gethst_r.c. */ | |
33 | extern int __nss_not_use_nscd_hosts; | |
34 | ||
35 | ||
ed2ced8a | 36 | /* We use the mapping from nscd_gethst. */ |
6f8a7dff | 37 | libc_locked_map_ptr (extern, __hst_map_handle) attribute_hidden; |
d19687d6 UD |
38 | |
39 | ||
40 | int | |
41 | __nscd_getai (const char *key, struct nscd_ai_result **result, int *h_errnop) | |
42 | { | |
43 | size_t keylen = strlen (key) + 1; | |
0891f970 UD |
44 | int gc_cycle; |
45 | ||
46 | /* If the mapping is available, try to search there instead of | |
47 | communicating with the nscd. */ | |
48 | struct mapped_database *mapped; | |
ed2ced8a UD |
49 | mapped = __nscd_get_map_ref (GETFDHST, "hosts", &__hst_map_handle, |
50 | &gc_cycle); | |
0891f970 UD |
51 | |
52 | retry:; | |
11bf311e | 53 | const ai_response_header *ai_resp = NULL; |
d19687d6 UD |
54 | struct nscd_ai_result *resultbuf = NULL; |
55 | const char *recend = (const char *) ~UINTMAX_C (0); | |
56 | char *respdata = NULL; | |
57 | int retval = -1; | |
58 | int sock = -1; | |
d19687d6 | 59 | |
81177191 | 60 | if (mapped != NO_MAPPING) |
d19687d6 | 61 | { |
11bf311e UD |
62 | const struct datahead *found = __nscd_cache_search (GETAI, key, keylen, |
63 | mapped); | |
d19687d6 UD |
64 | if (found != NULL) |
65 | { | |
11bf311e UD |
66 | ai_resp = &found->data[0].aidata; |
67 | respdata = (char *) (ai_resp + 1); | |
d19687d6 UD |
68 | recend = (const char *) found->data + found->recsize; |
69 | } | |
70 | } | |
71 | ||
72 | /* If we do not have the cache mapped, try to get the data over the | |
73 | socket. */ | |
11bf311e UD |
74 | ai_response_header ai_resp_mem; |
75 | if (ai_resp == NULL) | |
d19687d6 | 76 | { |
11bf311e UD |
77 | sock = __nscd_open_socket (key, keylen, GETAI, &ai_resp_mem, |
78 | sizeof (ai_resp_mem)); | |
d19687d6 UD |
79 | if (sock == -1) |
80 | { | |
6aa10807 | 81 | /* nscd not running or wrong version. */ |
d19687d6 | 82 | __nss_not_use_nscd_hosts = 1; |
81177191 | 83 | goto out; |
d19687d6 | 84 | } |
11bf311e UD |
85 | |
86 | ai_resp = &ai_resp_mem; | |
d19687d6 UD |
87 | } |
88 | ||
11bf311e | 89 | if (ai_resp->found == 1) |
d19687d6 | 90 | { |
11bf311e | 91 | size_t datalen = ai_resp->naddrs + ai_resp->addrslen + ai_resp->canonlen; |
d19687d6 | 92 | |
11bf311e | 93 | /* This check is really only affects the case where the data |
d19687d6 | 94 | comes from the mapped cache. */ |
11bf311e | 95 | if ((char *) (ai_resp + 1) + datalen > recend) |
d19687d6 UD |
96 | { |
97 | assert (sock == -1); | |
98 | goto out; | |
99 | } | |
100 | ||
101 | /* Create result. */ | |
102 | resultbuf = (struct nscd_ai_result *) malloc (sizeof (*resultbuf) | |
103 | + datalen); | |
104 | if (resultbuf == NULL) | |
105 | { | |
106 | *h_errnop = NETDB_INTERNAL; | |
8dd71997 | 107 | goto out_close; |
d19687d6 UD |
108 | } |
109 | ||
110 | /* Set up the data structure, including pointers. */ | |
11bf311e | 111 | resultbuf->naddrs = ai_resp->naddrs; |
d19687d6 | 112 | resultbuf->addrs = (char *) (resultbuf + 1); |
11bf311e UD |
113 | resultbuf->family = (uint8_t *) (resultbuf->addrs + ai_resp->addrslen); |
114 | if (ai_resp->canonlen != 0) | |
d19687d6 UD |
115 | resultbuf->canon = (char *) (resultbuf->family + resultbuf->naddrs); |
116 | else | |
117 | resultbuf->canon = NULL; | |
118 | ||
119 | if (respdata == NULL) | |
120 | { | |
121 | /* Read the data from the socket. */ | |
d2dc7d84 | 122 | if ((size_t) __readall (sock, resultbuf + 1, datalen) == datalen) |
d19687d6 UD |
123 | { |
124 | retval = 0; | |
125 | *result = resultbuf; | |
126 | } | |
0891f970 UD |
127 | else |
128 | { | |
129 | free (resultbuf); | |
130 | *h_errnop = NETDB_INTERNAL; | |
131 | } | |
d19687d6 UD |
132 | } |
133 | else | |
134 | { | |
135 | /* Copy the data in the block. */ | |
136 | memcpy (resultbuf + 1, respdata, datalen); | |
137 | ||
5429ff76 UD |
138 | /* Try to detect corrupt databases. */ |
139 | if (resultbuf->canon != NULL | |
11bf311e | 140 | && resultbuf->canon[ai_resp->canonlen - 1] != '\0') |
5429ff76 | 141 | /* We cannot use the database. */ |
8dd71997 | 142 | { |
11bf311e | 143 | free (resultbuf); |
8dd71997 UD |
144 | goto out_close; |
145 | } | |
5429ff76 | 146 | |
d19687d6 UD |
147 | retval = 0; |
148 | *result = resultbuf; | |
149 | } | |
150 | } | |
151 | else | |
152 | { | |
11bf311e | 153 | if (__builtin_expect (ai_resp->found == -1, 0)) |
6aa10807 UD |
154 | { |
155 | /* The daemon does not cache this database. */ | |
156 | __nss_not_use_nscd_hosts = 1; | |
157 | goto out_close; | |
158 | } | |
159 | ||
d19687d6 | 160 | /* Store the error number. */ |
11bf311e | 161 | *h_errnop = ai_resp->error; |
d19687d6 UD |
162 | |
163 | /* The `errno' to some value != ERANGE. */ | |
164 | __set_errno (ENOENT); | |
165 | /* Even though we have not found anything, the result is zero. */ | |
166 | retval = 0; | |
167 | } | |
168 | ||
5429ff76 | 169 | out_close: |
d19687d6 UD |
170 | if (sock != -1) |
171 | close_not_cancel_no_status (sock); | |
172 | out: | |
11bf311e | 173 | if (__nscd_drop_map_ref (mapped, &gc_cycle) != 0 && retval != -1) |
0891f970 UD |
174 | { |
175 | /* When we come here this means there has been a GC cycle while we | |
176 | were looking for the data. This means the data might have been | |
177 | inconsistent. Retry if possible. */ | |
11bf311e | 178 | if ((gc_cycle & 1) != 0) |
0891f970 UD |
179 | { |
180 | /* nscd is just running gc now. Disable using the mapping. */ | |
11bf311e | 181 | __nscd_unmap (mapped); |
0891f970 UD |
182 | mapped = NO_MAPPING; |
183 | } | |
184 | ||
11bf311e UD |
185 | *result = NULL; |
186 | free (resultbuf); | |
187 | ||
188 | goto retry; | |
0891f970 | 189 | } |
d19687d6 UD |
190 | |
191 | return retval; | |
192 | } |