]> git.ipfire.org Git - thirdparty/glibc.git/blame - nscd/hstcache.c
Update copyright notices with scripts/update-copyrights
[thirdparty/glibc.git] / nscd / hstcache.c
CommitLineData
67479a70 1/* Cache handling for host lookup.
d4697bc9 2 Copyright (C) 1998-2014 Free Software Foundation, Inc.
67479a70
UD
3 This file is part of the GNU C Library.
4 Contributed by Ulrich Drepper <drepper@cygnus.com>, 1998.
5
43bc8ac6 6 This program is free software; you can redistribute it and/or modify
2e2efe65
RM
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.
67479a70 10
43bc8ac6 11 This program is distributed in the hope that it will be useful,
67479a70 12 but WITHOUT ANY WARRANTY; without even the implied warranty of
43bc8ac6
UD
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
67479a70 15
43bc8ac6 16 You should have received a copy of the GNU General Public License
59ba27a6 17 along with this program; if not, see <http://www.gnu.org/licenses/>. */
67479a70 18
9caf4f1c 19#include <alloca.h>
67479a70
UD
20#include <assert.h>
21#include <errno.h>
22#include <error.h>
a95a08b4 23#include <libintl.h>
67479a70 24#include <netdb.h>
c7a9b6e2 25#include <stdbool.h>
67479a70
UD
26#include <stddef.h>
27#include <stdio.h>
28#include <stdlib.h>
29#include <string.h>
30#include <time.h>
31#include <unistd.h>
e054f494 32#include <stdint.h>
67479a70 33#include <arpa/inet.h>
9e56c380 34#include <arpa/nameser.h>
a95a08b4 35#include <sys/mman.h>
c7a9b6e2 36#include <stackinfo.h>
67479a70
UD
37
38#include "nscd.h"
39#include "dbg_log.h"
eac10791
UD
40#ifdef HAVE_SENDFILE
41# include <kernel-features.h>
42#endif
67479a70 43
67479a70
UD
44
45/* This is the standard reply in case the service is disabled. */
46static const hst_response_header disabled =
47{
c2e13112
RM
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
67479a70
UD
56};
57
58/* This is the struct describing how to write this record. */
59const struct iovec hst_iov_disabled =
60{
c2e13112
RM
61 .iov_base = (void *) &disabled,
62 .iov_len = sizeof (disabled)
67479a70
UD
63};
64
65
66/* This is the standard reply in case we haven't found the dataset. */
67static const hst_response_header notfound =
68{
c2e13112
RM
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
67479a70
UD
77};
78
67479a70 79
bc425b33
UD
80/* This is the standard reply in case there are temporary problems. */
81static const hst_response_header tryagain =
82{
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
91};
92
93
a4c7ea7b 94static time_t
a95a08b4 95cache_addhst (struct database_dyn *db, int fd, request_header *req,
c207f23b 96 const void *key, struct hostent *hst, uid_t owner,
20e498bd 97 struct hashentry *const he, struct datahead *dh, int errval,
384ca551 98 int32_t ttl)
67479a70 99{
9ad58cc3 100 bool all_written = true;
67479a70
UD
101 time_t t = time (NULL);
102
a95a08b4
UD
103 /* We allocate all data in one memory block: the iov vector,
104 the response header and the dataset itself. */
105 struct dataset
106 {
107 struct datahead head;
108 hst_response_header resp;
109 char strdata[0];
110 } *dataset;
111
112 assert (offsetof (struct dataset, resp) == offsetof (struct datahead, data));
113
a4c7ea7b 114 time_t timeout = MAX_TIMEOUT_VALUE;
67479a70
UD
115 if (hst == NULL)
116 {
a95a08b4
UD
117 if (he != NULL && errval == EAGAIN)
118 {
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;
a4c7ea7b
UD
125
126 /* Reload with the same time-to-live value. */
127 timeout = dh->timeout = t + dh->ttl;
a95a08b4
UD
128 }
129 else
130 {
131 /* We have no data. This means we send the standard reply for this
bc425b33 132 case. Possibly this is only temporary. */
9ad58cc3 133 ssize_t total = sizeof (notfound);
bc425b33
UD
134 assert (sizeof (notfound) == sizeof (tryagain));
135
136 const hst_response_header *resp = (errval == EAGAIN
137 ? &tryagain : &notfound);
67479a70 138
9ad58cc3 139 if (fd != -1 &&
bc425b33 140 TEMP_FAILURE_RETRY (send (fd, resp, total,
9ad58cc3
UD
141 MSG_NOSIGNAL)) != total)
142 all_written = false;
67479a70 143
3e1aa84e
UD
144 /* If we have a transient error or cannot permanently store
145 the result, so be it. */
146 if (errval == EAGAIN || __builtin_expect (db->negtimeout == 0, 0))
445b4a53
TK
147 {
148 /* Mark the old entry as obsolete. */
149 if (dh != NULL)
150 dh->usable = false;
151 }
99231d9a
UD
152 else if ((dataset = mempool_alloc (db, (sizeof (struct dataset)
153 + req->key_len), 1)) != NULL)
a95a08b4
UD
154 {
155 dataset->head.allocsize = sizeof (struct dataset) + req->key_len;
156 dataset->head.recsize = total;
157 dataset->head.notfound = true;
158 dataset->head.nreloads = 0;
159 dataset->head.usable = true;
67479a70 160
a95a08b4 161 /* Compute the timeout time. */
a4c7ea7b
UD
162 dataset->head.ttl = ttl == INT32_MAX ? db->negtimeout : ttl;
163 timeout = dataset->head.timeout = t + dataset->head.ttl;
67479a70 164
a95a08b4 165 /* This is the reply. */
bc425b33 166 memcpy (&dataset->resp, resp, total);
67479a70 167
a95a08b4
UD
168 /* Copy the key data. */
169 memcpy (dataset->strdata, key, req->key_len);
67479a70 170
8c89236f
UD
171 /* If necessary, we also propagate the data to disk. */
172 if (db->persistent)
173 {
174 // XXX async OK?
175 uintptr_t pval = (uintptr_t) dataset & ~pagesize_m1;
176 msync ((void *) pval,
177 ((uintptr_t) dataset & pagesize_m1)
178 + sizeof (struct dataset) + req->key_len, MS_ASYNC);
179 }
180
7e71e55f 181 (void) cache_add (req->type, &dataset->strdata, req->key_len,
528741cb 182 &dataset->head, true, db, owner, he == NULL);
a95a08b4 183
00ebd7ed
UD
184 pthread_rwlock_unlock (&db->lock);
185
a95a08b4
UD
186 /* Mark the old entry as obsolete. */
187 if (dh != NULL)
188 dh->usable = false;
189 }
99bb9f42 190 }
67479a70
UD
191 }
192 else
193 {
194 /* Determine the I/O structure. */
67479a70
UD
195 size_t h_name_len = strlen (hst->h_name) + 1;
196 size_t h_aliases_cnt;
3107c0c5 197 uint32_t *h_aliases_len;
67479a70 198 size_t h_addr_list_cnt;
67479a70
UD
199 char *addresses;
200 char *aliases;
201 char *key_copy = NULL;
202 char *cp;
203 size_t cnt;
9ad58cc3 204 ssize_t total;
67479a70
UD
205
206 /* Determine the number of aliases. */
207 h_aliases_cnt = 0;
208 for (cnt = 0; hst->h_aliases[cnt] != NULL; ++cnt)
209 ++h_aliases_cnt;
210 /* Determine the length of all aliases. */
3107c0c5 211 h_aliases_len = (uint32_t *) alloca (h_aliases_cnt * sizeof (uint32_t));
67479a70
UD
212 total = 0;
213 for (cnt = 0; cnt < h_aliases_cnt; ++cnt)
214 {
215 h_aliases_len[cnt] = strlen (hst->h_aliases[cnt]) + 1;
216 total += h_aliases_len[cnt];
217 }
218
219 /* Determine the number of addresses. */
220 h_addr_list_cnt = 0;
1ce7d80d 221 while (hst->h_addr_list[h_addr_list_cnt] != NULL)
67479a70
UD
222 ++h_addr_list_cnt;
223
a95a08b4
UD
224 if (h_addr_list_cnt == 0)
225 /* Invalid entry. */
a4c7ea7b 226 return MAX_TIMEOUT_VALUE;
a95a08b4
UD
227
228 total += (sizeof (struct dataset)
67479a70 229 + h_name_len
3107c0c5 230 + h_aliases_cnt * sizeof (uint32_t)
488fb3c7 231 + h_addr_list_cnt * hst->h_length);
67479a70 232
a95a08b4
UD
233 /* If we refill the cache, first assume the reconrd did not
234 change. Allocate memory on the cache since it is likely
235 discarded anyway. If it turns out to be necessary to have a
236 new record we can still allocate real memory. */
237 bool alloca_used = false;
238 dataset = NULL;
67479a70 239
a95a08b4
UD
240 /* If the record contains more than one IP address (used for
241 load balancing etc) don't cache the entry. This is something
242 the current cache handling cannot handle and it is more than
243 questionable whether it is worthwhile complicating the cache
244 handling just for handling such a special case. */
a30d41c1 245 if (he == NULL && h_addr_list_cnt == 1)
20e498bd
UD
246 dataset = (struct dataset *) mempool_alloc (db, total + req->key_len,
247 1);
67479a70 248
a95a08b4
UD
249 if (dataset == NULL)
250 {
251 /* We cannot permanently add the result in the moment. But
252 we can provide the result as is. Store the data in some
253 temporary memory. */
254 dataset = (struct dataset *) alloca (total + req->key_len);
255
256 /* We cannot add this record to the permanent database. */
257 alloca_used = true;
258 }
259
260 dataset->head.allocsize = total + req->key_len;
261 dataset->head.recsize = total - offsetof (struct dataset, resp);
262 dataset->head.notfound = false;
263 dataset->head.nreloads = he == NULL ? 0 : (dh->nreloads + 1);
264 dataset->head.usable = true;
265
266 /* Compute the timeout time. */
a4c7ea7b
UD
267 dataset->head.ttl = ttl == INT32_MAX ? db->postimeout : ttl;
268 timeout = dataset->head.timeout = t + dataset->head.ttl;
a95a08b4
UD
269
270 dataset->resp.version = NSCD_VERSION;
271 dataset->resp.found = 1;
272 dataset->resp.h_name_len = h_name_len;
273 dataset->resp.h_aliases_cnt = h_aliases_cnt;
274 dataset->resp.h_addrtype = hst->h_addrtype;
275 dataset->resp.h_length = hst->h_length;
276 dataset->resp.h_addr_list_cnt = h_addr_list_cnt;
277 dataset->resp.error = NETDB_SUCCESS;
278
9ad58cc3
UD
279 /* Make sure there is no gap. */
280 assert ((char *) (&dataset->resp.error + 1) == dataset->strdata);
281
a95a08b4 282 cp = dataset->strdata;
67479a70
UD
283
284 cp = mempcpy (cp, hst->h_name, h_name_len);
3107c0c5 285 cp = mempcpy (cp, h_aliases_len, h_aliases_cnt * sizeof (uint32_t));
67479a70
UD
286
287 /* The normal addresses first. */
288 addresses = cp;
289 for (cnt = 0; cnt < h_addr_list_cnt; ++cnt)
290 cp = mempcpy (cp, hst->h_addr_list[cnt], hst->h_length);
291
67479a70
UD
292 /* Then the aliases. */
293 aliases = cp;
294 for (cnt = 0; cnt < h_aliases_cnt; ++cnt)
295 cp = mempcpy (cp, hst->h_aliases[cnt], h_aliases_len[cnt]);
296
a95a08b4
UD
297 assert (cp
298 == dataset->strdata + total - offsetof (struct dataset,
299 strdata));
67479a70
UD
300
301 /* If we are adding a GETHOSTBYNAME{,v6} entry we must be prepared
302 that the answer we get from the NSS does not contain the key
303 itself. This is the case if the resolver is used and the name
304 is extended by the domainnames from /etc/resolv.conf. Therefore
305 we explicitly add the name here. */
c207f23b 306 key_copy = memcpy (cp, key, req->key_len);
67479a70 307
9ad58cc3
UD
308 assert ((char *) &dataset->resp + dataset->head.recsize == cp);
309
a95a08b4
UD
310 /* Now we can determine whether on refill we have to create a new
311 record or not. */
312 if (he != NULL)
313 {
314 assert (fd == -1);
67479a70 315
a95a08b4
UD
316 if (total + req->key_len == dh->allocsize
317 && total - offsetof (struct dataset, resp) == dh->recsize
318 && memcmp (&dataset->resp, dh->data,
319 dh->allocsize - offsetof (struct dataset, resp)) == 0)
320 {
8c89236f 321 /* The data has not changed. We will just bump the
a95a08b4
UD
322 timeout value. Note that the new record has been
323 allocated on the stack and need not be freed. */
c44d3bdf 324 assert (h_addr_list_cnt == 1);
a4c7ea7b 325 dh->ttl = dataset->head.ttl;
a95a08b4
UD
326 dh->timeout = dataset->head.timeout;
327 ++dh->nreloads;
328 }
329 else
330 {
c44d3bdf 331 if (h_addr_list_cnt == 1)
a95a08b4 332 {
c44d3bdf
UD
333 /* We have to create a new record. Just allocate
334 appropriate memory and copy it. */
335 struct dataset *newp
336 = (struct dataset *) mempool_alloc (db,
c52137d3 337 total + req->key_len,
20e498bd 338 1);
c44d3bdf
UD
339 if (newp != NULL)
340 {
341 /* Adjust pointers into the memory block. */
342 addresses = (char *) newp + (addresses
343 - (char *) dataset);
344 aliases = (char *) newp + (aliases - (char *) dataset);
345 assert (key_copy != NULL);
346 key_copy = (char *) newp + (key_copy - (char *) dataset);
347
348 dataset = memcpy (newp, dataset, total + req->key_len);
349 alloca_used = false;
350 }
a95a08b4
UD
351 }
352
353 /* Mark the old record as obsolete. */
354 dh->usable = false;
355 }
356 }
357 else
490998a5 358 {
a95a08b4
UD
359 /* We write the dataset before inserting it to the database
360 since while inserting this thread might block and so would
361 unnecessarily keep the receiver waiting. */
362 assert (fd != -1);
363
eac10791 364#ifdef HAVE_SENDFILE
74158740 365 if (__builtin_expect (db->mmap_used, 1) && !alloca_used)
eac10791
UD
366 {
367 assert (db->wr_fd != -1);
368 assert ((char *) &dataset->resp > (char *) db->data);
ea547a1a 369 assert ((char *) dataset - (char *) db->head
eac10791
UD
370 + total
371 <= (sizeof (struct database_pers_head)
372 + db->head->module * sizeof (ref_t)
373 + db->head->data_size));
9ad58cc3
UD
374 ssize_t written = sendfileall (fd, db->wr_fd,
375 (char *) &dataset->resp
376 - (char *) db->head,
377 dataset->head.recsize);
378 if (written != dataset->head.recsize)
379 {
eac10791 380# ifndef __ASSUME_SENDFILE
9ad58cc3
UD
381 if (written == -1 && errno == ENOSYS)
382 goto use_write;
eac10791 383# endif
9ad58cc3
UD
384 all_written = false;
385 }
eac10791
UD
386 }
387 else
388# ifndef __ASSUME_SENDFILE
389 use_write:
390# endif
391#endif
9ad58cc3
UD
392 if (writeall (fd, &dataset->resp, dataset->head.recsize)
393 != dataset->head.recsize)
394 all_written = false;
490998a5
UD
395 }
396
a95a08b4
UD
397 /* Add the record to the database. But only if it has not been
398 stored on the stack.
67479a70 399
a95a08b4
UD
400 If the record contains more than one IP address (used for
401 load balancing etc) don't cache the entry. This is something
402 the current cache handling cannot handle and it is more than
403 questionable whether it is worthwhile complicating the cache
404 handling just for handling such a special case. */
405 if (! alloca_used)
67479a70 406 {
a95a08b4
UD
407 /* If necessary, we also propagate the data to disk. */
408 if (db->persistent)
3418007e
UD
409 {
410 // XXX async OK?
411 uintptr_t pval = (uintptr_t) dataset & ~pagesize_m1;
412 msync ((void *) pval,
413 ((uintptr_t) dataset & pagesize_m1)
414 + total + req->key_len, MS_ASYNC);
415 }
a95a08b4 416
a95a08b4
UD
417 /* NB: the following code is really complicated. It has
418 seemlingly duplicated code paths which do the same. The
419 problem is that we always must add the hash table entry
420 with the FIRST flag set first. Otherwise we get dangling
421 pointers in case memory allocation fails. */
c207f23b 422 assert (hst->h_addr_list[1] == NULL);
a95a08b4 423
a95a08b4
UD
424 /* Avoid adding names if more than one address is available. See
425 above for more info. */
c207f23b
UD
426 assert (req->type == GETHOSTBYNAME
427 || req->type == GETHOSTBYNAMEv6
428 || req->type == GETHOSTBYADDR
429 || req->type == GETHOSTBYADDRv6);
a95a08b4 430
7e71e55f 431 (void) cache_add (req->type, key_copy, req->key_len,
528741cb 432 &dataset->head, true, db, owner, he == NULL);
00ebd7ed
UD
433
434 pthread_rwlock_unlock (&db->lock);
67479a70 435 }
67479a70
UD
436 }
437
9ad58cc3 438 if (__builtin_expect (!all_written, 0) && debug_level > 0)
67479a70
UD
439 {
440 char buf[256];
441 dbg_log (_("short write in %s: %s"), __FUNCTION__,
442 strerror_r (errno, buf, sizeof (buf)));
443 }
a4c7ea7b
UD
444
445 return timeout;
67479a70
UD
446}
447
448
a95a08b4
UD
449static int
450lookup (int type, void *key, struct hostent *resultbufp, char *buffer,
384ca551 451 size_t buflen, struct hostent **hst, int32_t *ttlp)
a95a08b4
UD
452{
453 if (type == GETHOSTBYNAME)
384ca551
UD
454 return __gethostbyname3_r (key, AF_INET, resultbufp, buffer, buflen, hst,
455 &h_errno, ttlp, NULL);
8c89236f 456 if (type == GETHOSTBYNAMEv6)
384ca551
UD
457 return __gethostbyname3_r (key, AF_INET6, resultbufp, buffer, buflen, hst,
458 &h_errno, ttlp, NULL);
8c89236f 459 if (type == GETHOSTBYADDR)
384ca551
UD
460 return __gethostbyaddr2_r (key, NS_INADDRSZ, AF_INET, resultbufp, buffer,
461 buflen, hst, &h_errno, ttlp);
462 return __gethostbyaddr2_r (key, NS_IN6ADDRSZ, AF_INET6, resultbufp, buffer,
463 buflen, hst, &h_errno, ttlp);
a95a08b4
UD
464}
465
466
a4c7ea7b 467static time_t
a95a08b4
UD
468addhstbyX (struct database_dyn *db, int fd, request_header *req,
469 void *key, uid_t uid, struct hashentry *he, struct datahead *dh)
67479a70
UD
470{
471 /* Search for the entry matching the key. Please note that we don't
472 look again in the table whether the dataset is now available. We
473 simply insert it. It does not matter if it is in there twice. The
474 pruning function only will look at the timestamp. */
c7a9b6e2
UD
475 int buflen = 1024;
476 char *buffer = (char *) alloca (buflen);
67479a70
UD
477 struct hostent resultbuf;
478 struct hostent *hst;
c7a9b6e2 479 bool use_malloc = false;
a95a08b4 480 int errval = 0;
384ca551 481 int32_t ttl = INT32_MAX;
67479a70 482
c7a9b6e2 483 if (__builtin_expect (debug_level > 0, 0))
a95a08b4 484 {
c207f23b
UD
485 const char *str;
486 char buf[INET6_ADDRSTRLEN + 1];
487 if (req->type == GETHOSTBYNAME || req->type == GETHOSTBYNAMEv6)
488 str = key;
489 else
490 str = inet_ntop (req->type == GETHOSTBYADDR ? AF_INET : AF_INET6,
491 key, buf, sizeof (buf));
492
a95a08b4 493 if (he == NULL)
c207f23b 494 dbg_log (_("Haven't found \"%s\" in hosts cache!"), (char *) str);
a95a08b4 495 else
c207f23b 496 dbg_log (_("Reloading \"%s\" in hosts cache!"), (char *) str);
a95a08b4 497 }
67479a70 498
384ca551 499 while (lookup (req->type, key, &resultbuf, buffer, buflen, &hst, &ttl) != 0
67479a70 500 && h_errno == NETDB_INTERNAL
a95a08b4 501 && (errval = errno) == ERANGE)
67479a70
UD
502 {
503 errno = 0;
c7a9b6e2
UD
504
505 if (__builtin_expect (buflen > 32768, 0))
506 {
b21fa963 507 char *old_buffer = buffer;
4379b403 508 buflen *= 2;
c7a9b6e2
UD
509 buffer = (char *) realloc (use_malloc ? buffer : NULL, buflen);
510 if (buffer == NULL)
511 {
512 /* We ran out of memory. We cannot do anything but
513 sending a negative response. In reality this should
514 never happen. */
515 hst = NULL;
516 buffer = old_buffer;
a95a08b4
UD
517
518 /* We set the error to indicate this is (possibly) a
519 temporary error and that it does not mean the entry
520 is not available at all. */
bc425b33 521 h_errno = TRY_AGAIN;
a95a08b4 522 errval = EAGAIN;
c7a9b6e2
UD
523 break;
524 }
525 use_malloc = true;
526 }
527 else
9caf4f1c
UD
528 /* Allocate a new buffer on the stack. If possible combine it
529 with the previously allocated buffer. */
4379b403 530 buffer = (char *) extend_alloca (buffer, buflen, 2 * buflen);
67479a70
UD
531 }
532
a4c7ea7b
UD
533 time_t timeout = cache_addhst (db, fd, req, key, hst, uid, he, dh,
534 h_errno == TRY_AGAIN ? errval : 0, ttl);
c7a9b6e2
UD
535
536 if (use_malloc)
537 free (buffer);
a4c7ea7b
UD
538
539 return timeout;
67479a70
UD
540}
541
542
543void
a95a08b4 544addhstbyname (struct database_dyn *db, int fd, request_header *req,
a1c542bf 545 void *key, uid_t uid)
67479a70 546{
a95a08b4
UD
547 addhstbyX (db, fd, req, key, uid, NULL, NULL);
548}
67479a70 549
67479a70 550
a4c7ea7b 551time_t
a95a08b4
UD
552readdhstbyname (struct database_dyn *db, struct hashentry *he,
553 struct datahead *dh)
554{
555 request_header req =
a1c542bf 556 {
a95a08b4
UD
557 .type = GETHOSTBYNAME,
558 .key_len = he->len
559 };
a1c542bf 560
a4c7ea7b 561 return addhstbyX (db, -1, &req, db->data + he->key, he->owner, he, dh);
a95a08b4 562}
c7a9b6e2 563
67479a70 564
a95a08b4
UD
565void
566addhstbyaddr (struct database_dyn *db, int fd, request_header *req,
567 void *key, uid_t uid)
568{
569 addhstbyX (db, fd, req, key, uid, NULL, NULL);
570}
a1c542bf 571
c7a9b6e2 572
a4c7ea7b 573time_t
a95a08b4
UD
574readdhstbyaddr (struct database_dyn *db, struct hashentry *he,
575 struct datahead *dh)
576{
577 request_header req =
578 {
579 .type = GETHOSTBYADDR,
580 .key_len = he->len
581 };
582
a4c7ea7b 583 return addhstbyX (db, -1, &req, db->data + he->key, he->owner, he, dh);
67479a70
UD
584}
585
586
587void
a95a08b4 588addhstbynamev6 (struct database_dyn *db, int fd, request_header *req,
a1c542bf 589 void *key, uid_t uid)
67479a70 590{
a95a08b4
UD
591 addhstbyX (db, fd, req, key, uid, NULL, NULL);
592}
67479a70 593
a1c542bf 594
a4c7ea7b 595time_t
a95a08b4
UD
596readdhstbynamev6 (struct database_dyn *db, struct hashentry *he,
597 struct datahead *dh)
598{
599 request_header req =
67479a70 600 {
a95a08b4
UD
601 .type = GETHOSTBYNAMEv6,
602 .key_len = he->len
603 };
c7a9b6e2 604
a4c7ea7b 605 return addhstbyX (db, -1, &req, db->data + he->key, he->owner, he, dh);
67479a70
UD
606}
607
608
609void
a95a08b4 610addhstbyaddrv6 (struct database_dyn *db, int fd, request_header *req,
a1c542bf 611 void *key, uid_t uid)
67479a70 612{
a95a08b4
UD
613 addhstbyX (db, fd, req, key, uid, NULL, NULL);
614}
67479a70 615
67479a70 616
a4c7ea7b 617time_t
a95a08b4
UD
618readdhstbyaddrv6 (struct database_dyn *db, struct hashentry *he,
619 struct datahead *dh)
620{
621 request_header req =
67479a70 622 {
a95a08b4
UD
623 .type = GETHOSTBYADDRv6,
624 .key_len = he->len
625 };
c7a9b6e2 626
a4c7ea7b 627 return addhstbyX (db, -1, &req, db->data + he->key, he->owner, he, dh);
67479a70 628}