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