summaryrefslogtreecommitdiff
path: root/nscd/nscd_helper.c
diff options
context:
space:
mode:
Diffstat (limited to 'nscd/nscd_helper.c')
-rw-r--r--nscd/nscd_helper.c153
1 files changed, 97 insertions, 56 deletions
diff --git a/nscd/nscd_helper.c b/nscd/nscd_helper.c
index 7c45981586..394b2f86e6 100644
--- a/nscd/nscd_helper.c
+++ b/nscd/nscd_helper.c
@@ -1,4 +1,5 @@
-/* Copyright (C) 1998-2002,2003,2004,2005,2006 Free Software Foundation, Inc.
+/* Copyright (C) 1998-2002,2003,2004,2005,2006,2007
+ Free Software Foundation, Inc.
This file is part of the GNU C Library.
Contributed by Ulrich Drepper <drepper@cygnus.com>, 1998.
@@ -21,6 +22,7 @@
#include <errno.h>
#include <fcntl.h>
#include <stdbool.h>
+#include <string.h>
#include <time.h>
#include <unistd.h>
#include <sys/mman.h>
@@ -95,16 +97,20 @@ __readvall (int fd, const struct iovec *iov, int iovcnt)
static int
-open_socket (void)
+open_socket (request_type type, const char *key, size_t keylen)
{
int sock = __socket (PF_UNIX, SOCK_STREAM, 0);
if (sock < 0)
return -1;
+ struct
+ {
+ request_header req;
+ char key[keylen];
+ } reqdata;
+
/* Make socket non-blocking. */
- int fl = __fcntl (sock, F_GETFL);
- if (fl != -1)
- __fcntl (sock, F_SETFL, fl | O_NONBLOCK);
+ __fcntl (sock, F_SETFL, O_RDWR | O_NONBLOCK);
struct sockaddr_un sun;
sun.sun_family = AF_UNIX;
@@ -113,13 +119,56 @@ open_socket (void)
&& errno != EINPROGRESS)
goto out;
- struct pollfd fds[1];
- fds[0].fd = sock;
- fds[0].events = POLLOUT | POLLERR | POLLHUP;
- if (__poll (fds, 1, 5 * 1000) > 0)
- /* Success. We do not check for success of the connect call here.
- If it failed, the following operations will fail. */
- return sock;
+ reqdata.req.version = NSCD_VERSION;
+ reqdata.req.type = type;
+ reqdata.req.key_len = keylen;
+
+ memcpy (reqdata.key, key, keylen);
+
+ bool first_try = true;
+ struct timeval tvend;
+ while (1)
+ {
+#ifndef MSG_NOSIGNAL
+# define MSG_NOSIGNAL 0
+#endif
+ ssize_t wres = TEMP_FAILURE_RETRY (__send (sock, &reqdata,
+ sizeof (reqdata),
+ MSG_NOSIGNAL));
+ if (__builtin_expect (wres == (ssize_t) sizeof (reqdata), 1))
+ /* We managed to send the request. */
+ return sock;
+
+ if (wres != -1 || errno != EAGAIN)
+ /* Something is really wrong, no chance to continue. */
+ break;
+
+ /* The daemon is busy wait for it. */
+ int to;
+ if (first_try)
+ {
+ gettimeofday (&tvend, NULL);
+ tvend.tv_sec += 5;
+ to = 5 * 1000;
+ first_try = false;
+ }
+ else
+ {
+ struct timeval now;
+ gettimeofday (&now, NULL);
+ to = ((tvend.tv_sec - now.tv_sec) * 1000
+ + (tvend.tv_usec - now.tv_usec) / 1000);
+ }
+
+ struct pollfd fds[1];
+ fds[0].fd = sock;
+ fds[0].events = POLLOUT | POLLERR | POLLHUP;
+ if (__poll (fds, 1, to) <= 0)
+ /* The connection timed out or broke down. */
+ break;
+
+ /* We try to write again. */
+ }
out:
close_not_cancel_no_status (sock);
@@ -179,36 +228,15 @@ get_mapping (request_type type, const char *key,
int saved_errno = errno;
int mapfd = -1;
+ char resdata[keylen];
- /* Send the request. */
- struct
- {
- request_header req;
- char key[keylen];
- } reqdata;
-
- int sock = open_socket ();
+ /* Open a socket and send the request. */
+ int sock = open_socket (type, key, keylen);
if (sock < 0)
goto out;
- reqdata.req.version = NSCD_VERSION;
- reqdata.req.type = type;
- reqdata.req.key_len = keylen;
- memcpy (reqdata.key, key, keylen);
-
-# ifndef MSG_NOSIGNAL
-# define MSG_NOSIGNAL 0
-# endif
- if (__builtin_expect (TEMP_FAILURE_RETRY (__send (sock, &reqdata,
- sizeof (reqdata),
- MSG_NOSIGNAL))
- != sizeof (reqdata), 0))
- /* We cannot even write the request. */
- goto out_close2;
-
/* Room for the data sent along with the file descriptor. We expect
the key name back. */
-# define resdata reqdata.key
struct iovec iov[1];
iov[0].iov_base = resdata;
iov[0].iov_len = keylen;
@@ -362,7 +390,10 @@ __nscd_get_map_ref (request_type type, const char *name,
}
-const struct datahead *
+/* Don't return const struct datahead *, as eventhough the record
+ is normally constant, it can change arbitrarily during nscd
+ garbage collection. */
+struct datahead *
__nscd_cache_search (request_type type, const char *key, size_t keylen,
const struct mapped_database *mapped)
{
@@ -374,16 +405,32 @@ __nscd_cache_search (request_type type, const char *key, size_t keylen,
{
struct hashentry *here = (struct hashentry *) (mapped->data + work);
+#ifndef _STRING_ARCH_unaligned
+ /* Although during garbage collection when moving struct hashentry
+ records around we first copy from old to new location and then
+ adjust pointer from previous hashentry to it, there is no barrier
+ between those memory writes. It is very unlikely to hit it,
+ so check alignment only if a misaligned load can crash the
+ application. */
+ if ((uintptr_t) here & (__alignof__ (*here) - 1))
+ return NULL;
+#endif
+
if (type == here->type
&& keylen == here->len
- && here->key + here->len <= datasize
+ && here->key + keylen <= datasize
&& memcmp (key, mapped->data + here->key, keylen) == 0
&& here->packet + sizeof (struct datahead) <= datasize)
{
/* We found the entry. Increment the appropriate counter. */
- const struct datahead *dh
+ struct datahead *dh
= (struct datahead *) (mapped->data + here->packet);
+#ifndef _STRING_ARCH_unaligned
+ if ((uintptr_t) dh & (__alignof__ (*dh) - 1))
+ return NULL;
+#endif
+
/* See whether we must ignore the entry or whether something
is wrong because garbage collection is in progress. */
if (dh->usable && here->packet + dh->allocsize <= datasize)
@@ -402,28 +449,22 @@ int
__nscd_open_socket (const char *key, size_t keylen, request_type type,
void *response, size_t responselen)
{
+ /* This should never happen and it is something the nscd daemon
+ enforces, too. He it helps to limit the amount of stack
+ used. */
+ if (keylen > MAXKEYLEN)
+ return -1;
+
int saved_errno = errno;
- int sock = open_socket ();
+ int sock = open_socket (type, key, keylen);
if (sock >= 0)
{
- request_header req;
- req.version = NSCD_VERSION;
- req.type = type;
- req.key_len = keylen;
-
- struct iovec vec[2];
- vec[0].iov_base = &req;
- vec[0].iov_len = sizeof (request_header);
- vec[1].iov_base = (void *) key;
- vec[1].iov_len = keylen;
-
- ssize_t nbytes = TEMP_FAILURE_RETRY (__writev (sock, vec, 2));
- if (nbytes == (ssize_t) (sizeof (request_header) + keylen)
- /* Wait for data. */
- && wait_on_socket (sock) > 0)
+ /* Wait for data. */
+ if (wait_on_socket (sock) > 0)
{
- nbytes = TEMP_FAILURE_RETRY (__read (sock, response, responselen));
+ ssize_t nbytes = TEMP_FAILURE_RETRY (__read (sock, response,
+ responselen));
if (nbytes == (ssize_t) responselen)
return sock;
}