summaryrefslogtreecommitdiffstats
path: root/lib/libc/yp
diff options
context:
space:
mode:
authorwpaul <wpaul@FreeBSD.org>1998-03-07 05:06:10 +0000
committerwpaul <wpaul@FreeBSD.org>1998-03-07 05:06:10 +0000
commitb5a6d61144d61bee4a3f4e2af816065ad84fc974 (patch)
tree52fbfb312c63d6429cd611e7b24da83d478deff8 /lib/libc/yp
parenta7987039c367704a1ecc2d84b9161863b0a63b85 (diff)
downloadFreeBSD-src-b5a6d61144d61bee4a3f4e2af816065ad84fc974.zip
FreeBSD-src-b5a6d61144d61bee4a3f4e2af816065ad84fc974.tar.gz
Fix resource allocation problems:
- Completely recoded the ypmatch cache code. The old code could leak memory: it would allow the cache to grow, but never shrink. The new code imposes the following limits: o The cache is capped at a limit of 5 entries. o Each entry expires after five seconds, at which point its slot is freed. o If an insertion is to be done and all five slots are filled, the oldest entry is forcibly expired to release its slot. Also, the cache is implemented on a per-binding basis rather than having a global cache covering all bindings. This means that each bound domain has its own 5 slot cache. - Changed clntudp_create() to clntudp_bufcreate() so that the xmit/recv message buffer sizes can be set explicitly. NIS transactions are rarely much larger than 1024 bytes since YPMAXRECORD is 1024. The defaults chosen by clntudb_create() are actually much larger than needed. I set the xmit buffer to a little over 1024 and the recv buffer to a little over 2048. This saves a few Kbytes for each NIS binding. - Add my name to the copyright. I think I've made enough changes to this file to merit it. :) Note: these changes should go into the 2.2.x branch, but I'm waiting on feedback from a tester to see if the cache fixes solve the reported memory leak problem.
Diffstat (limited to 'lib/libc/yp')
-rw-r--r--lib/libc/yp/yplib.c270
1 files changed, 176 insertions, 94 deletions
diff --git a/lib/libc/yp/yplib.c b/lib/libc/yp/yplib.c
index 2e0223d..c464b1c 100644
--- a/lib/libc/yp/yplib.c
+++ b/lib/libc/yp/yplib.c
@@ -1,5 +1,6 @@
/*
* Copyright (c) 1992/3 Theo de Raadt <deraadt@fsa.ca>
+ * Copyright (c) 1998 Bill Paul <wpaul@ctr.columbia.edu>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -28,7 +29,7 @@
*/
#ifndef LINT
-static char *rcsid = "$Id: yplib.c,v 1.28 1997/02/22 15:05:02 peter Exp $";
+static char *rcsid = "$Id: yplib.c,v 1.29 1997/04/10 20:26:04 wpaul Exp $";
#endif
#include <sys/param.h>
@@ -45,21 +46,38 @@ static char *rcsid = "$Id: yplib.c,v 1.28 1997/02/22 15:05:02 peter Exp $";
#include <rpc/xdr.h>
#include <rpcsvc/yp.h>
-
/*
* We have to define these here due to clashes between yp_prot.h and
* yp.h.
*/
+#define YPMATCHCACHE
+
+#ifdef YPMATCHCACHE
+struct ypmatch_ent {
+ char *ypc_map;
+ keydat ypc_key;
+ valdat ypc_val;
+ time_t ypc_expire_t;
+ struct ypmatch_ent *ypc_next;
+};
+#define YPLIB_MAXCACHE 5 /* At most 5 entries */
+#define YPLIB_EXPIRE 5 /* Expire after 5 seconds */
+#endif
+
struct dom_binding {
- struct dom_binding *dom_pnext;
- char dom_domain[YPMAXDOMAIN + 1];
- struct sockaddr_in dom_server_addr;
- u_short dom_server_port;
- int dom_socket;
- CLIENT *dom_client;
- u_short dom_local_port; /* now I finally know what this is for. */
- long dom_vers;
+ struct dom_binding *dom_pnext;
+ char dom_domain[YPMAXDOMAIN + 1];
+ struct sockaddr_in dom_server_addr;
+ u_short dom_server_port;
+ int dom_socket;
+ CLIENT *dom_client;
+ u_short dom_local_port; /* now I finally know what this is for. */
+ long dom_vers;
+#ifdef YPMATCHCACHE
+ struct ypmatch_ent *cache;
+ int ypmatch_cachecnt;
+#endif
};
#include <rpcsvc/ypclnt.h>
@@ -67,7 +85,6 @@ struct dom_binding {
#ifndef BINDINGDIR
#define BINDINGDIR "/var/yp/binding"
#endif
-#define YPMATCHCACHE
#define MAX_RETRIES 20
extern bool_t xdr_domainname(), xdr_ypbind_resp();
@@ -85,106 +102,163 @@ static char _yp_domain[MAXHOSTNAMELEN];
int _yplib_timeout = 10;
#ifdef YPMATCHCACHE
-int _yplib_cache = 5;
+static void ypmatch_cache_delete(ypdb, prev, cur)
+ struct dom_binding *ypdb;
+ struct ypmatch_ent *prev;
+ struct ypmatch_ent *cur;
+{
+ if (prev == NULL)
+ ypdb->cache = cur->ypc_next;
+ else
+ prev->ypc_next = cur->ypc_next;
-static struct ypmatch_ent {
- struct ypmatch_ent *next;
- char *map, *key, *val;
- int keylen, vallen;
- time_t expire_t;
-} *ypmc;
+ free(cur->ypc_map);
+ free(cur->ypc_key.keydat_val);
+ free(cur->ypc_val.valdat_val);
+ free(cur);
-static void
-ypmatch_add(map, key, keylen, val, vallen)
- char *map;
- char *key;
- int keylen;
- char *val;
- int vallen;
+ ypdb->ypmatch_cachecnt--;
+
+ return;
+}
+
+static void ypmatch_cache_flush(ypdb)
+ struct dom_binding *ypdb;
{
- struct ypmatch_ent *ep;
- time_t t;
+ struct ypmatch_ent *n, *c = ypdb->cache;
+
+ while (c != NULL) {
+ n = c->ypc_next;
+ ypmatch_cache_delete(ypdb, NULL, c);
+ c = n;
+ }
+
+ return;
+}
+
+static void ypmatch_cache_expire(ypdb)
+ struct dom_binding *ypdb;
+{
+ struct ypmatch_ent *c = ypdb->cache;
+ struct ypmatch_ent *n, *p = NULL;
+ time_t t;
time(&t);
- for(ep=ypmc; ep; ep=ep->next)
- if(ep->expire_t < t)
- break;
- if(ep==NULL) {
- ep = (struct ypmatch_ent *)malloc(sizeof *ep);
- bzero((char *)ep, sizeof *ep);
- if(ypmc)
- ep->next = ypmc;
- ypmc = ep;
+ while (c != NULL) {
+ if (t >= c->ypc_expire_t) {
+ n = c->ypc_next;
+ ypmatch_cache_delete(ypdb, p, c);
+ c = n;
+ } else {
+ p = c;
+ c = c->ypc_next;
+ }
}
- if(ep->key)
- free(ep->key);
- if(ep->val)
- free(ep->val);
+ return;
+}
+
+static void ypmatch_cache_insert(ypdb, map, key, val)
+ struct dom_binding *ypdb;
+ char *map;
+ keydat *key;
+ valdat *val;
+{
+ struct ypmatch_ent *new;
+
+ /* Do an expire run to maybe open up a slot. */
+ if (ypdb->ypmatch_cachecnt)
+ ypmatch_cache_expire(ypdb);
+
+ /*
+ * If there are no slots free, then force an expire of
+ * the least recently used entry.
+ */
+ if (ypdb->ypmatch_cachecnt >= YPLIB_MAXCACHE) {
+ struct ypmatch_ent *o = NULL, *c = ypdb->cache;
+ time_t oldest = 0;
+
+ oldest = ~oldest;
+
+ while(c != NULL) {
+ if (c->ypc_expire_t < oldest) {
+ oldest = c->ypc_expire_t;
+ o = c;
+ }
+ c = c->ypc_next;
+ }
- ep->key = NULL;
- ep->val = NULL;
+ if (o == NULL)
+ return;
+ o->ypc_expire_t = 0;
+ ypmatch_cache_expire(ypdb);
+ }
- ep->key = (char *)malloc(keylen);
- if(ep->key==NULL)
+ new = malloc(sizeof(struct ypmatch_ent));
+ if (new == NULL)
return;
- ep->val = (char *)malloc(vallen);
- if(ep->key==NULL) {
- free(ep->key);
- ep->key = NULL;
+ new->ypc_map = strdup(map);
+ if (new->ypc_map == NULL) {
+ free(new);
+ return;
+ }
+ new->ypc_key.keydat_val = malloc(key->keydat_len);
+ if (new->ypc_key.keydat_val == NULL) {
+ free(new->ypc_map);
+ free(new);
+ return;
+ }
+ new->ypc_val.valdat_val = malloc(val->valdat_len);
+ if (new->ypc_val.valdat_val == NULL) {
+ free(new->ypc_val.valdat_val);
+ free(new->ypc_map);
+ free(new);
return;
}
- ep->keylen = keylen;
- ep->vallen = vallen;
- bcopy(key, ep->key, ep->keylen);
- bcopy(val, ep->val, ep->vallen);
+ new->ypc_expire_t = time(NULL) + YPLIB_EXPIRE;
+ new->ypc_key.keydat_len = key->keydat_len;
+ new->ypc_val.valdat_len = val->valdat_len;
+ bcopy(key->keydat_val, new->ypc_key.keydat_val, key->keydat_len);
+ bcopy(val->valdat_val, new->ypc_val.valdat_val, val->valdat_len);
- if(ep->map) {
- if( strcmp(ep->map, map) ) {
- free(ep->map);
- ep->map = strdup(map);
- }
- } else {
- ep->map = strdup(map);
- }
+ new->ypc_next = ypdb->cache;
+ ypdb->cache = new;
- ep->expire_t = t + _yplib_cache;
+ ypdb->ypmatch_cachecnt++;
+
+ return;
}
-static bool_t
-ypmatch_find(map, key, keylen, val, vallen)
- char *map;
- char *key;
- int keylen;
- char **val;
- int *vallen;
+static bool_t ypmatch_cache_lookup(ypdb, map, key, val)
+ struct dom_binding *ypdb;
+ char *map;
+ keydat *key;
+ valdat *val;
{
- struct ypmatch_ent *ep;
- time_t t;
+ struct ypmatch_ent *c = ypdb->cache;
- if(ypmc==NULL)
- return 0;
-
- time(&t);
+ ypmatch_cache_expire(ypdb);
- for(ep=ypmc; ep; ep=ep->next) {
- if(ep->keylen != keylen)
+ for (c = ypdb->cache; c != NULL; c = c->ypc_next) {
+ if (strcmp(map, c->ypc_map))
continue;
- if(strcmp(ep->map, map))
+ if (key->keydat_len != c->ypc_key.keydat_len)
continue;
- if(bcmp(ep->key, key, keylen))
+ if (bcmp(key->keydat_val, c->ypc_key.keydat_val,
+ key->keydat_len))
continue;
- if(t > ep->expire_t)
- continue;
-
- *val = ep->val;
- *vallen = ep->vallen;
- return 1;
}
- return 0;
+
+ if (c == NULL)
+ return(FALSE);
+
+ val->valdat_len = c->ypc_val.valdat_len;
+ val->valdat_val = c->ypc_val.valdat_val;
+
+ return(TRUE);
}
#endif
@@ -437,8 +511,8 @@ gotit:
tv.tv_sec = _yplib_timeout/2;
tv.tv_usec = 0;
ysd->dom_socket = RPC_ANYSOCK;
- ysd->dom_client = clntudp_create(&ysd->dom_server_addr,
- YPPROG, YPVERS, tv, &ysd->dom_socket);
+ ysd->dom_client = clntudp_bufcreate(&ysd->dom_server_addr,
+ YPPROG, YPVERS, tv, &ysd->dom_socket, 1280, 2304);
if(ysd->dom_client==NULL) {
clnt_pcreateerror("clntudp_create");
ysd->dom_vers = -1;
@@ -501,6 +575,9 @@ _yp_unbind(ypb)
ypb->dom_client = NULL;
ypb->dom_socket = -1;
ypb->dom_vers = -1;
+#ifdef YPMATCHCACHE
+ ypmatch_cache_flush(ypb);
+#endif
}
int
@@ -557,9 +634,20 @@ yp_match(indomain, inmap, inkey, inkeylen, outval, outvallen)
indomain == NULL || !strlen(indomain))
return YPERR_BADARGS;
+ if (_yp_dobind(indomain, &ysd) != 0)
+ return(YPERR_DOMAIN);
+
+ yprk.domain = indomain;
+ yprk.map = inmap;
+ yprk.key.keydat_val = (char *)inkey;
+ yprk.key.keydat_len = inkeylen;
+
#ifdef YPMATCHCACHE
+ if (ypmatch_cache_lookup(ysd, yprk.map, &yprk.key, &yprv.val) == TRUE) {
+/*
if( !strcmp(_yp_domain, indomain) && ypmatch_find(inmap, inkey,
inkeylen, &yprv.val.valdat_val, &yprv.val.valdat_len)) {
+*/
*outvallen = yprv.val.valdat_len;
*outval = (char *)malloc(*outvallen+1);
bcopy(yprv.val.valdat_val, *outval, *outvallen);
@@ -575,11 +663,6 @@ again:
tv.tv_sec = _yplib_timeout;
tv.tv_usec = 0;
- yprk.domain = indomain;
- yprk.map = inmap;
- yprk.key.keydat_val = (char *)inkey;
- yprk.key.keydat_len = inkeylen;
-
bzero((char *)&yprv, sizeof yprv);
r = clnt_call(ysd->dom_client, YPPROC_MATCH,
@@ -596,8 +679,7 @@ again:
bcopy(yprv.val.valdat_val, *outval, *outvallen);
(*outval)[*outvallen] = '\0';
#ifdef YPMATCHCACHE
- if( strcmp(_yp_domain, indomain)==0 )
- ypmatch_add(inmap, inkey, inkeylen, *outval, *outvallen);
+ ypmatch_cache_insert(ysd, yprk.map, &yprk.key, &yprv.val);
#endif
}
OpenPOWER on IntegriCloud