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
30 #include <sys/socket.h>
35 #include <not-cancel.h>
36 #include <nis/rpcsvc/nis.h>
38 #include "nscd-client.h"
42 __readall (int fd
, void *buf
, size_t len
)
48 ret
= TEMP_FAILURE_RETRY (__read (fd
, buf
, n
));
51 buf
= (char *) buf
+ ret
;
55 return ret
< 0 ? ret
: len
- n
;
60 __readvall (int fd
, const struct iovec
*iov
, int iovcnt
)
62 ssize_t ret
= TEMP_FAILURE_RETRY (__readv (fd
, iov
, iovcnt
));
67 for (int i
= 0; i
< iovcnt
; ++i
)
68 total
+= iov
[i
].iov_len
;
72 struct iovec iov_buf
[iovcnt
];
75 struct iovec
*iovp
= memcpy (iov_buf
, iov
, iovcnt
* sizeof (*iov
));
78 while (iovp
->iov_len
<= r
)
84 iovp
->iov_base
= (char *) iovp
->iov_base
+ r
;
86 r
= TEMP_FAILURE_RETRY (__readv (fd
, iovp
, iovcnt
));
100 open_socket (request_type type
, const char *key
, size_t keylen
)
102 int sock
= __socket (PF_UNIX
, SOCK_STREAM
, 0);
111 size_t real_sizeof_reqdata
= sizeof (request_header
) + keylen
;
113 /* Make socket non-blocking. */
114 __fcntl (sock
, F_SETFL
, O_RDWR
| O_NONBLOCK
);
116 struct sockaddr_un sun
;
117 sun
.sun_family
= AF_UNIX
;
118 strcpy (sun
.sun_path
, _PATH_NSCDSOCKET
);
119 if (__connect (sock
, (struct sockaddr
*) &sun
, sizeof (sun
)) < 0
120 && errno
!= EINPROGRESS
)
123 reqdata
.req
.version
= NSCD_VERSION
;
124 reqdata
.req
.type
= type
;
125 reqdata
.req
.key_len
= keylen
;
127 memcpy (reqdata
.key
, key
, keylen
);
129 bool first_try
= true;
130 struct timeval tvend
;
131 /* Fake initializing tvend. */
132 asm ("" : "=m" (tvend
));
136 # define MSG_NOSIGNAL 0
138 ssize_t wres
= TEMP_FAILURE_RETRY (__send (sock
, &reqdata
,
141 if (__builtin_expect (wres
== (ssize_t
) real_sizeof_reqdata
, 1))
142 /* We managed to send the request. */
145 if (wres
!= -1 || errno
!= EAGAIN
)
146 /* Something is really wrong, no chance to continue. */
149 /* The daemon is busy wait for it. */
152 (void) __gettimeofday (&now
, NULL
);
155 tvend
.tv_usec
= now
.tv_usec
;
156 tvend
.tv_sec
= now
.tv_sec
+ 5;
161 to
= ((tvend
.tv_sec
- now
.tv_sec
) * 1000
162 + (tvend
.tv_usec
- now
.tv_usec
) / 1000);
164 struct pollfd fds
[1];
166 fds
[0].events
= POLLOUT
| POLLERR
| POLLHUP
;
167 if (__poll (fds
, 1, to
) <= 0)
168 /* The connection timed out or broke down. */
171 /* We try to write again. */
175 close_not_cancel_no_status (sock
);
182 __nscd_unmap (struct mapped_database
*mapped
)
184 assert (mapped
->counter
== 0);
185 __munmap ((void *) mapped
->head
, mapped
->mapsize
);
191 wait_on_socket (int sock
)
193 struct pollfd fds
[1];
195 fds
[0].events
= POLLIN
| POLLERR
| POLLHUP
;
196 int n
= __poll (fds
, 1, 5 * 1000);
197 if (n
== -1 && __builtin_expect (errno
== EINTR
, 0))
199 /* Handle the case where the poll() call is interrupted by a
200 signal. We cannot just use TEMP_FAILURE_RETRY since it might
201 lead to infinite loops. */
203 (void) __gettimeofday (&now
, NULL
);
204 long int end
= (now
.tv_sec
+ 5) * 1000 + (now
.tv_usec
+ 500) / 1000;
207 long int timeout
= end
- (now
.tv_sec
* 1000
208 + (now
.tv_usec
+ 500) / 1000);
209 n
= __poll (fds
, 1, timeout
);
210 if (n
!= -1 || errno
!= EINTR
)
212 (void) __gettimeofday (&now
, NULL
);
220 /* Try to get a file descriptor for the shared meory segment
221 containing the database. */
222 static struct mapped_database
*
223 get_mapping (request_type type
, const char *key
,
224 struct mapped_database
**mappedp
)
226 struct mapped_database
*result
= NO_MAPPING
;
228 const size_t keylen
= strlen (key
) + 1;
229 int saved_errno
= errno
;
232 char resdata
[keylen
];
234 /* Open a socket and send the request. */
235 int sock
= open_socket (type
, key
, keylen
);
239 /* Room for the data sent along with the file descriptor. We expect
240 the key name back. */
242 iov
[0].iov_base
= resdata
;
243 iov
[0].iov_len
= keylen
;
248 char bytes
[CMSG_SPACE (sizeof (int))];
250 struct msghdr msg
= { .msg_iov
= iov
, .msg_iovlen
= 1,
251 .msg_control
= buf
.bytes
,
252 .msg_controllen
= sizeof (buf
) };
253 struct cmsghdr
*cmsg
= CMSG_FIRSTHDR (&msg
);
255 cmsg
->cmsg_level
= SOL_SOCKET
;
256 cmsg
->cmsg_type
= SCM_RIGHTS
;
257 cmsg
->cmsg_len
= CMSG_LEN (sizeof (int));
259 /* This access is well-aligned since BUF is correctly aligned for an
260 int and CMSG_DATA preserves this alignment. */
261 *(int *) CMSG_DATA (cmsg
) = -1;
263 msg
.msg_controllen
= cmsg
->cmsg_len
;
265 if (wait_on_socket (sock
) <= 0)
268 # ifndef MSG_CMSG_CLOEXEC
269 # define MSG_CMSG_CLOEXEC 0
271 if (__builtin_expect (TEMP_FAILURE_RETRY (__recvmsg (sock
, &msg
,
276 if (__builtin_expect (CMSG_FIRSTHDR (&msg
) == NULL
277 || (CMSG_FIRSTHDR (&msg
)->cmsg_len
278 != CMSG_LEN (sizeof (int))), 0))
281 mapfd
= *(int *) CMSG_DATA (cmsg
);
284 if (__builtin_expect (strcmp (resdata
, key
) != 0, 0)
285 || __builtin_expect (fstat64 (mapfd
, &st
) != 0, 0)
286 || __builtin_expect (st
.st_size
< sizeof (struct database_pers_head
), 0))
289 struct database_pers_head head
;
290 if (__builtin_expect (TEMP_FAILURE_RETRY (__pread (mapfd
, &head
,
292 != sizeof (head
), 0))
295 if (__builtin_expect (head
.version
!= DB_VERSION
, 0)
296 || __builtin_expect (head
.header_size
!= sizeof (head
), 0)
297 /* This really should not happen but who knows, maybe the update
299 || __builtin_expect (! head
.nscd_certainly_running
300 && head
.timestamp
+ MAPPING_TIMEOUT
< time (NULL
),
304 size_t size
= (sizeof (head
) + roundup (head
.module
* sizeof (ref_t
), ALIGN
)
307 if (__builtin_expect (st
.st_size
< size
, 0))
310 /* The file is large enough, map it now. */
311 void *mapping
= __mmap (NULL
, size
, PROT_READ
, MAP_SHARED
, mapfd
, 0);
312 if (__builtin_expect (mapping
!= MAP_FAILED
, 1))
314 /* Allocate a record for the mapping. */
315 struct mapped_database
*newp
= malloc (sizeof (*newp
));
318 /* Ugh, after all we went through the memory allocation failed. */
319 __munmap (mapping
, size
);
323 newp
->head
= mapping
;
324 newp
->data
= ((char *) mapping
+ head
.header_size
325 + roundup (head
.module
* sizeof (ref_t
), ALIGN
));
326 newp
->mapsize
= size
;
327 newp
->datasize
= head
.data_size
;
328 /* Set counter to 1 to show it is usable. */
339 __set_errno (saved_errno
);
340 #endif /* SCM_RIGHTS */
342 struct mapped_database
*oldval
= *mappedp
;
345 if (oldval
!= NULL
&& atomic_decrement_val (&oldval
->counter
) == 0)
346 __nscd_unmap (oldval
);
352 struct mapped_database
*
353 __nscd_get_map_ref (request_type type
, const char *name
,
354 volatile struct locked_map_ptr
*mapptr
, int *gc_cyclep
)
356 struct mapped_database
*cur
= mapptr
->mapped
;
357 if (cur
== NO_MAPPING
)
361 while (__builtin_expect (atomic_compare_and_exchange_val_acq (&mapptr
->lock
,
364 // XXX Best number of rounds?
365 if (__builtin_expect (++cnt
> 5, 0))
371 cur
= mapptr
->mapped
;
373 if (__builtin_expect (cur
!= NO_MAPPING
, 1))
375 /* If not mapped or timestamp not updated, request new map. */
377 || (cur
->head
->nscd_certainly_running
== 0
378 && cur
->head
->timestamp
+ MAPPING_TIMEOUT
< time (NULL
))
379 || cur
->head
->data_size
> cur
->datasize
)
380 cur
= get_mapping (type
, name
,
381 (struct mapped_database
**) &mapptr
->mapped
);
383 if (__builtin_expect (cur
!= NO_MAPPING
, 1))
385 if (__builtin_expect (((*gc_cyclep
= cur
->head
->gc_cycle
) & 1) != 0,
389 atomic_increment (&cur
->counter
);
399 /* Don't return const struct datahead *, as eventhough the record
400 is normally constant, it can change arbitrarily during nscd
401 garbage collection. */
403 __nscd_cache_search (request_type type
, const char *key
, size_t keylen
,
404 const struct mapped_database
*mapped
)
406 unsigned long int hash
= __nis_hash (key
, keylen
) % mapped
->head
->module
;
407 size_t datasize
= mapped
->datasize
;
409 ref_t work
= mapped
->head
->array
[hash
];
410 while (work
!= ENDREF
&& work
+ sizeof (struct hashentry
) <= datasize
)
412 struct hashentry
*here
= (struct hashentry
*) (mapped
->data
+ work
);
414 #ifndef _STRING_ARCH_unaligned
415 /* Although during garbage collection when moving struct hashentry
416 records around we first copy from old to new location and then
417 adjust pointer from previous hashentry to it, there is no barrier
418 between those memory writes. It is very unlikely to hit it,
419 so check alignment only if a misaligned load can crash the
421 if ((uintptr_t) here
& (__alignof__ (*here
) - 1))
425 if (type
== here
->type
426 && keylen
== here
->len
427 && here
->key
+ keylen
<= datasize
428 && memcmp (key
, mapped
->data
+ here
->key
, keylen
) == 0
429 && here
->packet
+ sizeof (struct datahead
) <= datasize
)
431 /* We found the entry. Increment the appropriate counter. */
433 = (struct datahead
*) (mapped
->data
+ here
->packet
);
435 #ifndef _STRING_ARCH_unaligned
436 if ((uintptr_t) dh
& (__alignof__ (*dh
) - 1))
440 /* See whether we must ignore the entry or whether something
441 is wrong because garbage collection is in progress. */
442 if (dh
->usable
&& here
->packet
+ dh
->allocsize
<= datasize
)
453 /* Create a socket connected to a name. */
455 __nscd_open_socket (const char *key
, size_t keylen
, request_type type
,
456 void *response
, size_t responselen
)
458 /* This should never happen and it is something the nscd daemon
459 enforces, too. He it helps to limit the amount of stack
461 if (keylen
> MAXKEYLEN
)
464 int saved_errno
= errno
;
466 int sock
= open_socket (type
, key
, keylen
);
470 if (wait_on_socket (sock
) > 0)
472 ssize_t nbytes
= TEMP_FAILURE_RETRY (__read (sock
, response
,
474 if (nbytes
== (ssize_t
) responselen
)
478 close_not_cancel_no_status (sock
);
481 __set_errno (saved_errno
);