1 /* Copyright (C) 1998-2002,2003,2004,2005,2006 Free Software Foundation, Inc.
2 This file is part of the GNU C Library.
3 Contributed by Ulrich Drepper <drepper@cygnus.com>, 1998.
5 The GNU C Library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
10 The GNU C Library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
15 You should have received a copy of the GNU Lesser General Public
16 License along with the GNU C Library; if not, write to the Free
17 Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
28 #include <sys/socket.h>
33 #include <not-cancel.h>
34 #include <nis/rpcsvc/nis.h>
36 #include "nscd-client.h"
40 __readall (int fd
, void *buf
, size_t len
)
46 ret
= TEMP_FAILURE_RETRY (__read (fd
, buf
, n
));
49 buf
= (char *) buf
+ ret
;
53 return ret
< 0 ? ret
: len
- n
;
58 __readvall (int fd
, const struct iovec
*iov
, int iovcnt
)
60 ssize_t ret
= TEMP_FAILURE_RETRY (__readv (fd
, iov
, iovcnt
));
65 for (int i
= 0; i
< iovcnt
; ++i
)
66 total
+= iov
[i
].iov_len
;
70 struct iovec iov_buf
[iovcnt
];
73 struct iovec
*iovp
= memcpy (iov_buf
, iov
, iovcnt
* sizeof (*iov
));
76 while (iovp
->iov_len
<= r
)
82 iovp
->iov_base
= (char *) iovp
->iov_base
+ r
;
84 r
= TEMP_FAILURE_RETRY (__readv (fd
, iovp
, iovcnt
));
100 int sock
= __socket (PF_UNIX
, SOCK_STREAM
, 0);
104 /* Make socket non-blocking. */
105 int fl
= __fcntl (sock
, F_GETFL
);
107 __fcntl (sock
, F_SETFL
, fl
| O_NONBLOCK
);
109 struct sockaddr_un sun
;
110 sun
.sun_family
= AF_UNIX
;
111 strcpy (sun
.sun_path
, _PATH_NSCDSOCKET
);
112 if (__connect (sock
, (struct sockaddr
*) &sun
, sizeof (sun
)) < 0
113 && errno
!= EINPROGRESS
)
116 struct pollfd fds
[1];
118 fds
[0].events
= POLLOUT
| POLLERR
| POLLHUP
;
119 if (__poll (fds
, 1, 5 * 1000) > 0)
120 /* Success. We do not check for success of the connect call here.
121 If it failed, the following operations will fail. */
125 close_not_cancel_no_status (sock
);
132 __nscd_unmap (struct mapped_database
*mapped
)
134 assert (mapped
->counter
== 0);
135 __munmap ((void *) mapped
->head
, mapped
->mapsize
);
141 wait_on_socket (int sock
)
143 struct pollfd fds
[1];
145 fds
[0].events
= POLLIN
| POLLERR
| POLLHUP
;
146 int n
= __poll (fds
, 1, 5 * 1000);
147 if (n
== -1 && __builtin_expect (errno
== EINTR
, 0))
149 /* Handle the case where the poll() call is interrupted by a
150 signal. We cannot just use TEMP_FAILURE_RETRY since it might
151 lead to infinite loops. */
153 (void) __gettimeofday (&now
, NULL
);
154 long int end
= (now
.tv_sec
+ 5) * 1000 + (now
.tv_usec
+ 500) / 1000;
157 long int timeout
= end
- (now
.tv_sec
* 1000
158 + (now
.tv_usec
+ 500) / 1000);
159 n
= __poll (fds
, 1, timeout
);
160 if (n
!= -1 || errno
!= EINTR
)
162 (void) __gettimeofday (&now
, NULL
);
170 /* Try to get a file descriptor for the shared meory segment
171 containing the database. */
172 static struct mapped_database
*
173 get_mapping (request_type type
, const char *key
,
174 struct mapped_database
**mappedp
)
176 struct mapped_database
*result
= NO_MAPPING
;
178 const size_t keylen
= strlen (key
) + 1;
179 int saved_errno
= errno
;
183 /* Send the request. */
190 int sock
= open_socket ();
194 reqdata
.req
.version
= NSCD_VERSION
;
195 reqdata
.req
.type
= type
;
196 reqdata
.req
.key_len
= keylen
;
197 memcpy (reqdata
.key
, key
, keylen
);
199 # ifndef MSG_NOSIGNAL
200 # define MSG_NOSIGNAL 0
202 if (__builtin_expect (TEMP_FAILURE_RETRY (__send (sock
, &reqdata
,
205 != sizeof (reqdata
), 0))
206 /* We cannot even write the request. */
209 /* Room for the data sent along with the file descriptor. We expect
210 the key name back. */
211 # define resdata reqdata.key
213 iov
[0].iov_base
= resdata
;
214 iov
[0].iov_len
= keylen
;
219 char bytes
[CMSG_SPACE (sizeof (int))];
221 struct msghdr msg
= { .msg_iov
= iov
, .msg_iovlen
= 1,
222 .msg_control
= buf
.bytes
,
223 .msg_controllen
= sizeof (buf
) };
224 struct cmsghdr
*cmsg
= CMSG_FIRSTHDR (&msg
);
226 cmsg
->cmsg_level
= SOL_SOCKET
;
227 cmsg
->cmsg_type
= SCM_RIGHTS
;
228 cmsg
->cmsg_len
= CMSG_LEN (sizeof (int));
230 /* This access is well-aligned since BUF is correctly aligned for an
231 int and CMSG_DATA preserves this alignment. */
232 *(int *) CMSG_DATA (cmsg
) = -1;
234 msg
.msg_controllen
= cmsg
->cmsg_len
;
236 if (wait_on_socket (sock
) <= 0)
239 if (__builtin_expect (TEMP_FAILURE_RETRY (__recvmsg (sock
, &msg
, 0))
243 mapfd
= *(int *) CMSG_DATA (cmsg
);
245 if (__builtin_expect (CMSG_FIRSTHDR (&msg
)->cmsg_len
246 != CMSG_LEN (sizeof (int)), 0))
250 if (__builtin_expect (strcmp (resdata
, key
) != 0, 0)
251 || __builtin_expect (fstat64 (mapfd
, &st
) != 0, 0)
252 || __builtin_expect (st
.st_size
< sizeof (struct database_pers_head
), 0))
255 struct database_pers_head head
;
256 if (__builtin_expect (TEMP_FAILURE_RETRY (__pread (mapfd
, &head
,
258 != sizeof (head
), 0))
261 if (__builtin_expect (head
.version
!= DB_VERSION
, 0)
262 || __builtin_expect (head
.header_size
!= sizeof (head
), 0)
263 /* This really should not happen but who knows, maybe the update
265 || __builtin_expect (! head
.nscd_certainly_running
266 && head
.timestamp
+ MAPPING_TIMEOUT
< time (NULL
),
270 size_t size
= (sizeof (head
) + roundup (head
.module
* sizeof (ref_t
), ALIGN
)
273 if (__builtin_expect (st
.st_size
< size
, 0))
276 /* The file is large enough, map it now. */
277 void *mapping
= __mmap (NULL
, size
, PROT_READ
, MAP_SHARED
, mapfd
, 0);
278 if (__builtin_expect (mapping
!= MAP_FAILED
, 1))
280 /* Allocate a record for the mapping. */
281 struct mapped_database
*newp
= malloc (sizeof (*newp
));
284 /* Ugh, after all we went through the memory allocation failed. */
285 __munmap (mapping
, size
);
289 newp
->head
= mapping
;
290 newp
->data
= ((char *) mapping
+ head
.header_size
291 + roundup (head
.module
* sizeof (ref_t
), ALIGN
));
292 newp
->mapsize
= size
;
293 /* Set counter to 1 to show it is usable. */
304 __set_errno (saved_errno
);
305 #endif /* SCM_RIGHTS */
307 struct mapped_database
*oldval
= *mappedp
;
310 if (oldval
!= NULL
&& atomic_decrement_val (&oldval
->counter
) == 0)
311 __nscd_unmap (oldval
);
317 struct mapped_database
*
318 __nscd_get_map_ref (request_type type
, const char *name
,
319 volatile struct locked_map_ptr
*mapptr
, int *gc_cyclep
)
321 struct mapped_database
*cur
= mapptr
->mapped
;
322 if (cur
== NO_MAPPING
)
326 while (__builtin_expect (atomic_compare_and_exchange_val_acq (&mapptr
->lock
,
329 // XXX Best number of rounds?
330 if (__builtin_expect (++cnt
> 5, 0))
336 cur
= mapptr
->mapped
;
338 if (__builtin_expect (cur
!= NO_MAPPING
, 1))
340 /* If not mapped or timestamp not updated, request new map. */
342 || (cur
->head
->nscd_certainly_running
== 0
343 && cur
->head
->timestamp
+ MAPPING_TIMEOUT
< time (NULL
)))
344 cur
= get_mapping (type
, name
,
345 (struct mapped_database
**) &mapptr
->mapped
);
347 if (__builtin_expect (cur
!= NO_MAPPING
, 1))
349 if (__builtin_expect (((*gc_cyclep
= cur
->head
->gc_cycle
) & 1) != 0,
353 atomic_increment (&cur
->counter
);
363 const struct datahead
*
364 __nscd_cache_search (request_type type
, const char *key
, size_t keylen
,
365 const struct mapped_database
*mapped
)
367 unsigned long int hash
= __nis_hash (key
, keylen
) % mapped
->head
->module
;
369 ref_t work
= mapped
->head
->array
[hash
];
370 while (work
!= ENDREF
)
372 struct hashentry
*here
= (struct hashentry
*) (mapped
->data
+ work
);
374 if (type
== here
->type
&& keylen
== here
->len
375 && memcmp (key
, mapped
->data
+ here
->key
, keylen
) == 0)
377 /* We found the entry. Increment the appropriate counter. */
378 const struct datahead
*dh
379 = (struct datahead
*) (mapped
->data
+ here
->packet
);
381 /* See whether we must ignore the entry or whether something
382 is wrong because garbage collection is in progress. */
383 if (dh
->usable
&& ((char *) dh
+ dh
->allocsize
384 <= (char *) mapped
->head
+ mapped
->mapsize
))
395 /* Create a socket connected to a name. */
397 __nscd_open_socket (const char *key
, size_t keylen
, request_type type
,
398 void *response
, size_t responselen
)
400 int saved_errno
= errno
;
402 int sock
= open_socket ();
406 req
.version
= NSCD_VERSION
;
408 req
.key_len
= keylen
;
411 vec
[0].iov_base
= &req
;
412 vec
[0].iov_len
= sizeof (request_header
);
413 vec
[1].iov_base
= (void *) key
;
414 vec
[1].iov_len
= keylen
;
416 ssize_t nbytes
= TEMP_FAILURE_RETRY (__writev (sock
, vec
, 2));
417 if (nbytes
== (ssize_t
) (sizeof (request_header
) + keylen
)
419 && wait_on_socket (sock
) > 0)
421 nbytes
= TEMP_FAILURE_RETRY (__read (sock
, response
, responselen
));
422 if (nbytes
== (ssize_t
) responselen
)
426 close_not_cancel_no_status (sock
);
429 __set_errno (saved_errno
);