/* Cache handling for services lookup.
- Copyright (C) 2007, 2008, 2009 Free Software Foundation, Inc.
+ Copyright (C) 2007-2014 Free Software Foundation, Inc.
This file is part of the GNU C Library.
Contributed by Ulrich Drepper <drepper@drepper.com>, 2007.
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software Foundation,
- Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+ along with this program; if not, see <http://www.gnu.org/licenses/>. */
#include <alloca.h>
#include <assert.h>
#include <libintl.h>
#include <netdb.h>
#include <unistd.h>
+#include <stdint.h>
#include <sys/mman.h>
#include <kernel-features.h>
};
-static void
+static time_t
cache_addserv (struct database_dyn *db, int fd, request_header *req,
const void *key, struct servent *serv, uid_t owner,
struct hashentry *const he, struct datahead *dh, int errval)
{
+ bool all_written = true;
ssize_t total;
- ssize_t written;
time_t t = time (NULL);
/* We allocate all data in one memory block: the iov vector,
assert (offsetof (struct dataset, resp) == offsetof (struct datahead, data));
+ time_t timeout = MAX_TIMEOUT_VALUE;
if (serv == NULL)
{
if (he != NULL && errval == EAGAIN)
/* Do not reset the value if we never not reload the record. */
dh->nreloads = reload_count - 1;
- written = total = 0;
+ /* Reload with the same time-to-live value. */
+ timeout = dh->timeout = t + db->postimeout;
+
+ total = 0;
}
else
{
case. */
total = sizeof (notfound);
- written = TEMP_FAILURE_RETRY (send (fd, ¬found, total,
- MSG_NOSIGNAL));
+ if (fd != -1
+ && TEMP_FAILURE_RETRY (send (fd, ¬found, total,
+ MSG_NOSIGNAL)) != total)
+ all_written = false;
- dataset = mempool_alloc (db, sizeof (struct dataset) + req->key_len,
- 1);
- /* If we cannot permanently store the result, so be it. */
- if (dataset != NULL)
+ /* If we have a transient error or cannot permanently store
+ the result, so be it. */
+ if (errval == EAGAIN || __builtin_expect (db->negtimeout == 0, 0))
+ {
+ /* Mark the old entry as obsolete. */
+ if (dh != NULL)
+ dh->usable = false;
+ }
+ else if ((dataset = mempool_alloc (db, (sizeof (struct dataset)
+ + req->key_len), 1)) != NULL)
{
dataset->head.allocsize = sizeof (struct dataset) + req->key_len;
dataset->head.recsize = total;
dataset->head.usable = true;
/* Compute the timeout time. */
- dataset->head.timeout = t + db->negtimeout;
+ timeout = dataset->head.timeout = t + db->negtimeout;
/* This is the reply. */
memcpy (&dataset->resp, ¬found, total);
+ s_name_len
+ s_proto_len
+ s_aliases_cnt * sizeof (uint32_t));
- written = total;
/* If we refill the cache, first assume the reconrd did not
change. Allocate memory on the cache since it is likely
dataset->head.usable = true;
/* Compute the timeout time. */
- dataset->head.timeout = t + db->postimeout;
+ timeout = dataset->head.timeout = t + db->postimeout;
dataset->resp.version = NSCD_VERSION;
dataset->resp.found = 1;
{
assert (db->wr_fd != -1);
assert ((char *) &dataset->resp > (char *) db->data);
- assert ((char *) &dataset->resp - (char *) db->head
+ assert ((char *) dataset - (char *) db->head
+ total
<= (sizeof (struct database_pers_head)
+ db->head->module * sizeof (ref_t)
+ db->head->data_size));
- written = sendfileall (fd, db->wr_fd,
- (char *) &dataset->resp
- - (char *) db->head, total);
+ ssize_t written = sendfileall (fd, db->wr_fd,
+ (char *) &dataset->resp
+ - (char *) db->head,
+ dataset->head.recsize);
+ if (written != dataset->head.recsize)
+ {
# ifndef __ASSUME_SENDFILE
- if (written == -1 && errno == ENOSYS)
- goto use_write;
+ if (written == -1 && errno == ENOSYS)
+ goto use_write;
# endif
+ all_written = false;
+ }
}
else
# ifndef __ASSUME_SENDFILE
use_write:
# endif
#endif
- written = writeall (fd, &dataset->resp, total);
+ if (writeall (fd, &dataset->resp, dataset->head.recsize)
+ != dataset->head.recsize)
+ all_written = false;
}
/* Add the record to the database. But only if it has not been
}
}
- if (__builtin_expect (written != total, 0) && debug_level > 0)
+ if (__builtin_expect (!all_written, 0) && debug_level > 0)
{
char buf[256];
dbg_log (_("short write in %s: %s"), __FUNCTION__,
strerror_r (errno, buf, sizeof (buf)));
}
+
+ return timeout;
}
}
-static void
+static time_t
addservbyX (struct database_dyn *db, int fd, request_header *req,
char *key, uid_t uid, struct hashentry *he, struct datahead *dh)
{
buffer = (char *) extend_alloca (buffer, buflen, 2 * buflen);
}
- cache_addserv (db, fd, req, key, serv, uid, he, dh, errval);
+ time_t timeout = cache_addserv (db, fd, req, key, serv, uid, he, dh, errval);
if (use_malloc)
free (buffer);
+
+ return timeout;
}
}
-void
+time_t
readdservbyname (struct database_dyn *db, struct hashentry *he,
struct datahead *dh)
{
.key_len = he->len
};
- addservbyX (db, -1, &req, db->data + he->key, he->owner, he, dh);
+ return addservbyX (db, -1, &req, db->data + he->key, he->owner, he, dh);
}
}
-void
+time_t
readdservbyport (struct database_dyn *db, struct hashentry *he,
struct datahead *dh)
{
.key_len = he->len
};
- addservbyX (db, -1, &req, db->data + he->key, he->owner, he, dh);
+ return addservbyX (db, -1, &req, db->data + he->key, he->owner, he, dh);
}