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
));
102 int sock
= __socket (PF_UNIX
, SOCK_STREAM
, 0);
106 /* Make socket non-blocking. */
107 int fl
= __fcntl (sock
, F_GETFL
);
109 __fcntl (sock
, F_SETFL
, fl
| O_NONBLOCK
);
111 struct sockaddr_un sun
;
112 sun
.sun_family
= AF_UNIX
;
113 strcpy (sun
.sun_path
, _PATH_NSCDSOCKET
);
114 if (__connect (sock
, (struct sockaddr
*) &sun
, sizeof (sun
)) < 0
115 && errno
!= EINPROGRESS
)
118 struct pollfd fds
[1];
120 fds
[0].events
= POLLOUT
| POLLERR
| POLLHUP
;
121 if (__poll (fds
, 1, 5 * 1000) > 0)
122 /* Success. We do not check for success of the connect call here.
123 If it failed, the following operations will fail. */
127 close_not_cancel_no_status (sock
);
134 __nscd_unmap (struct mapped_database
*mapped
)
136 assert (mapped
->counter
== 0);
137 __munmap ((void *) mapped
->head
, mapped
->mapsize
);
143 wait_on_socket (int sock
)
145 struct pollfd fds
[1];
147 fds
[0].events
= POLLIN
| POLLERR
| POLLHUP
;
148 int n
= __poll (fds
, 1, 5 * 1000);
149 if (n
== -1 && __builtin_expect (errno
== EINTR
, 0))
151 /* Handle the case where the poll() call is interrupted by a
152 signal. We cannot just use TEMP_FAILURE_RETRY since it might
153 lead to infinite loops. */
155 (void) __gettimeofday (&now
, NULL
);
156 long int end
= (now
.tv_sec
+ 5) * 1000 + (now
.tv_usec
+ 500) / 1000;
159 long int timeout
= end
- (now
.tv_sec
* 1000
160 + (now
.tv_usec
+ 500) / 1000);
161 n
= __poll (fds
, 1, timeout
);
162 if (n
!= -1 || errno
!= EINTR
)
164 (void) __gettimeofday (&now
, NULL
);
172 /* Try to get a file descriptor for the shared meory segment
173 containing the database. */
174 static struct mapped_database
*
175 get_mapping (request_type type
, const char *key
,
176 struct mapped_database
**mappedp
)
178 struct mapped_database
*result
= NO_MAPPING
;
180 const size_t keylen
= strlen (key
) + 1;
181 int saved_errno
= errno
;
185 /* Send the request. */
191 size_t real_sizeof_reqdata
= sizeof (request_header
) + keylen
;
193 int sock
= open_socket ();
197 reqdata
.req
.version
= NSCD_VERSION
;
198 reqdata
.req
.type
= type
;
199 reqdata
.req
.key_len
= keylen
;
200 memcpy (reqdata
.key
, key
, keylen
);
202 # ifndef MSG_NOSIGNAL
203 # define MSG_NOSIGNAL 0
205 if (__builtin_expect (TEMP_FAILURE_RETRY (__send (sock
, &reqdata
,
208 != real_sizeof_reqdata
, 0))
209 /* We cannot even write the request. */
212 /* Room for the data sent along with the file descriptor. We expect
213 the key name back. */
214 # define resdata reqdata.key
216 iov
[0].iov_base
= resdata
;
217 iov
[0].iov_len
= keylen
;
222 char bytes
[CMSG_SPACE (sizeof (int))];
224 struct msghdr msg
= { .msg_iov
= iov
, .msg_iovlen
= 1,
225 .msg_control
= buf
.bytes
,
226 .msg_controllen
= sizeof (buf
) };
227 struct cmsghdr
*cmsg
= CMSG_FIRSTHDR (&msg
);
229 cmsg
->cmsg_level
= SOL_SOCKET
;
230 cmsg
->cmsg_type
= SCM_RIGHTS
;
231 cmsg
->cmsg_len
= CMSG_LEN (sizeof (int));
233 /* This access is well-aligned since BUF is correctly aligned for an
234 int and CMSG_DATA preserves this alignment. */
235 *(int *) CMSG_DATA (cmsg
) = -1;
237 msg
.msg_controllen
= cmsg
->cmsg_len
;
239 if (wait_on_socket (sock
) <= 0)
242 if (__builtin_expect (TEMP_FAILURE_RETRY (__recvmsg (sock
, &msg
, 0))
246 if (__builtin_expect (CMSG_FIRSTHDR (&msg
) == NULL
247 || (CMSG_FIRSTHDR (&msg
)->cmsg_len
248 != CMSG_LEN (sizeof (int))), 0))
251 mapfd
= *(int *) CMSG_DATA (cmsg
);
254 if (__builtin_expect (strcmp (resdata
, key
) != 0, 0)
255 || __builtin_expect (fstat64 (mapfd
, &st
) != 0, 0)
256 || __builtin_expect (st
.st_size
< sizeof (struct database_pers_head
), 0))
259 struct database_pers_head head
;
260 if (__builtin_expect (TEMP_FAILURE_RETRY (__pread (mapfd
, &head
,
262 != sizeof (head
), 0))
265 if (__builtin_expect (head
.version
!= DB_VERSION
, 0)
266 || __builtin_expect (head
.header_size
!= sizeof (head
), 0)
267 /* This really should not happen but who knows, maybe the update
269 || __builtin_expect (! head
.nscd_certainly_running
270 && head
.timestamp
+ MAPPING_TIMEOUT
< time (NULL
),
274 size_t size
= (sizeof (head
) + roundup (head
.module
* sizeof (ref_t
), ALIGN
)
277 if (__builtin_expect (st
.st_size
< size
, 0))
280 /* The file is large enough, map it now. */
281 void *mapping
= __mmap (NULL
, size
, PROT_READ
, MAP_SHARED
, mapfd
, 0);
282 if (__builtin_expect (mapping
!= MAP_FAILED
, 1))
284 /* Allocate a record for the mapping. */
285 struct mapped_database
*newp
= malloc (sizeof (*newp
));
288 /* Ugh, after all we went through the memory allocation failed. */
289 __munmap (mapping
, size
);
293 newp
->head
= mapping
;
294 newp
->data
= ((char *) mapping
+ head
.header_size
295 + roundup (head
.module
* sizeof (ref_t
), ALIGN
));
296 newp
->mapsize
= size
;
297 newp
->datasize
= head
.data_size
;
298 /* Set counter to 1 to show it is usable. */
309 __set_errno (saved_errno
);
310 #endif /* SCM_RIGHTS */
312 struct mapped_database
*oldval
= *mappedp
;
315 if (oldval
!= NULL
&& atomic_decrement_val (&oldval
->counter
) == 0)
316 __nscd_unmap (oldval
);
322 struct mapped_database
*
323 __nscd_get_map_ref (request_type type
, const char *name
,
324 volatile struct locked_map_ptr
*mapptr
, int *gc_cyclep
)
326 struct mapped_database
*cur
= mapptr
->mapped
;
327 if (cur
== NO_MAPPING
)
331 while (__builtin_expect (atomic_compare_and_exchange_val_acq (&mapptr
->lock
,
334 // XXX Best number of rounds?
335 if (__builtin_expect (++cnt
> 5, 0))
341 cur
= mapptr
->mapped
;
343 if (__builtin_expect (cur
!= NO_MAPPING
, 1))
345 /* If not mapped or timestamp not updated, request new map. */
347 || (cur
->head
->nscd_certainly_running
== 0
348 && cur
->head
->timestamp
+ MAPPING_TIMEOUT
< time (NULL
))
349 || cur
->head
->data_size
> cur
->datasize
)
350 cur
= get_mapping (type
, name
,
351 (struct mapped_database
**) &mapptr
->mapped
);
353 if (__builtin_expect (cur
!= NO_MAPPING
, 1))
355 if (__builtin_expect (((*gc_cyclep
= cur
->head
->gc_cycle
) & 1) != 0,
359 atomic_increment (&cur
->counter
);
369 /* Don't return const struct datahead *, as eventhough the record
370 is normally constant, it can change arbitrarily during nscd
371 garbage collection. */
373 __nscd_cache_search (request_type type
, const char *key
, size_t keylen
,
374 const struct mapped_database
*mapped
)
376 unsigned long int hash
= __nis_hash (key
, keylen
) % mapped
->head
->module
;
377 size_t datasize
= mapped
->datasize
;
379 ref_t work
= mapped
->head
->array
[hash
];
380 while (work
!= ENDREF
&& work
+ sizeof (struct hashentry
) <= datasize
)
382 struct hashentry
*here
= (struct hashentry
*) (mapped
->data
+ work
);
384 #ifndef _STRING_ARCH_unaligned
385 /* Although during garbage collection when moving struct hashentry
386 records around we first copy from old to new location and then
387 adjust pointer from previous hashentry to it, there is no barrier
388 between those memory writes. It is very unlikely to hit it,
389 so check alignment only if a misaligned load can crash the
391 if ((uintptr_t) here
& (__alignof__ (*here
) - 1))
395 if (type
== here
->type
396 && keylen
== here
->len
397 && here
->key
+ keylen
<= datasize
398 && memcmp (key
, mapped
->data
+ here
->key
, keylen
) == 0
399 && here
->packet
+ sizeof (struct datahead
) <= datasize
)
401 /* We found the entry. Increment the appropriate counter. */
403 = (struct datahead
*) (mapped
->data
+ here
->packet
);
405 #ifndef _STRING_ARCH_unaligned
406 if ((uintptr_t) dh
& (__alignof__ (*dh
) - 1))
410 /* See whether we must ignore the entry or whether something
411 is wrong because garbage collection is in progress. */
412 if (dh
->usable
&& here
->packet
+ dh
->allocsize
<= datasize
)
423 /* Create a socket connected to a name. */
425 __nscd_open_socket (const char *key
, size_t keylen
, request_type type
,
426 void *response
, size_t responselen
)
428 int saved_errno
= errno
;
430 int sock
= open_socket ();
434 req
.version
= NSCD_VERSION
;
436 req
.key_len
= keylen
;
439 vec
[0].iov_base
= &req
;
440 vec
[0].iov_len
= sizeof (request_header
);
441 vec
[1].iov_base
= (void *) key
;
442 vec
[1].iov_len
= keylen
;
444 ssize_t nbytes
= TEMP_FAILURE_RETRY (__writev (sock
, vec
, 2));
445 if (nbytes
== (ssize_t
) (sizeof (request_header
) + keylen
)
447 && wait_on_socket (sock
) > 0)
449 nbytes
= TEMP_FAILURE_RETRY (__read (sock
, response
, responselen
));
450 if (nbytes
== (ssize_t
) responselen
)
454 close_not_cancel_no_status (sock
);
457 __set_errno (saved_errno
);