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