Fix build with multiarch disabled.
[glibc.git] / nscd / hstcache.c
blob1ab5860f2dc9c49a44fd671a1e27cda52bb0a5d8
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 char *addresses;
194 char *aliases;
195 char *key_copy = NULL;
196 char *cp;
197 size_t cnt;
198 ssize_t total;
200 /* Determine the number of aliases. */
201 h_aliases_cnt = 0;
202 for (cnt = 0; hst->h_aliases[cnt] != NULL; ++cnt)
203 ++h_aliases_cnt;
204 /* Determine the length of all aliases. */
205 h_aliases_len = (uint32_t *) alloca (h_aliases_cnt * sizeof (uint32_t));
206 total = 0;
207 for (cnt = 0; cnt < h_aliases_cnt; ++cnt)
209 h_aliases_len[cnt] = strlen (hst->h_aliases[cnt]) + 1;
210 total += h_aliases_len[cnt];
213 /* Determine the number of addresses. */
214 h_addr_list_cnt = 0;
215 while (hst->h_addr_list[h_addr_list_cnt] != NULL)
216 ++h_addr_list_cnt;
218 if (h_addr_list_cnt == 0)
219 /* Invalid entry. */
220 return MAX_TIMEOUT_VALUE;
222 total += (sizeof (struct dataset)
223 + h_name_len
224 + h_aliases_cnt * sizeof (uint32_t)
225 + h_addr_list_cnt * hst->h_length);
227 /* If we refill the cache, first assume the reconrd did not
228 change. Allocate memory on the cache since it is likely
229 discarded anyway. If it turns out to be necessary to have a
230 new record we can still allocate real memory. */
231 bool alloca_used = false;
232 dataset = NULL;
234 /* If the record contains more than one IP address (used for
235 load balancing etc) don't cache the entry. This is something
236 the current cache handling cannot handle and it is more than
237 questionable whether it is worthwhile complicating the cache
238 handling just for handling such a special case. */
239 if (he == NULL && h_addr_list_cnt == 1)
240 dataset = (struct dataset *) mempool_alloc (db, total + req->key_len,
243 if (dataset == NULL)
245 /* We cannot permanently add the result in the moment. But
246 we can provide the result as is. Store the data in some
247 temporary memory. */
248 dataset = (struct dataset *) alloca (total + req->key_len);
250 /* We cannot add this record to the permanent database. */
251 alloca_used = true;
254 dataset->head.allocsize = total + req->key_len;
255 dataset->head.recsize = total - offsetof (struct dataset, resp);
256 dataset->head.notfound = false;
257 dataset->head.nreloads = he == NULL ? 0 : (dh->nreloads + 1);
258 dataset->head.usable = true;
260 /* Compute the timeout time. */
261 dataset->head.ttl = ttl == INT32_MAX ? db->postimeout : ttl;
262 timeout = dataset->head.timeout = t + dataset->head.ttl;
264 dataset->resp.version = NSCD_VERSION;
265 dataset->resp.found = 1;
266 dataset->resp.h_name_len = h_name_len;
267 dataset->resp.h_aliases_cnt = h_aliases_cnt;
268 dataset->resp.h_addrtype = hst->h_addrtype;
269 dataset->resp.h_length = hst->h_length;
270 dataset->resp.h_addr_list_cnt = h_addr_list_cnt;
271 dataset->resp.error = NETDB_SUCCESS;
273 /* Make sure there is no gap. */
274 assert ((char *) (&dataset->resp.error + 1) == dataset->strdata);
276 cp = dataset->strdata;
278 cp = mempcpy (cp, hst->h_name, h_name_len);
279 cp = mempcpy (cp, h_aliases_len, h_aliases_cnt * sizeof (uint32_t));
281 /* The normal addresses first. */
282 addresses = cp;
283 for (cnt = 0; cnt < h_addr_list_cnt; ++cnt)
284 cp = mempcpy (cp, hst->h_addr_list[cnt], hst->h_length);
286 /* Then the aliases. */
287 aliases = cp;
288 for (cnt = 0; cnt < h_aliases_cnt; ++cnt)
289 cp = mempcpy (cp, hst->h_aliases[cnt], h_aliases_len[cnt]);
291 assert (cp
292 == dataset->strdata + total - offsetof (struct dataset,
293 strdata));
295 /* If we are adding a GETHOSTBYNAME{,v6} entry we must be prepared
296 that the answer we get from the NSS does not contain the key
297 itself. This is the case if the resolver is used and the name
298 is extended by the domainnames from /etc/resolv.conf. Therefore
299 we explicitly add the name here. */
300 key_copy = memcpy (cp, key, req->key_len);
302 assert ((char *) &dataset->resp + dataset->head.recsize == cp);
304 /* Now we can determine whether on refill we have to create a new
305 record or not. */
306 if (he != NULL)
308 assert (fd == -1);
310 if (total + req->key_len == dh->allocsize
311 && total - offsetof (struct dataset, resp) == dh->recsize
312 && memcmp (&dataset->resp, dh->data,
313 dh->allocsize - offsetof (struct dataset, resp)) == 0)
315 /* The data has not changed. We will just bump the
316 timeout value. Note that the new record has been
317 allocated on the stack and need not be freed. */
318 assert (h_addr_list_cnt == 1);
319 dh->ttl = dataset->head.ttl;
320 dh->timeout = dataset->head.timeout;
321 ++dh->nreloads;
323 else
325 if (h_addr_list_cnt == 1)
327 /* We have to create a new record. Just allocate
328 appropriate memory and copy it. */
329 struct dataset *newp
330 = (struct dataset *) mempool_alloc (db,
331 total + req->key_len,
333 if (newp != NULL)
335 /* Adjust pointers into the memory block. */
336 addresses = (char *) newp + (addresses
337 - (char *) dataset);
338 aliases = (char *) newp + (aliases - (char *) dataset);
339 assert (key_copy != NULL);
340 key_copy = (char *) newp + (key_copy - (char *) dataset);
342 dataset = memcpy (newp, dataset, total + req->key_len);
343 alloca_used = false;
347 /* Mark the old record as obsolete. */
348 dh->usable = false;
351 else
353 /* We write the dataset before inserting it to the database
354 since while inserting this thread might block and so would
355 unnecessarily keep the receiver waiting. */
356 assert (fd != -1);
358 #ifdef HAVE_SENDFILE
359 if (__builtin_expect (db->mmap_used, 1) && !alloca_used)
361 assert (db->wr_fd != -1);
362 assert ((char *) &dataset->resp > (char *) db->data);
363 assert ((char *) dataset - (char *) db->head
364 + total
365 <= (sizeof (struct database_pers_head)
366 + db->head->module * sizeof (ref_t)
367 + db->head->data_size));
368 ssize_t written = sendfileall (fd, db->wr_fd,
369 (char *) &dataset->resp
370 - (char *) db->head,
371 dataset->head.recsize);
372 if (written != dataset->head.recsize)
374 # ifndef __ASSUME_SENDFILE
375 if (written == -1 && errno == ENOSYS)
376 goto use_write;
377 # endif
378 all_written = false;
381 else
382 # ifndef __ASSUME_SENDFILE
383 use_write:
384 # endif
385 #endif
386 if (writeall (fd, &dataset->resp, dataset->head.recsize)
387 != dataset->head.recsize)
388 all_written = false;
391 /* Add the record to the database. But only if it has not been
392 stored on the stack.
394 If the record contains more than one IP address (used for
395 load balancing etc) don't cache the entry. This is something
396 the current cache handling cannot handle and it is more than
397 questionable whether it is worthwhile complicating the cache
398 handling just for handling such a special case. */
399 if (! alloca_used)
401 /* If necessary, we also propagate the data to disk. */
402 if (db->persistent)
404 // XXX async OK?
405 uintptr_t pval = (uintptr_t) dataset & ~pagesize_m1;
406 msync ((void *) pval,
407 ((uintptr_t) dataset & pagesize_m1)
408 + total + req->key_len, MS_ASYNC);
411 /* NB: the following code is really complicated. It has
412 seemlingly duplicated code paths which do the same. The
413 problem is that we always must add the hash table entry
414 with the FIRST flag set first. Otherwise we get dangling
415 pointers in case memory allocation fails. */
416 assert (hst->h_addr_list[1] == NULL);
418 /* Avoid adding names if more than one address is available. See
419 above for more info. */
420 assert (req->type == GETHOSTBYNAME
421 || req->type == GETHOSTBYNAMEv6
422 || req->type == GETHOSTBYADDR
423 || req->type == GETHOSTBYADDRv6);
425 (void) cache_add (req->type, key_copy, req->key_len,
426 &dataset->head, true, db, owner, he == NULL);
428 pthread_rwlock_unlock (&db->lock);
432 if (__builtin_expect (!all_written, 0) && debug_level > 0)
434 char buf[256];
435 dbg_log (_("short write in %s: %s"), __FUNCTION__,
436 strerror_r (errno, buf, sizeof (buf)));
439 return timeout;
443 static int
444 lookup (int type, void *key, struct hostent *resultbufp, char *buffer,
445 size_t buflen, struct hostent **hst, int32_t *ttlp)
447 if (type == GETHOSTBYNAME)
448 return __gethostbyname3_r (key, AF_INET, resultbufp, buffer, buflen, hst,
449 &h_errno, ttlp, NULL);
450 if (type == GETHOSTBYNAMEv6)
451 return __gethostbyname3_r (key, AF_INET6, resultbufp, buffer, buflen, hst,
452 &h_errno, ttlp, NULL);
453 if (type == GETHOSTBYADDR)
454 return __gethostbyaddr2_r (key, NS_INADDRSZ, AF_INET, resultbufp, buffer,
455 buflen, hst, &h_errno, ttlp);
456 return __gethostbyaddr2_r (key, NS_IN6ADDRSZ, AF_INET6, resultbufp, buffer,
457 buflen, hst, &h_errno, ttlp);
461 static time_t
462 addhstbyX (struct database_dyn *db, int fd, request_header *req,
463 void *key, uid_t uid, struct hashentry *he, struct datahead *dh)
465 /* Search for the entry matching the key. Please note that we don't
466 look again in the table whether the dataset is now available. We
467 simply insert it. It does not matter if it is in there twice. The
468 pruning function only will look at the timestamp. */
469 int buflen = 1024;
470 char *buffer = (char *) alloca (buflen);
471 struct hostent resultbuf;
472 struct hostent *hst;
473 bool use_malloc = false;
474 int errval = 0;
475 int32_t ttl = INT32_MAX;
477 if (__builtin_expect (debug_level > 0, 0))
479 const char *str;
480 char buf[INET6_ADDRSTRLEN + 1];
481 if (req->type == GETHOSTBYNAME || req->type == GETHOSTBYNAMEv6)
482 str = key;
483 else
484 str = inet_ntop (req->type == GETHOSTBYADDR ? AF_INET : AF_INET6,
485 key, buf, sizeof (buf));
487 if (he == NULL)
488 dbg_log (_("Haven't found \"%s\" in hosts cache!"), (char *) str);
489 else
490 dbg_log (_("Reloading \"%s\" in hosts cache!"), (char *) str);
493 while (lookup (req->type, key, &resultbuf, buffer, buflen, &hst, &ttl) != 0
494 && h_errno == NETDB_INTERNAL
495 && (errval = errno) == ERANGE)
497 errno = 0;
499 if (__builtin_expect (buflen > 32768, 0))
501 char *old_buffer = buffer;
502 buflen *= 2;
503 buffer = (char *) realloc (use_malloc ? buffer : NULL, buflen);
504 if (buffer == NULL)
506 /* We ran out of memory. We cannot do anything but
507 sending a negative response. In reality this should
508 never happen. */
509 hst = NULL;
510 buffer = old_buffer;
512 /* We set the error to indicate this is (possibly) a
513 temporary error and that it does not mean the entry
514 is not available at all. */
515 h_errno = TRY_AGAIN;
516 errval = EAGAIN;
517 break;
519 use_malloc = true;
521 else
522 /* Allocate a new buffer on the stack. If possible combine it
523 with the previously allocated buffer. */
524 buffer = (char *) extend_alloca (buffer, buflen, 2 * buflen);
527 time_t timeout = cache_addhst (db, fd, req, key, hst, uid, he, dh,
528 h_errno == TRY_AGAIN ? errval : 0, ttl);
530 if (use_malloc)
531 free (buffer);
533 return timeout;
537 void
538 addhstbyname (struct database_dyn *db, int fd, request_header *req,
539 void *key, uid_t uid)
541 addhstbyX (db, fd, req, key, uid, NULL, NULL);
545 time_t
546 readdhstbyname (struct database_dyn *db, struct hashentry *he,
547 struct datahead *dh)
549 request_header req =
551 .type = GETHOSTBYNAME,
552 .key_len = he->len
555 return addhstbyX (db, -1, &req, db->data + he->key, he->owner, he, dh);
559 void
560 addhstbyaddr (struct database_dyn *db, int fd, request_header *req,
561 void *key, uid_t uid)
563 addhstbyX (db, fd, req, key, uid, NULL, NULL);
567 time_t
568 readdhstbyaddr (struct database_dyn *db, struct hashentry *he,
569 struct datahead *dh)
571 request_header req =
573 .type = GETHOSTBYADDR,
574 .key_len = he->len
577 return addhstbyX (db, -1, &req, db->data + he->key, he->owner, he, dh);
581 void
582 addhstbynamev6 (struct database_dyn *db, int fd, request_header *req,
583 void *key, uid_t uid)
585 addhstbyX (db, fd, req, key, uid, NULL, NULL);
589 time_t
590 readdhstbynamev6 (struct database_dyn *db, struct hashentry *he,
591 struct datahead *dh)
593 request_header req =
595 .type = GETHOSTBYNAMEv6,
596 .key_len = he->len
599 return addhstbyX (db, -1, &req, db->data + he->key, he->owner, he, dh);
603 void
604 addhstbyaddrv6 (struct database_dyn *db, int fd, request_header *req,
605 void *key, uid_t uid)
607 addhstbyX (db, fd, req, key, uid, NULL, NULL);
611 time_t
612 readdhstbyaddrv6 (struct database_dyn *db, struct hashentry *he,
613 struct datahead *dh)
615 request_header req =
617 .type = GETHOSTBYADDRv6,
618 .key_len = he->len
621 return addhstbyX (db, -1, &req, db->data + he->key, he->owner, he, dh);