2007-11-18 Roland McGrath <roland@frob.com>
[glibc.git] / nscd / nscd_helper.c
blob866535200f496d5480974cadae8d8c25e72a9b7c
1 /* Copyright (C) 1998-2002,2003,2004,2005,2006,2007
2 Free Software Foundation, Inc.
3 This file is part of the GNU C Library.
4 Contributed by Ulrich Drepper <drepper@cygnus.com>, 1998.
6 The GNU C Library is free software; you can redistribute it and/or
7 modify it under the terms of the GNU Lesser General Public
8 License as published by the Free Software Foundation; either
9 version 2.1 of the License, or (at your option) any later version.
11 The GNU C Library 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 GNU
14 Lesser General Public License for more details.
16 You should have received a copy of the GNU Lesser General Public
17 License along with the GNU C Library; if not, write to the Free
18 Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
19 02111-1307 USA. */
21 #include <assert.h>
22 #include <errno.h>
23 #include <fcntl.h>
24 #include <stdbool.h>
25 #include <string.h>
26 #include <time.h>
27 #include <unistd.h>
28 #include <sys/mman.h>
29 #include <sys/poll.h>
30 #include <sys/socket.h>
31 #include <sys/stat.h>
32 #include <sys/time.h>
33 #include <sys/uio.h>
34 #include <sys/un.h>
35 #include <not-cancel.h>
36 #include <nis/rpcsvc/nis.h>
38 #include "nscd-client.h"
41 /* Extra time we wait if the socket is still receiving data. This
42 value is in milliseconds. Note that the other side is nscd on the
43 local machine and it is already transmitting data. So the wait
44 time need not be long. */
45 #define EXTRA_RECEIVE_TIME 200
48 static int
49 wait_on_socket (int sock, long int usectmo)
51 struct pollfd fds[1];
52 fds[0].fd = sock;
53 fds[0].events = POLLIN | POLLERR | POLLHUP;
54 int n = __poll (fds, 1, usectmo);
55 if (n == -1 && __builtin_expect (errno == EINTR, 0))
57 /* Handle the case where the poll() call is interrupted by a
58 signal. We cannot just use TEMP_FAILURE_RETRY since it might
59 lead to infinite loops. */
60 struct timeval now;
61 (void) __gettimeofday (&now, NULL);
62 long int end = now.tv_sec * 1000 + usectmo + (now.tv_usec + 500) / 1000;
63 long int timeout = usectmo;
64 while (1)
66 n = __poll (fds, 1, timeout);
67 if (n != -1 || errno != EINTR)
68 break;
70 /* Recompute the timeout time. */
71 (void) __gettimeofday (&now, NULL);
72 timeout = end - (now.tv_sec * 1000 + (now.tv_usec + 500) / 1000);
76 return n;
80 ssize_t
81 __readall (int fd, void *buf, size_t len)
83 size_t n = len;
84 ssize_t ret;
87 again:
88 ret = TEMP_FAILURE_RETRY (__read (fd, buf, n));
89 if (ret <= 0)
91 if (__builtin_expect (ret < 0 && errno == EAGAIN, 0)
92 /* The socket is still receiving data. Wait a bit more. */
93 && wait_on_socket (fd, EXTRA_RECEIVE_TIME) > 0)
94 goto again;
96 break;
98 buf = (char *) buf + ret;
99 n -= ret;
101 while (n > 0);
102 return ret < 0 ? ret : len - n;
106 ssize_t
107 __readvall (int fd, const struct iovec *iov, int iovcnt)
109 ssize_t ret = TEMP_FAILURE_RETRY (__readv (fd, iov, iovcnt));
110 if (ret <= 0)
112 if (__builtin_expect (ret == 0 || errno != EAGAIN, 1))
113 /* A genuine error or no data to read. */
114 return ret;
116 /* The data has not all yet been received. Do as if we have not
117 read anything yet. */
118 ret = 0;
121 size_t total = 0;
122 for (int i = 0; i < iovcnt; ++i)
123 total += iov[i].iov_len;
125 if (ret < total)
127 struct iovec iov_buf[iovcnt];
128 ssize_t r = ret;
130 struct iovec *iovp = memcpy (iov_buf, iov, iovcnt * sizeof (*iov));
133 while (iovp->iov_len <= r)
135 r -= iovp->iov_len;
136 --iovcnt;
137 ++iovp;
139 iovp->iov_base = (char *) iovp->iov_base + r;
140 iovp->iov_len -= r;
141 again:
142 r = TEMP_FAILURE_RETRY (__readv (fd, iovp, iovcnt));
143 if (r <= 0)
145 if (__builtin_expect (r < 0 && errno == EAGAIN, 0)
146 /* The socket is still receiving data. Wait a bit more. */
147 && wait_on_socket (fd, EXTRA_RECEIVE_TIME) > 0)
148 goto again;
150 break;
152 ret += r;
154 while (ret < total);
155 if (r < 0)
156 ret = r;
158 return ret;
162 static int
163 open_socket (request_type type, const char *key, size_t keylen)
165 int sock = __socket (PF_UNIX, SOCK_STREAM, 0);
166 if (sock < 0)
167 return -1;
169 struct
171 request_header req;
172 char key[keylen];
173 } reqdata;
174 size_t real_sizeof_reqdata = sizeof (request_header) + keylen;
176 /* Make socket non-blocking. */
177 __fcntl (sock, F_SETFL, O_RDWR | O_NONBLOCK);
179 struct sockaddr_un sun;
180 sun.sun_family = AF_UNIX;
181 strcpy (sun.sun_path, _PATH_NSCDSOCKET);
182 if (__connect (sock, (struct sockaddr *) &sun, sizeof (sun)) < 0
183 && errno != EINPROGRESS)
184 goto out;
186 reqdata.req.version = NSCD_VERSION;
187 reqdata.req.type = type;
188 reqdata.req.key_len = keylen;
190 memcpy (reqdata.key, key, keylen);
192 bool first_try = true;
193 struct timeval tvend;
194 /* Fake initializing tvend. */
195 asm ("" : "=m" (tvend));
196 while (1)
198 #ifndef MSG_NOSIGNAL
199 # define MSG_NOSIGNAL 0
200 #endif
201 ssize_t wres = TEMP_FAILURE_RETRY (__send (sock, &reqdata,
202 real_sizeof_reqdata,
203 MSG_NOSIGNAL));
204 if (__builtin_expect (wres == (ssize_t) real_sizeof_reqdata, 1))
205 /* We managed to send the request. */
206 return sock;
208 if (wres != -1 || errno != EAGAIN)
209 /* Something is really wrong, no chance to continue. */
210 break;
212 /* The daemon is busy wait for it. */
213 int to;
214 struct timeval now;
215 (void) __gettimeofday (&now, NULL);
216 if (first_try)
218 tvend.tv_usec = now.tv_usec;
219 tvend.tv_sec = now.tv_sec + 5;
220 to = 5 * 1000;
221 first_try = false;
223 else
224 to = ((tvend.tv_sec - now.tv_sec) * 1000
225 + (tvend.tv_usec - now.tv_usec) / 1000);
227 struct pollfd fds[1];
228 fds[0].fd = sock;
229 fds[0].events = POLLOUT | POLLERR | POLLHUP;
230 if (__poll (fds, 1, to) <= 0)
231 /* The connection timed out or broke down. */
232 break;
234 /* We try to write again. */
237 out:
238 close_not_cancel_no_status (sock);
240 return -1;
244 void
245 __nscd_unmap (struct mapped_database *mapped)
247 assert (mapped->counter == 0);
248 __munmap ((void *) mapped->head, mapped->mapsize);
249 free (mapped);
253 /* Try to get a file descriptor for the shared meory segment
254 containing the database. */
255 static struct mapped_database *
256 get_mapping (request_type type, const char *key,
257 struct mapped_database **mappedp)
259 struct mapped_database *result = NO_MAPPING;
260 #ifdef SCM_RIGHTS
261 const size_t keylen = strlen (key) + 1;
262 int saved_errno = errno;
264 int mapfd = -1;
265 char resdata[keylen];
267 /* Open a socket and send the request. */
268 int sock = open_socket (type, key, keylen);
269 if (sock < 0)
270 goto out;
272 /* Room for the data sent along with the file descriptor. We expect
273 the key name back. */
274 uint64_t mapsize;
275 struct iovec iov[2];
276 iov[0].iov_base = resdata;
277 iov[0].iov_len = keylen;
278 iov[1].iov_base = &mapsize;
279 iov[1].iov_len = sizeof (mapsize);
281 union
283 struct cmsghdr hdr;
284 char bytes[CMSG_SPACE (sizeof (int))];
285 } buf;
286 struct msghdr msg = { .msg_iov = iov, .msg_iovlen = 2,
287 .msg_control = buf.bytes,
288 .msg_controllen = sizeof (buf) };
289 struct cmsghdr *cmsg = CMSG_FIRSTHDR (&msg);
291 cmsg->cmsg_level = SOL_SOCKET;
292 cmsg->cmsg_type = SCM_RIGHTS;
293 cmsg->cmsg_len = CMSG_LEN (sizeof (int));
295 /* This access is well-aligned since BUF is correctly aligned for an
296 int and CMSG_DATA preserves this alignment. */
297 *(int *) CMSG_DATA (cmsg) = -1;
299 msg.msg_controllen = cmsg->cmsg_len;
301 if (wait_on_socket (sock, 5 * 1000) <= 0)
302 goto out_close2;
304 # ifndef MSG_CMSG_CLOEXEC
305 # define MSG_CMSG_CLOEXEC 0
306 # endif
307 ssize_t n = TEMP_FAILURE_RETRY (__recvmsg (sock, &msg, MSG_CMSG_CLOEXEC));
309 if (__builtin_expect (CMSG_FIRSTHDR (&msg) == NULL
310 || (CMSG_FIRSTHDR (&msg)->cmsg_len
311 != CMSG_LEN (sizeof (int))), 0))
312 goto out_close2;
314 mapfd = *(int *) CMSG_DATA (cmsg);
316 if (__builtin_expect (n != keylen && n != keylen + sizeof (mapsize), 0))
317 goto out_close;
319 if (__builtin_expect (strcmp (resdata, key) != 0, 0))
320 goto out_close;
322 if (__builtin_expect (n == keylen, 0))
324 struct stat64 st;
325 if (__builtin_expect (fstat64 (mapfd, &st) != 0, 0)
326 || __builtin_expect (st.st_size < sizeof (struct database_pers_head),
328 goto out_close;
330 mapsize = st.st_size;
333 /* The file is large enough, map it now. */
334 void *mapping = __mmap (NULL, mapsize, PROT_READ, MAP_SHARED, mapfd, 0);
335 if (__builtin_expect (mapping != MAP_FAILED, 1))
337 /* Check whether the database is correct and up-to-date. */
338 struct database_pers_head *head = mapping;
340 if (__builtin_expect (head->version != DB_VERSION, 0)
341 || __builtin_expect (head->header_size != sizeof (*head), 0)
342 /* This really should not happen but who knows, maybe the update
343 thread got stuck. */
344 || __builtin_expect (! head->nscd_certainly_running
345 && (head->timestamp + MAPPING_TIMEOUT
346 < time (NULL)), 0))
348 out_unmap:
349 __munmap (mapping, mapsize);
350 goto out_close;
353 size_t size = (sizeof (*head) + roundup (head->module * sizeof (ref_t),
354 ALIGN)
355 + head->data_size);
357 if (__builtin_expect (mapsize < size, 0))
358 goto out_unmap;
360 /* Allocate a record for the mapping. */
361 struct mapped_database *newp = malloc (sizeof (*newp));
362 if (newp == NULL)
363 /* Ugh, after all we went through the memory allocation failed. */
364 goto out_unmap;
366 newp->head = mapping;
367 newp->data = ((char *) mapping + head->header_size
368 + roundup (head->module * sizeof (ref_t), ALIGN));
369 newp->mapsize = size;
370 newp->datasize = head->data_size;
371 /* Set counter to 1 to show it is usable. */
372 newp->counter = 1;
374 result = newp;
377 out_close:
378 __close (mapfd);
379 out_close2:
380 __close (sock);
381 out:
382 __set_errno (saved_errno);
383 #endif /* SCM_RIGHTS */
385 struct mapped_database *oldval = *mappedp;
386 *mappedp = result;
388 if (oldval != NULL && atomic_decrement_val (&oldval->counter) == 0)
389 __nscd_unmap (oldval);
391 return result;
395 struct mapped_database *
396 __nscd_get_map_ref (request_type type, const char *name,
397 volatile struct locked_map_ptr *mapptr, int *gc_cyclep)
399 struct mapped_database *cur = mapptr->mapped;
400 if (cur == NO_MAPPING)
401 return cur;
403 int cnt = 0;
404 while (__builtin_expect (atomic_compare_and_exchange_val_acq (&mapptr->lock,
405 1, 0) != 0, 0))
407 // XXX Best number of rounds?
408 if (__builtin_expect (++cnt > 5, 0))
409 return NO_MAPPING;
411 atomic_delay ();
414 cur = mapptr->mapped;
416 if (__builtin_expect (cur != NO_MAPPING, 1))
418 /* If not mapped or timestamp not updated, request new map. */
419 if (cur == NULL
420 || (cur->head->nscd_certainly_running == 0
421 && cur->head->timestamp + MAPPING_TIMEOUT < time (NULL))
422 || cur->head->data_size > cur->datasize)
423 cur = get_mapping (type, name,
424 (struct mapped_database **) &mapptr->mapped);
426 if (__builtin_expect (cur != NO_MAPPING, 1))
428 if (__builtin_expect (((*gc_cyclep = cur->head->gc_cycle) & 1) != 0,
430 cur = NO_MAPPING;
431 else
432 atomic_increment (&cur->counter);
436 mapptr->lock = 0;
438 return cur;
442 /* Don't return const struct datahead *, as eventhough the record
443 is normally constant, it can change arbitrarily during nscd
444 garbage collection. */
445 struct datahead *
446 __nscd_cache_search (request_type type, const char *key, size_t keylen,
447 const struct mapped_database *mapped)
449 unsigned long int hash = __nis_hash (key, keylen) % mapped->head->module;
450 size_t datasize = mapped->datasize;
452 ref_t trail = mapped->head->array[hash];
453 ref_t work = trail;
454 int tick = 0;
456 while (work != ENDREF && work + sizeof (struct hashentry) <= datasize)
458 struct hashentry *here = (struct hashentry *) (mapped->data + work);
460 #ifndef _STRING_ARCH_unaligned
461 /* Although during garbage collection when moving struct hashentry
462 records around we first copy from old to new location and then
463 adjust pointer from previous hashentry to it, there is no barrier
464 between those memory writes. It is very unlikely to hit it,
465 so check alignment only if a misaligned load can crash the
466 application. */
467 if ((uintptr_t) here & (__alignof__ (*here) - 1))
468 return NULL;
469 #endif
471 if (type == here->type
472 && keylen == here->len
473 && here->key + keylen <= datasize
474 && memcmp (key, mapped->data + here->key, keylen) == 0
475 && here->packet + sizeof (struct datahead) <= datasize)
477 /* We found the entry. Increment the appropriate counter. */
478 struct datahead *dh
479 = (struct datahead *) (mapped->data + here->packet);
481 #ifndef _STRING_ARCH_unaligned
482 if ((uintptr_t) dh & (__alignof__ (*dh) - 1))
483 return NULL;
484 #endif
486 /* See whether we must ignore the entry or whether something
487 is wrong because garbage collection is in progress. */
488 if (dh->usable && here->packet + dh->allocsize <= datasize)
489 return dh;
492 work = here->next;
493 /* Prevent endless loops. This should never happen but perhaps
494 the database got corrupted, accidentally or deliberately. */
495 if (work == trail)
496 break;
497 if (tick)
499 struct hashentry *trailelem;
500 trailelem = (struct hashentry *) (mapped->data + trail);
502 #ifndef _STRING_ARCH_unaligned
503 /* We have to redo the checks. Maybe the data changed. */
504 if ((uintptr_t) trailelem & (__alignof__ (*trailelem) - 1))
505 return NULL;
506 #endif
507 trail = trailelem->next;
509 tick = 1 - tick;
512 return NULL;
516 /* Create a socket connected to a name. */
518 __nscd_open_socket (const char *key, size_t keylen, request_type type,
519 void *response, size_t responselen)
521 /* This should never happen and it is something the nscd daemon
522 enforces, too. He it helps to limit the amount of stack
523 used. */
524 if (keylen > MAXKEYLEN)
525 return -1;
527 int saved_errno = errno;
529 int sock = open_socket (type, key, keylen);
530 if (sock >= 0)
532 /* Wait for data. */
533 if (wait_on_socket (sock, 5 * 1000) > 0)
535 ssize_t nbytes = TEMP_FAILURE_RETRY (__read (sock, response,
536 responselen));
537 if (nbytes == (ssize_t) responselen)
538 return sock;
541 close_not_cancel_no_status (sock);
544 __set_errno (saved_errno);
546 return -1;