(open_socket): Minor size optimization.
[kopensolaris-gnu/glibc.git] / nscd / nscd_helper.c
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.
5
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.
10
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.
15
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.  */
20
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>
37
38 #include "nscd-client.h"
39
40
41 ssize_t
42 __readall (int fd, void *buf, size_t len)
43 {
44   size_t n = len;
45   ssize_t ret;
46   do
47     {
48       ret = TEMP_FAILURE_RETRY (__read (fd, buf, n));
49       if (ret <= 0)
50         break;
51       buf = (char *) buf + ret;
52       n -= ret;
53     }
54   while (n > 0);
55   return ret < 0 ? ret : len - n;
56 }
57
58
59 ssize_t
60 __readvall (int fd, const struct iovec *iov, int iovcnt)
61 {
62   ssize_t ret = TEMP_FAILURE_RETRY (__readv (fd, iov, iovcnt));
63   if (ret <= 0)
64     return ret;
65
66   size_t total = 0;
67   for (int i = 0; i < iovcnt; ++i)
68     total += iov[i].iov_len;
69
70   if (ret < total)
71     {
72       struct iovec iov_buf[iovcnt];
73       ssize_t r = ret;
74
75       struct iovec *iovp = memcpy (iov_buf, iov, iovcnt * sizeof (*iov));
76       do
77         {
78           while (iovp->iov_len <= r)
79             {
80               r -= iovp->iov_len;
81               --iovcnt;
82               ++iovp;
83             }
84           iovp->iov_base = (char *) iovp->iov_base + r;
85           iovp->iov_len -= r;
86           r = TEMP_FAILURE_RETRY (__readv (fd, iovp, iovcnt));
87           if (r <= 0)
88             break;
89           ret += r;
90         }
91       while (ret < total);
92       if (r < 0)
93         ret = r;
94     }
95   return ret;
96 }
97
98
99 static int
100 open_socket (request_type type, const char *key, size_t keylen)
101 {
102   int sock = __socket (PF_UNIX, SOCK_STREAM, 0);
103   if (sock < 0)
104     return -1;
105
106   struct
107   {
108     request_header req;
109     char key[keylen];
110   } reqdata;
111
112   /* Make socket non-blocking.  */
113   __fcntl (sock, F_SETFL, O_RDWR | O_NONBLOCK);
114
115   struct sockaddr_un sun;
116   sun.sun_family = AF_UNIX;
117   strcpy (sun.sun_path, _PATH_NSCDSOCKET);
118   if (__connect (sock, (struct sockaddr *) &sun, sizeof (sun)) < 0
119       && errno != EINPROGRESS)
120     goto out;
121
122   reqdata.req.version = NSCD_VERSION;
123   reqdata.req.type = type;
124   reqdata.req.key_len = keylen;
125
126   memcpy (reqdata.key, key, keylen);
127
128   bool first_try = true;
129   struct timeval tvend;
130   /* Fake initializing tvend.  */
131   asm ("" : "=m" (tvend));
132   while (1)
133     {
134 #ifndef MSG_NOSIGNAL
135 # define MSG_NOSIGNAL 0
136 #endif
137       ssize_t wres = TEMP_FAILURE_RETRY (__send (sock, &reqdata,
138                                                  sizeof (reqdata),
139                                                  MSG_NOSIGNAL));
140       if (__builtin_expect (wres == (ssize_t) sizeof (reqdata), 1))
141         /* We managed to send the request.  */
142         return sock;
143
144       if (wres != -1 || errno != EAGAIN)
145         /* Something is really wrong, no chance to continue.  */
146         break;
147
148       /* The daemon is busy wait for it.  */
149       int to;
150       struct timeval now;
151       (void) __gettimeofday (&now, NULL);
152       if (first_try)
153         {
154           tvend.tv_usec = now.tv_usec;
155           tvend.tv_sec = now.tv_sec + 5;
156           to = 5 * 1000;
157           first_try = false;
158         }
159       else
160         to = ((tvend.tv_sec - now.tv_sec) * 1000
161               + (tvend.tv_usec - now.tv_usec) / 1000);
162
163       struct pollfd fds[1];
164       fds[0].fd = sock;
165       fds[0].events = POLLOUT | POLLERR | POLLHUP;
166       if (__poll (fds, 1, to) <= 0)
167         /* The connection timed out or broke down.  */
168         break;
169
170       /* We try to write again.  */
171     }
172
173  out:
174   close_not_cancel_no_status (sock);
175
176   return -1;
177 }
178
179
180 void
181 __nscd_unmap (struct mapped_database *mapped)
182 {
183   assert (mapped->counter == 0);
184   __munmap ((void *) mapped->head, mapped->mapsize);
185   free (mapped);
186 }
187
188
189 static int
190 wait_on_socket (int sock)
191 {
192   struct pollfd fds[1];
193   fds[0].fd = sock;
194   fds[0].events = POLLIN | POLLERR | POLLHUP;
195   int n = __poll (fds, 1, 5 * 1000);
196   if (n == -1 && __builtin_expect (errno == EINTR, 0))
197     {
198       /* Handle the case where the poll() call is interrupted by a
199          signal.  We cannot just use TEMP_FAILURE_RETRY since it might
200          lead to infinite loops.  */
201       struct timeval now;
202       (void) __gettimeofday (&now, NULL);
203       long int end = (now.tv_sec + 5) * 1000 + (now.tv_usec + 500) / 1000;
204       while (1)
205         {
206           long int timeout = end - (now.tv_sec * 1000
207                                     + (now.tv_usec + 500) / 1000);
208           n = __poll (fds, 1, timeout);
209           if (n != -1 || errno != EINTR)
210             break;
211           (void) __gettimeofday (&now, NULL);
212         }
213     }
214
215   return n;
216 }
217
218
219 /* Try to get a file descriptor for the shared meory segment
220    containing the database.  */
221 static struct mapped_database *
222 get_mapping (request_type type, const char *key,
223              struct mapped_database **mappedp)
224 {
225   struct mapped_database *result = NO_MAPPING;
226 #ifdef SCM_RIGHTS
227   const size_t keylen = strlen (key) + 1;
228   int saved_errno = errno;
229
230   int mapfd = -1;
231   char resdata[keylen];
232
233   /* Open a socket and send the request.  */
234   int sock = open_socket (type, key, keylen);
235   if (sock < 0)
236     goto out;
237
238   /* Room for the data sent along with the file descriptor.  We expect
239      the key name back.  */
240   struct iovec iov[1];
241   iov[0].iov_base = resdata;
242   iov[0].iov_len = keylen;
243
244   union
245   {
246     struct cmsghdr hdr;
247     char bytes[CMSG_SPACE (sizeof (int))];
248   } buf;
249   struct msghdr msg = { .msg_iov = iov, .msg_iovlen = 1,
250                         .msg_control = buf.bytes,
251                         .msg_controllen = sizeof (buf) };
252   struct cmsghdr *cmsg = CMSG_FIRSTHDR (&msg);
253
254   cmsg->cmsg_level = SOL_SOCKET;
255   cmsg->cmsg_type = SCM_RIGHTS;
256   cmsg->cmsg_len = CMSG_LEN (sizeof (int));
257
258   /* This access is well-aligned since BUF is correctly aligned for an
259      int and CMSG_DATA preserves this alignment.  */
260   *(int *) CMSG_DATA (cmsg) = -1;
261
262   msg.msg_controllen = cmsg->cmsg_len;
263
264   if (wait_on_socket (sock) <= 0)
265     goto out_close2;
266
267   if (__builtin_expect (TEMP_FAILURE_RETRY (__recvmsg (sock, &msg, 0))
268                         != keylen, 0))
269     goto out_close2;
270
271   mapfd = *(int *) CMSG_DATA (cmsg);
272
273   if (__builtin_expect (CMSG_FIRSTHDR (&msg)->cmsg_len
274                         != CMSG_LEN (sizeof (int)), 0))
275     goto out_close;
276
277   struct stat64 st;
278   if (__builtin_expect (strcmp (resdata, key) != 0, 0)
279       || __builtin_expect (fstat64 (mapfd, &st) != 0, 0)
280       || __builtin_expect (st.st_size < sizeof (struct database_pers_head), 0))
281     goto out_close;
282
283   struct database_pers_head head;
284   if (__builtin_expect (TEMP_FAILURE_RETRY (__pread (mapfd, &head,
285                                                      sizeof (head), 0))
286                         != sizeof (head), 0))
287     goto out_close;
288
289   if (__builtin_expect (head.version != DB_VERSION, 0)
290       || __builtin_expect (head.header_size != sizeof (head), 0)
291       /* This really should not happen but who knows, maybe the update
292          thread got stuck.  */
293       || __builtin_expect (! head.nscd_certainly_running
294                            && head.timestamp + MAPPING_TIMEOUT < time (NULL),
295                            0))
296     goto out_close;
297
298   size_t size = (sizeof (head) + roundup (head.module * sizeof (ref_t), ALIGN)
299                  + head.data_size);
300
301   if (__builtin_expect (st.st_size < size, 0))
302     goto out_close;
303
304   /* The file is large enough, map it now.  */
305   void *mapping = __mmap (NULL, size, PROT_READ, MAP_SHARED, mapfd, 0);
306   if (__builtin_expect (mapping != MAP_FAILED, 1))
307     {
308       /* Allocate a record for the mapping.  */
309       struct mapped_database *newp = malloc (sizeof (*newp));
310       if (newp == NULL)
311         {
312           /* Ugh, after all we went through the memory allocation failed.  */
313           __munmap (mapping, size);
314           goto out_close;
315         }
316
317       newp->head = mapping;
318       newp->data = ((char *) mapping + head.header_size
319                     + roundup (head.module * sizeof (ref_t), ALIGN));
320       newp->mapsize = size;
321       newp->datasize = head.data_size;
322       /* Set counter to 1 to show it is usable.  */
323       newp->counter = 1;
324
325       result = newp;
326     }
327
328  out_close:
329   __close (mapfd);
330  out_close2:
331   __close (sock);
332  out:
333   __set_errno (saved_errno);
334 #endif  /* SCM_RIGHTS */
335
336   struct mapped_database *oldval = *mappedp;
337   *mappedp = result;
338
339   if (oldval != NULL && atomic_decrement_val (&oldval->counter) == 0)
340     __nscd_unmap (oldval);
341
342   return result;
343 }
344
345
346 struct mapped_database *
347 __nscd_get_map_ref (request_type type, const char *name,
348                     volatile struct locked_map_ptr *mapptr, int *gc_cyclep)
349 {
350   struct mapped_database *cur = mapptr->mapped;
351   if (cur == NO_MAPPING)
352     return cur;
353
354   int cnt = 0;
355   while (__builtin_expect (atomic_compare_and_exchange_val_acq (&mapptr->lock,
356                                                                 1, 0) != 0, 0))
357     {
358       // XXX Best number of rounds?
359       if (__builtin_expect (++cnt > 5, 0))
360         return NO_MAPPING;
361
362       atomic_delay ();
363     }
364
365   cur = mapptr->mapped;
366
367   if (__builtin_expect (cur != NO_MAPPING, 1))
368     {
369       /* If not mapped or timestamp not updated, request new map.  */
370       if (cur == NULL
371           || (cur->head->nscd_certainly_running == 0
372               && cur->head->timestamp + MAPPING_TIMEOUT < time (NULL))
373           || cur->head->data_size > cur->datasize)
374         cur = get_mapping (type, name,
375                            (struct mapped_database **) &mapptr->mapped);
376
377       if (__builtin_expect (cur != NO_MAPPING, 1))
378         {
379           if (__builtin_expect (((*gc_cyclep = cur->head->gc_cycle) & 1) != 0,
380                                 0))
381             cur = NO_MAPPING;
382           else
383             atomic_increment (&cur->counter);
384         }
385     }
386
387   mapptr->lock = 0;
388
389   return cur;
390 }
391
392
393 /* Don't return const struct datahead *, as eventhough the record
394    is normally constant, it can change arbitrarily during nscd
395    garbage collection.  */
396 struct datahead *
397 __nscd_cache_search (request_type type, const char *key, size_t keylen,
398                      const struct mapped_database *mapped)
399 {
400   unsigned long int hash = __nis_hash (key, keylen) % mapped->head->module;
401   size_t datasize = mapped->datasize;
402
403   ref_t work = mapped->head->array[hash];
404   while (work != ENDREF && work + sizeof (struct hashentry) <= datasize)
405     {
406       struct hashentry *here = (struct hashentry *) (mapped->data + work);
407
408 #ifndef _STRING_ARCH_unaligned
409       /* Although during garbage collection when moving struct hashentry
410          records around we first copy from old to new location and then
411          adjust pointer from previous hashentry to it, there is no barrier
412          between those memory writes.  It is very unlikely to hit it,
413          so check alignment only if a misaligned load can crash the
414          application.  */
415       if ((uintptr_t) here & (__alignof__ (*here) - 1))
416         return NULL;
417 #endif
418
419       if (type == here->type
420           && keylen == here->len
421           && here->key + keylen <= datasize
422           && memcmp (key, mapped->data + here->key, keylen) == 0
423           && here->packet + sizeof (struct datahead) <= datasize)
424         {
425           /* We found the entry.  Increment the appropriate counter.  */
426           struct datahead *dh
427             = (struct datahead *) (mapped->data + here->packet);
428
429 #ifndef _STRING_ARCH_unaligned
430           if ((uintptr_t) dh & (__alignof__ (*dh) - 1))
431             return NULL;
432 #endif
433
434           /* See whether we must ignore the entry or whether something
435              is wrong because garbage collection is in progress.  */
436           if (dh->usable && here->packet + dh->allocsize <= datasize)
437             return dh;
438         }
439
440       work = here->next;
441     }
442
443   return NULL;
444 }
445
446
447 /* Create a socket connected to a name. */
448 int
449 __nscd_open_socket (const char *key, size_t keylen, request_type type,
450                     void *response, size_t responselen)
451 {
452   /* This should never happen and it is something the nscd daemon
453      enforces, too.  He it helps to limit the amount of stack
454      used.  */
455   if (keylen > MAXKEYLEN)
456     return -1;
457
458   int saved_errno = errno;
459
460   int sock = open_socket (type, key, keylen);
461   if (sock >= 0)
462     {
463       /* Wait for data.  */
464       if (wait_on_socket (sock) > 0)
465         {
466           ssize_t nbytes = TEMP_FAILURE_RETRY (__read (sock, response,
467                                                        responselen));
468           if (nbytes == (ssize_t) responselen)
469             return sock;
470         }
471
472       close_not_cancel_no_status (sock);
473     }
474
475   __set_errno (saved_errno);
476
477   return -1;
478 }