1 /* Copyright (C) 1998-2002, 2003, 2004 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
27 #include <sys/socket.h>
31 #include <not-cancel.h>
32 #include <nis/rpcsvc/nis.h>
34 #include "nscd-client.h"
40 int sock
= __socket (PF_UNIX
, SOCK_STREAM
, 0);
44 /* Make socket non-blocking. */
45 int fl
= __fcntl (sock
, F_GETFL
);
47 __fcntl (sock
, F_SETFL
, fl
| O_NONBLOCK
);
49 struct sockaddr_un sun
;
50 sun
.sun_family
= AF_UNIX
;
51 strcpy (sun
.sun_path
, _PATH_NSCDSOCKET
);
52 if (__connect (sock
, (struct sockaddr
*) &sun
, sizeof (sun
)) < 0
53 && errno
!= EINPROGRESS
)
58 fds
[0].events
= POLLOUT
| POLLERR
| POLLHUP
;
59 if (__poll (fds
, 1, 5 * 1000) > 0)
60 /* Success. We do not check for success of the connect call here.
61 If it failed, the following operations will fail. */
65 close_not_cancel_no_status (sock
);
72 __nscd_unmap (struct mapped_database
*mapped
)
74 assert (mapped
->counter
== 0);
75 munmap ((void *) mapped
->head
, mapped
->mapsize
);
80 /* Try to get a file descriptor for the shared meory segment
81 containing the database. */
82 static struct mapped_database
*
83 get_mapping (request_type type
, const char *key
,
84 struct mapped_database
**mappedp
)
86 struct mapped_database
*result
= NO_MAPPING
;
88 const size_t keylen
= strlen (key
) + 1;
90 int saved_errno
= errno
;
94 /* Send the request. */
98 int sock
= open_socket ();
102 req
.version
= NSCD_VERSION
;
104 req
.key_len
= keylen
;
106 iov
[0].iov_base
= &req
;
107 iov
[0].iov_len
= sizeof (req
);
108 iov
[1].iov_base
= (void *) key
;
109 iov
[1].iov_len
= keylen
;
111 if (TEMP_FAILURE_RETRY (__writev (sock
, iov
, 2))
112 != iov
[0].iov_len
+ iov
[1].iov_len
)
113 /* We cannot even write the request. */
116 /* Room for the data sent along with the file descriptor. We expect
117 the key name back. */
118 iov
[0].iov_base
= resdata
;
119 iov
[0].iov_len
= keylen
;
121 char buf
[CMSG_SPACE (sizeof (int))];
122 struct msghdr msg
= { .msg_iov
= iov
, .msg_iovlen
= 1,
123 .msg_control
= buf
, .msg_controllen
= sizeof (buf
) };
124 struct cmsghdr
*cmsg
= CMSG_FIRSTHDR (&msg
);
126 cmsg
->cmsg_level
= SOL_SOCKET
;
127 cmsg
->cmsg_type
= SCM_RIGHTS
;
128 cmsg
->cmsg_len
= CMSG_LEN (sizeof (int));
130 *(int *) CMSG_DATA (cmsg
) = -1;
132 msg
.msg_controllen
= cmsg
->cmsg_len
;
134 struct pollfd fds
[1];
136 fds
[0].events
= POLLIN
| POLLERR
| POLLHUP
;
137 if (__poll (fds
, 1, 5 * 1000) <= 0)
138 /* Failure or timeout. */
141 if (TEMP_FAILURE_RETRY (__recvmsg (sock
, &msg
, 0)) != keylen
142 || msg
.msg_controllen
!= CMSG_LEN (sizeof (int)))
145 mapfd
= *(int *) CMSG_DATA (cmsg
);
148 if (strcmp (resdata
, key
) != 0
149 || fstat64 (mapfd
, &st
) != 0
150 || st
.st_size
< sizeof (struct database_pers_head
))
153 struct database_pers_head head
;
154 if (TEMP_FAILURE_RETRY (__pread (mapfd
, &head
, sizeof (head
), 0))
158 if (head
.version
!= DB_VERSION
|| head
.header_size
!= sizeof (head
)
159 /* This really should not happen but who knows, maybe the update
161 || head
.timestamp
+ MAPPING_TIMEOUT
< time (NULL
))
164 size_t size
= (sizeof (head
) + roundup (head
.module
* sizeof (ref_t
), ALIGN
)
167 if (st
.st_size
< size
)
170 /* The file is large enough, map it now. */
171 void *mapping
= __mmap (NULL
, size
, PROT_READ
, MAP_SHARED
, mapfd
, 0);
172 if (mapping
!= MAP_FAILED
)
174 /* Allocate a record for the mapping. */
175 struct mapped_database
*newp
;
177 newp
= malloc (sizeof (*newp
));
180 /* Ugh, after all we went through the memory allocation failed. */
181 munmap (result
, size
);
185 newp
->head
= mapping
;
186 newp
->data
= ((char *) mapping
+ head
.header_size
187 + roundup (head
.module
* sizeof (ref_t
), ALIGN
));
188 newp
->mapsize
= size
;
189 /* Set counter to 1 to show it is usable. */
200 __set_errno (saved_errno
);
201 #endif /* SCM_RIGHTS */
203 struct mapped_database
*oldval
= *mappedp
;
206 if (oldval
!= NULL
&& atomic_decrement_val (&oldval
->counter
) == 0)
207 __nscd_unmap (oldval
);
213 struct mapped_database
*
214 __nscd_get_map_ref (request_type type
, const char *name
,
215 struct locked_map_ptr
*mapptr
, volatile int *gc_cyclep
)
217 struct mapped_database
*cur
= mapptr
->mapped
;
218 if (cur
== NO_MAPPING
)
222 while (atomic_compare_and_exchange_val_acq (&mapptr
->lock
, 1, 0) != 0)
224 // XXX Best number of rounds?
231 cur
= mapptr
->mapped
;
233 if (__builtin_expect (cur
!= NO_MAPPING
, 1))
235 /* If not mapped or timestamp not updated, request new map. */
237 || (cur
->head
->nscd_certainly_running
== 0
238 && cur
->head
->timestamp
+ MAPPING_TIMEOUT
< time (NULL
)))
239 cur
= get_mapping (type
, name
, &mapptr
->mapped
);
241 if (__builtin_expect (cur
!= NO_MAPPING
, 1))
243 if (__builtin_expect (((*gc_cyclep
= cur
->head
->gc_cycle
) & 1) != 0,
247 atomic_increment (&cur
->counter
);
257 const struct datahead
*
258 __nscd_cache_search (request_type type
, const char *key
, size_t keylen
,
259 const struct mapped_database
*mapped
)
261 unsigned long int hash
= __nis_hash (key
, keylen
) % mapped
->head
->module
;
263 ref_t work
= mapped
->head
->array
[hash
];
264 while (work
!= ENDREF
)
266 struct hashentry
*here
= (struct hashentry
*) (mapped
->data
+ work
);
268 if (type
== here
->type
&& keylen
== here
->len
269 && memcmp (key
, mapped
->data
+ here
->key
, keylen
) == 0)
271 /* We found the entry. Increment the appropriate counter. */
272 const struct datahead
*dh
273 = (struct datahead
*) (mapped
->data
+ here
->packet
);
275 /* See whether we must ignore the entry or whether something
276 is wrong because garbage collection is in progress. */
277 if (dh
->usable
&& ((char *) dh
+ dh
->allocsize
278 <= (char *) mapped
->head
+ mapped
->mapsize
))
289 /* Create a socket connected to a name. */
291 __nscd_open_socket (const char *key
, size_t keylen
, request_type type
,
292 void *response
, size_t responselen
)
294 int saved_errno
= errno
;
296 int sock
= open_socket ();
300 req
.version
= NSCD_VERSION
;
302 req
.key_len
= keylen
;
305 vec
[0].iov_base
= &req
;
306 vec
[0].iov_len
= sizeof (request_header
);
307 vec
[1].iov_base
= (void *) key
;
308 vec
[1].iov_len
= keylen
;
310 ssize_t nbytes
= TEMP_FAILURE_RETRY (__writev (sock
, vec
, 2));
311 if (nbytes
== (ssize_t
) (sizeof (request_header
) + keylen
))
314 struct pollfd fds
[1];
316 fds
[0].events
= POLLIN
| POLLERR
| POLLHUP
;
317 if (__poll (fds
, 1, 5 * 1000) > 0)
319 nbytes
= TEMP_FAILURE_RETRY (__read (sock
, response
,
321 if (nbytes
== (ssize_t
) responselen
)
326 close_not_cancel_no_status (sock
);
329 __set_errno (saved_errno
);