summaryrefslogtreecommitdiffstats
path: root/modules/ldap/util_ldap_cache_mgr.c
diff options
context:
space:
mode:
Diffstat (limited to 'modules/ldap/util_ldap_cache_mgr.c')
-rw-r--r--modules/ldap/util_ldap_cache_mgr.c901
1 files changed, 901 insertions, 0 deletions
diff --git a/modules/ldap/util_ldap_cache_mgr.c b/modules/ldap/util_ldap_cache_mgr.c
new file mode 100644
index 0000000..9bef3f8
--- /dev/null
+++ b/modules/ldap/util_ldap_cache_mgr.c
@@ -0,0 +1,901 @@
+/* Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ * 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 "httpd.h"
+#include "util_ldap.h"
+#include "util_ldap_cache.h"
+#include <apr_strings.h>
+
+APLOG_USE_MODULE(ldap);
+
+#if APR_HAS_LDAP
+
+/* only here until strdup is gone */
+#include <string.h>
+
+/* here till malloc is gone */
+#include <stdlib.h>
+
+static const unsigned long 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(util_ald_cache_t *cache, const void *ptr)
+{
+#if APR_HAS_SHARED_MEMORY
+ if (cache->rmm_addr) {
+ if (ptr)
+ /* Free in shared memory */
+ apr_rmm_free(cache->rmm_addr, apr_rmm_offset_get(cache->rmm_addr, (void *)ptr));
+ }
+ else {
+ if (ptr)
+ /* Cache shm is not used */
+ free((void *)ptr);
+ }
+#else
+ if (ptr)
+ free((void *)ptr);
+#endif
+}
+
+void *util_ald_alloc(util_ald_cache_t *cache, unsigned long size)
+{
+ if (0 == size)
+ return NULL;
+#if APR_HAS_SHARED_MEMORY
+ if (cache->rmm_addr) {
+ /* allocate from shared memory */
+ apr_rmm_off_t block = apr_rmm_calloc(cache->rmm_addr, size);
+ return block ? (void *)apr_rmm_addr_get(cache->rmm_addr, block) : NULL;
+ }
+ else {
+ /* Cache shm is not used */
+ return (void *)calloc(sizeof(char), size);
+ }
+#else
+ return (void *)calloc(sizeof(char), size);
+#endif
+}
+
+const char *util_ald_strdup(util_ald_cache_t *cache, const char *s)
+{
+#if APR_HAS_SHARED_MEMORY
+ if (cache->rmm_addr) {
+ /* allocate from shared memory */
+ apr_rmm_off_t block = apr_rmm_calloc(cache->rmm_addr, strlen(s)+1);
+ char *buf = block ? (char *)apr_rmm_addr_get(cache->rmm_addr, block) : NULL;
+ if (buf) {
+ strcpy(buf, s);
+ return buf;
+ }
+ else {
+ return NULL;
+ }
+ }
+ else {
+ /* Cache shm is not used */
+ return strdup(s);
+ }
+#else
+ return strdup(s);
+#endif
+}
+
+/*
+ * Duplicate a subgroupList from one compare entry to another.
+ * Returns: ptr to a new copy of the subgroupList or NULL if allocation failed.
+ */
+util_compare_subgroup_t *util_ald_sgl_dup(util_ald_cache_t *cache, util_compare_subgroup_t *sgl_in)
+{
+ int i = 0;
+ util_compare_subgroup_t *sgl_out = NULL;
+
+ if (!sgl_in) {
+ return NULL;
+ }
+
+ sgl_out = (util_compare_subgroup_t *) util_ald_alloc(cache, sizeof(util_compare_subgroup_t));
+ if (sgl_out) {
+ sgl_out->subgroupDNs = util_ald_alloc(cache, sizeof(char *) * sgl_in->len);
+ if (sgl_out->subgroupDNs) {
+ for (i = 0; i < sgl_in->len; i++) {
+ sgl_out->subgroupDNs[i] = util_ald_strdup(cache, sgl_in->subgroupDNs[i]);
+ if (!sgl_out->subgroupDNs[i]) {
+ /* We ran out of SHM, delete the strings we allocated for the SGL */
+ for (i = (i - 1); i >= 0; i--) {
+ util_ald_free(cache, sgl_out->subgroupDNs[i]);
+ }
+ util_ald_free(cache, sgl_out->subgroupDNs);
+ util_ald_free(cache, sgl_out);
+ sgl_out = NULL;
+ break;
+ }
+ }
+ /* We were able to allocate new strings for all the subgroups */
+ if (sgl_out != NULL) {
+ sgl_out->len = sgl_in->len;
+ }
+ }
+ }
+
+ return sgl_out;
+}
+
+/*
+ * Delete an entire subgroupList.
+ */
+void util_ald_sgl_free(util_ald_cache_t *cache, util_compare_subgroup_t **sgl)
+{
+ int i = 0;
+ if (sgl == NULL || *sgl == NULL) {
+ return;
+ }
+
+ for (i = 0; i < (*sgl)->len; i++) {
+ util_ald_free(cache, (*sgl)->subgroupDNs[i]);
+ }
+ util_ald_free(cache, *sgl);
+}
+
+/*
+ * 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)
+{
+ unsigned long i;
+ util_cache_node_t *p, *q, **pp;
+ apr_time_t now;
+
+ if (!cache)
+ return;
+
+ now = cache->last_purge = apr_time_now();
+ cache->npurged = 0;
+ cache->numpurges++;
+
+ /* If the marktime is farther back than TTL from now,
+ move the marktime forward to include additional expired entries.
+ */
+ if (now - cache->ttl > cache->marktime) {
+ cache->marktime = now - cache->ttl;
+ }
+
+ for (i=0; i < cache->size; ++i) {
+ pp = cache->nodes + i;
+ p = *pp;
+ while (p != NULL) {
+ if (p->add_time < cache->marktime) {
+ q = p->next;
+ (*cache->free)(cache, p->payload);
+ util_ald_free(cache, p);
+ cache->numentries--;
+ cache->npurged++;
+ p = *pp = q;
+ }
+ else {
+ pp = &(p->next);
+ p = *pp;
+ }
+ }
+ }
+
+ now = apr_time_now();
+ cache->avg_purgetime =
+ ((now - 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, *newcurl = 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,
+ st->search_cache_size,
+ st->search_cache_ttl,
+ util_ldap_search_node_hash,
+ util_ldap_search_node_compare,
+ util_ldap_search_node_copy,
+ util_ldap_search_node_free,
+ util_ldap_search_node_display);
+ compare_cache = util_ald_create_cache(st,
+ st->compare_cache_size,
+ st->compare_cache_ttl,
+ util_ldap_compare_node_hash,
+ util_ldap_compare_node_compare,
+ util_ldap_compare_node_copy,
+ util_ldap_compare_node_free,
+ util_ldap_compare_node_display);
+ dn_compare_cache = util_ald_create_cache(st,
+ st->compare_cache_size,
+ st->compare_cache_ttl,
+ util_ldap_dn_compare_node_hash,
+ util_ldap_dn_compare_node_compare,
+ util_ldap_dn_compare_node_copy,
+ util_ldap_dn_compare_node_free,
+ util_ldap_dn_compare_node_display);
+
+ /* check that all the caches initialised successfully */
+ if (search_cache && compare_cache && dn_compare_cache) {
+
+ /* The contents of this structure will be duplicated in shared
+ memory during the insert. So use stack memory rather than
+ pool memory to avoid a memory leak. */
+ memset (&curl, 0, 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;
+
+ newcurl = util_ald_cache_insert(st->util_ldap_cache, &curl);
+
+ }
+
+ return newcurl;
+}
+
+
+util_ald_cache_t *util_ald_create_cache(util_ldap_state_t *st,
+ long cache_size,
+ long cache_ttl,
+ unsigned long (*hashfunc)(void *),
+ int (*comparefunc)(void *, void *),
+ void * (*copyfunc)(util_ald_cache_t *cache, void *),
+ void (*freefunc)(util_ald_cache_t *cache, void *),
+ void (*displayfunc)(request_rec *r, util_ald_cache_t *cache, void *))
+{
+ util_ald_cache_t *cache;
+ unsigned long i;
+#if APR_HAS_SHARED_MEMORY
+ apr_rmm_off_t block;
+#endif
+
+ if (cache_size <= 0)
+ return NULL;
+
+#if APR_HAS_SHARED_MEMORY
+ if (!st->cache_rmm) {
+ cache = (util_ald_cache_t *)calloc(sizeof(util_ald_cache_t), 1);
+ }
+ else {
+ block = apr_rmm_calloc(st->cache_rmm, sizeof(util_ald_cache_t));
+ cache = block ? (util_ald_cache_t *)apr_rmm_addr_get(st->cache_rmm, block) : NULL;
+ }
+#else
+ cache = (util_ald_cache_t *)calloc(sizeof(util_ald_cache_t), 1);
+#endif
+ if (!cache)
+ return NULL;
+
+#if APR_HAS_SHARED_MEMORY
+ cache->rmm_addr = st->cache_rmm;
+ cache->shm_addr = st->cache_shm;
+#endif
+ cache->maxentries = cache_size;
+ cache->numentries = 0;
+ cache->size = cache_size / 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, cache->size * sizeof(util_cache_node_t *));
+ if (!cache->nodes) {
+ /* This frees cache in the right way even if !APR_HAS_SHARED_MEMORY or !st->cache_rmm */
+ util_ald_free(cache, 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->display = displayfunc;
+
+
+ cache->fullmark = cache->maxentries / 4 * 3;
+ cache->marktime = 0;
+ cache->ttl = cache_ttl;
+ 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)
+{
+ unsigned long 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)(cache, p->payload);
+ util_ald_free(cache, p);
+ p = q;
+ }
+ }
+ util_ald_free(cache, cache->nodes);
+ util_ald_free(cache, cache);
+}
+
+void *util_ald_cache_fetch(util_ald_cache_t *cache, void *payload)
+{
+ unsigned long 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)
+{
+ unsigned long hashval;
+ void *tmp_payload;
+ util_cache_node_t *node;
+
+ /* sanity check */
+ if (cache == NULL || payload == NULL) {
+ return NULL;
+ }
+
+ /* check if we are full - if so, try purge */
+ if (cache->numentries >= cache->maxentries) {
+ util_ald_cache_purge(cache);
+ if (cache->numentries >= cache->maxentries) {
+ /* if the purge was not effective, we leave now to avoid an overflow */
+ ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, APLOGNO(01323)
+ "Purge of LDAP cache failed");
+ return NULL;
+ }
+ }
+
+ node = (util_cache_node_t *)util_ald_alloc(cache,
+ sizeof(util_cache_node_t));
+ if (node == NULL) {
+ /*
+ * XXX: The cache management should be rewritten to work
+ * properly when LDAPSharedCacheSize is too small.
+ */
+ ap_log_error(APLOG_MARK, APLOG_WARNING, 0, NULL, APLOGNO(01324)
+ "LDAPSharedCacheSize is too small. Increase it or "
+ "reduce LDAPCacheEntries/LDAPOpCacheEntries!");
+ if (cache->numentries < cache->fullmark) {
+ /*
+ * We have not even reached fullmark, trigger a complete purge.
+ * This is still better than not being able to add new entries
+ * at all.
+ */
+ cache->marktime = apr_time_now();
+ }
+ util_ald_cache_purge(cache);
+ node = (util_cache_node_t *)util_ald_alloc(cache,
+ sizeof(util_cache_node_t));
+ if (node == NULL) {
+ ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, APLOGNO(01325)
+ "Could not allocate memory for LDAP cache entry");
+ return NULL;
+ }
+ }
+
+ /* Take a copy of the payload before proceeding. */
+ tmp_payload = (*cache->copy)(cache, payload);
+ if (tmp_payload == NULL) {
+ /*
+ * XXX: The cache management should be rewritten to work
+ * properly when LDAPSharedCacheSize is too small.
+ */
+ ap_log_error(APLOG_MARK, APLOG_WARNING, 0, NULL, APLOGNO(01326)
+ "LDAPSharedCacheSize is too small. Increase it or "
+ "reduce LDAPCacheEntries/LDAPOpCacheEntries!");
+ if (cache->numentries < cache->fullmark) {
+ /*
+ * We have not even reached fullmark, trigger a complete purge.
+ * This is still better than not being able to add new entries
+ * at all.
+ */
+ cache->marktime = apr_time_now();
+ }
+ util_ald_cache_purge(cache);
+ tmp_payload = (*cache->copy)(cache, payload);
+ if (tmp_payload == NULL) {
+ ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, APLOGNO(01327)
+ "Could not allocate memory for LDAP cache value");
+ util_ald_free(cache, node);
+ return NULL;
+ }
+ }
+ payload = tmp_payload;
+
+ /* populate the entry */
+ cache->inserts++;
+ hashval = (*cache->hash)(payload) % cache->size;
+ node->add_time = apr_time_now();
+ node->payload = payload;
+ node->next = cache->nodes[hashval];
+ cache->nodes[hashval] = node;
+
+ /* if we reach the full mark, note the time we did so
+ * for the benefit of the purge function
+ */
+ if (++cache->numentries == cache->fullmark) {
+ cache->marktime=apr_time_now();
+ }
+
+ return node->payload;
+}
+
+void util_ald_cache_remove(util_ald_cache_t *cache, void *payload)
+{
+ unsigned long 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)(cache, p->payload);
+ util_ald_free(cache, p);
+ cache->numentries--;
+}
+
+char *util_ald_cache_display_stats(request_rec *r, util_ald_cache_t *cache, char *name, char *id)
+{
+ unsigned long i;
+ int totchainlen = 0;
+ int nchains = 0;
+ double chainlen;
+ util_cache_node_t *n;
+ char *buf, *buf2;
+ apr_pool_t *p = r->pool;
+
+ 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;
+ n = n->next) {
+ totchainlen++;
+ }
+ }
+ }
+ chainlen = nchains? (double)totchainlen / (double)nchains : 0;
+
+ if (id) {
+ buf2 = apr_psprintf(p,
+ "<a href=\"%s?%s\">%s</a>",
+ ap_escape_html(r->pool, ap_escape_uri(r->pool, r->uri)),
+ id,
+ name);
+ }
+ else {
+ buf2 = name;
+ }
+
+ 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>",
+ buf2,
+ 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'>%.2gms</td>\n</tr>", buf, cache->avg_purgetime);
+
+ return buf;
+}
+
+char *util_ald_cache_display(request_rec *r, util_ldap_state_t *st)
+{
+ unsigned long i,j;
+ char *buf, *t1, *t2, *t3;
+ char *id1, *id2, *id3;
+ char *argfmt = "cache=%s&id=%d&off=%d";
+ char *scanfmt = "cache=%4s&id=%u&off=%u%1s";
+ apr_pool_t *pool = r->pool;
+ util_cache_node_t *p = NULL;
+ util_url_node_t *n = NULL;
+
+ util_ald_cache_t *util_ldap_cache = st->util_ldap_cache;
+
+
+ if (!util_ldap_cache) {
+ ap_rputs("<tr valign='top'><td nowrap colspan=7>Cache has not been enabled/initialised.</td></tr>", r);
+ return NULL;
+ }
+
+ if (r->args && strlen(r->args)) {
+ char cachetype[5], lint[2];
+ unsigned int id, off;
+ char date_str[APR_CTIME_LEN];
+
+ if ((3 == sscanf(r->args, scanfmt, cachetype, &id, &off, lint)) &&
+ (id < util_ldap_cache->size)) {
+
+ if ((p = util_ldap_cache->nodes[id]) != NULL) {
+ n = (util_url_node_t *)p->payload;
+ buf = (char*)n->url;
+ }
+ else {
+ buf = "";
+ }
+
+ ap_rprintf(r,
+ "<p>\n"
+ "<table border='0'>\n"
+ "<tr>\n"
+ "<td bgcolor='#000000'><font size='-1' face='Arial,Helvetica' color='#ffffff'><b>Cache Name:</b></font></td>"
+ "<td bgcolor='#ffffff'><font size='-1' face='Arial,Helvetica' color='#000000'><b>%s (%s)</b></font></td>"
+ "</tr>\n"
+ "</table>\n</p>\n",
+ buf,
+ cachetype[0] == 'm'? "Main" :
+ (cachetype[0] == 's' ? "Search" :
+ (cachetype[0] == 'c' ? "Compares" : "DNCompares")));
+
+ switch (cachetype[0]) {
+ case 'm':
+ if (util_ldap_cache->marktime) {
+ apr_ctime(date_str, util_ldap_cache->marktime);
+ }
+ else
+ date_str[0] = 0;
+
+ ap_rprintf(r,
+ "<p>\n"
+ "<table border='0'>\n"
+ "<tr>\n"
+ "<td bgcolor='#000000'><font size='-1' face='Arial,Helvetica' color='#ffffff'><b>Size:</b></font></td>"
+ "<td bgcolor='#ffffff'><font size='-1' face='Arial,Helvetica' color='#000000'><b>%ld</b></font></td>"
+ "</tr>\n"
+ "<tr>\n"
+ "<td bgcolor='#000000'><font size='-1' face='Arial,Helvetica' color='#ffffff'><b>Max Entries:</b></font></td>"
+ "<td bgcolor='#ffffff'><font size='-1' face='Arial,Helvetica' color='#000000'><b>%ld</b></font></td>"
+ "</tr>\n"
+ "<tr>\n"
+ "<td bgcolor='#000000'><font size='-1' face='Arial,Helvetica' color='#ffffff'><b># Entries:</b></font></td>"
+ "<td bgcolor='#ffffff'><font size='-1' face='Arial,Helvetica' color='#000000'><b>%ld</b></font></td>"
+ "</tr>\n"
+ "<tr>\n"
+ "<td bgcolor='#000000'><font size='-1' face='Arial,Helvetica' color='#ffffff'><b>TTL (sec):</b></font></td>"
+ "<td bgcolor='#ffffff'><font size='-1' face='Arial,Helvetica' color='#000000'><b>%" APR_TIME_T_FMT "</b></font></td>"
+ "</tr>\n"
+ "<tr>\n"
+ "<td bgcolor='#000000'><font size='-1' face='Arial,Helvetica' color='#ffffff'><b>Full Mark:</b></font></td>"
+ "<td bgcolor='#ffffff'><font size='-1' face='Arial,Helvetica' color='#000000'><b>%ld</b></font></td>"
+ "</tr>\n"
+ "<tr>\n"
+ "<td bgcolor='#000000'><font size='-1' face='Arial,Helvetica' color='#ffffff'><b>Full Mark Time:</b></font></td>"
+ "<td bgcolor='#ffffff'><font size='-1' face='Arial,Helvetica' color='#000000'><b>%s</b></font></td>"
+ "</tr>\n"
+ "</table>\n</p>\n",
+ util_ldap_cache->size,
+ util_ldap_cache->maxentries,
+ util_ldap_cache->numentries,
+ apr_time_sec(util_ldap_cache->ttl),
+ util_ldap_cache->fullmark,
+ date_str);
+
+ ap_rputs("<p>\n"
+ "<table border='0'>\n"
+ "<tr bgcolor='#000000'>\n"
+ "<td><font size='-1' face='Arial,Helvetica' color='#ffffff'><b>LDAP URL</b></font></td>"
+ "<td><font size='-1' face='Arial,Helvetica' color='#ffffff'><b>Size</b></font></td>"
+ "<td><font size='-1' face='Arial,Helvetica' color='#ffffff'><b>Max Entries</b></font></td>"
+ "<td><font size='-1' face='Arial,Helvetica' color='#ffffff'><b># Entries</b></font></td>"
+ "<td><font size='-1' face='Arial,Helvetica' color='#ffffff'><b>TTL (sec)</b></font></td>"
+ "<td><font size='-1' face='Arial,Helvetica' color='#ffffff'><b>Full Mark</b></font></td>"
+ "<td><font size='-1' face='Arial,Helvetica' color='#ffffff'><b>Full Mark Time</b></font></td>"
+ "</tr>\n", r
+ );
+ for (i=0; i < util_ldap_cache->size; ++i) {
+ for (p = util_ldap_cache->nodes[i]; p != NULL; p = p->next) {
+
+ (*util_ldap_cache->display)(r, util_ldap_cache, p->payload);
+ }
+ }
+ ap_rputs("</table>\n</p>\n", r);
+
+
+ break;
+ case 's':
+ ap_rputs("<p>\n"
+ "<table border='0'>\n"
+ "<tr bgcolor='#000000'>\n"
+ "<td><font size='-1' face='Arial,Helvetica' color='#ffffff'><b>LDAP Filter</b></font></td>"
+ "<td><font size='-1' face='Arial,Helvetica' color='#ffffff'><b>User Name</b></font></td>"
+ "<td><font size='-1' face='Arial,Helvetica' color='#ffffff'><b>Last Bind</b></font></td>"
+ "</tr>\n", r
+ );
+ if (n) {
+ for (i=0; i < n->search_cache->size; ++i) {
+ for (p = n->search_cache->nodes[i]; p != NULL; p = p->next) {
+
+ (*n->search_cache->display)(r, n->search_cache, p->payload);
+ }
+ }
+ }
+ ap_rputs("</table>\n</p>\n", r);
+ break;
+ case 'c':
+ ap_rputs("<p>\n"
+ "<table border='0'>\n"
+ "<tr bgcolor='#000000'>\n"
+ "<td><font size='-1' face='Arial,Helvetica' color='#ffffff'><b>DN</b></font></td>"
+ "<td><font size='-1' face='Arial,Helvetica' color='#ffffff'><b>Attribute</b></font></td>"
+ "<td><font size='-1' face='Arial,Helvetica' color='#ffffff'><b>Value</b></font></td>"
+ "<td><font size='-1' face='Arial,Helvetica' color='#ffffff'><b>Last Compare</b></font></td>"
+ "<td><font size='-1' face='Arial,Helvetica' color='#ffffff'><b>Result</b></font></td>"
+ "<td><font size='-1' face='Arial,Helvetica' color='#ffffff'><b>Sub-groups?</b></font></td>"
+ "<td><font size='-1' face='Arial,Helvetica' color='#ffffff'><b>S-G Checked?</b></font></td>"
+ "</tr>\n", r
+ );
+ if (n) {
+ for (i=0; i < n->compare_cache->size; ++i) {
+ for (p = n->compare_cache->nodes[i]; p != NULL; p = p->next) {
+
+ (*n->compare_cache->display)(r, n->compare_cache, p->payload);
+ }
+ }
+ }
+ ap_rputs("</table>\n</p>\n", r);
+ break;
+ case 'd':
+ ap_rputs("<p>\n"
+ "<table border='0'>\n"
+ "<tr bgcolor='#000000'>\n"
+ "<td><font size='-1' face='Arial,Helvetica' color='#ffffff'><b>Require DN</b></font></td>"
+ "<td><font size='-1' face='Arial,Helvetica' color='#ffffff'><b>Actual DN</b></font></td>"
+ "</tr>\n", r
+ );
+ if (n) {
+ for (i=0; i < n->dn_compare_cache->size; ++i) {
+ for (p = n->dn_compare_cache->nodes[i]; p != NULL; p = p->next) {
+
+ (*n->dn_compare_cache->display)(r, n->dn_compare_cache, p->payload);
+ }
+ }
+ }
+ ap_rputs("</table>\n</p>\n", r);
+ break;
+ default:
+ break;
+ }
+
+ }
+ else {
+ buf = "";
+ }
+ }
+ else {
+ ap_rputs("<p>\n"
+ "<table border='0'>\n"
+ "<tr bgcolor='#000000'>\n"
+ "<td><font size='-1' face='Arial,Helvetica' color='#ffffff'><b>Cache Name</b></font></td>"
+ "<td><font size='-1' face='Arial,Helvetica' color='#ffffff'><b>Entries</b></font></td>"
+ "<td><font size='-1' face='Arial,Helvetica' color='#ffffff'><b>Avg. Chain Len.</b></font></td>"
+ "<td colspan='2'><font size='-1' face='Arial,Helvetica' color='#ffffff'><b>Hits</b></font></td>"
+ "<td><font size='-1' face='Arial,Helvetica' color='#ffffff'><b>Ins/Rem</b></font></td>"
+ "<td colspan='2'><font size='-1' face='Arial,Helvetica' color='#ffffff'><b>Purges</b></font></td>"
+ "<td><font size='-1' face='Arial,Helvetica' color='#ffffff'><b>Avg Purge Time</b></font></td>"
+ "</tr>\n", r
+ );
+
+
+ id1 = apr_psprintf(pool, argfmt, "main", 0, 0);
+ buf = util_ald_cache_display_stats(r, st->util_ldap_cache, "LDAP URL Cache", id1);
+
+ for (i=0; i < util_ldap_cache->size; ++i) {
+ for (p = util_ldap_cache->nodes[i],j=0; p != NULL; p = p->next,j++) {
+
+ 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);
+ id1 = apr_psprintf(pool, argfmt, "srch", i, j);
+ id2 = apr_psprintf(pool, argfmt, "cmpr", i, j);
+ id3 = apr_psprintf(pool, argfmt, "dncp", i, j);
+
+ buf = apr_psprintf(pool, "%s\n\n"
+ "%s\n\n"
+ "%s\n\n"
+ "%s\n\n",
+ buf,
+ util_ald_cache_display_stats(r, n->search_cache, t1, id1),
+ util_ald_cache_display_stats(r, n->compare_cache, t2, id2),
+ util_ald_cache_display_stats(r, n->dn_compare_cache, t3, id3)
+ );
+ }
+ }
+ ap_rputs(buf, r);
+ ap_rputs("</table>\n</p>\n", r);
+ }
+
+ return buf;
+}
+
+#endif /* APR_HAS_LDAP */