Add support for name_to_handle_at and open_by_handle.
[glibc.git] / nscd / hstcache.c
blob101ad2a775a9d20df1a784df4bb99c44cff5d7f7
1 /* Cache handling for host lookup.
2 Copyright (C) 1998-2008, 2009, 2011 Free Software Foundation, Inc.
3 This file is part of the GNU C Library.
4 Contributed by Ulrich Drepper <drepper@cygnus.com>, 1998.
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published
8 by the Free Software Foundation; version 2 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software Foundation,
18 Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
20 #include <alloca.h>
21 #include <assert.h>
22 #include <errno.h>
23 #include <error.h>
24 #include <libintl.h>
25 #include <netdb.h>
26 #include <stdbool.h>
27 #include <stddef.h>
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <string.h>
31 #include <time.h>
32 #include <unistd.h>
33 #include <arpa/inet.h>
34 #include <arpa/nameser.h>
35 #include <sys/mman.h>
36 #include <stackinfo.h>
38 #include "nscd.h"
39 #include "dbg_log.h"
40 #ifdef HAVE_SENDFILE
41 # include <kernel-features.h>
42 #endif
45 /* This is the standard reply in case the service is disabled. */
46 static const hst_response_header disabled =
48 .version = NSCD_VERSION,
49 .found = -1,
50 .h_name_len = 0,
51 .h_aliases_cnt = 0,
52 .h_addrtype = -1,
53 .h_length = -1,
54 .h_addr_list_cnt = 0,
55 .error = NETDB_INTERNAL
58 /* This is the struct describing how to write this record. */
59 const struct iovec hst_iov_disabled =
61 .iov_base = (void *) &disabled,
62 .iov_len = sizeof (disabled)
66 /* This is the standard reply in case we haven't found the dataset. */
67 static const hst_response_header notfound =
69 .version = NSCD_VERSION,
70 .found = 0,
71 .h_name_len = 0,
72 .h_aliases_cnt = 0,
73 .h_addrtype = -1,
74 .h_length = -1,
75 .h_addr_list_cnt = 0,
76 .error = HOST_NOT_FOUND
80 /* This is the standard reply in case there are temporary problems. */
81 static const hst_response_header tryagain =
83 .version = NSCD_VERSION,
84 .found = 0,
85 .h_name_len = 0,
86 .h_aliases_cnt = 0,
87 .h_addrtype = -1,
88 .h_length = -1,
89 .h_addr_list_cnt = 0,
90 .error = TRY_AGAIN
94 static time_t
95 cache_addhst (struct database_dyn *db, int fd, request_header *req,
96 const void *key, struct hostent *hst, uid_t owner,
97 struct hashentry *const he, struct datahead *dh, int errval,
98 int32_t ttl)
100 bool all_written = true;
101 time_t t = time (NULL);
103 /* We allocate all data in one memory block: the iov vector,
104 the response header and the dataset itself. */
105 struct dataset
107 struct datahead head;
108 hst_response_header resp;
109 char strdata[0];
110 } *dataset;
112 assert (offsetof (struct dataset, resp) == offsetof (struct datahead, data));
114 time_t timeout = MAX_TIMEOUT_VALUE;
115 if (hst == NULL)
117 if (he != NULL && errval == EAGAIN)
119 /* If we have an old record available but cannot find one
120 now because the service is not available we keep the old
121 record and make sure it does not get removed. */
122 if (reload_count != UINT_MAX)
123 /* Do not reset the value if we never not reload the record. */
124 dh->nreloads = reload_count - 1;
126 /* Reload with the same time-to-live value. */
127 timeout = dh->timeout = t + dh->ttl;
129 else
131 /* We have no data. This means we send the standard reply for this
132 case. Possibly this is only temporary. */
133 ssize_t total = sizeof (notfound);
134 assert (sizeof (notfound) == sizeof (tryagain));
136 const hst_response_header *resp = (errval == EAGAIN
137 ? &tryagain : &notfound);
139 if (fd != -1 &&
140 TEMP_FAILURE_RETRY (send (fd, resp, total,
141 MSG_NOSIGNAL)) != total)
142 all_written = false;
144 dataset = mempool_alloc (db, sizeof (struct dataset) + req->key_len,
146 /* If we cannot permanently store the result, so be it. */
147 if (dataset != NULL)
149 dataset->head.allocsize = sizeof (struct dataset) + req->key_len;
150 dataset->head.recsize = total;
151 dataset->head.notfound = true;
152 dataset->head.nreloads = 0;
153 dataset->head.usable = true;
155 /* Compute the timeout time. */
156 dataset->head.ttl = ttl == INT32_MAX ? db->negtimeout : ttl;
157 timeout = dataset->head.timeout = t + dataset->head.ttl;
159 /* This is the reply. */
160 memcpy (&dataset->resp, resp, total);
162 /* Copy the key data. */
163 memcpy (dataset->strdata, key, req->key_len);
165 /* If necessary, we also propagate the data to disk. */
166 if (db->persistent)
168 // XXX async OK?
169 uintptr_t pval = (uintptr_t) dataset & ~pagesize_m1;
170 msync ((void *) pval,
171 ((uintptr_t) dataset & pagesize_m1)
172 + sizeof (struct dataset) + req->key_len, MS_ASYNC);
175 (void) cache_add (req->type, &dataset->strdata, req->key_len,
176 &dataset->head, true, db, owner, he == NULL);
178 pthread_rwlock_unlock (&db->lock);
180 /* Mark the old entry as obsolete. */
181 if (dh != NULL)
182 dh->usable = false;
186 else
188 /* Determine the I/O structure. */
189 size_t h_name_len = strlen (hst->h_name) + 1;
190 size_t h_aliases_cnt;
191 uint32_t *h_aliases_len;
192 size_t h_addr_list_cnt;
193 int addr_list_type;
194 char *addresses;
195 char *aliases;
196 char *key_copy = NULL;
197 char *cp;
198 size_t cnt;
199 ssize_t total;
201 /* Determine the number of aliases. */
202 h_aliases_cnt = 0;
203 for (cnt = 0; hst->h_aliases[cnt] != NULL; ++cnt)
204 ++h_aliases_cnt;
205 /* Determine the length of all aliases. */
206 h_aliases_len = (uint32_t *) alloca (h_aliases_cnt * sizeof (uint32_t));
207 total = 0;
208 for (cnt = 0; cnt < h_aliases_cnt; ++cnt)
210 h_aliases_len[cnt] = strlen (hst->h_aliases[cnt]) + 1;
211 total += h_aliases_len[cnt];
214 /* Determine the number of addresses. */
215 h_addr_list_cnt = 0;
216 while (hst->h_addr_list[h_addr_list_cnt] != NULL)
217 ++h_addr_list_cnt;
219 if (h_addr_list_cnt == 0)
220 /* Invalid entry. */
221 return MAX_TIMEOUT_VALUE;
223 total += (sizeof (struct dataset)
224 + h_name_len
225 + h_aliases_cnt * sizeof (uint32_t)
226 + h_addr_list_cnt * hst->h_length);
228 /* If we refill the cache, first assume the reconrd did not
229 change. Allocate memory on the cache since it is likely
230 discarded anyway. If it turns out to be necessary to have a
231 new record we can still allocate real memory. */
232 bool alloca_used = false;
233 dataset = NULL;
235 /* If the record contains more than one IP address (used for
236 load balancing etc) don't cache the entry. This is something
237 the current cache handling cannot handle and it is more than
238 questionable whether it is worthwhile complicating the cache
239 handling just for handling such a special case. */
240 if (he == NULL && h_addr_list_cnt == 1)
241 dataset = (struct dataset *) mempool_alloc (db, total + req->key_len,
244 if (dataset == NULL)
246 /* We cannot permanently add the result in the moment. But
247 we can provide the result as is. Store the data in some
248 temporary memory. */
249 dataset = (struct dataset *) alloca (total + req->key_len);
251 /* We cannot add this record to the permanent database. */
252 alloca_used = true;
255 dataset->head.allocsize = total + req->key_len;
256 dataset->head.recsize = total - offsetof (struct dataset, resp);
257 dataset->head.notfound = false;
258 dataset->head.nreloads = he == NULL ? 0 : (dh->nreloads + 1);
259 dataset->head.usable = true;
261 /* Compute the timeout time. */
262 dataset->head.ttl = ttl == INT32_MAX ? db->postimeout : ttl;
263 timeout = dataset->head.timeout = t + dataset->head.ttl;
265 dataset->resp.version = NSCD_VERSION;
266 dataset->resp.found = 1;
267 dataset->resp.h_name_len = h_name_len;
268 dataset->resp.h_aliases_cnt = h_aliases_cnt;
269 dataset->resp.h_addrtype = hst->h_addrtype;
270 dataset->resp.h_length = hst->h_length;
271 dataset->resp.h_addr_list_cnt = h_addr_list_cnt;
272 dataset->resp.error = NETDB_SUCCESS;
274 /* Make sure there is no gap. */
275 assert ((char *) (&dataset->resp.error + 1) == dataset->strdata);
277 cp = dataset->strdata;
279 cp = mempcpy (cp, hst->h_name, h_name_len);
280 cp = mempcpy (cp, h_aliases_len, h_aliases_cnt * sizeof (uint32_t));
282 /* The normal addresses first. */
283 addresses = cp;
284 for (cnt = 0; cnt < h_addr_list_cnt; ++cnt)
285 cp = mempcpy (cp, hst->h_addr_list[cnt], hst->h_length);
287 /* Then the aliases. */
288 aliases = cp;
289 for (cnt = 0; cnt < h_aliases_cnt; ++cnt)
290 cp = mempcpy (cp, hst->h_aliases[cnt], h_aliases_len[cnt]);
292 assert (cp
293 == dataset->strdata + total - offsetof (struct dataset,
294 strdata));
296 /* If we are adding a GETHOSTBYNAME{,v6} entry we must be prepared
297 that the answer we get from the NSS does not contain the key
298 itself. This is the case if the resolver is used and the name
299 is extended by the domainnames from /etc/resolv.conf. Therefore
300 we explicitly add the name here. */
301 key_copy = memcpy (cp, key, req->key_len);
303 assert ((char *) &dataset->resp + dataset->head.recsize == cp);
305 /* Now we can determine whether on refill we have to create a new
306 record or not. */
307 if (he != NULL)
309 assert (fd == -1);
311 if (total + req->key_len == dh->allocsize
312 && total - offsetof (struct dataset, resp) == dh->recsize
313 && memcmp (&dataset->resp, dh->data,
314 dh->allocsize - offsetof (struct dataset, resp)) == 0)
316 /* The data has not changed. We will just bump the
317 timeout value. Note that the new record has been
318 allocated on the stack and need not be freed. */
319 assert (h_addr_list_cnt == 1);
320 dh->ttl = dataset->head.ttl;
321 dh->timeout = dataset->head.timeout;
322 ++dh->nreloads;
324 else
326 if (h_addr_list_cnt == 1)
328 /* We have to create a new record. Just allocate
329 appropriate memory and copy it. */
330 struct dataset *newp
331 = (struct dataset *) mempool_alloc (db,
332 total + req->key_len,
334 if (newp != NULL)
336 /* Adjust pointers into the memory block. */
337 addresses = (char *) newp + (addresses
338 - (char *) dataset);
339 aliases = (char *) newp + (aliases - (char *) dataset);
340 assert (key_copy != NULL);
341 key_copy = (char *) newp + (key_copy - (char *) dataset);
343 dataset = memcpy (newp, dataset, total + req->key_len);
344 alloca_used = false;
348 /* Mark the old record as obsolete. */
349 dh->usable = false;
352 else
354 /* We write the dataset before inserting it to the database
355 since while inserting this thread might block and so would
356 unnecessarily keep the receiver waiting. */
357 assert (fd != -1);
359 #ifdef HAVE_SENDFILE
360 if (__builtin_expect (db->mmap_used, 1) && !alloca_used)
362 assert (db->wr_fd != -1);
363 assert ((char *) &dataset->resp > (char *) db->data);
364 assert ((char *) dataset - (char *) db->head
365 + total
366 <= (sizeof (struct database_pers_head)
367 + db->head->module * sizeof (ref_t)
368 + db->head->data_size));
369 ssize_t written = sendfileall (fd, db->wr_fd,
370 (char *) &dataset->resp
371 - (char *) db->head,
372 dataset->head.recsize);
373 if (written != dataset->head.recsize)
375 # ifndef __ASSUME_SENDFILE
376 if (written == -1 && errno == ENOSYS)
377 goto use_write;
378 # endif
379 all_written = false;
382 else
383 # ifndef __ASSUME_SENDFILE
384 use_write:
385 # endif
386 #endif
387 if (writeall (fd, &dataset->resp, dataset->head.recsize)
388 != dataset->head.recsize)
389 all_written = false;
392 /* Add the record to the database. But only if it has not been
393 stored on the stack.
395 If the record contains more than one IP address (used for
396 load balancing etc) don't cache the entry. This is something
397 the current cache handling cannot handle and it is more than
398 questionable whether it is worthwhile complicating the cache
399 handling just for handling such a special case. */
400 if (! alloca_used)
402 /* If necessary, we also propagate the data to disk. */
403 if (db->persistent)
405 // XXX async OK?
406 uintptr_t pval = (uintptr_t) dataset & ~pagesize_m1;
407 msync ((void *) pval,
408 ((uintptr_t) dataset & pagesize_m1)
409 + total + req->key_len, MS_ASYNC);
412 addr_list_type = (hst->h_length == NS_INADDRSZ
413 ? GETHOSTBYADDR : GETHOSTBYADDRv6);
415 /* NB: the following code is really complicated. It has
416 seemlingly duplicated code paths which do the same. The
417 problem is that we always must add the hash table entry
418 with the FIRST flag set first. Otherwise we get dangling
419 pointers in case memory allocation fails. */
420 assert (hst->h_addr_list[1] == NULL);
422 /* Avoid adding names if more than one address is available. See
423 above for more info. */
424 assert (req->type == GETHOSTBYNAME
425 || req->type == GETHOSTBYNAMEv6
426 || req->type == GETHOSTBYADDR
427 || req->type == GETHOSTBYADDRv6);
429 (void) cache_add (req->type, key_copy, req->key_len,
430 &dataset->head, true, db, owner, he == NULL);
432 pthread_rwlock_unlock (&db->lock);
436 if (__builtin_expect (!all_written, 0) && debug_level > 0)
438 char buf[256];
439 dbg_log (_("short write in %s: %s"), __FUNCTION__,
440 strerror_r (errno, buf, sizeof (buf)));
443 return timeout;
447 static int
448 lookup (int type, void *key, struct hostent *resultbufp, char *buffer,
449 size_t buflen, struct hostent **hst, int32_t *ttlp)
451 if (type == GETHOSTBYNAME)
452 return __gethostbyname3_r (key, AF_INET, resultbufp, buffer, buflen, hst,
453 &h_errno, ttlp, NULL);
454 if (type == GETHOSTBYNAMEv6)
455 return __gethostbyname3_r (key, AF_INET6, resultbufp, buffer, buflen, hst,
456 &h_errno, ttlp, NULL);
457 if (type == GETHOSTBYADDR)
458 return __gethostbyaddr2_r (key, NS_INADDRSZ, AF_INET, resultbufp, buffer,
459 buflen, hst, &h_errno, ttlp);
460 return __gethostbyaddr2_r (key, NS_IN6ADDRSZ, AF_INET6, resultbufp, buffer,
461 buflen, hst, &h_errno, ttlp);
465 static time_t
466 addhstbyX (struct database_dyn *db, int fd, request_header *req,
467 void *key, uid_t uid, struct hashentry *he, struct datahead *dh)
469 /* Search for the entry matching the key. Please note that we don't
470 look again in the table whether the dataset is now available. We
471 simply insert it. It does not matter if it is in there twice. The
472 pruning function only will look at the timestamp. */
473 int buflen = 1024;
474 char *buffer = (char *) alloca (buflen);
475 struct hostent resultbuf;
476 struct hostent *hst;
477 bool use_malloc = false;
478 int errval = 0;
479 int32_t ttl = INT32_MAX;
481 if (__builtin_expect (debug_level > 0, 0))
483 const char *str;
484 char buf[INET6_ADDRSTRLEN + 1];
485 if (req->type == GETHOSTBYNAME || req->type == GETHOSTBYNAMEv6)
486 str = key;
487 else
488 str = inet_ntop (req->type == GETHOSTBYADDR ? AF_INET : AF_INET6,
489 key, buf, sizeof (buf));
491 if (he == NULL)
492 dbg_log (_("Haven't found \"%s\" in hosts cache!"), (char *) str);
493 else
494 dbg_log (_("Reloading \"%s\" in hosts cache!"), (char *) str);
497 while (lookup (req->type, key, &resultbuf, buffer, buflen, &hst, &ttl) != 0
498 && h_errno == NETDB_INTERNAL
499 && (errval = errno) == ERANGE)
501 errno = 0;
503 if (__builtin_expect (buflen > 32768, 0))
505 char *old_buffer = buffer;
506 buflen *= 2;
507 buffer = (char *) realloc (use_malloc ? buffer : NULL, buflen);
508 if (buffer == NULL)
510 /* We ran out of memory. We cannot do anything but
511 sending a negative response. In reality this should
512 never happen. */
513 hst = NULL;
514 buffer = old_buffer;
516 /* We set the error to indicate this is (possibly) a
517 temporary error and that it does not mean the entry
518 is not available at all. */
519 h_errno = TRY_AGAIN;
520 errval = EAGAIN;
521 break;
523 use_malloc = true;
525 else
526 /* Allocate a new buffer on the stack. If possible combine it
527 with the previously allocated buffer. */
528 buffer = (char *) extend_alloca (buffer, buflen, 2 * buflen);
531 time_t timeout = cache_addhst (db, fd, req, key, hst, uid, he, dh,
532 h_errno == TRY_AGAIN ? errval : 0, ttl);
534 if (use_malloc)
535 free (buffer);
537 return timeout;
541 void
542 addhstbyname (struct database_dyn *db, int fd, request_header *req,
543 void *key, uid_t uid)
545 addhstbyX (db, fd, req, key, uid, NULL, NULL);
549 time_t
550 readdhstbyname (struct database_dyn *db, struct hashentry *he,
551 struct datahead *dh)
553 request_header req =
555 .type = GETHOSTBYNAME,
556 .key_len = he->len
559 return addhstbyX (db, -1, &req, db->data + he->key, he->owner, he, dh);
563 void
564 addhstbyaddr (struct database_dyn *db, int fd, request_header *req,
565 void *key, uid_t uid)
567 addhstbyX (db, fd, req, key, uid, NULL, NULL);
571 time_t
572 readdhstbyaddr (struct database_dyn *db, struct hashentry *he,
573 struct datahead *dh)
575 request_header req =
577 .type = GETHOSTBYADDR,
578 .key_len = he->len
581 return addhstbyX (db, -1, &req, db->data + he->key, he->owner, he, dh);
585 void
586 addhstbynamev6 (struct database_dyn *db, int fd, request_header *req,
587 void *key, uid_t uid)
589 addhstbyX (db, fd, req, key, uid, NULL, NULL);
593 time_t
594 readdhstbynamev6 (struct database_dyn *db, struct hashentry *he,
595 struct datahead *dh)
597 request_header req =
599 .type = GETHOSTBYNAMEv6,
600 .key_len = he->len
603 return addhstbyX (db, -1, &req, db->data + he->key, he->owner, he, dh);
607 void
608 addhstbyaddrv6 (struct database_dyn *db, int fd, request_header *req,
609 void *key, uid_t uid)
611 addhstbyX (db, fd, req, key, uid, NULL, NULL);
615 time_t
616 readdhstbyaddrv6 (struct database_dyn *db, struct hashentry *he,
617 struct datahead *dh)
619 request_header req =
621 .type = GETHOSTBYADDRv6,
622 .key_len = he->len
625 return addhstbyX (db, -1, &req, db->data + he->key, he->owner, he, dh);