Avoid warnings for unused results in nscd/connections.c.
[platform/upstream/glibc.git] / nscd / servicescache.c
1 /* Cache handling for services lookup.
2    Copyright (C) 2007-2014 Free Software Foundation, Inc.
3    This file is part of the GNU C Library.
4    Contributed by Ulrich Drepper <drepper@drepper.com>, 2007.
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, see <http://www.gnu.org/licenses/>.  */
18
19 #include <alloca.h>
20 #include <assert.h>
21 #include <errno.h>
22 #include <libintl.h>
23 #include <netdb.h>
24 #include <unistd.h>
25 #include <stdint.h>
26 #include <sys/mman.h>
27 #include <kernel-features.h>
28
29 #include "nscd.h"
30 #include "dbg_log.h"
31
32
33 /* This is the standard reply in case the service is disabled.  */
34 static const serv_response_header disabled =
35 {
36   .version = NSCD_VERSION,
37   .found = -1,
38   .s_name_len = 0,
39   .s_proto_len = 0,
40   .s_aliases_cnt = 0,
41   .s_port = -1
42 };
43
44 /* This is the struct describing how to write this record.  */
45 const struct iovec serv_iov_disabled =
46 {
47   .iov_base = (void *) &disabled,
48   .iov_len = sizeof (disabled)
49 };
50
51
52 /* This is the standard reply in case we haven't found the dataset.  */
53 static const serv_response_header notfound =
54 {
55   .version = NSCD_VERSION,
56   .found = 0,
57   .s_name_len = 0,
58   .s_proto_len = 0,
59   .s_aliases_cnt = 0,
60   .s_port = -1
61 };
62
63
64 static time_t
65 cache_addserv (struct database_dyn *db, int fd, request_header *req,
66                const void *key, struct servent *serv, uid_t owner,
67                struct hashentry *const he, struct datahead *dh, int errval)
68 {
69   bool all_written = true;
70   ssize_t total;
71   time_t t = time (NULL);
72
73   /* We allocate all data in one memory block: the iov vector,
74      the response header and the dataset itself.  */
75   struct dataset
76   {
77     struct datahead head;
78     serv_response_header resp;
79     char strdata[0];
80   } *dataset;
81
82   assert (offsetof (struct dataset, resp) == offsetof (struct datahead, data));
83
84   time_t timeout = MAX_TIMEOUT_VALUE;
85   if (serv == NULL)
86     {
87       if (he != NULL && errval == EAGAIN)
88         {
89           /* If we have an old record available but cannot find one
90              now because the service is not available we keep the old
91              record and make sure it does not get removed.  */
92           if (reload_count != UINT_MAX)
93             /* Do not reset the value if we never not reload the record.  */
94             dh->nreloads = reload_count - 1;
95
96           /* Reload with the same time-to-live value.  */
97           timeout = dh->timeout = t + db->postimeout;
98
99           total = 0;
100         }
101       else
102         {
103           /* We have no data.  This means we send the standard reply for this
104              case.  */
105           total = sizeof (notfound);
106
107           if (fd != -1
108               && TEMP_FAILURE_RETRY (send (fd, &notfound, total,
109                                            MSG_NOSIGNAL)) != total)
110             all_written = false;
111
112           /* If we have a transient error or cannot permanently store
113              the result, so be it.  */
114           if (errval == EAGAIN || __builtin_expect (db->negtimeout == 0, 0))
115             {
116               /* Mark the old entry as obsolete.  */
117               if (dh != NULL)
118                 dh->usable = false;
119             }
120           else if ((dataset = mempool_alloc (db, (sizeof (struct dataset)
121                                                   + req->key_len), 1)) != NULL)
122             {
123               timeout = datahead_init_neg (&dataset->head,
124                                            (sizeof (struct dataset)
125                                             + req->key_len), total,
126                                            db->negtimeout);
127
128               /* This is the reply.  */
129               memcpy (&dataset->resp, &notfound, total);
130
131               /* Copy the key data.  */
132               memcpy (dataset->strdata, key, req->key_len);
133
134               /* If necessary, we also propagate the data to disk.  */
135               if (db->persistent)
136                 {
137                   // XXX async OK?
138                   uintptr_t pval = (uintptr_t) dataset & ~pagesize_m1;
139                   msync ((void *) pval,
140                          ((uintptr_t) dataset & pagesize_m1)
141                          + sizeof (struct dataset) + req->key_len, MS_ASYNC);
142                 }
143
144               (void) cache_add (req->type, &dataset->strdata, req->key_len,
145                                 &dataset->head, true, db, owner, he == NULL);
146
147               pthread_rwlock_unlock (&db->lock);
148
149               /* Mark the old entry as obsolete.  */
150               if (dh != NULL)
151                 dh->usable = false;
152             }
153         }
154     }
155   else
156     {
157       /* Determine the I/O structure.  */
158       size_t s_name_len = strlen (serv->s_name) + 1;
159       size_t s_proto_len = strlen (serv->s_proto) + 1;
160       uint32_t *s_aliases_len;
161       size_t s_aliases_cnt;
162       char *aliases;
163       char *cp;
164       size_t cnt;
165
166       /* Determine the number of aliases.  */
167       s_aliases_cnt = 0;
168       for (cnt = 0; serv->s_aliases[cnt] != NULL; ++cnt)
169         ++s_aliases_cnt;
170       /* Determine the length of all aliases.  */
171       s_aliases_len = (uint32_t *) alloca (s_aliases_cnt * sizeof (uint32_t));
172       total = 0;
173       for (cnt = 0; cnt < s_aliases_cnt; ++cnt)
174         {
175           s_aliases_len[cnt] = strlen (serv->s_aliases[cnt]) + 1;
176           total += s_aliases_len[cnt];
177         }
178
179       total += (offsetof (struct dataset, strdata)
180                 + s_name_len
181                 + s_proto_len
182                 + s_aliases_cnt * sizeof (uint32_t));
183
184       /* If we refill the cache, first assume the reconrd did not
185          change.  Allocate memory on the cache since it is likely
186          discarded anyway.  If it turns out to be necessary to have a
187          new record we can still allocate real memory.  */
188       bool alloca_used = false;
189       dataset = NULL;
190
191       if (he == NULL)
192         dataset = (struct dataset *) mempool_alloc (db, total + req->key_len,
193                                                     1);
194
195       if (dataset == NULL)
196         {
197           /* We cannot permanently add the result in the moment.  But
198              we can provide the result as is.  Store the data in some
199              temporary memory.  */
200           dataset = (struct dataset *) alloca (total + req->key_len);
201
202           /* We cannot add this record to the permanent database.  */
203           alloca_used = true;
204         }
205
206       timeout = datahead_init_pos (&dataset->head, total + req->key_len,
207                                    total - offsetof (struct dataset, resp),
208                                    he == NULL ? 0 : dh->nreloads + 1,
209                                    db->postimeout);
210
211       dataset->resp.version = NSCD_VERSION;
212       dataset->resp.found = 1;
213       dataset->resp.s_name_len = s_name_len;
214       dataset->resp.s_proto_len = s_proto_len;
215       dataset->resp.s_port = serv->s_port;
216       dataset->resp.s_aliases_cnt = s_aliases_cnt;
217
218       cp = dataset->strdata;
219
220       cp = mempcpy (cp, serv->s_name, s_name_len);
221       cp = mempcpy (cp, serv->s_proto, s_proto_len);
222       cp = mempcpy (cp, s_aliases_len, s_aliases_cnt * sizeof (uint32_t));
223
224       /* Then the aliases.  */
225       aliases = cp;
226       for (cnt = 0; cnt < s_aliases_cnt; ++cnt)
227         cp = mempcpy (cp, serv->s_aliases[cnt], s_aliases_len[cnt]);
228
229       assert (cp
230               == dataset->strdata + total - offsetof (struct dataset,
231                                                       strdata));
232
233       char *key_copy = memcpy (cp, key, req->key_len);
234
235       /* Now we can determine whether on refill we have to create a new
236          record or not.  */
237       if (he != NULL)
238         {
239           assert (fd == -1);
240
241           if (total + req->key_len == dh->allocsize
242               && total - offsetof (struct dataset, resp) == dh->recsize
243               && memcmp (&dataset->resp, dh->data,
244                          dh->allocsize - offsetof (struct dataset, resp)) == 0)
245             {
246               /* The data has not changed.  We will just bump the
247                  timeout value.  Note that the new record has been
248                  allocated on the stack and need not be freed.  */
249               dh->timeout = dataset->head.timeout;
250               ++dh->nreloads;
251             }
252           else
253             {
254               /* We have to create a new record.  Just allocate
255                  appropriate memory and copy it.  */
256               struct dataset *newp
257                 = (struct dataset *) mempool_alloc (db, total + req->key_len,
258                                                     1);
259               if (newp != NULL)
260                 {
261                   /* Adjust pointers into the memory block.  */
262                   aliases = (char *) newp + (aliases - (char *) dataset);
263                   assert (key_copy != NULL);
264                   key_copy = (char *) newp + (key_copy - (char *) dataset);
265
266                   dataset = memcpy (newp, dataset, total + req->key_len);
267                   alloca_used = false;
268                 }
269
270               /* Mark the old record as obsolete.  */
271               dh->usable = false;
272             }
273         }
274       else
275         {
276           /* We write the dataset before inserting it to the database
277              since while inserting this thread might block and so would
278              unnecessarily keep the receiver waiting.  */
279           assert (fd != -1);
280
281 #ifdef HAVE_SENDFILE
282           if (__builtin_expect (db->mmap_used, 1) && !alloca_used)
283             {
284               assert (db->wr_fd != -1);
285               assert ((char *) &dataset->resp > (char *) db->data);
286               assert ((char *) dataset - (char *) db->head
287                       + total
288                       <= (sizeof (struct database_pers_head)
289                           + db->head->module * sizeof (ref_t)
290                           + db->head->data_size));
291               ssize_t written = sendfileall (fd, db->wr_fd,
292                                              (char *) &dataset->resp
293                                              - (char *) db->head,
294                                              dataset->head.recsize);
295               if (written != dataset->head.recsize)
296                 {
297 # ifndef __ASSUME_SENDFILE
298                   if (written == -1 && errno == ENOSYS)
299                     goto use_write;
300 # endif
301                   all_written = false;
302                 }
303             }
304           else
305 # ifndef __ASSUME_SENDFILE
306           use_write:
307 # endif
308 #endif
309             if (writeall (fd, &dataset->resp, dataset->head.recsize)
310                 != dataset->head.recsize)
311               all_written = false;
312         }
313
314       /* Add the record to the database.  But only if it has not been
315          stored on the stack.  */
316       if (! alloca_used)
317         {
318           /* If necessary, we also propagate the data to disk.  */
319           if (db->persistent)
320             {
321               // XXX async OK?
322               uintptr_t pval = (uintptr_t) dataset & ~pagesize_m1;
323               msync ((void *) pval,
324                      ((uintptr_t) dataset & pagesize_m1)
325                      + total + req->key_len, MS_ASYNC);
326             }
327
328           (void) cache_add (req->type, key_copy, req->key_len,
329                             &dataset->head, true, db, owner, he == NULL);
330
331           pthread_rwlock_unlock (&db->lock);
332         }
333     }
334
335   if (__builtin_expect (!all_written, 0) && debug_level > 0)
336     {
337       char buf[256];
338       dbg_log (_("short write in %s: %s"),  __FUNCTION__,
339                strerror_r (errno, buf, sizeof (buf)));
340     }
341
342   return timeout;
343 }
344
345
346 static int
347 lookup (int type, char *key, struct servent *resultbufp, char *buffer,
348         size_t buflen, struct servent **serv)
349 {
350   char *proto = strrchr (key, '/');
351   if (proto != NULL && proto != key)
352     {
353       key = strndupa (key, proto - key);
354       if (proto[1] == '\0')
355         proto = NULL;
356       else
357         ++proto;
358     }
359
360   if (type == GETSERVBYNAME)
361     return __getservbyname_r (key, proto, resultbufp, buffer, buflen, serv);
362
363   assert (type == GETSERVBYPORT);
364   return __getservbyport_r (atol (key), proto, resultbufp, buffer, buflen,
365                             serv);
366 }
367
368
369 static time_t
370 addservbyX (struct database_dyn *db, int fd, request_header *req,
371             char *key, uid_t uid, struct hashentry *he, struct datahead *dh)
372 {
373   /* Search for the entry matching the key.  Please note that we don't
374      look again in the table whether the dataset is now available.  We
375      simply insert it.  It does not matter if it is in there twice.  The
376      pruning function only will look at the timestamp.  */
377   size_t buflen = 1024;
378   char *buffer = (char *) alloca (buflen);
379   struct servent resultbuf;
380   struct servent *serv;
381   bool use_malloc = false;
382   int errval = 0;
383
384   if (__glibc_unlikely (debug_level > 0))
385     {
386       if (he == NULL)
387         dbg_log (_("Haven't found \"%s\" in services cache!"), key);
388       else
389         dbg_log (_("Reloading \"%s\" in services cache!"), key);
390     }
391
392   while (lookup (req->type, key, &resultbuf, buffer, buflen, &serv) != 0
393          && (errval = errno) == ERANGE)
394     {
395       errno = 0;
396
397       if (__glibc_unlikely (buflen > 32768))
398         {
399           char *old_buffer = buffer;
400           buflen *= 2;
401           buffer = (char *) realloc (use_malloc ? buffer : NULL, buflen);
402           if (buffer == NULL)
403             {
404               /* We ran out of memory.  We cannot do anything but
405                  sending a negative response.  In reality this should
406                  never happen.  */
407               serv = NULL;
408               buffer = old_buffer;
409
410               /* We set the error to indicate this is (possibly) a
411                  temporary error and that it does not mean the entry
412                  is not available at all.  */
413               errval = EAGAIN;
414               break;
415             }
416           use_malloc = true;
417         }
418       else
419         /* Allocate a new buffer on the stack.  If possible combine it
420            with the previously allocated buffer.  */
421         buffer = (char *) extend_alloca (buffer, buflen, 2 * buflen);
422     }
423
424   time_t timeout = cache_addserv (db, fd, req, key, serv, uid, he, dh, errval);
425
426   if (use_malloc)
427     free (buffer);
428
429   return timeout;
430 }
431
432
433 void
434 addservbyname (struct database_dyn *db, int fd, request_header *req,
435                void *key, uid_t uid)
436 {
437   addservbyX (db, fd, req, key, uid, NULL, NULL);
438 }
439
440
441 time_t
442 readdservbyname (struct database_dyn *db, struct hashentry *he,
443                  struct datahead *dh)
444 {
445   request_header req =
446     {
447       .type = GETSERVBYNAME,
448       .key_len = he->len
449     };
450
451   return addservbyX (db, -1, &req, db->data + he->key, he->owner, he, dh);
452 }
453
454
455 void
456 addservbyport (struct database_dyn *db, int fd, request_header *req,
457                void *key, uid_t uid)
458 {
459   addservbyX (db, fd, req, key, uid, NULL, NULL);
460 }
461
462
463 time_t
464 readdservbyport (struct database_dyn *db, struct hashentry *he,
465                  struct datahead *dh)
466 {
467   request_header req =
468     {
469       .type = GETSERVBYPORT,
470       .key_len = he->len
471     };
472
473   return addservbyX (db, -1, &req, db->data + he->key, he->owner, he, dh);
474 }