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.
This commit is contained in:
parent
c89f86ce8f
commit
4e6ace0853
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=34146
@ -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 struct ypmatch_ent {
|
||||
struct ypmatch_ent *next;
|
||||
char *map, *key, *val;
|
||||
int keylen, vallen;
|
||||
time_t expire_t;
|
||||
} *ypmc;
|
||||
|
||||
static void
|
||||
ypmatch_add(map, key, keylen, val, vallen)
|
||||
char *map;
|
||||
char *key;
|
||||
int keylen;
|
||||
char *val;
|
||||
int vallen;
|
||||
static void ypmatch_cache_delete(ypdb, prev, cur)
|
||||
struct dom_binding *ypdb;
|
||||
struct ypmatch_ent *prev;
|
||||
struct ypmatch_ent *cur;
|
||||
{
|
||||
struct ypmatch_ent *ep;
|
||||
time_t t;
|
||||
if (prev == NULL)
|
||||
ypdb->cache = cur->ypc_next;
|
||||
else
|
||||
prev->ypc_next = cur->ypc_next;
|
||||
|
||||
time(&t);
|
||||
free(cur->ypc_map);
|
||||
free(cur->ypc_key.keydat_val);
|
||||
free(cur->ypc_val.valdat_val);
|
||||
free(cur);
|
||||
|
||||
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;
|
||||
}
|
||||
ypdb->ypmatch_cachecnt--;
|
||||
|
||||
if(ep->key)
|
||||
free(ep->key);
|
||||
if(ep->val)
|
||||
free(ep->val);
|
||||
|
||||
ep->key = NULL;
|
||||
ep->val = NULL;
|
||||
|
||||
ep->key = (char *)malloc(keylen);
|
||||
if(ep->key==NULL)
|
||||
return;
|
||||
|
||||
ep->val = (char *)malloc(vallen);
|
||||
if(ep->key==NULL) {
|
||||
free(ep->key);
|
||||
ep->key = NULL;
|
||||
return;
|
||||
}
|
||||
ep->keylen = keylen;
|
||||
ep->vallen = vallen;
|
||||
|
||||
bcopy(key, ep->key, ep->keylen);
|
||||
bcopy(val, ep->val, ep->vallen);
|
||||
|
||||
if(ep->map) {
|
||||
if( strcmp(ep->map, map) ) {
|
||||
free(ep->map);
|
||||
ep->map = strdup(map);
|
||||
}
|
||||
} else {
|
||||
ep->map = strdup(map);
|
||||
}
|
||||
|
||||
ep->expire_t = t + _yplib_cache;
|
||||
return;
|
||||
}
|
||||
|
||||
static bool_t
|
||||
ypmatch_find(map, key, keylen, val, vallen)
|
||||
char *map;
|
||||
char *key;
|
||||
int keylen;
|
||||
char **val;
|
||||
int *vallen;
|
||||
static void ypmatch_cache_flush(ypdb)
|
||||
struct dom_binding *ypdb;
|
||||
{
|
||||
struct ypmatch_ent *ep;
|
||||
time_t t;
|
||||
struct ypmatch_ent *n, *c = ypdb->cache;
|
||||
|
||||
if(ypmc==NULL)
|
||||
return 0;
|
||||
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->keylen != keylen)
|
||||
continue;
|
||||
if(strcmp(ep->map, map))
|
||||
continue;
|
||||
if(bcmp(ep->key, key, keylen))
|
||||
continue;
|
||||
if(t > ep->expire_t)
|
||||
continue;
|
||||
|
||||
*val = ep->val;
|
||||
*vallen = ep->vallen;
|
||||
return 1;
|
||||
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;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
if (o == NULL)
|
||||
return;
|
||||
o->ypc_expire_t = 0;
|
||||
ypmatch_cache_expire(ypdb);
|
||||
}
|
||||
|
||||
new = malloc(sizeof(struct ypmatch_ent));
|
||||
if (new == NULL)
|
||||
return;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
new->ypc_next = ypdb->cache;
|
||||
ypdb->cache = new;
|
||||
|
||||
ypdb->ypmatch_cachecnt++;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
static bool_t ypmatch_cache_lookup(ypdb, map, key, val)
|
||||
struct dom_binding *ypdb;
|
||||
char *map;
|
||||
keydat *key;
|
||||
valdat *val;
|
||||
{
|
||||
struct ypmatch_ent *c = ypdb->cache;
|
||||
|
||||
ypmatch_cache_expire(ypdb);
|
||||
|
||||
for (c = ypdb->cache; c != NULL; c = c->ypc_next) {
|
||||
if (strcmp(map, c->ypc_map))
|
||||
continue;
|
||||
if (key->keydat_len != c->ypc_key.keydat_len)
|
||||
continue;
|
||||
if (bcmp(key->keydat_val, c->ypc_key.keydat_val,
|
||||
key->keydat_len))
|
||||
continue;
|
||||
}
|
||||
|
||||
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 @@ _yp_dobind(dom, ypdb)
|
||||
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 @@ yp_match(indomain, inmap, inkey, inkeylen, outval, outvallen)
|
||||
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 @@ yp_match(indomain, inmap, inkey, inkeylen, outval, outvallen)
|
||||
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
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user