mirror of
https://github.com/apache/httpd.git
synced 2025-08-07 04:02:58 +03:00
Landing of mod_ldap - the LDAP cache and connection pooling module.
git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@90321 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
3
modules/ldap/Makefile.in
Normal file
3
modules/ldap/Makefile.in
Normal file
@@ -0,0 +1,3 @@
|
||||
|
||||
include $(top_srcdir)/build/special.mk
|
||||
|
8
modules/ldap/config2.m4
Normal file
8
modules/ldap/config2.m4
Normal file
@@ -0,0 +1,8 @@
|
||||
dnl modules enabled in this directory by default
|
||||
|
||||
APACHE_MODPATH_INIT(ldap)
|
||||
|
||||
ldap_objects="util_ldap.lo util_ldap_cache.lo util_ldap_cache_mgr.lo"
|
||||
APACHE_MODULE(ldap, LDAP caching and connection pooling services, $ldap_objects, , no)
|
||||
|
||||
APACHE_MODPATH_FINISH
|
1045
modules/ldap/util_ldap.c
Normal file
1045
modules/ldap/util_ldap.c
Normal file
File diff suppressed because it is too large
Load Diff
253
modules/ldap/util_ldap_cache.c
Normal file
253
modules/ldap/util_ldap_cache.c
Normal file
@@ -0,0 +1,253 @@
|
||||
/* ====================================================================
|
||||
* The Apache Software License, Version 1.1
|
||||
*
|
||||
* Copyright (c) 2000-2001 The Apache Software Foundation. All rights
|
||||
* reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in
|
||||
* the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
*
|
||||
* 3. The end-user documentation included with the redistribution,
|
||||
* if any, must include the following acknowledgment:
|
||||
* "This product includes software developed by the
|
||||
* Apache Software Foundation (http://www.apache.org/)."
|
||||
* Alternately, this acknowledgment may appear in the software itself,
|
||||
* if and wherever such third-party acknowledgments normally appear.
|
||||
*
|
||||
* 4. The names "Apache" and "Apache Software Foundation" must
|
||||
* not be used to endorse or promote products derived from this
|
||||
* software without prior written permission. For written
|
||||
* permission, please contact apache@apache.org.
|
||||
*
|
||||
* 5. Products derived from this software may not be called "Apache",
|
||||
* nor may "Apache" appear in their name, without prior written
|
||||
* permission of the Apache Software Foundation.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
|
||||
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
|
||||
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
|
||||
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
* ====================================================================
|
||||
*
|
||||
* This software consists of voluntary contributions made by many
|
||||
* individuals on behalf of the Apache Software Foundation. For more
|
||||
* information on the Apache Software Foundation, please see
|
||||
* <http://www.apache.org/>.
|
||||
*/
|
||||
|
||||
/*
|
||||
* util_ldap_cache.c: LDAP cache things
|
||||
*
|
||||
* Original code from auth_ldap module for Apache v1.3:
|
||||
* Copyright 1998, 1999 Enbridge Pipelines Inc.
|
||||
* Copyright 1999-2001 Dave Carrigan
|
||||
*/
|
||||
|
||||
#include <apr_ldap.h>
|
||||
#include "util_ldap.h"
|
||||
#include "util_ldap_cache.h"
|
||||
|
||||
#ifdef APU_HAS_LDAP
|
||||
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------ */
|
||||
|
||||
unsigned long util_ldap_url_node_hash(void *n)
|
||||
{
|
||||
util_url_node_t *node = (util_url_node_t *)n;
|
||||
return util_ald_hash_string(1, node->url);
|
||||
}
|
||||
|
||||
int util_ldap_url_node_compare(void *a, void *b)
|
||||
{
|
||||
util_url_node_t *na = (util_url_node_t *)a;
|
||||
util_url_node_t *nb = (util_url_node_t *)b;
|
||||
|
||||
return(strcmp(na->url, nb->url) == 0);
|
||||
}
|
||||
|
||||
void *util_ldap_url_node_copy(void *c)
|
||||
{
|
||||
util_url_node_t *n = (util_url_node_t *)c;
|
||||
util_url_node_t *node = (util_url_node_t *)util_ald_alloc(sizeof(util_url_node_t));
|
||||
|
||||
node->url = util_ald_strdup(n->url);
|
||||
node->search_cache = n->search_cache;
|
||||
node->compare_cache = n->compare_cache;
|
||||
node->dn_compare_cache = n->dn_compare_cache;
|
||||
return node;
|
||||
}
|
||||
|
||||
void util_ldap_url_node_free(void *n)
|
||||
{
|
||||
util_url_node_t *node = (util_url_node_t *)n;
|
||||
|
||||
util_ald_free(node->url);
|
||||
util_ald_destroy_cache(node->search_cache);
|
||||
util_ald_destroy_cache(node->compare_cache);
|
||||
util_ald_destroy_cache(node->dn_compare_cache);
|
||||
util_ald_free(node);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------ */
|
||||
|
||||
/* Cache functions for search nodes */
|
||||
unsigned long util_ldap_search_node_hash(void *n)
|
||||
{
|
||||
util_search_node_t *node = (util_search_node_t *)n;
|
||||
return util_ald_hash_string(1, ((util_search_node_t *)(node))->username);
|
||||
}
|
||||
|
||||
int util_ldap_search_node_compare(void *a, void *b)
|
||||
{
|
||||
return(strcmp(((util_search_node_t *)a)->username,
|
||||
((util_search_node_t *)b)->username) == 0);
|
||||
}
|
||||
|
||||
void *util_ldap_search_node_copy(void *c)
|
||||
{
|
||||
util_search_node_t *node = (util_search_node_t *)c;
|
||||
util_search_node_t *newnode = util_ald_alloc(sizeof(util_search_node_t));
|
||||
newnode->username = util_ald_strdup(node->username);
|
||||
newnode->dn = util_ald_strdup(node->dn);
|
||||
newnode->bindpw = util_ald_strdup(node->bindpw);
|
||||
newnode->lastbind = node->lastbind;
|
||||
return (void *)newnode;
|
||||
}
|
||||
|
||||
void util_ldap_search_node_free(void *n)
|
||||
{
|
||||
util_search_node_t *node = (util_search_node_t *)n;
|
||||
util_ald_free(node->username);
|
||||
util_ald_free(node->dn);
|
||||
util_ald_free(node->bindpw);
|
||||
util_ald_free(node);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------ */
|
||||
|
||||
unsigned long util_ldap_compare_node_hash(void *n)
|
||||
{
|
||||
util_compare_node_t *node = (util_compare_node_t *)n;
|
||||
return util_ald_hash_string(3, node->dn, node->attrib, node->value);
|
||||
}
|
||||
|
||||
int util_ldap_compare_node_compare(void *a, void *b)
|
||||
{
|
||||
util_compare_node_t *na = (util_compare_node_t *)a;
|
||||
util_compare_node_t *nb = (util_compare_node_t *)b;
|
||||
return (strcmp(na->dn, nb->dn) == 0 &&
|
||||
strcmp(na->attrib, nb->attrib) == 0 &&
|
||||
strcmp(na->value, nb->value) == 0);
|
||||
}
|
||||
|
||||
void *util_ldap_compare_node_copy(void *c)
|
||||
{
|
||||
util_compare_node_t *n = (util_compare_node_t *)c;
|
||||
util_compare_node_t *node = (util_compare_node_t *)util_ald_alloc(sizeof(util_compare_node_t));
|
||||
node->dn = util_ald_strdup(n->dn);
|
||||
node->attrib = util_ald_strdup(n->attrib);
|
||||
node->value = util_ald_strdup(n->value);
|
||||
node->lastcompare = n->lastcompare;
|
||||
return node;
|
||||
}
|
||||
|
||||
void util_ldap_compare_node_free(void *n)
|
||||
{
|
||||
util_compare_node_t *node = (util_compare_node_t *)n;
|
||||
util_ald_free(node->dn);
|
||||
util_ald_free(node->attrib);
|
||||
util_ald_free(node->value);
|
||||
util_ald_free(node);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------ */
|
||||
|
||||
unsigned long util_ldap_dn_compare_node_hash(void *n)
|
||||
{
|
||||
return util_ald_hash_string(1, ((util_dn_compare_node_t *)n)->reqdn);
|
||||
}
|
||||
|
||||
int util_ldap_dn_compare_node_compare(void *a, void *b)
|
||||
{
|
||||
return (strcmp(((util_dn_compare_node_t *)a)->reqdn,
|
||||
((util_dn_compare_node_t *)b)->reqdn) == 0);
|
||||
}
|
||||
|
||||
void *util_ldap_dn_compare_node_copy(void *c)
|
||||
{
|
||||
util_dn_compare_node_t *n = (util_dn_compare_node_t *)c;
|
||||
util_dn_compare_node_t *node = (util_dn_compare_node_t *)util_ald_alloc(sizeof(util_dn_compare_node_t));
|
||||
node->reqdn = util_ald_strdup(n->reqdn);
|
||||
node->dn = util_ald_strdup(n->dn);
|
||||
return node;
|
||||
}
|
||||
|
||||
void util_ldap_dn_compare_node_free(void *n)
|
||||
{
|
||||
util_dn_compare_node_t *node = (util_dn_compare_node_t *)n;
|
||||
util_ald_free(node->reqdn);
|
||||
util_ald_free(node->dn);
|
||||
util_ald_free(node);
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------ */
|
||||
apr_status_t util_ldap_cache_child_kill(void *data);
|
||||
apr_status_t util_ldap_cache_module_kill(void *data);
|
||||
|
||||
apr_status_t util_ldap_cache_module_kill(void *data)
|
||||
{
|
||||
#ifdef APU_HAS_LDAP_SHARED_CACHE
|
||||
if (util_ldap_shm != NULL) {
|
||||
apr_status_t result = apr_shm_destroy(util_ldap_shm);
|
||||
util_ldap_shm = NULL;
|
||||
return result;
|
||||
}
|
||||
#endif
|
||||
return APR_SUCCESS;
|
||||
}
|
||||
|
||||
apr_status_t util_ldap_cache_child_kill(void *data)
|
||||
{
|
||||
/* Nothing to do */
|
||||
return APR_SUCCESS;
|
||||
}
|
||||
|
||||
apr_status_t util_ldap_cache_init(apr_pool_t *pool, apr_size_t reqsize)
|
||||
{
|
||||
apr_status_t result = APR_SUCCESS;
|
||||
apr_pool_cleanup_register(pool, NULL, util_ldap_cache_module_kill, util_ldap_cache_child_kill);
|
||||
|
||||
#ifdef APU_HAS_LDAP_SHARED_CACHE
|
||||
result = apr_shm_init(&util_ldap_shm, reqsize, "/tmp/ldap_cache", pool);
|
||||
#endif
|
||||
util_ldap_cache = util_ald_create_cache(50,
|
||||
util_ldap_url_node_hash,
|
||||
util_ldap_url_node_compare,
|
||||
util_ldap_url_node_copy,
|
||||
util_ldap_url_node_free);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
#endif /* APU_HAS_LDAP */
|
216
modules/ldap/util_ldap_cache.h
Normal file
216
modules/ldap/util_ldap_cache.h
Normal file
@@ -0,0 +1,216 @@
|
||||
/* ====================================================================
|
||||
* The Apache Software License, Version 1.1
|
||||
*
|
||||
* Copyright (c) 2000-2001 The Apache Software Foundation. All rights
|
||||
* reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in
|
||||
* the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
*
|
||||
* 3. The end-user documentation included with the redistribution,
|
||||
* if any, must include the following acknowledgment:
|
||||
* "This product includes software developed by the
|
||||
* Apache Software Foundation (http://www.apache.org/)."
|
||||
* Alternately, this acknowledgment may appear in the software itself,
|
||||
* if and wherever such third-party acknowledgments normally appear.
|
||||
*
|
||||
* 4. The names "Apache" and "Apache Software Foundation" must
|
||||
* not be used to endorse or promote products derived from this
|
||||
* software without prior written permission. For written
|
||||
* permission, please contact apache@apache.org.
|
||||
*
|
||||
* 5. Products derived from this software may not be called "Apache",
|
||||
* nor may "Apache" appear in their name, without prior written
|
||||
* permission of the Apache Software Foundation.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
|
||||
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
|
||||
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
|
||||
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
* ====================================================================
|
||||
*
|
||||
* This software consists of voluntary contributions made by many
|
||||
* individuals on behalf of the Apache Software Foundation. For more
|
||||
* information on the Apache Software Foundation, please see
|
||||
* <http://www.apache.org/>.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef APU_LDAP_CACHE_H
|
||||
#define APU_LDAP_CACHE_H
|
||||
|
||||
/*
|
||||
* This switches LDAP support on or off.
|
||||
*/
|
||||
|
||||
/* this whole thing disappears if LDAP is not enabled */
|
||||
#ifdef APU_HAS_LDAP
|
||||
|
||||
/* FIXME */
|
||||
#define APU_HAS_LDAP_SHARED_CACHE
|
||||
|
||||
/*
|
||||
* LDAP Cache Manager
|
||||
*/
|
||||
|
||||
#ifdef APU_HAS_LDAP_SHARED_CACHE
|
||||
#include <apr_shmem.h>
|
||||
#endif
|
||||
|
||||
typedef struct util_cache_node_t {
|
||||
void *payload; /* Pointer to the payload */
|
||||
time_t add_time; /* Time node was added to cache */
|
||||
struct util_cache_node_t *next;
|
||||
} util_cache_node_t;
|
||||
|
||||
typedef struct util_ald_cache_t {
|
||||
unsigned long size; /* Size of cache array */
|
||||
unsigned long maxentries; /* Maximum number of cache entries */
|
||||
unsigned long numentries; /* Current number of cache entries */
|
||||
unsigned long fullmark; /* Used to keep track of when cache becomes 3/4 full */
|
||||
time_t marktime; /* Time that the cache became 3/4 full */
|
||||
unsigned long (*hash)(void *); /* Func to hash the payload */
|
||||
int (*compare)(void *, void *); /* Func to compare two payloads */
|
||||
void * (*copy)(void *); /* Func to alloc mem and copy payload to new mem */
|
||||
void (*free)(void *); /* Func to free mem used by the payload */
|
||||
util_cache_node_t **nodes;
|
||||
|
||||
unsigned long numpurges; /* No. of times the cache has been purged */
|
||||
double avg_purgetime; /* Average time to purge the cache */
|
||||
time_t last_purge; /* Time of the last purge */
|
||||
unsigned long npurged; /* Number of elements purged in last purge. This is not
|
||||
obvious: it won't be 3/4 the size of the cache if
|
||||
there were a lot of expired entries. */
|
||||
|
||||
unsigned long fetches; /* Number of fetches */
|
||||
unsigned long hits; /* Number of cache hits */
|
||||
unsigned long inserts; /* Number of inserts */
|
||||
unsigned long removes; /* Number of removes */
|
||||
} util_ald_cache_t;
|
||||
|
||||
#ifdef APU_HAS_LDAP_SHARED_CACHE
|
||||
apr_shmem_t *util_ldap_shm;
|
||||
#endif
|
||||
util_ald_cache_t *util_ldap_cache;
|
||||
apr_lock_t *util_ldap_cache_lock;
|
||||
|
||||
#ifndef WIN32
|
||||
#define ALD_MM_FILE_MODE ( S_IRUSR|S_IWUSR )
|
||||
#else
|
||||
#define ALD_MM_FILE_MODE ( _S_IREAD|_S_IWRITE )
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
* LDAP Cache
|
||||
*/
|
||||
|
||||
/*
|
||||
* Maintain a cache of LDAP URLs that the server handles. Each node in
|
||||
* the cache contains the search cache for that URL, and a compare cache
|
||||
* for the URL. The compare cash is populated when doing require group
|
||||
* compares.
|
||||
*/
|
||||
typedef struct util_url_node_t {
|
||||
const char *url;
|
||||
util_ald_cache_t *search_cache;
|
||||
util_ald_cache_t *compare_cache;
|
||||
util_ald_cache_t *dn_compare_cache;
|
||||
} util_url_node_t;
|
||||
|
||||
/*
|
||||
* We cache every successful search and bind operation, using the username
|
||||
* as the key. Each node in the cache contains the returned DN, plus the
|
||||
* password used to bind.
|
||||
*/
|
||||
typedef struct util_search_node_t {
|
||||
const char *username; /* Cache key */
|
||||
const char *dn; /* DN returned from search */
|
||||
const char *bindpw; /* The most recently used bind password;
|
||||
NULL if the bind failed */
|
||||
apr_time_t lastbind; /* Time of last successful bind */
|
||||
} util_search_node_t;
|
||||
|
||||
/*
|
||||
* We cache every successful compare operation, using the DN, attrib, and
|
||||
* value as the key.
|
||||
*/
|
||||
typedef struct util_compare_node_t {
|
||||
const char *dn; /* DN, attrib and value combine to be the key */
|
||||
const char *attrib;
|
||||
const char *value;
|
||||
apr_time_t lastcompare;
|
||||
} util_compare_node_t;
|
||||
|
||||
/*
|
||||
* We cache every successful compare dn operation, using the dn in the require
|
||||
* statement and the dn fetched based on the client-provided username.
|
||||
*/
|
||||
typedef struct util_dn_compare_node_t {
|
||||
const char *reqdn; /* The DN in the require dn statement */
|
||||
const char *dn; /* The DN found in the search */
|
||||
} util_dn_compare_node_t;
|
||||
|
||||
|
||||
/*
|
||||
* Function prototypes for LDAP cache
|
||||
*/
|
||||
|
||||
/* util_ldap_cache.c */
|
||||
unsigned long util_ldap_url_node_hash(void *n);
|
||||
int util_ldap_url_node_compare(void *a, void *b);
|
||||
void *util_ldap_url_node_copy(void *c);
|
||||
void util_ldap_url_node_free(void *n);
|
||||
unsigned long util_ldap_search_node_hash(void *n);
|
||||
int util_ldap_search_node_compare(void *a, void *b);
|
||||
void *util_ldap_search_node_copy(void *c);
|
||||
void util_ldap_search_node_free(void *n);
|
||||
unsigned long util_ldap_compare_node_hash(void *n);
|
||||
int util_ldap_compare_node_compare(void *a, void *b);
|
||||
void *util_ldap_compare_node_copy(void *c);
|
||||
void util_ldap_compare_node_free(void *n);
|
||||
unsigned long util_ldap_dn_compare_node_hash(void *n);
|
||||
int util_ldap_dn_compare_node_compare(void *a, void *b);
|
||||
void *util_ldap_dn_compare_node_copy(void *c);
|
||||
void util_ldap_dn_compare_node_free(void *n);
|
||||
|
||||
|
||||
/* util_ldap_cache_mgr.c */
|
||||
|
||||
void util_ald_free(const void *ptr);
|
||||
void *util_ald_alloc(int size);
|
||||
const char *util_ald_strdup(const char *s);
|
||||
unsigned long util_ald_hash_string(int nstr, ...);
|
||||
void util_ald_cache_purge(util_ald_cache_t *cache);
|
||||
util_url_node_t *util_ald_create_caches(util_ldap_state_t *s, const char *url);
|
||||
util_ald_cache_t *util_ald_create_cache(unsigned long maxentries,
|
||||
unsigned long (*hashfunc)(void *),
|
||||
int (*comparefunc)(void *, void *),
|
||||
void * (*copyfunc)(void *),
|
||||
void (*freefunc)(void *));
|
||||
void util_ald_destroy_cache(util_ald_cache_t *cache);
|
||||
void *util_ald_cache_fetch(util_ald_cache_t *cache, void *payload);
|
||||
void util_ald_cache_insert(util_ald_cache_t *cache, void *payload);
|
||||
void util_ald_cache_remove(util_ald_cache_t *cache, void *payload);
|
||||
char *util_ald_cache_display_stats(apr_pool_t *p, util_ald_cache_t *cache,
|
||||
char *name);
|
||||
|
||||
#endif /* APU_HAS_LDAP */
|
||||
#endif /* APU_LDAP_CACHE_H */
|
529
modules/ldap/util_ldap_cache_mgr.c
Normal file
529
modules/ldap/util_ldap_cache_mgr.c
Normal file
@@ -0,0 +1,529 @@
|
||||
/* ====================================================================
|
||||
* The Apache Software License, Version 1.1
|
||||
*
|
||||
* Copyright (c) 2000-2001 The Apache Software Foundation. All rights
|
||||
* reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in
|
||||
* the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
*
|
||||
* 3. The end-user documentation included with the redistribution,
|
||||
* if any, must include the following acknowledgment:
|
||||
* "This product includes software developed by the
|
||||
* Apache Software Foundation (http://www.apache.org/)."
|
||||
* Alternately, this acknowledgment may appear in the software itself,
|
||||
* if and wherever such third-party acknowledgments normally appear.
|
||||
*
|
||||
* 4. The names "Apache" and "Apache Software Foundation" must
|
||||
* not be used to endorse or promote products derived from this
|
||||
* software without prior written permission. For written
|
||||
* permission, please contact apache@apache.org.
|
||||
*
|
||||
* 5. Products derived from this software may not be called "Apache",
|
||||
* nor may "Apache" appear in their name, without prior written
|
||||
* permission of the Apache Software Foundation.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
|
||||
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
|
||||
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
|
||||
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
* ====================================================================
|
||||
*
|
||||
* This software consists of voluntary contributions made by many
|
||||
* individuals on behalf of the Apache Software Foundation. For more
|
||||
* information on the Apache Software Foundation, please see
|
||||
* <http://www.apache.org/>.
|
||||
*/
|
||||
|
||||
/*
|
||||
* util_ldap_cache_mgr.c: LDAP cache manager things
|
||||
*
|
||||
* Original code from auth_ldap module for Apache v1.3:
|
||||
* Copyright 1998, 1999 Enbridge Pipelines Inc.
|
||||
* Copyright 1999-2001 Dave Carrigan
|
||||
*/
|
||||
|
||||
#include <apr_ldap.h>
|
||||
#include "util_ldap.h"
|
||||
#include "util_ldap_cache.h"
|
||||
#include <apr_strings.h>
|
||||
|
||||
#ifdef APU_HAS_LDAP
|
||||
|
||||
/* only here until strdup is gone */
|
||||
#include <string.h>
|
||||
|
||||
/* here till malloc is gone */
|
||||
#include <stdlib.h>
|
||||
|
||||
static const int primes[] =
|
||||
{
|
||||
11,
|
||||
19,
|
||||
37,
|
||||
73,
|
||||
109,
|
||||
163,
|
||||
251,
|
||||
367,
|
||||
557,
|
||||
823,
|
||||
1237,
|
||||
1861,
|
||||
2777,
|
||||
4177,
|
||||
6247,
|
||||
9371,
|
||||
14057,
|
||||
21089,
|
||||
31627,
|
||||
47431,
|
||||
71143,
|
||||
106721,
|
||||
160073,
|
||||
240101,
|
||||
360163,
|
||||
540217,
|
||||
810343,
|
||||
1215497,
|
||||
1823231,
|
||||
2734867,
|
||||
4102283,
|
||||
6153409,
|
||||
9230113,
|
||||
13845163,
|
||||
0
|
||||
};
|
||||
|
||||
void util_ald_free(const void *ptr)
|
||||
{
|
||||
#ifdef APU_HAS_LDAP_SHARED_CACHE
|
||||
if (util_ldap_shm) {
|
||||
apr_shm_free(util_ldap_shm, (void *)ptr);
|
||||
} else {
|
||||
free((void *)ptr);
|
||||
}
|
||||
#else
|
||||
free((void *)ptr);
|
||||
#endif
|
||||
}
|
||||
|
||||
void *util_ald_alloc(int size)
|
||||
{
|
||||
#ifdef APU_HAS_LDAP_SHARED_CACHE
|
||||
if (util_ldap_shm) {
|
||||
return (void *)apr_shm_malloc(util_ldap_shm, size);
|
||||
} else {
|
||||
return (void *)malloc(size);
|
||||
}
|
||||
#else
|
||||
return (void *)malloc(size);
|
||||
#endif
|
||||
}
|
||||
|
||||
const char *util_ald_strdup(const char *s)
|
||||
{
|
||||
#ifdef APU_HAS_LDAP_SHARED_CACHE
|
||||
if (util_ldap_shm) {
|
||||
char *buf = apr_shm_malloc(util_ldap_shm, strlen(s)+1);
|
||||
if (buf) {
|
||||
strcpy(buf, s);
|
||||
return buf;
|
||||
}
|
||||
else {
|
||||
return NULL;
|
||||
}
|
||||
} else {
|
||||
return strdup(s);
|
||||
}
|
||||
#else
|
||||
return strdup(s);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Computes the hash on a set of strings. The first argument is the number
|
||||
* of strings to hash, the rest of the args are strings.
|
||||
* Algorithm taken from glibc.
|
||||
*/
|
||||
unsigned long util_ald_hash_string(int nstr, ...)
|
||||
{
|
||||
int i;
|
||||
va_list args;
|
||||
unsigned long h=0, g;
|
||||
char *str, *p;
|
||||
|
||||
va_start(args, nstr);
|
||||
for (i=0; i < nstr; ++i) {
|
||||
str = va_arg(args, char *);
|
||||
for (p = str; *p; ++p) {
|
||||
h = ( h << 4 ) + *p;
|
||||
if ( ( g = h & 0xf0000000 ) ) {
|
||||
h = h ^ (g >> 24);
|
||||
h = h ^ g;
|
||||
}
|
||||
}
|
||||
}
|
||||
va_end(args);
|
||||
|
||||
return h;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Purges a cache that has gotten full. We keep track of the time that we
|
||||
added the entry that made the cache 3/4 full, then delete all entries
|
||||
that were added before that time. It's pretty simplistic, but time to
|
||||
purge is only O(n), which is more important.
|
||||
*/
|
||||
void util_ald_cache_purge(util_ald_cache_t *cache)
|
||||
{
|
||||
int i;
|
||||
util_cache_node_t *p, *q;
|
||||
apr_time_t t;
|
||||
|
||||
cache->last_purge = apr_time_now();
|
||||
cache->npurged = 0;
|
||||
cache->numpurges++;
|
||||
|
||||
for (i=0; i < cache->size; ++i) {
|
||||
p = cache->nodes[i];
|
||||
while (p != NULL) {
|
||||
if (p->add_time < cache->marktime) {
|
||||
q = p->next;
|
||||
(*cache->free)(p->payload);
|
||||
util_ald_free(p);
|
||||
cache->numentries--;
|
||||
cache->npurged++;
|
||||
p = q;
|
||||
}
|
||||
else {
|
||||
p = p->next;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
t = apr_time_now();
|
||||
cache->avg_purgetime =
|
||||
((t - cache->last_purge) + (cache->avg_purgetime * (cache->numpurges-1))) /
|
||||
cache->numpurges;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* create caches
|
||||
*/
|
||||
util_url_node_t *util_ald_create_caches(util_ldap_state_t *st, const char *url)
|
||||
{
|
||||
util_url_node_t *curl = NULL;
|
||||
util_ald_cache_t *search_cache;
|
||||
util_ald_cache_t *compare_cache;
|
||||
util_ald_cache_t *dn_compare_cache;
|
||||
|
||||
/* create the three caches */
|
||||
search_cache = util_ald_create_cache(st->search_cache_size,
|
||||
util_ldap_search_node_hash,
|
||||
util_ldap_search_node_compare,
|
||||
util_ldap_search_node_copy,
|
||||
util_ldap_search_node_free);
|
||||
compare_cache = util_ald_create_cache(st->compare_cache_size,
|
||||
util_ldap_compare_node_hash,
|
||||
util_ldap_compare_node_compare,
|
||||
util_ldap_compare_node_copy,
|
||||
util_ldap_compare_node_free);
|
||||
dn_compare_cache = util_ald_create_cache(st->compare_cache_size,
|
||||
util_ldap_dn_compare_node_hash,
|
||||
util_ldap_dn_compare_node_compare,
|
||||
util_ldap_dn_compare_node_copy,
|
||||
util_ldap_dn_compare_node_free);
|
||||
|
||||
/* check that all the caches initialised successfully */
|
||||
if (search_cache && compare_cache && dn_compare_cache) {
|
||||
|
||||
curl = (util_url_node_t *)apr_pcalloc(st->pool, sizeof(util_url_node_t));
|
||||
curl->url = url;
|
||||
curl->search_cache = search_cache;
|
||||
curl->compare_cache = compare_cache;
|
||||
curl->dn_compare_cache = dn_compare_cache;
|
||||
|
||||
util_ald_cache_insert(util_ldap_cache, curl);
|
||||
|
||||
}
|
||||
|
||||
return curl;
|
||||
}
|
||||
|
||||
|
||||
util_ald_cache_t *util_ald_create_cache(unsigned long maxentries,
|
||||
unsigned long (*hashfunc)(void *),
|
||||
int (*comparefunc)(void *, void *),
|
||||
void * (*copyfunc)(void *),
|
||||
void (*freefunc)(void *))
|
||||
{
|
||||
util_ald_cache_t *cache;
|
||||
int i;
|
||||
|
||||
if (maxentries <= 0)
|
||||
return NULL;
|
||||
|
||||
cache = (util_ald_cache_t *)util_ald_alloc(sizeof(util_ald_cache_t));
|
||||
if (!cache)
|
||||
return NULL;
|
||||
|
||||
cache->maxentries = maxentries;
|
||||
cache->numentries = 0;
|
||||
cache->size = maxentries / 3;
|
||||
if (cache->size < 64) cache->size = 64;
|
||||
for (i = 0; primes[i] && primes[i] < cache->size; ++i) ;
|
||||
cache->size = primes[i]? primes[i] : primes[i-1];
|
||||
|
||||
cache->nodes = (util_cache_node_t **)util_ald_alloc(cache->size * sizeof(util_cache_node_t *));
|
||||
if (!cache->nodes) {
|
||||
util_ald_free(cache);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
for (i=0; i < cache->size; ++i)
|
||||
cache->nodes[i] = NULL;
|
||||
|
||||
cache->hash = hashfunc;
|
||||
cache->compare = comparefunc;
|
||||
cache->copy = copyfunc;
|
||||
cache->free = freefunc;
|
||||
|
||||
cache->fullmark = cache->maxentries / 4 * 3;
|
||||
cache->marktime = 0;
|
||||
cache->avg_purgetime = 0.0;
|
||||
cache->numpurges = 0;
|
||||
cache->last_purge = 0;
|
||||
cache->npurged = 0;
|
||||
|
||||
cache->fetches = 0;
|
||||
cache->hits = 0;
|
||||
cache->inserts = 0;
|
||||
cache->removes = 0;
|
||||
|
||||
return cache;
|
||||
}
|
||||
|
||||
void util_ald_destroy_cache(util_ald_cache_t *cache)
|
||||
{
|
||||
int i;
|
||||
util_cache_node_t *p, *q;
|
||||
|
||||
if (cache == NULL)
|
||||
return;
|
||||
|
||||
for (i = 0; i < cache->size; ++i) {
|
||||
p = cache->nodes[i];
|
||||
q = NULL;
|
||||
while (p != NULL) {
|
||||
q = p->next;
|
||||
(*cache->free)(p->payload);
|
||||
util_ald_free(p);
|
||||
p = q;
|
||||
}
|
||||
}
|
||||
util_ald_free(cache->nodes);
|
||||
}
|
||||
|
||||
void *util_ald_cache_fetch(util_ald_cache_t *cache, void *payload)
|
||||
{
|
||||
int hashval;
|
||||
util_cache_node_t *p;
|
||||
|
||||
if (cache == NULL)
|
||||
return NULL;
|
||||
|
||||
cache->fetches++;
|
||||
|
||||
hashval = (*cache->hash)(payload) % cache->size;
|
||||
for (p = cache->nodes[hashval];
|
||||
p && !(*cache->compare)(p->payload, payload);
|
||||
p = p->next) ;
|
||||
|
||||
if (p != NULL) {
|
||||
cache->hits++;
|
||||
return p->payload;
|
||||
}
|
||||
else {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Insert an item into the cache.
|
||||
* *** Does not catch duplicates!!! ***
|
||||
*/
|
||||
void util_ald_cache_insert(util_ald_cache_t *cache, void *payload)
|
||||
{
|
||||
int hashval;
|
||||
util_cache_node_t *node;
|
||||
|
||||
if (cache == NULL || payload == NULL)
|
||||
return;
|
||||
|
||||
cache->inserts++;
|
||||
hashval = (*cache->hash)(payload) % cache->size;
|
||||
node = (util_cache_node_t *)util_ald_alloc(sizeof(util_cache_node_t));
|
||||
node->add_time = apr_time_now();
|
||||
node->payload = (*cache->copy)(payload);
|
||||
node->next = cache->nodes[hashval];
|
||||
cache->nodes[hashval] = node;
|
||||
if (++cache->numentries == cache->fullmark)
|
||||
cache->marktime=apr_time_now();
|
||||
if (cache->numentries >= cache->maxentries)
|
||||
util_ald_cache_purge(cache);
|
||||
}
|
||||
|
||||
void util_ald_cache_remove(util_ald_cache_t *cache, void *payload)
|
||||
{
|
||||
int hashval;
|
||||
util_cache_node_t *p, *q;
|
||||
|
||||
if (cache == NULL)
|
||||
return;
|
||||
|
||||
cache->removes++;
|
||||
hashval = (*cache->hash)(payload) % cache->size;
|
||||
for (p = cache->nodes[hashval], q=NULL;
|
||||
p && !(*cache->compare)(p->payload, payload);
|
||||
p = p->next) {
|
||||
q = p;
|
||||
}
|
||||
|
||||
/* If p is null, it means that we couldn't find the node, so just return */
|
||||
if (p == NULL)
|
||||
return;
|
||||
|
||||
if (q == NULL) {
|
||||
/* We found the node, and it's the first in the list */
|
||||
cache->nodes[hashval] = p->next;
|
||||
}
|
||||
else {
|
||||
/* We found the node and it's not the first in the list */
|
||||
q->next = p->next;
|
||||
}
|
||||
(*cache->free)(p->payload);
|
||||
util_ald_free(p);
|
||||
cache->numentries--;
|
||||
}
|
||||
|
||||
char *util_ald_cache_display_stats(apr_pool_t *p, util_ald_cache_t *cache, char *name)
|
||||
{
|
||||
int i;
|
||||
int totchainlen = 0;
|
||||
int nchains = 0;
|
||||
double chainlen;
|
||||
util_cache_node_t *n;
|
||||
char *buf;
|
||||
|
||||
if (cache == NULL) {
|
||||
return "";
|
||||
}
|
||||
|
||||
for (i=0; i < cache->size; ++i) {
|
||||
if (cache->nodes[i] != NULL) {
|
||||
nchains++;
|
||||
for (n = cache->nodes[i]; n != NULL; n = n->next)
|
||||
totchainlen++;
|
||||
}
|
||||
}
|
||||
chainlen = nchains? (double)totchainlen / (double)nchains : 0;
|
||||
|
||||
buf = apr_psprintf(p,
|
||||
"<tr valign='top'>"
|
||||
"<td nowrap>%s</td>"
|
||||
"<td align='right' nowrap>%lu (%.0f%% full)</td>"
|
||||
"<td align='right'>%.1f</td>"
|
||||
"<td align='right'>%lu/%lu</td>"
|
||||
"<td align='right'>%.0f%%</td>"
|
||||
"<td align='right'>%lu/%lu</td>",
|
||||
name,
|
||||
cache->numentries,
|
||||
(double)cache->numentries / (double)cache->maxentries * 100.0,
|
||||
chainlen,
|
||||
cache->hits,
|
||||
cache->fetches,
|
||||
(cache->fetches > 0 ? (double)(cache->hits) / (double)(cache->fetches) * 100.0 : 100.0),
|
||||
cache->inserts,
|
||||
cache->removes);
|
||||
|
||||
if (cache->numpurges) {
|
||||
char str_ctime[APR_CTIME_LEN];
|
||||
|
||||
apr_ctime(str_ctime, cache->last_purge);
|
||||
buf = apr_psprintf(p,
|
||||
"%s"
|
||||
"<td align='right'>%lu</td>\n"
|
||||
"<td align='right' nowrap>%s</td>\n",
|
||||
buf,
|
||||
cache->numpurges,
|
||||
str_ctime);
|
||||
}
|
||||
else {
|
||||
buf = apr_psprintf(p,
|
||||
"%s<td colspan='2' align='center'>(none)</td>\n",
|
||||
buf);
|
||||
}
|
||||
|
||||
buf = apr_psprintf(p, "%s<td align='right'>%.2g</td>\n</tr>", buf, cache->avg_purgetime);
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
char *util_ald_cache_display(apr_pool_t *pool)
|
||||
{
|
||||
int i;
|
||||
char *buf, *t1, *t2, *t3;
|
||||
|
||||
if (!util_ldap_cache) {
|
||||
return "<tr valign='top'><td nowrap colspan=7>Cache has not been enabled/initialised.</td></tr>";
|
||||
}
|
||||
|
||||
buf = util_ald_cache_display_stats(pool, util_ldap_cache, "LDAP URL Cache");
|
||||
|
||||
for (i=0; i < util_ldap_cache->size; ++i) {
|
||||
util_cache_node_t *p;
|
||||
for (p = util_ldap_cache->nodes[i]; p != NULL; p = p->next) {
|
||||
util_url_node_t *n;
|
||||
|
||||
n = (util_url_node_t *)p->payload;
|
||||
|
||||
t1 = apr_psprintf(pool, "%s (Searches)", n->url);
|
||||
t2 = apr_psprintf(pool, "%s (Compares)", n->url);
|
||||
t3 = apr_psprintf(pool, "%s (DNCompares)", n->url);
|
||||
|
||||
buf = apr_psprintf(pool, "%s\n\n"
|
||||
"%s\n\n"
|
||||
"%s\n\n"
|
||||
"%s\n\n",
|
||||
buf,
|
||||
util_ald_cache_display_stats(pool, n->search_cache, t1),
|
||||
util_ald_cache_display_stats(pool, n->compare_cache, t2),
|
||||
util_ald_cache_display_stats(pool, n->dn_compare_cache, t3)
|
||||
);
|
||||
}
|
||||
}
|
||||
return buf;
|
||||
}
|
||||
|
||||
#endif /* APU_HAS_LDAP */
|
Reference in New Issue
Block a user