#include <assert.h>
#include "ldap-int.h"
#define EXTRA_SIZE 1024
#define MEMCACHE_ACCESS_ADD 0
#define MEMCACHE_ACCESS_APPEND 1
#define MEMCACHE_ACCESS_APPEND_LAST 2
#define MEMCACHE_ACCESS_FIND 3
#define MEMCACHE_ACCESS_DELETE 4
#define MEMCACHE_ACCESS_DELETE_ALL 5
#define MEMCACHE_ACCESS_UPDATE 6
#define MEMCACHE_ACCESS_FLUSH 7
#define MEMCACHE_ACCESS_FLUSH_ALL 8
#define MEMCACHE_ACCESS_FLUSH_LRU 9
#define MEMCACHE_SIZE_DEDUCT 0
#define MEMCACHE_SIZE_ADD 1
#define MEMCACHE_SIZE_ENTRIES 1
#define MEMCACHE_SIZE_NON_ENTRIES 2
#define MEMCACHE_DEF_SIZE 131072
#define LIST_TTL 0
#define LIST_LRU 1
#define LIST_TMP 2
#define LIST_TOTAL 3
static char *emptyStr = "";
#define NSLDAPI_VALID_MEMCACHE_POINTER( cp ) ( (cp) != NULL )
#define NSLDAPI_STR_NONNULL( s ) ( (s) ? (s) : emptyStr )
#define NSLDAPI_SAFE_STRLEN( s ) ( (s) ? strlen((s)) + 1 : 1 )
#define LDAP_MEMCACHE_MUTEX_LOCK( c ) \
if ( (c) && ((c)->ldmemc_lock_fns).ltf_mutex_lock ) { \
((c)->ldmemc_lock_fns).ltf_mutex_lock( (c)->ldmemc_lock ); \
}
#define LDAP_MEMCACHE_MUTEX_UNLOCK( c ) \
if ( (c) && ((c)->ldmemc_lock_fns).ltf_mutex_unlock ) { \
((c)->ldmemc_lock_fns).ltf_mutex_unlock( (c)->ldmemc_lock ); \
}
#define LDAP_MEMCACHE_MUTEX_ALLOC( c ) \
((c) && ((c)->ldmemc_lock_fns).ltf_mutex_alloc ? \
((c)->ldmemc_lock_fns).ltf_mutex_alloc() : NULL)
#define LDAP_MEMCACHE_MUTEX_FREE( c ) \
if ( (c) && ((c)->ldmemc_lock_fns).ltf_mutex_free ) { \
((c)->ldmemc_lock_fns).ltf_mutex_free( (c)->ldmemc_lock ); \
}
#define NSLDAPI_IS_SPACE( c ) \
(((c) == ' ') || ((c) == '\t') || ((c) == '\n'))
#define NSLDAPI_IS_SEPARATER( c ) \
((c) == ',')
typedef int (*HashFuncPtr)(int table_size, void *key);
typedef int (*PutDataPtr)(void **ppTableData, void *key, void *pData);
typedef int (*GetDataPtr)(void *pTableData, void *key, void **ppData);
typedef int (*RemoveDataPtr)(void **ppTableData, void *key, void **ppData);
typedef int (*MiscFuncPtr)(void **ppTableData, void *key, void *pData);
typedef void (*ClrTableNodePtr)(void **ppTableData, void *pData);
typedef struct HashTableNode_struct {
void *pData;
} HashTableNode;
typedef struct HashTable_struct {
HashTableNode *table;
int size;
HashFuncPtr hashfunc;
PutDataPtr putdata;
GetDataPtr getdata;
MiscFuncPtr miscfunc;
RemoveDataPtr removedata;
ClrTableNodePtr clrtablenode;
} HashTable;
typedef struct ldapmemcacheReqId_struct {
LDAP *ldmemcrid_ld;
int ldmemcrid_msgid;
} ldapmemcacheReqId;
typedef struct ldapmemcacheld_struct {
LDAP *ldmemcl_ld;
struct ldapmemcacheld_struct *ldmemcl_next;
} ldapmemcacheld;
typedef struct ldapmemcacheRes_struct {
char *ldmemcr_basedn;
unsigned long ldmemcr_crc_key;
unsigned long ldmemcr_resSize;
unsigned long ldmemcr_timestamp;
LDAPMessage *ldmemcr_resHead;
LDAPMessage *ldmemcr_resTail;
ldapmemcacheReqId ldmemcr_req_id;
struct ldapmemcacheRes_struct *ldmemcr_next[LIST_TOTAL];
struct ldapmemcacheRes_struct *ldmemcr_prev[LIST_TOTAL];
struct ldapmemcacheRes_struct *ldmemcr_htable_next;
} ldapmemcacheRes;
typedef struct ldapmemcacheStats_struct {
unsigned long ldmemcstat_tries;
unsigned long ldmemcstat_hits;
} ldapmemcacheStats;
struct ldapmemcache {
unsigned long ldmemc_ttl;
unsigned long ldmemc_size;
unsigned long ldmemc_size_used;
unsigned long ldmemc_size_entries;
char **ldmemc_basedns;
void *ldmemc_lock;
ldapmemcacheld *ldmemc_lds;
HashTable *ldmemc_resTmp;
HashTable *ldmemc_resLookup;
ldapmemcacheRes *ldmemc_resHead[LIST_TOTAL];
ldapmemcacheRes *ldmemc_resTail[LIST_TOTAL];
struct ldap_thread_fns ldmemc_lock_fns;
ldapmemcacheStats ldmemc_stats;
};
static int memcache_exist(LDAP *ld);
static int memcache_add_to_ld(LDAP *ld, int msgid, LDAPMessage *pMsg);
static int memcache_compare_dn(const char *main_dn, const char *dn, int scope);
static int memcache_dup_message(LDAPMessage *res, int msgid, int fromcache,
LDAPMessage **ppResCopy, unsigned long *pSize);
static BerElement* memcache_ber_dup(BerElement* pBer, unsigned long *pSize);
static void memcache_trim_basedn_spaces(char *basedn);
static int memcache_validate_basedn(LDAPMemCache *cache, const char *basedn);
static int memcache_get_ctrls_len(LDAPControl **ctrls);
static void memcache_append_ctrls(char *buf, LDAPControl **serverCtrls,
LDAPControl **clientCtrls);
static int memcache_adj_size(LDAPMemCache *cache, unsigned long size,
int usageFlags, int bAdd);
static int memcache_free_entry(LDAPMemCache *cache, ldapmemcacheRes *pRes);
static int memcache_expired(LDAPMemCache *cache, ldapmemcacheRes *pRes,
unsigned long curTime);
static int memcache_add_to_list(LDAPMemCache *cache, ldapmemcacheRes *pRes,
int index);
static int memcache_add_res_to_list(ldapmemcacheRes *pRes, LDAPMessage *pMsg,
unsigned long size);
static int memcache_free_from_list(LDAPMemCache *cache, ldapmemcacheRes *pRes,
int index);
static int memcache_search(LDAP *ld, unsigned long key, LDAPMessage **ppRes);
static int memcache_add(LDAP *ld, unsigned long key, int msgid,
const char *basedn);
static int memcache_append(LDAP *ld, int msgid, LDAPMessage *pRes);
static int memcache_append_last(LDAP *ld, int msgid, LDAPMessage *pRes);
static int memcache_remove(LDAP *ld, int msgid);
#if 0
static int memcache_remove_all(LDAP *ld);
#endif
static int memcache_access(LDAPMemCache *cache, int mode,
void *pData1, void *pData2, void *pData3);
#ifdef LDAP_DEBUG
static void memcache_print_list( LDAPMemCache *cache, int index );
static void memcache_report_statistics( LDAPMemCache *cache );
#endif
static int htable_calculate_size(int sizelimit);
static int htable_sizeinbytes(HashTable *pTable);
static int htable_put(HashTable *pTable, void *key, void *pData);
static int htable_get(HashTable *pTable, void *key, void **ppData);
static int htable_misc(HashTable *pTable, void *key, void *pData);
static int htable_remove(HashTable *pTable, void *key, void **ppData);
static int htable_removeall(HashTable *pTable, void *pData);
static int htable_create(int size_limit, HashFuncPtr hashf,
PutDataPtr putDataf, GetDataPtr getDataf,
RemoveDataPtr removeDataf, ClrTableNodePtr clrNodef,
MiscFuncPtr miscOpf, HashTable **ppTable);
static int htable_free(HashTable *pTable);
static int msgid_hashf(int table_size, void *key);
static int msgid_putdata(void **ppTableData, void *key, void *pData);
static int msgid_getdata(void *pTableData, void *key, void **ppData);
static int msgid_removedata(void **ppTableData, void *key, void **ppData);
static int msgid_clear_ld_items(void **ppTableData, void *key, void *pData);
static void msgid_clearnode(void **ppTableData, void *pData);
static int attrkey_hashf(int table_size, void *key);
static int attrkey_putdata(void **ppTableData, void *key, void *pData);
static int attrkey_getdata(void *pTableData, void *key, void **ppData);
static int attrkey_removedata(void **ppTableData, void *key, void **ppData);
static void attrkey_clearnode(void **ppTableData, void *pData);
static unsigned long crc32_convert(char *buf, int len);
int
LDAP_CALL
ldap_memcache_init( unsigned long ttl, unsigned long size,
char **baseDNs, struct ldap_thread_fns *thread_fns,
LDAPMemCache **cachep )
{
unsigned long total_size = 0;
LDAPDebug( LDAP_DEBUG_TRACE, "ldap_memcache_init\n", 0, 0, 0 );
if ( cachep == NULL ) {
return( LDAP_PARAM_ERROR );
}
if ((*cachep = (LDAPMemCache*)NSLDAPI_CALLOC(1,
sizeof(LDAPMemCache))) == NULL) {
return ( LDAP_NO_MEMORY );
}
total_size += sizeof(LDAPMemCache);
(*cachep)->ldmemc_ttl = ttl;
(*cachep)->ldmemc_size = size;
(*cachep)->ldmemc_lds = NULL;
size = (size ? size : MEMCACHE_DEF_SIZE);
if (thread_fns) {
memcpy(&((*cachep)->ldmemc_lock_fns), thread_fns,
sizeof(struct ldap_thread_fns));
} else {
memset(&((*cachep)->ldmemc_lock_fns), 0,
sizeof(struct ldap_thread_fns));
}
(*cachep)->ldmemc_lock = LDAP_MEMCACHE_MUTEX_ALLOC( *cachep );
if (baseDNs != NULL) {
int i;
for (i = 0; baseDNs[i]; i++) {
;
}
(*cachep)->ldmemc_basedns = (char**)NSLDAPI_CALLOC(i + 1,
sizeof(char*));
if ((*cachep)->ldmemc_basedns == NULL) {
ldap_memcache_destroy(*cachep);
*cachep = NULL;
return ( LDAP_NO_MEMORY );
}
total_size += (i + 1) * sizeof(char*);
for (i = 0; baseDNs[i]; i++) {
(*cachep)->ldmemc_basedns[i] = nsldapi_strdup(baseDNs[i]);
if ((*cachep)->ldmemc_basedns[i] == NULL)
return ( LDAP_NO_MEMORY );
total_size += strlen(baseDNs[i]) + 1;
}
(*cachep)->ldmemc_basedns[i] = NULL;
}
if (htable_create(size, msgid_hashf, msgid_putdata, msgid_getdata,
msgid_removedata, msgid_clearnode, msgid_clear_ld_items,
&((*cachep)->ldmemc_resTmp)) != LDAP_SUCCESS) {
ldap_memcache_destroy(*cachep);
*cachep = NULL;
return( LDAP_NO_MEMORY );
}
total_size += htable_sizeinbytes((*cachep)->ldmemc_resTmp);
if (htable_create(size, attrkey_hashf, attrkey_putdata,
attrkey_getdata, attrkey_removedata, attrkey_clearnode,
NULL, &((*cachep)->ldmemc_resLookup)) != LDAP_SUCCESS) {
ldap_memcache_destroy(*cachep);
*cachep = NULL;
return( LDAP_NO_MEMORY );
}
total_size += htable_sizeinbytes((*cachep)->ldmemc_resLookup);
if (memcache_adj_size(*cachep, total_size, MEMCACHE_SIZE_NON_ENTRIES,
MEMCACHE_SIZE_ADD) != LDAP_SUCCESS) {
ldap_memcache_destroy(*cachep);
*cachep = NULL;
return( LDAP_SIZELIMIT_EXCEEDED );
}
LDAPDebug( LDAP_DEBUG_TRACE, "ldap_memcache_init new cache 0x%x\n",
*cachep, 0, 0 );
return( LDAP_SUCCESS );
}
int
LDAP_CALL
ldap_memcache_set( LDAP *ld, LDAPMemCache *cache )
{
int nRes = LDAP_SUCCESS;
LDAPDebug( LDAP_DEBUG_TRACE, "ldap_memcache_set\n", 0, 0, 0 );
if ( !NSLDAPI_VALID_LDAP_POINTER( ld ) )
return( LDAP_PARAM_ERROR );
LDAP_MUTEX_LOCK( ld, LDAP_MEMCACHE_LOCK );
if (ld->ld_memcache != cache) {
LDAPMemCache *c = ld->ld_memcache;
ldapmemcacheld *pCur = NULL;
ldapmemcacheld *pPrev = NULL;
LDAP_MEMCACHE_MUTEX_LOCK( c );
pCur = (c ? c->ldmemc_lds : NULL);
for (; pCur; pCur = pCur->ldmemcl_next) {
if (pCur->ldmemcl_ld == ld)
break;
pPrev = pCur;
}
if (pCur) {
ldapmemcacheReqId reqid;
reqid.ldmemcrid_ld = ld;
reqid.ldmemcrid_msgid = -1;
htable_misc(c->ldmemc_resTmp, (void*)&reqid, (void*)c);
if (pPrev)
pPrev->ldmemcl_next = pCur->ldmemcl_next;
else
c->ldmemc_lds = pCur->ldmemcl_next;
NSLDAPI_FREE(pCur);
pCur = NULL;
memcache_adj_size(c, sizeof(ldapmemcacheld),
MEMCACHE_SIZE_NON_ENTRIES, MEMCACHE_SIZE_DEDUCT);
}
LDAP_MEMCACHE_MUTEX_UNLOCK( c );
ld->ld_memcache = NULL;
if (cache == NULL) {
LDAP_MUTEX_UNLOCK( ld, LDAP_MEMCACHE_LOCK );
return( LDAP_SUCCESS );
}
LDAP_MEMCACHE_MUTEX_LOCK( cache );
if ((nRes = memcache_adj_size(cache, sizeof(ldapmemcacheld),
MEMCACHE_SIZE_NON_ENTRIES, MEMCACHE_SIZE_ADD)) != LDAP_SUCCESS) {
LDAP_MEMCACHE_MUTEX_UNLOCK( cache );
LDAP_MUTEX_UNLOCK( ld, LDAP_MEMCACHE_LOCK );
return nRes;
}
pCur = (ldapmemcacheld*)NSLDAPI_CALLOC(1, sizeof(ldapmemcacheld));
if (pCur == NULL) {
memcache_adj_size(cache, sizeof(ldapmemcacheld),
MEMCACHE_SIZE_NON_ENTRIES, MEMCACHE_SIZE_DEDUCT);
nRes = LDAP_NO_MEMORY;
} else {
pCur->ldmemcl_ld = ld;
pCur->ldmemcl_next = cache->ldmemc_lds;
cache->ldmemc_lds = pCur;
ld->ld_memcache = cache;
}
LDAP_MEMCACHE_MUTEX_UNLOCK( cache );
}
LDAP_MUTEX_UNLOCK( ld, LDAP_MEMCACHE_LOCK );
return nRes;
}
int
LDAP_CALL
ldap_memcache_get( LDAP *ld, LDAPMemCache **cachep )
{
LDAPDebug( LDAP_DEBUG_TRACE, "ldap_memcache_get ld: 0x%x\n", ld, 0, 0 );
if ( !NSLDAPI_VALID_LDAP_POINTER( ld ) || cachep == NULL ) {
return( LDAP_PARAM_ERROR );
}
LDAP_MUTEX_LOCK( ld, LDAP_MEMCACHE_LOCK );
*cachep = ld->ld_memcache;
LDAP_MUTEX_UNLOCK( ld, LDAP_MEMCACHE_LOCK );
return( LDAP_SUCCESS );
}
void
LDAP_CALL
ldap_memcache_update( LDAPMemCache *cache )
{
LDAPDebug( LDAP_DEBUG_TRACE, "ldap_memcache_update: cache 0x%x\n",
cache, 0, 0 );
if ( !NSLDAPI_VALID_MEMCACHE_POINTER( cache )) {
return;
}
LDAP_MEMCACHE_MUTEX_LOCK( cache );
memcache_access(cache, MEMCACHE_ACCESS_UPDATE, NULL, NULL, NULL);
LDAP_MEMCACHE_MUTEX_UNLOCK( cache );
}
void
LDAP_CALL
ldap_memcache_flush( LDAPMemCache *cache, char *dn, int scope )
{
LDAPDebug( LDAP_DEBUG_TRACE,
"ldap_memcache_flush( cache: 0x%x, dn: %s, scope: %d)\n",
cache, ( dn == NULL ) ? "(null)" : dn, scope );
if ( !NSLDAPI_VALID_MEMCACHE_POINTER( cache )) {
return;
}
LDAP_MEMCACHE_MUTEX_LOCK( cache );
if (!dn) {
memcache_access(cache, MEMCACHE_ACCESS_FLUSH_ALL, NULL, NULL, NULL);
} else {
memcache_access(cache, MEMCACHE_ACCESS_FLUSH,
(void*)dn, (void*)(uintptr_t)scope, NULL);
}
LDAP_MEMCACHE_MUTEX_UNLOCK( cache );
}
void
LDAP_CALL
ldap_memcache_destroy( LDAPMemCache *cache )
{
int i = 0;
unsigned long size = sizeof(LDAPMemCache);
ldapmemcacheld *pNode = NULL, *pNextNode = NULL;
LDAPDebug( LDAP_DEBUG_TRACE, "ldap_memcache_destroy( 0x%x )\n",
cache, 0, 0 );
if ( !NSLDAPI_VALID_MEMCACHE_POINTER( cache )) {
return;
}
LDAP_MEMCACHE_MUTEX_LOCK( cache );
for (pNode = cache->ldmemc_lds; pNode; pNode = pNextNode, i++) {
LDAP_MUTEX_LOCK( pNode->ldmemcl_ld, LDAP_MEMCACHE_LOCK );
cache->ldmemc_lds = pNode->ldmemcl_next;
pNode->ldmemcl_ld->ld_memcache = NULL;
LDAP_MUTEX_UNLOCK( pNode->ldmemcl_ld, LDAP_MEMCACHE_LOCK );
pNextNode = pNode->ldmemcl_next;
NSLDAPI_FREE(pNode);
}
size += i * sizeof(ldapmemcacheld);
LDAP_MEMCACHE_MUTEX_UNLOCK( cache );
if (cache->ldmemc_basedns) {
for (i = 0; cache->ldmemc_basedns[i]; i++) {
size += strlen(cache->ldmemc_basedns[i]) + 1;
NSLDAPI_FREE(cache->ldmemc_basedns[i]);
}
size += (i + 1) * sizeof(char*);
NSLDAPI_FREE(cache->ldmemc_basedns);
}
if (cache->ldmemc_resTmp) {
size += htable_sizeinbytes(cache->ldmemc_resTmp);
memcache_access(cache, MEMCACHE_ACCESS_DELETE_ALL, NULL, NULL, NULL);
htable_free(cache->ldmemc_resTmp);
}
if (cache->ldmemc_resLookup) {
size += htable_sizeinbytes(cache->ldmemc_resLookup);
memcache_access(cache, MEMCACHE_ACCESS_FLUSH_ALL, NULL, NULL, NULL);
htable_free(cache->ldmemc_resLookup);
}
memcache_adj_size(cache, size, MEMCACHE_SIZE_NON_ENTRIES,
MEMCACHE_SIZE_DEDUCT);
LDAP_MEMCACHE_MUTEX_FREE( cache );
NSLDAPI_FREE(cache);
}
int
ldap_memcache_createkey(LDAP *ld, const char *base, int scope,
const char *filter, char **attrs,
int attrsonly, LDAPControl **serverctrls,
LDAPControl **clientctrls, unsigned long *keyp)
{
int nRes, i, j, i_smallest;
int len;
int defport;
char buf[50];
char *tmp, *defhost, *binddn, *keystr, *tmpbase;
if ( !NSLDAPI_VALID_LDAP_POINTER( ld ) || (keyp == NULL) )
return( LDAP_PARAM_ERROR );
*keyp = 0;
if (!memcache_exist(ld))
return( LDAP_LOCAL_ERROR );
LDAP_MUTEX_LOCK( ld, LDAP_MEMCACHE_LOCK );
LDAP_MEMCACHE_MUTEX_LOCK( ld->ld_memcache );
nRes = memcache_validate_basedn(ld->ld_memcache, base);
LDAP_MEMCACHE_MUTEX_UNLOCK( ld->ld_memcache );
LDAP_MUTEX_UNLOCK( ld, LDAP_MEMCACHE_LOCK );
if (nRes != LDAP_SUCCESS)
return nRes;
defhost = NSLDAPI_STR_NONNULL(ld->ld_defhost);
defport = ld->ld_defport;
tmpbase = nsldapi_strdup(NSLDAPI_STR_NONNULL(base));
if (tmpbase == NULL)
return( LDAP_LOCAL_ERROR );
memcache_trim_basedn_spaces(tmpbase);
if ((binddn = nsldapi_get_binddn(ld)) == NULL)
binddn = "";
sprintf(buf, "%i\n%i\n%i\n", defport, scope, (attrsonly ? 1 : 0));
len = NSLDAPI_SAFE_STRLEN(buf) + NSLDAPI_SAFE_STRLEN(tmpbase) +
NSLDAPI_SAFE_STRLEN(filter) + NSLDAPI_SAFE_STRLEN(defhost) +
NSLDAPI_SAFE_STRLEN(binddn);
if (attrs) {
for (i = 0; attrs[i]; i++) {
for (i_smallest = j = i; attrs[j]; j++) {
if (strcasecmp(attrs[i_smallest], attrs[j]) > 0)
i_smallest = j;
}
if (i != i_smallest) {
tmp = attrs[i];
attrs[i] = attrs[i_smallest];
attrs[i_smallest] = tmp;
}
len += NSLDAPI_SAFE_STRLEN(attrs[i]);
}
} else {
len += 1;
}
len += memcache_get_ctrls_len(serverctrls) +
memcache_get_ctrls_len(clientctrls) + 1;
if ((keystr = (char*)NSLDAPI_CALLOC(len, sizeof(char))) == NULL) {
if (defhost != emptyStr)
NSLDAPI_FREE(defhost);
NSLDAPI_FREE(tmpbase);
return( LDAP_NO_MEMORY );
}
sprintf(keystr, "%s\n%s\n%s\n%s\n%s\n", binddn, tmpbase,
NSLDAPI_STR_NONNULL(defhost), NSLDAPI_STR_NONNULL(filter),
NSLDAPI_STR_NONNULL(buf));
if (attrs) {
for (i = 0; attrs[i]; i++) {
strcat(keystr, NSLDAPI_STR_NONNULL(attrs[i]));
strcat(keystr, "\n");
}
} else {
strcat(keystr, "\n");
}
for (tmp = keystr; *tmp;
*tmp += (*tmp >= 'a' && *tmp <= 'z' ? 'A'-'a' : 0), tmp++) {
;
}
memcache_append_ctrls(keystr, serverctrls, clientctrls);
*keyp = crc32_convert(keystr, len);
NSLDAPI_FREE(keystr);
NSLDAPI_FREE(tmpbase);
return LDAP_SUCCESS;
}
int
ldap_memcache_result(LDAP *ld, int msgid, unsigned long key)
{
int nRes;
LDAPMessage *pMsg = NULL;
LDAPDebug( LDAP_DEBUG_TRACE,
"ldap_memcache_result( ld: 0x%x, msgid: %d, key: 0x%8.8lx)\n",
ld, msgid, key );
if ( !NSLDAPI_VALID_LDAP_POINTER( ld ) || (msgid < 0) ) {
return( LDAP_PARAM_ERROR );
}
if (!memcache_exist(ld)) {
return( LDAP_LOCAL_ERROR );
}
LDAP_MUTEX_LOCK( ld, LDAP_MEMCACHE_LOCK );
LDAP_MEMCACHE_MUTEX_LOCK( ld->ld_memcache );
++ld->ld_memcache->ldmemc_stats.ldmemcstat_tries;
if ((nRes = memcache_search(ld, key, &pMsg)) == LDAP_SUCCESS) {
nRes = memcache_add_to_ld(ld, msgid, pMsg);
++ld->ld_memcache->ldmemc_stats.ldmemcstat_hits;
LDAPDebug( LDAP_DEBUG_TRACE,
"ldap_memcache_result: key 0x%8.8lx found in cache\n",
key, 0, 0 );
} else {
LDAPDebug( LDAP_DEBUG_TRACE,
"ldap_memcache_result: key 0x%8.8lx not found in cache\n",
key, 0, 0 );
}
#ifdef LDAP_DEBUG
memcache_print_list( ld->ld_memcache, LIST_LRU );
memcache_report_statistics( ld->ld_memcache );
#endif
LDAP_MEMCACHE_MUTEX_UNLOCK( ld->ld_memcache );
LDAP_MUTEX_UNLOCK( ld, LDAP_MEMCACHE_LOCK );
return nRes;
}
int
ldap_memcache_new(LDAP *ld, int msgid, unsigned long key, const char *basedn)
{
int nRes;
if ( !NSLDAPI_VALID_LDAP_POINTER( ld ) ) {
return( LDAP_PARAM_ERROR );
}
LDAP_MUTEX_LOCK( ld, LDAP_MEMCACHE_LOCK );
if (!memcache_exist(ld)) {
LDAP_MUTEX_UNLOCK( ld, LDAP_MEMCACHE_LOCK );
return( LDAP_LOCAL_ERROR );
}
LDAP_MEMCACHE_MUTEX_LOCK( ld->ld_memcache );
nRes = memcache_add(ld, key, msgid, basedn);
LDAP_MEMCACHE_MUTEX_UNLOCK( ld->ld_memcache );
LDAP_MUTEX_UNLOCK( ld, LDAP_MEMCACHE_LOCK );
return nRes;
}
int
ldap_memcache_append(LDAP *ld, int msgid, int bLast, LDAPMessage *result)
{
int nRes = LDAP_SUCCESS;
LDAPDebug( LDAP_DEBUG_TRACE, "ldap_memcache_append( ld: 0x%x, ", ld, 0, 0 );
LDAPDebug( LDAP_DEBUG_TRACE, "msgid %d, bLast: %d, result: 0x%x)\n",
msgid, bLast, result );
if ( !NSLDAPI_VALID_LDAP_POINTER( ld ) || !result ) {
return( LDAP_PARAM_ERROR );
}
LDAP_MUTEX_LOCK( ld, LDAP_MEMCACHE_LOCK );
if (!memcache_exist(ld)) {
LDAP_MUTEX_UNLOCK( ld, LDAP_MEMCACHE_LOCK );
return( LDAP_LOCAL_ERROR );
}
LDAP_MEMCACHE_MUTEX_LOCK( ld->ld_memcache );
if (!bLast)
nRes = memcache_append(ld, msgid, result);
else
nRes = memcache_append_last(ld, msgid, result);
LDAPDebug( LDAP_DEBUG_TRACE,
"ldap_memcache_append: %s result for msgid %d\n",
( nRes == LDAP_SUCCESS ) ? "added" : "failed to add", msgid , 0 );
LDAP_MEMCACHE_MUTEX_UNLOCK( ld->ld_memcache );
LDAP_MUTEX_UNLOCK( ld, LDAP_MEMCACHE_LOCK );
return nRes;
}
int
ldap_memcache_abandon(LDAP *ld, int msgid)
{
int nRes;
if ( !NSLDAPI_VALID_LDAP_POINTER( ld ) || (msgid < 0) ) {
return( LDAP_PARAM_ERROR );
}
LDAP_MUTEX_LOCK( ld, LDAP_MEMCACHE_LOCK );
if (!memcache_exist(ld)) {
LDAP_MUTEX_UNLOCK( ld, LDAP_MEMCACHE_LOCK );
return( LDAP_LOCAL_ERROR );
}
LDAP_MEMCACHE_MUTEX_LOCK( ld->ld_memcache );
nRes = memcache_remove(ld, msgid);
LDAP_MEMCACHE_MUTEX_UNLOCK( ld->ld_memcache );
LDAP_MUTEX_UNLOCK( ld, LDAP_MEMCACHE_LOCK );
return nRes;
}
static void
memcache_trim_basedn_spaces(char *basedn)
{
char *pRead, *pWrite;
if (!basedn)
return;
for (pWrite = pRead = basedn; *pRead; ) {
for (; *pRead && NSLDAPI_IS_SPACE(*pRead); pRead++) {
;
}
for (; *pRead && !NSLDAPI_IS_SEPARATER(*pRead);
*(pWrite++) = *(pRead++)) {
;
}
*(pWrite++) = (*pRead ? *(pRead++) : *pRead);
}
}
static int
memcache_validate_basedn(LDAPMemCache *cache, const char *basedn)
{
int i;
if ( cache->ldmemc_basedns == NULL ) {
return( LDAP_SUCCESS );
}
#if 1
if (basedn == NULL) {
basedn = "";
}
#else
if (basedn == NULL)
return (cache->ldmemc_basedns && cache->ldmemc_basedns[0] ?
LDAP_OPERATIONS_ERROR : LDAP_SUCCESS);
}
#endif
for (i = 0; cache->ldmemc_basedns[i]; i++) {
if (memcache_compare_dn(basedn, cache->ldmemc_basedns[i],
LDAP_SCOPE_SUBTREE) == LDAP_COMPARE_TRUE) {
return( LDAP_SUCCESS );
}
}
return( LDAP_OPERATIONS_ERROR );
}
static int
memcache_get_ctrls_len(LDAPControl **ctrls)
{
int len = 0, i;
if (ctrls) {
for (i = 0; ctrls[i]; i++) {
len += strlen(NSLDAPI_STR_NONNULL(ctrls[i]->ldctl_oid)) +
(ctrls[i]->ldctl_value).bv_len + 4;
}
}
return len;
}
static void
memcache_append_ctrls(char *buf, LDAPControl **serverCtrls,
LDAPControl **clientCtrls)
{
int i, j;
char *pCh = buf + strlen(buf);
LDAPControl **ctrls;
for (j = 0; j < 2; j++) {
if ((ctrls = (j ? clientCtrls : serverCtrls)) == NULL)
continue;
for (i = 0; ctrls[i]; i++) {
sprintf(pCh, "%s\n", NSLDAPI_STR_NONNULL(ctrls[i]->ldctl_oid));
pCh += strlen(NSLDAPI_STR_NONNULL(ctrls[i]->ldctl_oid)) + 1;
if ((ctrls[i]->ldctl_value).bv_len > 0) {
memcpy(pCh, (ctrls[i]->ldctl_value).bv_val,
(ctrls[i]->ldctl_value).bv_len);
pCh += (ctrls[i]->ldctl_value).bv_len;
}
sprintf(pCh, "\n%i\n", (ctrls[i]->ldctl_iscritical ? 1 : 0));
pCh += 3;
}
}
}
static int
memcache_adj_size(LDAPMemCache *cache, unsigned long size,
int usageFlags, int bAdd)
{
LDAPDebug( LDAP_DEBUG_TRACE,
"memcache_adj_size: attempting to %s %ld %s bytes...\n",
bAdd ? "add" : "remove", size,
( usageFlags & MEMCACHE_SIZE_ENTRIES ) ? "entry" : "non-entry" );
if (bAdd) {
cache->ldmemc_size_used += size;
if ((cache->ldmemc_size > 0) &&
(cache->ldmemc_size_used > cache->ldmemc_size)) {
if (size > cache->ldmemc_size_entries) {
cache->ldmemc_size_used -= size;
LDAPDebug( LDAP_DEBUG_TRACE,
"memcache_adj_size: failed (size > size_entries %ld).\n",
cache->ldmemc_size_entries, 0, 0 );
return( LDAP_SIZELIMIT_EXCEEDED );
}
while (cache->ldmemc_size_used > cache->ldmemc_size) {
if (memcache_access(cache, MEMCACHE_ACCESS_FLUSH_LRU,
NULL, NULL, NULL) != LDAP_SUCCESS) {
cache->ldmemc_size_used -= size;
LDAPDebug( LDAP_DEBUG_TRACE,
"memcache_adj_size: failed (LRU flush failed).\n",
0, 0, 0 );
return( LDAP_SIZELIMIT_EXCEEDED );
}
}
}
if (usageFlags & MEMCACHE_SIZE_ENTRIES)
cache->ldmemc_size_entries += size;
} else {
cache->ldmemc_size_used -= size;
assert(cache->ldmemc_size_used >= 0);
if (usageFlags & MEMCACHE_SIZE_ENTRIES)
cache->ldmemc_size_entries -= size;
}
#ifdef LDAP_DEBUG
if ( cache->ldmemc_size == 0 ) {
LDAPDebug( LDAP_DEBUG_TRACE,
"memcache_adj_size: succeeded (new size: %ld bytes).\n",
cache->ldmemc_size_used, 0, 0 );
} else {
LDAPDebug( LDAP_DEBUG_TRACE,
"memcache_adj_size: succeeded (new size: %ld bytes, "
"free space: %ld bytes).\n", cache->ldmemc_size_used,
cache->ldmemc_size - cache->ldmemc_size_used, 0 );
}
#endif
return( LDAP_SUCCESS );
}
static int
memcache_search(LDAP *ld, unsigned long key, LDAPMessage **ppRes)
{
int nRes;
ldapmemcacheRes *pRes;
*ppRes = NULL;
if (!memcache_exist(ld))
return LDAP_LOCAL_ERROR;
nRes = memcache_access(ld->ld_memcache, MEMCACHE_ACCESS_FIND,
(void*)&key, (void*)(&pRes), NULL);
if (nRes != LDAP_SUCCESS)
return nRes;
*ppRes = pRes->ldmemcr_resHead;
assert((pRes->ldmemcr_req_id).ldmemcrid_msgid == -1);
return( LDAP_SUCCESS );
}
static int
memcache_add(LDAP *ld, unsigned long key, int msgid,
const char *basedn)
{
ldapmemcacheReqId reqid;
if (!memcache_exist(ld))
return LDAP_LOCAL_ERROR;
reqid.ldmemcrid_msgid = msgid;
reqid.ldmemcrid_ld = ld;
return memcache_access(ld->ld_memcache, MEMCACHE_ACCESS_ADD,
(void*)&key, (void*)&reqid, (void*)basedn);
}
static int
memcache_append(LDAP *ld, int msgid, LDAPMessage *pRes)
{
ldapmemcacheReqId reqid;
if (!memcache_exist(ld))
return LDAP_LOCAL_ERROR;
reqid.ldmemcrid_msgid = msgid;
reqid.ldmemcrid_ld = ld;
return memcache_access(ld->ld_memcache, MEMCACHE_ACCESS_APPEND,
(void*)&reqid, (void*)pRes, NULL);
}
static int
memcache_append_last(LDAP *ld, int msgid, LDAPMessage *pRes)
{
ldapmemcacheReqId reqid;
if (!memcache_exist(ld))
return LDAP_LOCAL_ERROR;
reqid.ldmemcrid_msgid = msgid;
reqid.ldmemcrid_ld = ld;
return memcache_access(ld->ld_memcache, MEMCACHE_ACCESS_APPEND_LAST,
(void*)&reqid, (void*)pRes, NULL);
}
static int
memcache_remove(LDAP *ld, int msgid)
{
ldapmemcacheReqId reqid;
if (!memcache_exist(ld))
return LDAP_LOCAL_ERROR;
reqid.ldmemcrid_msgid = msgid;
reqid.ldmemcrid_ld = ld;
return memcache_access(ld->ld_memcache, MEMCACHE_ACCESS_DELETE,
(void*)&reqid, NULL, NULL);
}
#if 0
static int
memcache_remove_all(LDAP *ld)
{
if (!memcache_exist(ld))
return LDAP_LOCAL_ERROR;
return memcache_access(ld->ld_memcache, MEMCACHE_ACCESS_DELETE_ALL,
NULL, NULL, NULL);
}
#endif
static int
memcache_exist(LDAP *ld)
{
return (ld->ld_memcache != NULL);
}
static int
memcache_add_to_ld(LDAP *ld, int msgid, LDAPMessage *pMsg)
{
int nRes = LDAP_SUCCESS;
LDAPMessage **r;
LDAPMessage *pCopy;
nRes = memcache_dup_message(pMsg, msgid, 1, &pCopy, NULL);
if (nRes != LDAP_SUCCESS)
return nRes;
for (r = &(ld->ld_responses); *r; r = &((*r)->lm_next))
if ((*r)->lm_msgid == msgid)
break;
if (*r)
for (r = &((*r)->lm_chain); *r; r = &((*r)->lm_chain)) {
;
}
*r = pCopy;
return nRes;
}
static int
memcache_compare_dn(const char *main_dn, const char *dn, int scope)
{
int nRes;
char **components = NULL;
char **main_components = NULL;
components = ldap_explode_dn(dn, 0);
main_components = ldap_explode_dn(main_dn, 0);
if (!components || !main_components) {
nRes = LDAP_COMPARE_TRUE;
}
else {
int i, main_i;
main_i = ldap_count_values(main_components) - 1;
i = ldap_count_values(components) - 1;
for (; i >= 0 && main_i >= 0; i--, main_i--) {
if (strcasecmp(main_components[main_i], components[i]))
break;
}
if (i >= 0 && main_i >= 0) {
nRes = LDAP_COMPARE_FALSE;
}
else if (i < 0 && main_i < 0) {
if (scope != LDAP_SCOPE_ONELEVEL)
nRes = LDAP_COMPARE_TRUE;
else
nRes = LDAP_COMPARE_FALSE;
}
else if (main_i < 0) {
nRes = LDAP_COMPARE_FALSE;
}
else {
if (scope == LDAP_SCOPE_BASE)
nRes = LDAP_COMPARE_FALSE;
else if (scope == LDAP_SCOPE_SUBTREE)
nRes = LDAP_COMPARE_TRUE;
else if (main_i == 0)
nRes = LDAP_COMPARE_TRUE;
else
nRes = LDAP_COMPARE_FALSE;
}
}
if (components)
ldap_value_free(components);
if (main_components)
ldap_value_free(main_components);
return nRes;
}
static BerElement*
memcache_ber_dup(BerElement* pBer, unsigned long *pSize)
{
BerElement *p = ber_dup(pBer);
*pSize = 0;
if (p) {
*pSize += sizeof(BerElement) + EXTRA_SIZE;
if (p->ber_len <= EXTRA_SIZE) {
p->ber_flags |= LBER_FLAG_NO_FREE_BUFFER;
p->ber_buf = (char*)p + sizeof(BerElement);
} else {
p->ber_flags &= ~LBER_FLAG_NO_FREE_BUFFER;
p->ber_buf = (char*)NSLDAPI_CALLOC(1, p->ber_len);
*pSize += (p->ber_buf ? p->ber_len : 0);
}
if (p->ber_buf) {
p->ber_ptr = p->ber_buf + (pBer->ber_ptr - pBer->ber_buf);
p->ber_end = p->ber_buf + p->ber_len;
memcpy(p->ber_buf, pBer->ber_buf, p->ber_len);
} else {
ber_free(p, 0);
p = NULL;
*pSize = 0;
}
}
return p;
}
static int
memcache_dup_message(LDAPMessage *res, int msgid, int fromcache,
LDAPMessage **ppResCopy, unsigned long *pSize)
{
int nRes = LDAP_SUCCESS;
unsigned long ber_size;
LDAPMessage *pCur;
LDAPMessage **ppCurNew;
*ppResCopy = NULL;
if (pSize)
*pSize = 0;
for (pCur = res, ppCurNew = ppResCopy; pCur;
pCur = pCur->lm_chain, ppCurNew = &((*ppCurNew)->lm_chain)) {
if ((*ppCurNew = (LDAPMessage*)NSLDAPI_CALLOC(1,
sizeof(LDAPMessage))) == NULL) {
nRes = LDAP_NO_MEMORY;
break;
}
memcpy(*ppCurNew, pCur, sizeof(LDAPMessage));
(*ppCurNew)->lm_next = NULL;
(*ppCurNew)->lm_ber = memcache_ber_dup(pCur->lm_ber, &ber_size);
(*ppCurNew)->lm_msgid = msgid;
(*ppCurNew)->lm_fromcache = (fromcache != 0);
if (pSize)
*pSize += sizeof(LDAPMessage) + ber_size;
}
if ((nRes != LDAP_SUCCESS) && (*ppResCopy != NULL)) {
ldap_msgfree(*ppResCopy);
*ppResCopy = NULL;
if (pSize)
*pSize = 0;
}
return nRes;
}
static int
memcache_free_entry(LDAPMemCache *cache, ldapmemcacheRes *pRes)
{
if (pRes) {
unsigned long size = sizeof(ldapmemcacheRes);
if (pRes->ldmemcr_basedn) {
size += strlen(pRes->ldmemcr_basedn) + 1;
NSLDAPI_FREE(pRes->ldmemcr_basedn);
}
if (pRes->ldmemcr_resHead) {
size += pRes->ldmemcr_resSize;
ldap_msgfree(pRes->ldmemcr_resHead);
}
NSLDAPI_FREE(pRes);
memcache_adj_size(cache, size, MEMCACHE_SIZE_ENTRIES,
MEMCACHE_SIZE_DEDUCT);
}
return( LDAP_SUCCESS );
}
static int
memcache_free_from_list(LDAPMemCache *cache, ldapmemcacheRes *pRes, int index)
{
if (pRes->ldmemcr_prev[index])
pRes->ldmemcr_prev[index]->ldmemcr_next[index] =
pRes->ldmemcr_next[index];
if (pRes->ldmemcr_next[index])
pRes->ldmemcr_next[index]->ldmemcr_prev[index] =
pRes->ldmemcr_prev[index];
if (cache->ldmemc_resHead[index] == pRes)
cache->ldmemc_resHead[index] = pRes->ldmemcr_next[index];
if (cache->ldmemc_resTail[index] == pRes)
cache->ldmemc_resTail[index] = pRes->ldmemcr_prev[index];
pRes->ldmemcr_prev[index] = NULL;
pRes->ldmemcr_next[index] = NULL;
return( LDAP_SUCCESS );
}
static int
memcache_add_to_list(LDAPMemCache *cache, ldapmemcacheRes *pRes, int index)
{
if (cache->ldmemc_resHead[index])
cache->ldmemc_resHead[index]->ldmemcr_prev[index] = pRes;
else
cache->ldmemc_resTail[index] = pRes;
pRes->ldmemcr_prev[index] = NULL;
pRes->ldmemcr_next[index] = cache->ldmemc_resHead[index];
cache->ldmemc_resHead[index] = pRes;
return( LDAP_SUCCESS );
}
static int
memcache_add_res_to_list(ldapmemcacheRes *pRes, LDAPMessage *pMsg,
unsigned long size)
{
if (pRes->ldmemcr_resTail)
pRes->ldmemcr_resTail->lm_chain = pMsg;
else
pRes->ldmemcr_resHead = pMsg;
for (pRes->ldmemcr_resTail = pMsg;
pRes->ldmemcr_resTail->lm_chain;
pRes->ldmemcr_resTail = pRes->ldmemcr_resTail->lm_chain) {
;
}
pRes->ldmemcr_resSize += size;
return( LDAP_SUCCESS );
}
#ifdef LDAP_DEBUG
static void
memcache_print_list( LDAPMemCache *cache, int index )
{
char *name;
ldapmemcacheRes *restmp;
switch( index ) {
case LIST_TTL:
name = "TTL";
break;
case LIST_LRU:
name = "LRU";
break;
case LIST_TMP:
name = "TMP";
break;
case LIST_TOTAL:
name = "TOTAL";
break;
default:
name = "unknown";
}
LDAPDebug( LDAP_DEBUG_TRACE, "memcache 0x%x %s list:\n",
cache, name, 0 );
for ( restmp = cache->ldmemc_resHead[index]; restmp != NULL;
restmp = restmp->ldmemcr_next[index] ) {
LDAPDebug( LDAP_DEBUG_TRACE,
" key: 0x%8.8lx, ld: 0x%x, msgid: %d\n",
restmp->ldmemcr_crc_key,
restmp->ldmemcr_req_id.ldmemcrid_ld,
restmp->ldmemcr_req_id.ldmemcrid_msgid );
}
LDAPDebug( LDAP_DEBUG_TRACE, "memcache 0x%x end of %s list.\n",
cache, name, 0 );
}
#endif
static int
memcache_expired(LDAPMemCache *cache, ldapmemcacheRes *pRes,
unsigned long curTime)
{
if (!cache->ldmemc_ttl)
return 0;
return ((unsigned long)difftime(
(time_t)curTime,
(time_t)(pRes->ldmemcr_timestamp)) >=
cache->ldmemc_ttl);
}
static int
memcache_access(LDAPMemCache *cache, int mode,
void *pData1, void *pData2, void *pData3)
{
int nRes = LDAP_SUCCESS;
unsigned long size = 0;
if (mode == MEMCACHE_ACCESS_ADD) {
unsigned long key = *((unsigned long*)pData1);
char *basedn = (char*)pData3;
ldapmemcacheRes *pRes = NULL;
nRes = htable_get(cache->ldmemc_resTmp, pData2, (void**)&pRes);
if (nRes == LDAP_SUCCESS)
return( LDAP_ALREADY_EXISTS );
pRes = (ldapmemcacheRes*)NSLDAPI_CALLOC(1, sizeof(ldapmemcacheRes));
if (pRes == NULL)
return( LDAP_NO_MEMORY );
pRes->ldmemcr_crc_key = key;
pRes->ldmemcr_req_id = *((ldapmemcacheReqId*)pData2);
pRes->ldmemcr_basedn = (basedn ? nsldapi_strdup(basedn) : NULL);
size += sizeof(ldapmemcacheRes) + strlen(basedn) + 1;
nRes = memcache_adj_size(cache, size, MEMCACHE_SIZE_ENTRIES,
MEMCACHE_SIZE_ADD);
if (nRes == LDAP_SUCCESS)
nRes = htable_put(cache->ldmemc_resTmp, pData2, (void*)pRes);
if (nRes == LDAP_SUCCESS)
memcache_add_to_list(cache, pRes, LIST_TMP);
else
memcache_free_entry(cache, pRes);
}
else if ((mode == MEMCACHE_ACCESS_APPEND) ||
(mode == MEMCACHE_ACCESS_APPEND_LAST)) {
LDAPMessage *pMsg = (LDAPMessage*)pData2;
LDAPMessage *pCopy = NULL;
ldapmemcacheRes *pRes = NULL;
nRes = htable_get(cache->ldmemc_resTmp, pData1, (void**)&pRes);
if (nRes != LDAP_SUCCESS)
return nRes;
nRes = memcache_dup_message(pMsg, pMsg->lm_msgid, 0, &pCopy, &size);
if (nRes != LDAP_SUCCESS) {
nRes = htable_remove(cache->ldmemc_resTmp, pData1, NULL);
assert(nRes == LDAP_SUCCESS);
memcache_free_from_list(cache, pRes, LIST_TMP);
memcache_free_entry(cache, pRes);
return nRes;
}
nRes = memcache_adj_size(cache, size, MEMCACHE_SIZE_ENTRIES,
MEMCACHE_SIZE_ADD);
if (nRes != LDAP_SUCCESS) {
ldap_msgfree(pCopy);
nRes = htable_remove(cache->ldmemc_resTmp, pData1, NULL);
assert(nRes == LDAP_SUCCESS);
memcache_free_from_list(cache, pRes, LIST_TMP);
memcache_free_entry(cache, pRes);
return nRes;
}
memcache_add_res_to_list(pRes, pCopy, size);
if (mode == MEMCACHE_ACCESS_APPEND)
return( LDAP_SUCCESS );
nRes = htable_remove(cache->ldmemc_resTmp, pData1, NULL);
assert(nRes == LDAP_SUCCESS);
memcache_free_from_list(cache, pRes, LIST_TMP);
(pRes->ldmemcr_req_id).ldmemcrid_ld = NULL;
(pRes->ldmemcr_req_id).ldmemcrid_msgid = -1;
pRes->ldmemcr_timestamp = (unsigned long)time(NULL);
if ((nRes = htable_put(cache->ldmemc_resLookup,
(void*)&(pRes->ldmemcr_crc_key),
(void*)pRes)) == LDAP_SUCCESS) {
memcache_add_to_list(cache, pRes, LIST_TTL);
memcache_add_to_list(cache, pRes, LIST_LRU);
} else {
memcache_free_entry(cache, pRes);
}
}
else if (mode == MEMCACHE_ACCESS_FIND) {
ldapmemcacheRes **ppRes = (ldapmemcacheRes**)pData2;
nRes = htable_get(cache->ldmemc_resLookup, pData1, (void**)ppRes);
if (nRes != LDAP_SUCCESS)
return nRes;
if (!memcache_expired(cache, *ppRes, (unsigned long)time(0))) {
memcache_free_from_list(cache, *ppRes, LIST_LRU);
memcache_add_to_list(cache, *ppRes, LIST_LRU);
return( LDAP_SUCCESS );
}
nRes = htable_remove(cache->ldmemc_resLookup, pData1, NULL);
assert(nRes == LDAP_SUCCESS);
memcache_free_from_list(cache, *ppRes, LIST_TTL);
memcache_free_from_list(cache, *ppRes, LIST_LRU);
memcache_free_entry(cache, *ppRes);
nRes = LDAP_NO_SUCH_OBJECT;
*ppRes = NULL;
}
else if (mode == MEMCACHE_ACCESS_DELETE) {
ldapmemcacheRes *pCurRes = NULL;
if ((nRes = htable_remove(cache->ldmemc_resTmp, pData1,
(void**)&pCurRes)) == LDAP_SUCCESS) {
memcache_free_from_list(cache, pCurRes, LIST_TMP);
memcache_free_entry(cache, pCurRes);
}
}
else if (mode == MEMCACHE_ACCESS_DELETE_ALL) {
nRes = htable_removeall(cache->ldmemc_resTmp, (void*)cache);
}
else if (mode == MEMCACHE_ACCESS_UPDATE) {
ldapmemcacheRes *pCurRes = cache->ldmemc_resTail[LIST_TTL];
unsigned long curTime = (unsigned long)time(NULL);
for (; pCurRes; pCurRes = cache->ldmemc_resTail[LIST_TTL]) {
if (!memcache_expired(cache, pCurRes, curTime))
break;
nRes = htable_remove(cache->ldmemc_resLookup,
(void*)&(pCurRes->ldmemcr_crc_key), NULL);
assert(nRes == LDAP_SUCCESS);
memcache_free_from_list(cache, pCurRes, LIST_TTL);
memcache_free_from_list(cache, pCurRes, LIST_LRU);
memcache_free_entry(cache, pCurRes);
}
}
else if (mode == MEMCACHE_ACCESS_FLUSH_ALL) {
ldapmemcacheRes *pCurRes = cache->ldmemc_resHead[LIST_TTL];
nRes = htable_removeall(cache->ldmemc_resLookup, (void*)cache);
for (; pCurRes; pCurRes = cache->ldmemc_resHead[LIST_TTL]) {
memcache_free_from_list(cache, pCurRes, LIST_LRU);
cache->ldmemc_resHead[LIST_TTL] =
cache->ldmemc_resHead[LIST_TTL]->ldmemcr_next[LIST_TTL];
memcache_free_entry(cache, pCurRes);
}
cache->ldmemc_resTail[LIST_TTL] = NULL;
}
else if (mode == MEMCACHE_ACCESS_FLUSH) {
int i, list_id, bDone;
int scope = (int)(uintptr_t)pData2;
char *dn = (char*)pData1;
char *dnTmp;
BerElement ber;
LDAPMessage *pMsg;
ldapmemcacheRes *pRes;
if (cache->ldmemc_basedns) {
for (i = 0; cache->ldmemc_basedns[i]; i++) {
if ((memcache_compare_dn(cache->ldmemc_basedns[i], dn,
LDAP_SCOPE_SUBTREE) == LDAP_COMPARE_TRUE) ||
(memcache_compare_dn(dn, cache->ldmemc_basedns[i],
LDAP_SCOPE_SUBTREE) == LDAP_COMPARE_TRUE))
break;
}
if (cache->ldmemc_basedns[i] == NULL)
return( LDAP_SUCCESS );
}
for (i = 0; i < 2; i++) {
list_id = (i == 0 ? LIST_TTL : LIST_TMP);
for (pRes = cache->ldmemc_resHead[list_id]; pRes != NULL;
pRes = pRes->ldmemcr_next[list_id]) {
if ((memcache_compare_dn(pRes->ldmemcr_basedn, dn,
LDAP_SCOPE_SUBTREE) != LDAP_COMPARE_TRUE) &&
(memcache_compare_dn(dn, pRes->ldmemcr_basedn,
LDAP_SCOPE_SUBTREE) != LDAP_COMPARE_TRUE))
continue;
for (pMsg = pRes->ldmemcr_resHead, bDone = 0;
!bDone && pMsg; pMsg = pMsg->lm_chain) {
if (!NSLDAPI_IS_SEARCH_ENTRY( pMsg->lm_msgtype ))
continue;
ber = *(pMsg->lm_ber);
if (ber_scanf(&ber, "{a", &dnTmp) != LBER_ERROR) {
bDone = (memcache_compare_dn(dnTmp, dn, scope) ==
LDAP_COMPARE_TRUE);
ldap_memfree(dnTmp);
}
}
if (!bDone)
continue;
if (list_id == LIST_TTL) {
nRes = htable_remove(cache->ldmemc_resLookup,
(void*)&(pRes->ldmemcr_crc_key), NULL);
assert(nRes == LDAP_SUCCESS);
memcache_free_from_list(cache, pRes, LIST_TTL);
memcache_free_from_list(cache, pRes, LIST_LRU);
} else {
nRes = htable_remove(cache->ldmemc_resTmp,
(void*)&(pRes->ldmemcr_req_id), NULL);
assert(nRes == LDAP_SUCCESS);
memcache_free_from_list(cache, pRes, LIST_TMP);
}
memcache_free_entry(cache, pRes);
}
}
}
else if (mode == MEMCACHE_ACCESS_FLUSH_LRU) {
ldapmemcacheRes *pRes = cache->ldmemc_resTail[LIST_LRU];
if (pRes == NULL)
return LDAP_NO_SUCH_OBJECT;
LDAPDebug( LDAP_DEBUG_TRACE,
"memcache_access FLUSH_LRU: removing key 0x%8.8lx\n",
pRes->ldmemcr_crc_key, 0, 0 );
nRes = htable_remove(cache->ldmemc_resLookup,
(void*)&(pRes->ldmemcr_crc_key), NULL);
assert(nRes == LDAP_SUCCESS);
memcache_free_from_list(cache, pRes, LIST_TTL);
memcache_free_from_list(cache, pRes, LIST_LRU);
memcache_free_entry(cache, pRes);
}
else {
nRes = LDAP_PARAM_ERROR;
}
return nRes;
}
#ifdef LDAP_DEBUG
static void
memcache_report_statistics( LDAPMemCache *cache )
{
unsigned long hitrate;
if ( cache->ldmemc_stats.ldmemcstat_tries == 0 ) {
hitrate = 0;
} else {
hitrate = ( 100L * cache->ldmemc_stats.ldmemcstat_hits ) /
cache->ldmemc_stats.ldmemcstat_tries;
}
LDAPDebug( LDAP_DEBUG_STATS, "memcache 0x%x:\n", cache, 0, 0 );
LDAPDebug( LDAP_DEBUG_STATS, " tries: %ld hits: %ld hitrate: %ld%%\n",
cache->ldmemc_stats.ldmemcstat_tries,
cache->ldmemc_stats.ldmemcstat_hits, hitrate );
if ( cache->ldmemc_size <= 0 ) {
LDAPDebug( LDAP_DEBUG_STATS, " memory bytes used: %ld\n",
cache->ldmemc_size_used, 0, 0 );
} else {
LDAPDebug( LDAP_DEBUG_STATS, " memory bytes used: %ld free: %ld\n",
cache->ldmemc_size_used,
cache->ldmemc_size - cache->ldmemc_size_used, 0 );
}
}
#endif
static int
htable_calculate_size(int sizelimit)
{
int i, j;
int size = (int)(((double)sizelimit /
(double)(sizeof(BerElement) + EXTRA_SIZE)) / 1.5);
size = (size & 0x1 ? size : size + 1);
for (i = 3, j = size / 2; i < j; i++) {
if ((size % i) == 0) {
size += 2;
i = 3;
j = size / 2;
}
}
return size;
}
static int
htable_sizeinbytes(HashTable *pTable)
{
if (!pTable)
return 0;
return (pTable->size * sizeof(HashTableNode));
}
static int
htable_put(HashTable *pTable, void *key, void *pData)
{
int index = pTable->hashfunc(pTable->size, key);
if (index >= 0 && index < pTable->size)
return pTable->putdata(&(pTable->table[index].pData), key, pData);
return( LDAP_OPERATIONS_ERROR );
}
static int
htable_get(HashTable *pTable, void *key, void **ppData)
{
int index = pTable->hashfunc(pTable->size, key);
*ppData = NULL;
if (index >= 0 && index < pTable->size)
return pTable->getdata(pTable->table[index].pData, key, ppData);
return( LDAP_OPERATIONS_ERROR );
}
static int
htable_misc(HashTable *pTable, void *key, void *pData)
{
if (pTable->miscfunc) {
int index = pTable->hashfunc(pTable->size, key);
if (index >= 0 && index < pTable->size)
return pTable->miscfunc(&(pTable->table[index].pData), key, pData);
}
return( LDAP_OPERATIONS_ERROR );
}
static int
htable_remove(HashTable *pTable, void *key, void **ppData)
{
int index = pTable->hashfunc(pTable->size, key);
if (ppData)
*ppData = NULL;
if (index >= 0 && index < pTable->size)
return pTable->removedata(&(pTable->table[index].pData), key, ppData);
return( LDAP_OPERATIONS_ERROR );
}
static int
htable_removeall(HashTable *pTable, void *pData)
{
int i;
for (i = 0; i < pTable->size; i++)
pTable->clrtablenode(&(pTable->table[i].pData), pData);
return( LDAP_SUCCESS );
}
static int
htable_create(int size_limit, HashFuncPtr hashf,
PutDataPtr putDataf, GetDataPtr getDataf,
RemoveDataPtr removeDataf, ClrTableNodePtr clrNodef,
MiscFuncPtr miscOpf, HashTable **ppTable)
{
size_limit = htable_calculate_size(size_limit);
if ((*ppTable = (HashTable*)NSLDAPI_CALLOC(1, sizeof(HashTable))) == NULL)
return( LDAP_NO_MEMORY );
(*ppTable)->table = (HashTableNode*)NSLDAPI_CALLOC(size_limit,
sizeof(HashTableNode));
if ((*ppTable)->table == NULL) {
NSLDAPI_FREE(*ppTable);
*ppTable = NULL;
return( LDAP_NO_MEMORY );
}
(*ppTable)->size = size_limit;
(*ppTable)->hashfunc = hashf;
(*ppTable)->putdata = putDataf;
(*ppTable)->getdata = getDataf;
(*ppTable)->miscfunc = miscOpf;
(*ppTable)->removedata = removeDataf;
(*ppTable)->clrtablenode = clrNodef;
return( LDAP_SUCCESS );
}
static int
htable_free(HashTable *pTable)
{
NSLDAPI_FREE(pTable->table);
NSLDAPI_FREE(pTable);
return( LDAP_SUCCESS );
}
static int
msgid_hashf(int table_size, void *key)
{
uint_t code = (uint_t)(uintptr_t)((ldapmemcacheReqId*)key)->ldmemcrid_ld;
return (((code << 20) + (code >> 12)) % table_size);
}
static int
msgid_putdata(void **ppTableData, void *key, void *pData)
{
ldapmemcacheReqId *pReqId = (ldapmemcacheReqId*)key;
ldapmemcacheRes *pRes = (ldapmemcacheRes*)pData;
ldapmemcacheRes **ppHead = (ldapmemcacheRes**)ppTableData;
ldapmemcacheRes *pCurRes = *ppHead;
ldapmemcacheRes *pPrev = NULL;
for (; pCurRes; pCurRes = pCurRes->ldmemcr_htable_next) {
if ((pCurRes->ldmemcr_req_id).ldmemcrid_ld == pReqId->ldmemcrid_ld)
break;
pPrev = pCurRes;
}
if (pCurRes) {
for (; pCurRes; pCurRes = pCurRes->ldmemcr_next[LIST_TTL]) {
if ((pCurRes->ldmemcr_req_id).ldmemcrid_msgid ==
pReqId->ldmemcrid_msgid)
return( LDAP_ALREADY_EXISTS );
pPrev = pCurRes;
}
pPrev->ldmemcr_next[LIST_TTL] = pRes;
pRes->ldmemcr_prev[LIST_TTL] = pPrev;
pRes->ldmemcr_next[LIST_TTL] = NULL;
} else {
if (pPrev)
pPrev->ldmemcr_htable_next = pRes;
else
*ppHead = pRes;
pRes->ldmemcr_htable_next = NULL;
}
return( LDAP_SUCCESS );
}
static int
msgid_getdata(void *pTableData, void *key, void **ppData)
{
ldapmemcacheReqId *pReqId = (ldapmemcacheReqId*)key;
ldapmemcacheRes *pCurRes = (ldapmemcacheRes*)pTableData;
*ppData = NULL;
for (; pCurRes; pCurRes = pCurRes->ldmemcr_htable_next) {
if ((pCurRes->ldmemcr_req_id).ldmemcrid_ld == pReqId->ldmemcrid_ld)
break;
}
if (!pCurRes)
return( LDAP_NO_SUCH_OBJECT );
for (; pCurRes; pCurRes = pCurRes->ldmemcr_next[LIST_TTL]) {
if ((pCurRes->ldmemcr_req_id).ldmemcrid_msgid ==
pReqId->ldmemcrid_msgid) {
*ppData = (void*)pCurRes;
return( LDAP_SUCCESS );
}
}
return( LDAP_NO_SUCH_OBJECT );
}
static int
msgid_removedata(void **ppTableData, void *key, void **ppData)
{
ldapmemcacheRes *pHead = *((ldapmemcacheRes**)ppTableData);
ldapmemcacheRes *pCurRes = NULL;
ldapmemcacheRes *pPrev = NULL;
ldapmemcacheReqId *pReqId = (ldapmemcacheReqId*)key;
if (ppData)
*ppData = NULL;
for (; pHead; pHead = pHead->ldmemcr_htable_next) {
if ((pHead->ldmemcr_req_id).ldmemcrid_ld == pReqId->ldmemcrid_ld)
break;
pPrev = pHead;
}
if (!pHead)
return( LDAP_NO_SUCH_OBJECT );
for (pCurRes = pHead; pCurRes; pCurRes = pCurRes->ldmemcr_next[LIST_TTL]) {
if ((pCurRes->ldmemcr_req_id).ldmemcrid_msgid ==
pReqId->ldmemcrid_msgid)
break;
}
if (!pCurRes)
return( LDAP_NO_SUCH_OBJECT );
if (ppData) {
pCurRes->ldmemcr_next[LIST_TTL] = NULL;
pCurRes->ldmemcr_prev[LIST_TTL] = NULL;
pCurRes->ldmemcr_htable_next = NULL;
*ppData = (void*)pCurRes;
}
if (pCurRes != pHead) {
if (pCurRes->ldmemcr_prev[LIST_TTL])
pCurRes->ldmemcr_prev[LIST_TTL]->ldmemcr_next[LIST_TTL] =
pCurRes->ldmemcr_next[LIST_TTL];
if (pCurRes->ldmemcr_next[LIST_TTL])
pCurRes->ldmemcr_next[LIST_TTL]->ldmemcr_prev[LIST_TTL] =
pCurRes->ldmemcr_prev[LIST_TTL];
return( LDAP_SUCCESS );
}
if (pPrev) {
if (pHead->ldmemcr_next[LIST_TTL]) {
pPrev->ldmemcr_htable_next = pHead->ldmemcr_next[LIST_TTL];
pHead->ldmemcr_next[LIST_TTL]->ldmemcr_htable_next =
pHead->ldmemcr_htable_next;
} else {
pPrev->ldmemcr_htable_next = pHead->ldmemcr_htable_next;
}
} else {
if (pHead->ldmemcr_next[LIST_TTL]) {
*((ldapmemcacheRes**)ppTableData) = pHead->ldmemcr_next[LIST_TTL];
pHead->ldmemcr_next[LIST_TTL]->ldmemcr_htable_next =
pHead->ldmemcr_htable_next;
} else {
*((ldapmemcacheRes**)ppTableData) = pHead->ldmemcr_htable_next;
}
}
return( LDAP_SUCCESS );
}
static int
msgid_clear_ld_items(void **ppTableData, void *key, void *pData)
{
LDAPMemCache *cache = (LDAPMemCache*)pData;
ldapmemcacheRes *pHead = *((ldapmemcacheRes**)ppTableData);
ldapmemcacheRes *pPrev = NULL;
ldapmemcacheRes *pCurRes = NULL;
ldapmemcacheReqId *pReqId = (ldapmemcacheReqId*)key;
for (; pHead; pHead = pHead->ldmemcr_htable_next) {
if ((pHead->ldmemcr_req_id).ldmemcrid_ld == pReqId->ldmemcrid_ld)
break;
pPrev = pHead;
}
if (!pHead)
return( LDAP_NO_SUCH_OBJECT );
if (pPrev)
pPrev->ldmemcr_htable_next = pHead->ldmemcr_htable_next;
else
*((ldapmemcacheRes**)ppTableData) = pHead->ldmemcr_htable_next;
for (pCurRes = pHead; pHead; pCurRes = pHead) {
pHead = pHead->ldmemcr_next[LIST_TTL];
memcache_free_from_list(cache, pCurRes, LIST_TMP);
memcache_free_entry(cache, pCurRes);
}
return( LDAP_SUCCESS );
}
static void
msgid_clearnode(void **ppTableData, void *pData)
{
LDAPMemCache *cache = (LDAPMemCache*)pData;
ldapmemcacheRes **ppHead = (ldapmemcacheRes**)ppTableData;
ldapmemcacheRes *pSubHead = *ppHead;
ldapmemcacheRes *pCurRes = NULL;
for (; *ppHead; pSubHead = *ppHead) {
ppHead = &((*ppHead)->ldmemcr_htable_next);
for (pCurRes = pSubHead; pSubHead; pCurRes = pSubHead) {
pSubHead = pSubHead->ldmemcr_next[LIST_TTL];
memcache_free_from_list(cache, pCurRes, LIST_TMP);
memcache_free_entry(cache, pCurRes);
}
}
}
static int
attrkey_hashf(int table_size, void *key)
{
return ((*((unsigned long*)key)) % table_size);
}
static int
attrkey_putdata(void **ppTableData, void *key, void *pData)
{
unsigned long attrkey = *((unsigned long*)key);
ldapmemcacheRes **ppHead = (ldapmemcacheRes**)ppTableData;
ldapmemcacheRes *pRes = *ppHead;
for (; pRes; pRes = pRes->ldmemcr_htable_next) {
if (pRes->ldmemcr_crc_key == attrkey)
return( LDAP_ALREADY_EXISTS );
}
pRes = (ldapmemcacheRes*)pData;
pRes->ldmemcr_htable_next = *ppHead;
*ppHead = pRes;
return( LDAP_SUCCESS );
}
static int
attrkey_getdata(void *pTableData, void *key, void **ppData)
{
unsigned long attrkey = *((unsigned long*)key);
ldapmemcacheRes *pRes = (ldapmemcacheRes*)pTableData;
for (; pRes; pRes = pRes->ldmemcr_htable_next) {
if (pRes->ldmemcr_crc_key == attrkey) {
*ppData = (void*)pRes;
return( LDAP_SUCCESS );
}
}
*ppData = NULL;
return( LDAP_NO_SUCH_OBJECT );
}
static int
attrkey_removedata(void **ppTableData, void *key, void **ppData)
{
unsigned long attrkey = *((unsigned long*)key);
ldapmemcacheRes **ppHead = (ldapmemcacheRes**)ppTableData;
ldapmemcacheRes *pRes = *ppHead;
ldapmemcacheRes *pPrev = NULL;
for (; pRes; pRes = pRes->ldmemcr_htable_next) {
if (pRes->ldmemcr_crc_key == attrkey) {
if (ppData)
*ppData = (void*)pRes;
if (pPrev)
pPrev->ldmemcr_htable_next = pRes->ldmemcr_htable_next;
else
*ppHead = pRes->ldmemcr_htable_next;
pRes->ldmemcr_htable_next = NULL;
return( LDAP_SUCCESS );
}
pPrev = pRes;
}
if (ppData)
*ppData = NULL;
return( LDAP_NO_SUCH_OBJECT );
}
static void
attrkey_clearnode(void **ppTableData, void *pData)
{
ldapmemcacheRes **ppHead = (ldapmemcacheRes**)ppTableData;
ldapmemcacheRes *pRes = *ppHead;
(void)pData;
for (; *ppHead; pRes = *ppHead) {
ppHead = &((*ppHead)->ldmemcr_htable_next);
pRes->ldmemcr_htable_next = NULL;
}
}
#define NSLDAPI_CRC32_POLY 0x04c11db7
static unsigned long crc32_table[256] = {
0x00000000, 0x04c11db7, 0x09823b6e, 0x0d4326d9, 0x130476dc, 0x17c56b6b,
0x1a864db2, 0x1e475005, 0x2608edb8, 0x22c9f00f, 0x2f8ad6d6, 0x2b4bcb61,
0x350c9b64, 0x31cd86d3, 0x3c8ea00a, 0x384fbdbd, 0x4c11db70, 0x48d0c6c7,
0x4593e01e, 0x4152fda9, 0x5f15adac, 0x5bd4b01b, 0x569796c2, 0x52568b75,
0x6a1936c8, 0x6ed82b7f, 0x639b0da6, 0x675a1011, 0x791d4014, 0x7ddc5da3,
0x709f7b7a, 0x745e66cd, 0x9823b6e0, 0x9ce2ab57, 0x91a18d8e, 0x95609039,
0x8b27c03c, 0x8fe6dd8b, 0x82a5fb52, 0x8664e6e5, 0xbe2b5b58, 0xbaea46ef,
0xb7a96036, 0xb3687d81, 0xad2f2d84, 0xa9ee3033, 0xa4ad16ea, 0xa06c0b5d,
0xd4326d90, 0xd0f37027, 0xddb056fe, 0xd9714b49, 0xc7361b4c, 0xc3f706fb,
0xceb42022, 0xca753d95, 0xf23a8028, 0xf6fb9d9f, 0xfbb8bb46, 0xff79a6f1,
0xe13ef6f4, 0xe5ffeb43, 0xe8bccd9a, 0xec7dd02d, 0x34867077, 0x30476dc0,
0x3d044b19, 0x39c556ae, 0x278206ab, 0x23431b1c, 0x2e003dc5, 0x2ac12072,
0x128e9dcf, 0x164f8078, 0x1b0ca6a1, 0x1fcdbb16, 0x018aeb13, 0x054bf6a4,
0x0808d07d, 0x0cc9cdca, 0x7897ab07, 0x7c56b6b0, 0x71159069, 0x75d48dde,
0x6b93dddb, 0x6f52c06c, 0x6211e6b5, 0x66d0fb02, 0x5e9f46bf, 0x5a5e5b08,
0x571d7dd1, 0x53dc6066, 0x4d9b3063, 0x495a2dd4, 0x44190b0d, 0x40d816ba,
0xaca5c697, 0xa864db20, 0xa527fdf9, 0xa1e6e04e, 0xbfa1b04b, 0xbb60adfc,
0xb6238b25, 0xb2e29692, 0x8aad2b2f, 0x8e6c3698, 0x832f1041, 0x87ee0df6,
0x99a95df3, 0x9d684044, 0x902b669d, 0x94ea7b2a, 0xe0b41de7, 0xe4750050,
0xe9362689, 0xedf73b3e, 0xf3b06b3b, 0xf771768c, 0xfa325055, 0xfef34de2,
0xc6bcf05f, 0xc27dede8, 0xcf3ecb31, 0xcbffd686, 0xd5b88683, 0xd1799b34,
0xdc3abded, 0xd8fba05a, 0x690ce0ee, 0x6dcdfd59, 0x608edb80, 0x644fc637,
0x7a089632, 0x7ec98b85, 0x738aad5c, 0x774bb0eb, 0x4f040d56, 0x4bc510e1,
0x46863638, 0x42472b8f, 0x5c007b8a, 0x58c1663d, 0x558240e4, 0x51435d53,
0x251d3b9e, 0x21dc2629, 0x2c9f00f0, 0x285e1d47, 0x36194d42, 0x32d850f5,
0x3f9b762c, 0x3b5a6b9b, 0x0315d626, 0x07d4cb91, 0x0a97ed48, 0x0e56f0ff,
0x1011a0fa, 0x14d0bd4d, 0x19939b94, 0x1d528623, 0xf12f560e, 0xf5ee4bb9,
0xf8ad6d60, 0xfc6c70d7, 0xe22b20d2, 0xe6ea3d65, 0xeba91bbc, 0xef68060b,
0xd727bbb6, 0xd3e6a601, 0xdea580d8, 0xda649d6f, 0xc423cd6a, 0xc0e2d0dd,
0xcda1f604, 0xc960ebb3, 0xbd3e8d7e, 0xb9ff90c9, 0xb4bcb610, 0xb07daba7,
0xae3afba2, 0xaafbe615, 0xa7b8c0cc, 0xa379dd7b, 0x9b3660c6, 0x9ff77d71,
0x92b45ba8, 0x9675461f, 0x8832161a, 0x8cf30bad, 0x81b02d74, 0x857130c3,
0x5d8a9099, 0x594b8d2e, 0x5408abf7, 0x50c9b640, 0x4e8ee645, 0x4a4ffbf2,
0x470cdd2b, 0x43cdc09c, 0x7b827d21, 0x7f436096, 0x7200464f, 0x76c15bf8,
0x68860bfd, 0x6c47164a, 0x61043093, 0x65c52d24, 0x119b4be9, 0x155a565e,
0x18197087, 0x1cd86d30, 0x029f3d35, 0x065e2082, 0x0b1d065b, 0x0fdc1bec,
0x3793a651, 0x3352bbe6, 0x3e119d3f, 0x3ad08088, 0x2497d08d, 0x2056cd3a,
0x2d15ebe3, 0x29d4f654, 0xc5a92679, 0xc1683bce, 0xcc2b1d17, 0xc8ea00a0,
0xd6ad50a5, 0xd26c4d12, 0xdf2f6bcb, 0xdbee767c, 0xe3a1cbc1, 0xe760d676,
0xea23f0af, 0xeee2ed18, 0xf0a5bd1d, 0xf464a0aa, 0xf9278673, 0xfde69bc4,
0x89b8fd09, 0x8d79e0be, 0x803ac667, 0x84fbdbd0, 0x9abc8bd5, 0x9e7d9662,
0x933eb0bb, 0x97ffad0c, 0xafb010b1, 0xab710d06, 0xa6322bdf, 0xa2f33668,
0xbcb4666d, 0xb8757bda, 0xb5365d03, 0xb1f740b4 };
static unsigned long
crc32_convert(char *buf, int len)
{
char *p;
#ifdef OSF1V4D
unsigned int crc;
#else
unsigned long crc;
#endif
crc = 0xffffffff;
for (p = buf; len > 0; ++p, --len)
crc = ((crc << 8) ^ crc32_table[(crc >> 24) ^ *p]) & 0xffffffff;
return (unsigned long) ~crc;
}