1 /* Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 /*
18 * util_ldap_cache_mgr.c: LDAP cache manager things
19 *
20 * Original code from auth_ldap module for Apache v1.3:
21 * Copyright 1998, 1999 Enbridge Pipelines Inc.
22 * Copyright 1999-2001 Dave Carrigan
23 */
24
25 #include "httpd.h"
26 #include "util_ldap.h"
27 #include "util_ldap_cache.h"
28 #include <apr_strings.h>
29
30 APLOG_USE_MODULE(ldap);
31
32 #if APR_HAS_LDAP
33
34 /* only here until strdup is gone */
35 #include <string.h>
36
37 /* here till malloc is gone */
38 #include <stdlib.h>
39
40 static const unsigned long primes[] =
41 {
42 11,
43 19,
44 37,
45 73,
46 109,
47 163,
48 251,
49 367,
50 557,
51 823,
52 1237,
53 1861,
54 2777,
55 4177,
56 6247,
57 9371,
58 14057,
59 21089,
60 31627,
61 47431,
62 71143,
63 106721,
64 160073,
65 240101,
66 360163,
67 540217,
68 810343,
69 1215497,
70 1823231,
71 2734867,
72 4102283,
73 6153409,
74 9230113,
75 13845163,
76 0
77 };
78
util_ald_free(util_ald_cache_t * cache,const void * ptr)79 void util_ald_free(util_ald_cache_t *cache, const void *ptr)
80 {
81 #if APR_HAS_SHARED_MEMORY
82 if (cache->rmm_addr) {
83 if (ptr)
84 /* Free in shared memory */
85 apr_rmm_free(cache->rmm_addr, apr_rmm_offset_get(cache->rmm_addr, (void *)ptr));
86 }
87 else {
88 if (ptr)
89 /* Cache shm is not used */
90 free((void *)ptr);
91 }
92 #else
93 if (ptr)
94 free((void *)ptr);
95 #endif
96 }
97
util_ald_alloc(util_ald_cache_t * cache,unsigned long size)98 void *util_ald_alloc(util_ald_cache_t *cache, unsigned long size)
99 {
100 if (0 == size)
101 return NULL;
102 #if APR_HAS_SHARED_MEMORY
103 if (cache->rmm_addr) {
104 /* allocate from shared memory */
105 apr_rmm_off_t block = apr_rmm_calloc(cache->rmm_addr, size);
106 return block ? (void *)apr_rmm_addr_get(cache->rmm_addr, block) : NULL;
107 }
108 else {
109 /* Cache shm is not used */
110 return (void *)calloc(sizeof(char), size);
111 }
112 #else
113 return (void *)calloc(sizeof(char), size);
114 #endif
115 }
116
util_ald_strdup(util_ald_cache_t * cache,const char * s)117 const char *util_ald_strdup(util_ald_cache_t *cache, const char *s)
118 {
119 #if APR_HAS_SHARED_MEMORY
120 if (cache->rmm_addr) {
121 /* allocate from shared memory */
122 apr_rmm_off_t block = apr_rmm_calloc(cache->rmm_addr, strlen(s)+1);
123 char *buf = block ? (char *)apr_rmm_addr_get(cache->rmm_addr, block) : NULL;
124 if (buf) {
125 strcpy(buf, s);
126 return buf;
127 }
128 else {
129 return NULL;
130 }
131 }
132 else {
133 /* Cache shm is not used */
134 return strdup(s);
135 }
136 #else
137 return strdup(s);
138 #endif
139 }
140
141 /*
142 * Duplicate a subgroupList from one compare entry to another.
143 * Returns: ptr to a new copy of the subgroupList or NULL if allocation failed.
144 */
util_ald_sgl_dup(util_ald_cache_t * cache,util_compare_subgroup_t * sgl_in)145 util_compare_subgroup_t *util_ald_sgl_dup(util_ald_cache_t *cache, util_compare_subgroup_t *sgl_in)
146 {
147 int i = 0;
148 util_compare_subgroup_t *sgl_out = NULL;
149
150 if (!sgl_in) {
151 return NULL;
152 }
153
154 sgl_out = (util_compare_subgroup_t *) util_ald_alloc(cache, sizeof(util_compare_subgroup_t));
155 if (sgl_out) {
156 sgl_out->subgroupDNs = util_ald_alloc(cache, sizeof(char *) * sgl_in->len);
157 if (sgl_out->subgroupDNs) {
158 for (i = 0; i < sgl_in->len; i++) {
159 sgl_out->subgroupDNs[i] = util_ald_strdup(cache, sgl_in->subgroupDNs[i]);
160 if (!sgl_out->subgroupDNs[i]) {
161 /* We ran out of SHM, delete the strings we allocated for the SGL */
162 for (i = (i - 1); i >= 0; i--) {
163 util_ald_free(cache, sgl_out->subgroupDNs[i]);
164 }
165 util_ald_free(cache, sgl_out->subgroupDNs);
166 util_ald_free(cache, sgl_out);
167 sgl_out = NULL;
168 break;
169 }
170 }
171 /* We were able to allocate new strings for all the subgroups */
172 if (sgl_out != NULL) {
173 sgl_out->len = sgl_in->len;
174 }
175 }
176 }
177
178 return sgl_out;
179 }
180
181 /*
182 * Delete an entire subgroupList.
183 */
util_ald_sgl_free(util_ald_cache_t * cache,util_compare_subgroup_t ** sgl)184 void util_ald_sgl_free(util_ald_cache_t *cache, util_compare_subgroup_t **sgl)
185 {
186 int i = 0;
187 if (sgl == NULL || *sgl == NULL) {
188 return;
189 }
190
191 for (i = 0; i < (*sgl)->len; i++) {
192 util_ald_free(cache, (*sgl)->subgroupDNs[i]);
193 }
194 util_ald_free(cache, *sgl);
195 }
196
197 /*
198 * Computes the hash on a set of strings. The first argument is the number
199 * of strings to hash, the rest of the args are strings.
200 * Algorithm taken from glibc.
201 */
util_ald_hash_string(int nstr,...)202 unsigned long util_ald_hash_string(int nstr, ...)
203 {
204 int i;
205 va_list args;
206 unsigned long h=0, g;
207 char *str, *p;
208
209 va_start(args, nstr);
210 for (i=0; i < nstr; ++i) {
211 str = va_arg(args, char *);
212 for (p = str; *p; ++p) {
213 h = ( h << 4 ) + *p;
214 if ( ( g = h & 0xf0000000 ) ) {
215 h = h ^ (g >> 24);
216 h = h ^ g;
217 }
218 }
219 }
220 va_end(args);
221
222 return h;
223 }
224
225
226 /*
227 Purges a cache that has gotten full. We keep track of the time that we
228 added the entry that made the cache 3/4 full, then delete all entries
229 that were added before that time. It's pretty simplistic, but time to
230 purge is only O(n), which is more important.
231 */
util_ald_cache_purge(util_ald_cache_t * cache)232 void util_ald_cache_purge(util_ald_cache_t *cache)
233 {
234 unsigned long i;
235 util_cache_node_t *p, *q, **pp;
236 apr_time_t now;
237
238 if (!cache)
239 return;
240
241 now = cache->last_purge = apr_time_now();
242 cache->npurged = 0;
243 cache->numpurges++;
244
245 /* If the marktime is farther back than TTL from now,
246 move the marktime forward to include additional expired entries.
247 */
248 if (now - cache->ttl > cache->marktime) {
249 cache->marktime = now - cache->ttl;
250 }
251
252 for (i=0; i < cache->size; ++i) {
253 pp = cache->nodes + i;
254 p = *pp;
255 while (p != NULL) {
256 if (p->add_time < cache->marktime) {
257 q = p->next;
258 (*cache->free)(cache, p->payload);
259 util_ald_free(cache, p);
260 cache->numentries--;
261 cache->npurged++;
262 p = *pp = q;
263 }
264 else {
265 pp = &(p->next);
266 p = *pp;
267 }
268 }
269 }
270
271 now = apr_time_now();
272 cache->avg_purgetime =
273 ((now - cache->last_purge) + (cache->avg_purgetime * (cache->numpurges-1))) /
274 cache->numpurges;
275 }
276
277
278 /*
279 * create caches
280 */
util_ald_create_caches(util_ldap_state_t * st,const char * url)281 util_url_node_t *util_ald_create_caches(util_ldap_state_t *st, const char *url)
282 {
283 util_url_node_t curl;
284 util_ald_cache_t *search_cache;
285 util_ald_cache_t *compare_cache;
286 util_ald_cache_t *dn_compare_cache;
287
288 /* create the three caches */
289 search_cache = util_ald_create_cache(st,
290 st->search_cache_size,
291 st->search_cache_ttl,
292 util_ldap_search_node_hash,
293 util_ldap_search_node_compare,
294 util_ldap_search_node_copy,
295 util_ldap_search_node_free,
296 util_ldap_search_node_display);
297 compare_cache = util_ald_create_cache(st,
298 st->compare_cache_size,
299 st->compare_cache_ttl,
300 util_ldap_compare_node_hash,
301 util_ldap_compare_node_compare,
302 util_ldap_compare_node_copy,
303 util_ldap_compare_node_free,
304 util_ldap_compare_node_display);
305 dn_compare_cache = util_ald_create_cache(st,
306 st->compare_cache_size,
307 st->compare_cache_ttl,
308 util_ldap_dn_compare_node_hash,
309 util_ldap_dn_compare_node_compare,
310 util_ldap_dn_compare_node_copy,
311 util_ldap_dn_compare_node_free,
312 util_ldap_dn_compare_node_display);
313
314 /* check that all the caches initialised successfully */
315 if (search_cache && compare_cache && dn_compare_cache) {
316 /* The contents of this structure will be duplicated in shared
317 memory during the insert. So use stack memory rather than
318 pool memory to avoid a memory leak. */
319 memset (&curl, 0, sizeof(util_url_node_t));
320 curl.url = url;
321 curl.search_cache = search_cache;
322 curl.compare_cache = compare_cache;
323 curl.dn_compare_cache = dn_compare_cache;
324
325 return util_ald_cache_insert(st->util_ldap_cache, &curl);
326 }
327 else {
328 /* util_ald_destroy_cache is a noop for a NULL argument. */
329 util_ald_destroy_cache(search_cache);
330 util_ald_destroy_cache(compare_cache);
331 util_ald_destroy_cache(dn_compare_cache);
332
333 return NULL;
334 }
335 }
336
337
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 *))338 util_ald_cache_t *util_ald_create_cache(util_ldap_state_t *st,
339 long cache_size,
340 long cache_ttl,
341 unsigned long (*hashfunc)(void *),
342 int (*comparefunc)(void *, void *),
343 void * (*copyfunc)(util_ald_cache_t *cache, void *),
344 void (*freefunc)(util_ald_cache_t *cache, void *),
345 void (*displayfunc)(request_rec *r, util_ald_cache_t *cache, void *))
346 {
347 util_ald_cache_t *cache;
348 unsigned long i;
349 #if APR_HAS_SHARED_MEMORY
350 apr_rmm_off_t block;
351 #endif
352
353 if (cache_size <= 0)
354 return NULL;
355
356 #if APR_HAS_SHARED_MEMORY
357 if (!st->cache_rmm) {
358 cache = (util_ald_cache_t *)calloc(sizeof(util_ald_cache_t), 1);
359 }
360 else {
361 block = apr_rmm_calloc(st->cache_rmm, sizeof(util_ald_cache_t));
362 cache = block ? (util_ald_cache_t *)apr_rmm_addr_get(st->cache_rmm, block) : NULL;
363 }
364 #else
365 cache = (util_ald_cache_t *)calloc(sizeof(util_ald_cache_t), 1);
366 #endif
367 if (!cache)
368 return NULL;
369
370 #if APR_HAS_SHARED_MEMORY
371 cache->rmm_addr = st->cache_rmm;
372 cache->shm_addr = st->cache_shm;
373 #endif
374 cache->maxentries = cache_size;
375 cache->numentries = 0;
376 cache->size = cache_size / 3;
377 if (cache->size < 64)
378 cache->size = 64;
379 for (i = 0; primes[i] && primes[i] < cache->size; ++i)
380 ;
381 cache->size = primes[i] ? primes[i] : primes[i-1];
382
383 cache->nodes = (util_cache_node_t **)util_ald_alloc(cache, cache->size * sizeof(util_cache_node_t *));
384 if (!cache->nodes) {
385 /* This frees cache in the right way even if !APR_HAS_SHARED_MEMORY or !st->cache_rmm */
386 util_ald_free(cache, cache);
387 return NULL;
388 }
389
390 for (i=0; i < cache->size; ++i)
391 cache->nodes[i] = NULL;
392
393 cache->hash = hashfunc;
394 cache->compare = comparefunc;
395 cache->copy = copyfunc;
396 cache->free = freefunc;
397 cache->display = displayfunc;
398
399
400 cache->fullmark = cache->maxentries / 4 * 3;
401 cache->marktime = 0;
402 cache->ttl = cache_ttl;
403 cache->avg_purgetime = 0.0;
404 cache->numpurges = 0;
405 cache->last_purge = 0;
406 cache->npurged = 0;
407
408 cache->fetches = 0;
409 cache->hits = 0;
410 cache->inserts = 0;
411 cache->removes = 0;
412
413 return cache;
414 }
415
util_ald_destroy_cache(util_ald_cache_t * cache)416 void util_ald_destroy_cache(util_ald_cache_t *cache)
417 {
418 unsigned long i;
419 util_cache_node_t *p, *q;
420
421 if (cache == NULL)
422 return;
423
424 for (i = 0; i < cache->size; ++i) {
425 p = cache->nodes[i];
426 q = NULL;
427 while (p != NULL) {
428 q = p->next;
429 (*cache->free)(cache, p->payload);
430 util_ald_free(cache, p);
431 p = q;
432 }
433 }
434 util_ald_free(cache, cache->nodes);
435 util_ald_free(cache, cache);
436 }
437
util_ald_cache_fetch(util_ald_cache_t * cache,void * payload)438 void *util_ald_cache_fetch(util_ald_cache_t *cache, void *payload)
439 {
440 unsigned long hashval;
441 util_cache_node_t *p;
442
443 if (cache == NULL)
444 return NULL;
445
446 cache->fetches++;
447
448 hashval = (*cache->hash)(payload) % cache->size;
449
450 for (p = cache->nodes[hashval];
451 p && !(*cache->compare)(p->payload, payload);
452 p = p->next) ;
453
454 if (p != NULL) {
455 cache->hits++;
456 return p->payload;
457 }
458 else {
459 return NULL;
460 }
461 }
462
463 /*
464 * Insert an item into the cache.
465 * *** Does not catch duplicates!!! ***
466 */
util_ald_cache_insert(util_ald_cache_t * cache,void * payload)467 void *util_ald_cache_insert(util_ald_cache_t *cache, void *payload)
468 {
469 unsigned long hashval;
470 void *tmp_payload;
471 util_cache_node_t *node;
472
473 /* sanity check */
474 if (cache == NULL || payload == NULL) {
475 return NULL;
476 }
477
478 /* check if we are full - if so, try purge */
479 if (cache->numentries >= cache->maxentries) {
480 util_ald_cache_purge(cache);
481 if (cache->numentries >= cache->maxentries) {
482 /* if the purge was not effective, we leave now to avoid an overflow */
483 ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, APLOGNO(01323)
484 "Purge of LDAP cache failed");
485 return NULL;
486 }
487 }
488
489 node = (util_cache_node_t *)util_ald_alloc(cache,
490 sizeof(util_cache_node_t));
491 if (node == NULL) {
492 /*
493 * XXX: The cache management should be rewritten to work
494 * properly when LDAPSharedCacheSize is too small.
495 */
496 ap_log_error(APLOG_MARK, APLOG_WARNING, 0, NULL, APLOGNO(01324)
497 "LDAPSharedCacheSize is too small. Increase it or "
498 "reduce LDAPCacheEntries/LDAPOpCacheEntries!");
499 if (cache->numentries < cache->fullmark) {
500 /*
501 * We have not even reached fullmark, trigger a complete purge.
502 * This is still better than not being able to add new entries
503 * at all.
504 */
505 cache->marktime = apr_time_now();
506 }
507 util_ald_cache_purge(cache);
508 node = (util_cache_node_t *)util_ald_alloc(cache,
509 sizeof(util_cache_node_t));
510 if (node == NULL) {
511 ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, APLOGNO(01325)
512 "Could not allocate memory for LDAP cache entry");
513 return NULL;
514 }
515 }
516
517 /* Take a copy of the payload before proceeding. */
518 tmp_payload = (*cache->copy)(cache, payload);
519 if (tmp_payload == NULL) {
520 /*
521 * XXX: The cache management should be rewritten to work
522 * properly when LDAPSharedCacheSize is too small.
523 */
524 ap_log_error(APLOG_MARK, APLOG_WARNING, 0, NULL, APLOGNO(01326)
525 "LDAPSharedCacheSize is too small. Increase it or "
526 "reduce LDAPCacheEntries/LDAPOpCacheEntries!");
527 if (cache->numentries < cache->fullmark) {
528 /*
529 * We have not even reached fullmark, trigger a complete purge.
530 * This is still better than not being able to add new entries
531 * at all.
532 */
533 cache->marktime = apr_time_now();
534 }
535 util_ald_cache_purge(cache);
536 tmp_payload = (*cache->copy)(cache, payload);
537 if (tmp_payload == NULL) {
538 ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, APLOGNO(01327)
539 "Could not allocate memory for LDAP cache value");
540 util_ald_free(cache, node);
541 return NULL;
542 }
543 }
544 payload = tmp_payload;
545
546 /* populate the entry */
547 cache->inserts++;
548 hashval = (*cache->hash)(payload) % cache->size;
549 node->add_time = apr_time_now();
550 node->payload = payload;
551 node->next = cache->nodes[hashval];
552 cache->nodes[hashval] = node;
553
554 /* if we reach the full mark, note the time we did so
555 * for the benefit of the purge function
556 */
557 if (++cache->numentries == cache->fullmark) {
558 cache->marktime=apr_time_now();
559 }
560
561 return node->payload;
562 }
563
util_ald_cache_remove(util_ald_cache_t * cache,void * payload)564 void util_ald_cache_remove(util_ald_cache_t *cache, void *payload)
565 {
566 unsigned long hashval;
567 util_cache_node_t *p, *q;
568
569 if (cache == NULL)
570 return;
571
572 cache->removes++;
573 hashval = (*cache->hash)(payload) % cache->size;
574 for (p = cache->nodes[hashval], q=NULL;
575 p && !(*cache->compare)(p->payload, payload);
576 p = p->next) {
577 q = p;
578 }
579
580 /* If p is null, it means that we couldn't find the node, so just return */
581 if (p == NULL)
582 return;
583
584 if (q == NULL) {
585 /* We found the node, and it's the first in the list */
586 cache->nodes[hashval] = p->next;
587 }
588 else {
589 /* We found the node and it's not the first in the list */
590 q->next = p->next;
591 }
592 (*cache->free)(cache, p->payload);
593 util_ald_free(cache, p);
594 cache->numentries--;
595 }
596
util_ald_cache_display_stats(request_rec * r,util_ald_cache_t * cache,char * name,char * id)597 char *util_ald_cache_display_stats(request_rec *r, util_ald_cache_t *cache, char *name, char *id)
598 {
599 unsigned long i;
600 int totchainlen = 0;
601 int nchains = 0;
602 double chainlen;
603 util_cache_node_t *n;
604 char *buf, *buf2;
605 apr_pool_t *p = r->pool;
606
607 if (cache == NULL) {
608 return "";
609 }
610
611 for (i=0; i < cache->size; ++i) {
612 if (cache->nodes[i] != NULL) {
613 nchains++;
614 for (n = cache->nodes[i];
615 n != NULL && n != n->next;
616 n = n->next) {
617 totchainlen++;
618 }
619 }
620 }
621 chainlen = nchains? (double)totchainlen / (double)nchains : 0;
622
623 if (id) {
624 buf2 = apr_psprintf(p,
625 "<a href=\"%s?%s\">%s</a>",
626 ap_escape_html(r->pool, ap_escape_uri(r->pool, r->uri)),
627 id,
628 name);
629 }
630 else {
631 buf2 = name;
632 }
633
634 buf = apr_psprintf(p,
635 "<tr valign='top'>"
636 "<td nowrap>%s</td>"
637 "<td align='right' nowrap>%lu (%.0f%% full)</td>"
638 "<td align='right'>%.1f</td>"
639 "<td align='right'>%lu/%lu</td>"
640 "<td align='right'>%.0f%%</td>"
641 "<td align='right'>%lu/%lu</td>",
642 buf2,
643 cache->numentries,
644 (double)cache->numentries / (double)cache->maxentries * 100.0,
645 chainlen,
646 cache->hits,
647 cache->fetches,
648 (cache->fetches > 0 ? (double)(cache->hits) / (double)(cache->fetches) * 100.0 : 100.0),
649 cache->inserts,
650 cache->removes);
651
652 if (cache->numpurges) {
653 char str_ctime[APR_CTIME_LEN];
654
655 apr_ctime(str_ctime, cache->last_purge);
656 buf = apr_psprintf(p,
657 "%s"
658 "<td align='right'>%lu</td>\n"
659 "<td align='right' nowrap>%s</td>\n",
660 buf,
661 cache->numpurges,
662 str_ctime);
663 }
664 else {
665 buf = apr_psprintf(p,
666 "%s<td colspan='2' align='center'>(none)</td>\n",
667 buf);
668 }
669
670 buf = apr_psprintf(p, "%s<td align='right'>%.2gms</td>\n</tr>", buf, cache->avg_purgetime);
671
672 return buf;
673 }
674
util_ald_cache_display(request_rec * r,util_ldap_state_t * st)675 char *util_ald_cache_display(request_rec *r, util_ldap_state_t *st)
676 {
677 unsigned long i,j;
678 char *buf, *t1, *t2, *t3;
679 char *id1, *id2, *id3;
680 char *argfmt = "cache=%s&id=%d&off=%d";
681 char *scanfmt = "cache=%4s&id=%u&off=%u%1s";
682 apr_pool_t *pool = r->pool;
683 util_cache_node_t *p = NULL;
684 util_url_node_t *n = NULL;
685
686 util_ald_cache_t *util_ldap_cache = st->util_ldap_cache;
687
688
689 if (!util_ldap_cache) {
690 ap_rputs("<tr valign='top'><td nowrap colspan=7>Cache has not been enabled/initialised.</td></tr>", r);
691 return NULL;
692 }
693
694 if (r->args && strlen(r->args)) {
695 char cachetype[5], lint[2];
696 unsigned int id, off;
697 char date_str[APR_CTIME_LEN];
698
699 if ((3 == sscanf(r->args, scanfmt, cachetype, &id, &off, lint)) &&
700 (id < util_ldap_cache->size)) {
701
702 if ((p = util_ldap_cache->nodes[id]) != NULL) {
703 n = (util_url_node_t *)p->payload;
704 buf = (char*)n->url;
705 }
706 else {
707 buf = "";
708 }
709
710 ap_rprintf(r,
711 "<p>\n"
712 "<table border='0'>\n"
713 "<tr>\n"
714 "<td bgcolor='#000000'><font size='-1' face='Arial,Helvetica' color='#ffffff'><b>Cache Name:</b></font></td>"
715 "<td bgcolor='#ffffff'><font size='-1' face='Arial,Helvetica' color='#000000'><b>%s (%s)</b></font></td>"
716 "</tr>\n"
717 "</table>\n</p>\n",
718 buf,
719 cachetype[0] == 'm'? "Main" :
720 (cachetype[0] == 's' ? "Search" :
721 (cachetype[0] == 'c' ? "Compares" : "DNCompares")));
722
723 switch (cachetype[0]) {
724 case 'm':
725 if (util_ldap_cache->marktime) {
726 apr_ctime(date_str, util_ldap_cache->marktime);
727 }
728 else
729 date_str[0] = 0;
730
731 ap_rprintf(r,
732 "<p>\n"
733 "<table border='0'>\n"
734 "<tr>\n"
735 "<td bgcolor='#000000'><font size='-1' face='Arial,Helvetica' color='#ffffff'><b>Size:</b></font></td>"
736 "<td bgcolor='#ffffff'><font size='-1' face='Arial,Helvetica' color='#000000'><b>%ld</b></font></td>"
737 "</tr>\n"
738 "<tr>\n"
739 "<td bgcolor='#000000'><font size='-1' face='Arial,Helvetica' color='#ffffff'><b>Max Entries:</b></font></td>"
740 "<td bgcolor='#ffffff'><font size='-1' face='Arial,Helvetica' color='#000000'><b>%ld</b></font></td>"
741 "</tr>\n"
742 "<tr>\n"
743 "<td bgcolor='#000000'><font size='-1' face='Arial,Helvetica' color='#ffffff'><b># Entries:</b></font></td>"
744 "<td bgcolor='#ffffff'><font size='-1' face='Arial,Helvetica' color='#000000'><b>%ld</b></font></td>"
745 "</tr>\n"
746 "<tr>\n"
747 "<td bgcolor='#000000'><font size='-1' face='Arial,Helvetica' color='#ffffff'><b>TTL (sec):</b></font></td>"
748 "<td bgcolor='#ffffff'><font size='-1' face='Arial,Helvetica' color='#000000'><b>%" APR_TIME_T_FMT "</b></font></td>"
749 "</tr>\n"
750 "<tr>\n"
751 "<td bgcolor='#000000'><font size='-1' face='Arial,Helvetica' color='#ffffff'><b>Full Mark:</b></font></td>"
752 "<td bgcolor='#ffffff'><font size='-1' face='Arial,Helvetica' color='#000000'><b>%ld</b></font></td>"
753 "</tr>\n"
754 "<tr>\n"
755 "<td bgcolor='#000000'><font size='-1' face='Arial,Helvetica' color='#ffffff'><b>Full Mark Time:</b></font></td>"
756 "<td bgcolor='#ffffff'><font size='-1' face='Arial,Helvetica' color='#000000'><b>%s</b></font></td>"
757 "</tr>\n"
758 "</table>\n</p>\n",
759 util_ldap_cache->size,
760 util_ldap_cache->maxentries,
761 util_ldap_cache->numentries,
762 apr_time_sec(util_ldap_cache->ttl),
763 util_ldap_cache->fullmark,
764 date_str);
765
766 ap_rputs("<p>\n"
767 "<table border='0'>\n"
768 "<tr bgcolor='#000000'>\n"
769 "<td><font size='-1' face='Arial,Helvetica' color='#ffffff'><b>LDAP URL</b></font></td>"
770 "<td><font size='-1' face='Arial,Helvetica' color='#ffffff'><b>Size</b></font></td>"
771 "<td><font size='-1' face='Arial,Helvetica' color='#ffffff'><b>Max Entries</b></font></td>"
772 "<td><font size='-1' face='Arial,Helvetica' color='#ffffff'><b># Entries</b></font></td>"
773 "<td><font size='-1' face='Arial,Helvetica' color='#ffffff'><b>TTL (sec)</b></font></td>"
774 "<td><font size='-1' face='Arial,Helvetica' color='#ffffff'><b>Full Mark</b></font></td>"
775 "<td><font size='-1' face='Arial,Helvetica' color='#ffffff'><b>Full Mark Time</b></font></td>"
776 "</tr>\n", r
777 );
778 for (i=0; i < util_ldap_cache->size; ++i) {
779 for (p = util_ldap_cache->nodes[i]; p != NULL; p = p->next) {
780
781 (*util_ldap_cache->display)(r, util_ldap_cache, p->payload);
782 }
783 }
784 ap_rputs("</table>\n</p>\n", r);
785
786
787 break;
788 case 's':
789 ap_rputs("<p>\n"
790 "<table border='0'>\n"
791 "<tr bgcolor='#000000'>\n"
792 "<td><font size='-1' face='Arial,Helvetica' color='#ffffff'><b>LDAP Filter</b></font></td>"
793 "<td><font size='-1' face='Arial,Helvetica' color='#ffffff'><b>User Name</b></font></td>"
794 "<td><font size='-1' face='Arial,Helvetica' color='#ffffff'><b>Last Bind</b></font></td>"
795 "</tr>\n", r
796 );
797 if (n) {
798 for (i=0; i < n->search_cache->size; ++i) {
799 for (p = n->search_cache->nodes[i]; p != NULL; p = p->next) {
800
801 (*n->search_cache->display)(r, n->search_cache, p->payload);
802 }
803 }
804 }
805 ap_rputs("</table>\n</p>\n", r);
806 break;
807 case 'c':
808 ap_rputs("<p>\n"
809 "<table border='0'>\n"
810 "<tr bgcolor='#000000'>\n"
811 "<td><font size='-1' face='Arial,Helvetica' color='#ffffff'><b>DN</b></font></td>"
812 "<td><font size='-1' face='Arial,Helvetica' color='#ffffff'><b>Attribute</b></font></td>"
813 "<td><font size='-1' face='Arial,Helvetica' color='#ffffff'><b>Value</b></font></td>"
814 "<td><font size='-1' face='Arial,Helvetica' color='#ffffff'><b>Last Compare</b></font></td>"
815 "<td><font size='-1' face='Arial,Helvetica' color='#ffffff'><b>Result</b></font></td>"
816 "<td><font size='-1' face='Arial,Helvetica' color='#ffffff'><b>Sub-groups?</b></font></td>"
817 "<td><font size='-1' face='Arial,Helvetica' color='#ffffff'><b>S-G Checked?</b></font></td>"
818 "</tr>\n", r
819 );
820 if (n) {
821 for (i=0; i < n->compare_cache->size; ++i) {
822 for (p = n->compare_cache->nodes[i]; p != NULL; p = p->next) {
823
824 (*n->compare_cache->display)(r, n->compare_cache, p->payload);
825 }
826 }
827 }
828 ap_rputs("</table>\n</p>\n", r);
829 break;
830 case 'd':
831 ap_rputs("<p>\n"
832 "<table border='0'>\n"
833 "<tr bgcolor='#000000'>\n"
834 "<td><font size='-1' face='Arial,Helvetica' color='#ffffff'><b>Require DN</b></font></td>"
835 "<td><font size='-1' face='Arial,Helvetica' color='#ffffff'><b>Actual DN</b></font></td>"
836 "</tr>\n", r
837 );
838 if (n) {
839 for (i=0; i < n->dn_compare_cache->size; ++i) {
840 for (p = n->dn_compare_cache->nodes[i]; p != NULL; p = p->next) {
841
842 (*n->dn_compare_cache->display)(r, n->dn_compare_cache, p->payload);
843 }
844 }
845 }
846 ap_rputs("</table>\n</p>\n", r);
847 break;
848 default:
849 break;
850 }
851
852 }
853 else {
854 buf = "";
855 }
856 }
857 else {
858 ap_rputs("<p>\n"
859 "<table border='0'>\n"
860 "<tr bgcolor='#000000'>\n"
861 "<td><font size='-1' face='Arial,Helvetica' color='#ffffff'><b>Cache Name</b></font></td>"
862 "<td><font size='-1' face='Arial,Helvetica' color='#ffffff'><b>Entries</b></font></td>"
863 "<td><font size='-1' face='Arial,Helvetica' color='#ffffff'><b>Avg. Chain Len.</b></font></td>"
864 "<td colspan='2'><font size='-1' face='Arial,Helvetica' color='#ffffff'><b>Hits</b></font></td>"
865 "<td><font size='-1' face='Arial,Helvetica' color='#ffffff'><b>Ins/Rem</b></font></td>"
866 "<td colspan='2'><font size='-1' face='Arial,Helvetica' color='#ffffff'><b>Purges</b></font></td>"
867 "<td><font size='-1' face='Arial,Helvetica' color='#ffffff'><b>Avg Purge Time</b></font></td>"
868 "</tr>\n", r
869 );
870
871
872 id1 = apr_psprintf(pool, argfmt, "main", 0, 0);
873 buf = util_ald_cache_display_stats(r, st->util_ldap_cache, "LDAP URL Cache", id1);
874
875 for (i=0; i < util_ldap_cache->size; ++i) {
876 for (p = util_ldap_cache->nodes[i],j=0; p != NULL; p = p->next,j++) {
877
878 n = (util_url_node_t *)p->payload;
879
880 t1 = apr_psprintf(pool, "%s (Searches)", n->url);
881 t2 = apr_psprintf(pool, "%s (Compares)", n->url);
882 t3 = apr_psprintf(pool, "%s (DNCompares)", n->url);
883 id1 = apr_psprintf(pool, argfmt, "srch", i, j);
884 id2 = apr_psprintf(pool, argfmt, "cmpr", i, j);
885 id3 = apr_psprintf(pool, argfmt, "dncp", i, j);
886
887 buf = apr_psprintf(pool, "%s\n\n"
888 "%s\n\n"
889 "%s\n\n"
890 "%s\n\n",
891 buf,
892 util_ald_cache_display_stats(r, n->search_cache, t1, id1),
893 util_ald_cache_display_stats(r, n->compare_cache, t2, id2),
894 util_ald_cache_display_stats(r, n->dn_compare_cache, t3, id3)
895 );
896 }
897 }
898 ap_rputs(buf, r);
899 ap_rputs("</table>\n</p>\n", r);
900 }
901
902 return buf;
903 }
904
905 #endif /* APR_HAS_LDAP */
906