Replace an alloca use with a variable-length array.
[glibc.git] / nscd / hstcache.c
blobca2145212d434f1ef8fcc51df141ca4f7995624e
1 /* Cache handling for host lookup.
2 Copyright (C) 1998-2013 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, see <http://www.gnu.org/licenses/>. */
19 #include <alloca.h>
20 #include <assert.h>
21 #include <errno.h>
22 #include <error.h>
23 #include <libintl.h>
24 #include <netdb.h>
25 #include <stdbool.h>
26 #include <stddef.h>
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <string.h>
30 #include <time.h>
31 #include <unistd.h>
32 #include <arpa/inet.h>
33 #include <arpa/nameser.h>
34 #include <sys/mman.h>
35 #include <stackinfo.h>
37 #include "nscd.h"
38 #include "dbg_log.h"
39 #ifdef HAVE_SENDFILE
40 # include <kernel-features.h>
41 #endif
44 /* This is the standard reply in case the service is disabled. */
45 static const hst_response_header disabled =
47 .version = NSCD_VERSION,
48 .found = -1,
49 .h_name_len = 0,
50 .h_aliases_cnt = 0,
51 .h_addrtype = -1,
52 .h_length = -1,
53 .h_addr_list_cnt = 0,
54 .error = NETDB_INTERNAL
57 /* This is the struct describing how to write this record. */
58 const struct iovec hst_iov_disabled =
60 .iov_base = (void *) &disabled,
61 .iov_len = sizeof (disabled)
65 /* This is the standard reply in case we haven't found the dataset. */
66 static const hst_response_header notfound =
68 .version = NSCD_VERSION,
69 .found = 0,
70 .h_name_len = 0,
71 .h_aliases_cnt = 0,
72 .h_addrtype = -1,
73 .h_length = -1,
74 .h_addr_list_cnt = 0,
75 .error = HOST_NOT_FOUND
79 /* This is the standard reply in case there are temporary problems. */
80 static const hst_response_header tryagain =
82 .version = NSCD_VERSION,
83 .found = 0,
84 .h_name_len = 0,
85 .h_aliases_cnt = 0,
86 .h_addrtype = -1,
87 .h_length = -1,
88 .h_addr_list_cnt = 0,
89 .error = TRY_AGAIN
93 static time_t
94 cache_addhst (struct database_dyn *db, int fd, request_header *req,
95 const void *key, struct hostent *hst, uid_t owner,
96 struct hashentry *const he, struct datahead *dh, int errval,
97 int32_t ttl)
99 bool all_written = true;
100 time_t t = time (NULL);
102 /* We allocate all data in one memory block: the iov vector,
103 the response header and the dataset itself. */
104 struct dataset
106 struct datahead head;
107 hst_response_header resp;
108 char strdata[0];
109 } *dataset;
111 assert (offsetof (struct dataset, resp) == offsetof (struct datahead, data));
113 time_t timeout = MAX_TIMEOUT_VALUE;
114 if (hst == NULL)
116 if (he != NULL && errval == EAGAIN)
118 /* If we have an old record available but cannot find one
119 now because the service is not available we keep the old
120 record and make sure it does not get removed. */
121 if (reload_count != UINT_MAX)
122 /* Do not reset the value if we never not reload the record. */
123 dh->nreloads = reload_count - 1;
125 /* Reload with the same time-to-live value. */
126 timeout = dh->timeout = t + dh->ttl;
128 else
130 /* We have no data. This means we send the standard reply for this
131 case. Possibly this is only temporary. */
132 ssize_t total = sizeof (notfound);
133 assert (sizeof (notfound) == sizeof (tryagain));
135 const hst_response_header *resp = (errval == EAGAIN
136 ? &tryagain : &notfound);
138 if (fd != -1 &&
139 TEMP_FAILURE_RETRY (send (fd, resp, total,
140 MSG_NOSIGNAL)) != total)
141 all_written = false;
143 /* If we have a transient error or cannot permanently store
144 the result, so be it. */
145 if (errval == EAGAIN || __builtin_expect (db->negtimeout == 0, 0))
147 /* Mark the old entry as obsolete. */
148 if (dh != NULL)
149 dh->usable = false;
151 else if ((dataset = mempool_alloc (db, (sizeof (struct dataset)
152 + req->key_len), 1)) != NULL)
154 dataset->head.allocsize = sizeof (struct dataset) + req->key_len;
155 dataset->head.recsize = total;
156 dataset->head.notfound = true;
157 dataset->head.nreloads = 0;
158 dataset->head.usable = true;
160 /* Compute the timeout time. */
161 dataset->head.ttl = ttl == INT32_MAX ? db->negtimeout : ttl;
162 timeout = dataset->head.timeout = t + dataset->head.ttl;
164 /* This is the reply. */
165 memcpy (&dataset->resp, resp, total);
167 /* Copy the key data. */
168 memcpy (dataset->strdata, key, req->key_len);
170 /* If necessary, we also propagate the data to disk. */
171 if (db->persistent)
173 // XXX async OK?
174 uintptr_t pval = (uintptr_t) dataset & ~pagesize_m1;
175 msync ((void *) pval,
176 ((uintptr_t) dataset & pagesize_m1)
177 + sizeof (struct dataset) + req->key_len, MS_ASYNC);
180 (void) cache_add (req->type, &dataset->strdata, req->key_len,
181 &dataset->head, true, db, owner, he == NULL);
183 pthread_rwlock_unlock (&db->lock);
185 /* Mark the old entry as obsolete. */
186 if (dh != NULL)
187 dh->usable = false;
191 else
193 /* Determine the I/O structure. */
194 size_t h_name_len = strlen (hst->h_name) + 1;
195 size_t h_aliases_cnt;
196 uint32_t *h_aliases_len;
197 size_t h_addr_list_cnt;
198 char *addresses;
199 char *aliases;
200 char *key_copy = NULL;
201 char *cp;
202 size_t cnt;
203 ssize_t total;
205 /* Determine the number of aliases. */
206 h_aliases_cnt = 0;
207 for (cnt = 0; hst->h_aliases[cnt] != NULL; ++cnt)
208 ++h_aliases_cnt;
209 /* Determine the length of all aliases. */
210 h_aliases_len = (uint32_t *) alloca (h_aliases_cnt * sizeof (uint32_t));
211 total = 0;
212 for (cnt = 0; cnt < h_aliases_cnt; ++cnt)
214 h_aliases_len[cnt] = strlen (hst->h_aliases[cnt]) + 1;
215 total += h_aliases_len[cnt];
218 /* Determine the number of addresses. */
219 h_addr_list_cnt = 0;
220 while (hst->h_addr_list[h_addr_list_cnt] != NULL)
221 ++h_addr_list_cnt;
223 if (h_addr_list_cnt == 0)
224 /* Invalid entry. */
225 return MAX_TIMEOUT_VALUE;
227 total += (sizeof (struct dataset)
228 + h_name_len
229 + h_aliases_cnt * sizeof (uint32_t)
230 + h_addr_list_cnt * hst->h_length);
232 /* If we refill the cache, first assume the reconrd did not
233 change. Allocate memory on the cache since it is likely
234 discarded anyway. If it turns out to be necessary to have a
235 new record we can still allocate real memory. */
236 bool alloca_used = false;
237 dataset = NULL;
239 /* If the record contains more than one IP address (used for
240 load balancing etc) don't cache the entry. This is something
241 the current cache handling cannot handle and it is more than
242 questionable whether it is worthwhile complicating the cache
243 handling just for handling such a special case. */
244 if (he == NULL && h_addr_list_cnt == 1)
245 dataset = (struct dataset *) mempool_alloc (db, total + req->key_len,
248 if (dataset == NULL)
250 /* We cannot permanently add the result in the moment. But
251 we can provide the result as is. Store the data in some
252 temporary memory. */
253 dataset = (struct dataset *) alloca (total + req->key_len);
255 /* We cannot add this record to the permanent database. */
256 alloca_used = true;
259 dataset->head.allocsize = total + req->key_len;
260 dataset->head.recsize = total - offsetof (struct dataset, resp);
261 dataset->head.notfound = false;
262 dataset->head.nreloads = he == NULL ? 0 : (dh->nreloads + 1);
263 dataset->head.usable = true;
265 /* Compute the timeout time. */
266 dataset->head.ttl = ttl == INT32_MAX ? db->postimeout : ttl;
267 timeout = dataset->head.timeout = t + dataset->head.ttl;
269 dataset->resp.version = NSCD_VERSION;
270 dataset->resp.found = 1;
271 dataset->resp.h_name_len = h_name_len;
272 dataset->resp.h_aliases_cnt = h_aliases_cnt;
273 dataset->resp.h_addrtype = hst->h_addrtype;
274 dataset->resp.h_length = hst->h_length;
275 dataset->resp.h_addr_list_cnt = h_addr_list_cnt;
276 dataset->resp.error = NETDB_SUCCESS;
278 /* Make sure there is no gap. */
279 assert ((char *) (&dataset->resp.error + 1) == dataset->strdata);
281 cp = dataset->strdata;
283 cp = mempcpy (cp, hst->h_name, h_name_len);
284 cp = mempcpy (cp, h_aliases_len, h_aliases_cnt * sizeof (uint32_t));
286 /* The normal addresses first. */
287 addresses = cp;
288 for (cnt = 0; cnt < h_addr_list_cnt; ++cnt)
289 cp = mempcpy (cp, hst->h_addr_list[cnt], hst->h_length);
291 /* Then the aliases. */
292 aliases = cp;
293 for (cnt = 0; cnt < h_aliases_cnt; ++cnt)
294 cp = mempcpy (cp, hst->h_aliases[cnt], h_aliases_len[cnt]);
296 assert (cp
297 == dataset->strdata + total - offsetof (struct dataset,
298 strdata));
300 /* If we are adding a GETHOSTBYNAME{,v6} entry we must be prepared
301 that the answer we get from the NSS does not contain the key
302 itself. This is the case if the resolver is used and the name
303 is extended by the domainnames from /etc/resolv.conf. Therefore
304 we explicitly add the name here. */
305 key_copy = memcpy (cp, key, req->key_len);
307 assert ((char *) &dataset->resp + dataset->head.recsize == cp);
309 /* Now we can determine whether on refill we have to create a new
310 record or not. */
311 if (he != NULL)
313 assert (fd == -1);
315 if (total + req->key_len == dh->allocsize
316 && total - offsetof (struct dataset, resp) == dh->recsize
317 && memcmp (&dataset->resp, dh->data,
318 dh->allocsize - offsetof (struct dataset, resp)) == 0)
320 /* The data has not changed. We will just bump the
321 timeout value. Note that the new record has been
322 allocated on the stack and need not be freed. */
323 assert (h_addr_list_cnt == 1);
324 dh->ttl = dataset->head.ttl;
325 dh->timeout = dataset->head.timeout;
326 ++dh->nreloads;
328 else
330 if (h_addr_list_cnt == 1)
332 /* We have to create a new record. Just allocate
333 appropriate memory and copy it. */
334 struct dataset *newp
335 = (struct dataset *) mempool_alloc (db,
336 total + req->key_len,
338 if (newp != NULL)
340 /* Adjust pointers into the memory block. */
341 addresses = (char *) newp + (addresses
342 - (char *) dataset);
343 aliases = (char *) newp + (aliases - (char *) dataset);
344 assert (key_copy != NULL);
345 key_copy = (char *) newp + (key_copy - (char *) dataset);
347 dataset = memcpy (newp, dataset, total + req->key_len);
348 alloca_used = false;
352 /* Mark the old record as obsolete. */
353 dh->usable = false;
356 else
358 /* We write the dataset before inserting it to the database
359 since while inserting this thread might block and so would
360 unnecessarily keep the receiver waiting. */
361 assert (fd != -1);
363 #ifdef HAVE_SENDFILE
364 if (__builtin_expect (db->mmap_used, 1) && !alloca_used)
366 assert (db->wr_fd != -1);
367 assert ((char *) &dataset->resp > (char *) db->data);
368 assert ((char *) dataset - (char *) db->head
369 + total
370 <= (sizeof (struct database_pers_head)
371 + db->head->module * sizeof (ref_t)
372 + db->head->data_size));
373 ssize_t written = sendfileall (fd, db->wr_fd,
374 (char *) &dataset->resp
375 - (char *) db->head,
376 dataset->head.recsize);
377 if (written != dataset->head.recsize)
379 # ifndef __ASSUME_SENDFILE
380 if (written == -1 && errno == ENOSYS)
381 goto use_write;
382 # endif
383 all_written = false;
386 else
387 # ifndef __ASSUME_SENDFILE
388 use_write:
389 # endif
390 #endif
391 if (writeall (fd, &dataset->resp, dataset->head.recsize)
392 != dataset->head.recsize)
393 all_written = false;
396 /* Add the record to the database. But only if it has not been
397 stored on the stack.
399 If the record contains more than one IP address (used for
400 load balancing etc) don't cache the entry. This is something
401 the current cache handling cannot handle and it is more than
402 questionable whether it is worthwhile complicating the cache
403 handling just for handling such a special case. */
404 if (! alloca_used)
406 /* If necessary, we also propagate the data to disk. */
407 if (db->persistent)
409 // XXX async OK?
410 uintptr_t pval = (uintptr_t) dataset & ~pagesize_m1;
411 msync ((void *) pval,
412 ((uintptr_t) dataset & pagesize_m1)
413 + total + req->key_len, MS_ASYNC);
416 /* NB: the following code is really complicated. It has
417 seemlingly duplicated code paths which do the same. The
418 problem is that we always must add the hash table entry
419 with the FIRST flag set first. Otherwise we get dangling
420 pointers in case memory allocation fails. */
421 assert (hst->h_addr_list[1] == NULL);
423 /* Avoid adding names if more than one address is available. See
424 above for more info. */
425 assert (req->type == GETHOSTBYNAME
426 || req->type == GETHOSTBYNAMEv6
427 || req->type == GETHOSTBYADDR
428 || req->type == GETHOSTBYADDRv6);
430 (void) cache_add (req->type, key_copy, req->key_len,
431 &dataset->head, true, db, owner, he == NULL);
433 pthread_rwlock_unlock (&db->lock);
437 if (__builtin_expect (!all_written, 0) && debug_level > 0)
439 char buf[256];
440 dbg_log (_("short write in %s: %s"), __FUNCTION__,
441 strerror_r (errno, buf, sizeof (buf)));
444 return timeout;
448 static int
449 lookup (int type, void *key, struct hostent *resultbufp, char *buffer,
450 size_t buflen, struct hostent **hst, int32_t *ttlp)
452 if (type == GETHOSTBYNAME)
453 return __gethostbyname3_r (key, AF_INET, resultbufp, buffer, buflen, hst,
454 &h_errno, ttlp, NULL);
455 if (type == GETHOSTBYNAMEv6)
456 return __gethostbyname3_r (key, AF_INET6, resultbufp, buffer, buflen, hst,
457 &h_errno, ttlp, NULL);
458 if (type == GETHOSTBYADDR)
459 return __gethostbyaddr2_r (key, NS_INADDRSZ, AF_INET, resultbufp, buffer,
460 buflen, hst, &h_errno, ttlp);
461 return __gethostbyaddr2_r (key, NS_IN6ADDRSZ, AF_INET6, resultbufp, buffer,
462 buflen, hst, &h_errno, ttlp);
466 static time_t
467 addhstbyX (struct database_dyn *db, int fd, request_header *req,
468 void *key, uid_t uid, struct hashentry *he, struct datahead *dh)
470 /* Search for the entry matching the key. Please note that we don't
471 look again in the table whether the dataset is now available. We
472 simply insert it. It does not matter if it is in there twice. The
473 pruning function only will look at the timestamp. */
474 int buflen = 1024;
475 char *buffer = (char *) alloca (buflen);
476 struct hostent resultbuf;
477 struct hostent *hst;
478 bool use_malloc = false;
479 int errval = 0;
480 int32_t ttl = INT32_MAX;
482 if (__builtin_expect (debug_level > 0, 0))
484 const char *str;
485 char buf[INET6_ADDRSTRLEN + 1];
486 if (req->type == GETHOSTBYNAME || req->type == GETHOSTBYNAMEv6)
487 str = key;
488 else
489 str = inet_ntop (req->type == GETHOSTBYADDR ? AF_INET : AF_INET6,
490 key, buf, sizeof (buf));
492 if (he == NULL)
493 dbg_log (_("Haven't found \"%s\" in hosts cache!"), (char *) str);
494 else
495 dbg_log (_("Reloading \"%s\" in hosts cache!"), (char *) str);
498 while (lookup (req->type, key, &resultbuf, buffer, buflen, &hst, &ttl) != 0
499 && h_errno == NETDB_INTERNAL
500 && (errval = errno) == ERANGE)
502 errno = 0;
504 if (__builtin_expect (buflen > 32768, 0))
506 char *old_buffer = buffer;
507 buflen *= 2;
508 buffer = (char *) realloc (use_malloc ? buffer : NULL, buflen);
509 if (buffer == NULL)
511 /* We ran out of memory. We cannot do anything but
512 sending a negative response. In reality this should
513 never happen. */
514 hst = NULL;
515 buffer = old_buffer;
517 /* We set the error to indicate this is (possibly) a
518 temporary error and that it does not mean the entry
519 is not available at all. */
520 h_errno = TRY_AGAIN;
521 errval = EAGAIN;
522 break;
524 use_malloc = true;
526 else
527 /* Allocate a new buffer on the stack. If possible combine it
528 with the previously allocated buffer. */
529 buffer = (char *) extend_alloca (buffer, buflen, 2 * buflen);
532 time_t timeout = cache_addhst (db, fd, req, key, hst, uid, he, dh,
533 h_errno == TRY_AGAIN ? errval : 0, ttl);
535 if (use_malloc)
536 free (buffer);
538 return timeout;
542 void
543 addhstbyname (struct database_dyn *db, int fd, request_header *req,
544 void *key, uid_t uid)
546 addhstbyX (db, fd, req, key, uid, NULL, NULL);
550 time_t
551 readdhstbyname (struct database_dyn *db, struct hashentry *he,
552 struct datahead *dh)
554 request_header req =
556 .type = GETHOSTBYNAME,
557 .key_len = he->len
560 return addhstbyX (db, -1, &req, db->data + he->key, he->owner, he, dh);
564 void
565 addhstbyaddr (struct database_dyn *db, int fd, request_header *req,
566 void *key, uid_t uid)
568 addhstbyX (db, fd, req, key, uid, NULL, NULL);
572 time_t
573 readdhstbyaddr (struct database_dyn *db, struct hashentry *he,
574 struct datahead *dh)
576 request_header req =
578 .type = GETHOSTBYADDR,
579 .key_len = he->len
582 return addhstbyX (db, -1, &req, db->data + he->key, he->owner, he, dh);
586 void
587 addhstbynamev6 (struct database_dyn *db, int fd, request_header *req,
588 void *key, uid_t uid)
590 addhstbyX (db, fd, req, key, uid, NULL, NULL);
594 time_t
595 readdhstbynamev6 (struct database_dyn *db, struct hashentry *he,
596 struct datahead *dh)
598 request_header req =
600 .type = GETHOSTBYNAMEv6,
601 .key_len = he->len
604 return addhstbyX (db, -1, &req, db->data + he->key, he->owner, he, dh);
608 void
609 addhstbyaddrv6 (struct database_dyn *db, int fd, request_header *req,
610 void *key, uid_t uid)
612 addhstbyX (db, fd, req, key, uid, NULL, NULL);
616 time_t
617 readdhstbyaddrv6 (struct database_dyn *db, struct hashentry *he,
618 struct datahead *dh)
620 request_header req =
622 .type = GETHOSTBYADDRv6,
623 .key_len = he->len
626 return addhstbyX (db, -1, &req, db->data + he->key, he->owner, he, dh);