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 30APLOG_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 40static 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 79void 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 98void *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 117const 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 */ 145util_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 */ 184void 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 */ 202unsigned 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*/ 232void 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 t; 237 238 if (!cache) 239 return; 240 241 cache->last_purge = apr_time_now(); 242 cache->npurged = 0; 243 cache->numpurges++; 244 245 for (i=0; i < cache->size; ++i) { 246 pp = cache->nodes + i; 247 p = *pp; 248 while (p != NULL) { 249 if (p->add_time < cache->marktime) { 250 q = p->next; 251 (*cache->free)(cache, p->payload); 252 util_ald_free(cache, p); 253 cache->numentries--; 254 cache->npurged++; 255 p = *pp = q; 256 } 257 else { 258 pp = &(p->next); 259 p = *pp; 260 } 261 } 262 } 263 264 t = apr_time_now(); 265 cache->avg_purgetime = 266 ((t - cache->last_purge) + (cache->avg_purgetime * (cache->numpurges-1))) / 267 cache->numpurges; 268} 269 270 271/* 272 * create caches 273 */ 274util_url_node_t *util_ald_create_caches(util_ldap_state_t *st, const char *url) 275{ 276 util_url_node_t curl, *newcurl = NULL; 277 util_ald_cache_t *search_cache; 278 util_ald_cache_t *compare_cache; 279 util_ald_cache_t *dn_compare_cache; 280 281 /* create the three caches */ 282 search_cache = util_ald_create_cache(st, 283 st->search_cache_size, 284 util_ldap_search_node_hash, 285 util_ldap_search_node_compare, 286 util_ldap_search_node_copy, 287 util_ldap_search_node_free, 288 util_ldap_search_node_display); 289 compare_cache = util_ald_create_cache(st, 290 st->compare_cache_size, 291 util_ldap_compare_node_hash, 292 util_ldap_compare_node_compare, 293 util_ldap_compare_node_copy, 294 util_ldap_compare_node_free, 295 util_ldap_compare_node_display); 296 dn_compare_cache = util_ald_create_cache(st, 297 st->compare_cache_size, 298 util_ldap_dn_compare_node_hash, 299 util_ldap_dn_compare_node_compare, 300 util_ldap_dn_compare_node_copy, 301 util_ldap_dn_compare_node_free, 302 util_ldap_dn_compare_node_display); 303 304 /* check that all the caches initialised successfully */ 305 if (search_cache && compare_cache && dn_compare_cache) { 306 307 /* The contents of this structure will be duplicated in shared 308 memory during the insert. So use stack memory rather than 309 pool memory to avoid a memory leak. */ 310 memset (&curl, 0, sizeof(util_url_node_t)); 311 curl.url = url; 312 curl.search_cache = search_cache; 313 curl.compare_cache = compare_cache; 314 curl.dn_compare_cache = dn_compare_cache; 315 316 newcurl = util_ald_cache_insert(st->util_ldap_cache, &curl); 317 318 } 319 320 return newcurl; 321} 322 323 324util_ald_cache_t *util_ald_create_cache(util_ldap_state_t *st, 325 long cache_size, 326 unsigned long (*hashfunc)(void *), 327 int (*comparefunc)(void *, void *), 328 void * (*copyfunc)(util_ald_cache_t *cache, void *), 329 void (*freefunc)(util_ald_cache_t *cache, void *), 330 void (*displayfunc)(request_rec *r, util_ald_cache_t *cache, void *)) 331{ 332 util_ald_cache_t *cache; 333 unsigned long i; 334#if APR_HAS_SHARED_MEMORY 335 apr_rmm_off_t block; 336#endif 337 338 if (cache_size <= 0) 339 return NULL; 340 341#if APR_HAS_SHARED_MEMORY 342 if (!st->cache_rmm) { 343 cache = (util_ald_cache_t *)calloc(sizeof(util_ald_cache_t), 1); 344 } 345 else { 346 block = apr_rmm_calloc(st->cache_rmm, sizeof(util_ald_cache_t)); 347 cache = block ? (util_ald_cache_t *)apr_rmm_addr_get(st->cache_rmm, block) : NULL; 348 } 349#else 350 cache = (util_ald_cache_t *)calloc(sizeof(util_ald_cache_t), 1); 351#endif 352 if (!cache) 353 return NULL; 354 355#if APR_HAS_SHARED_MEMORY 356 cache->rmm_addr = st->cache_rmm; 357 cache->shm_addr = st->cache_shm; 358#endif 359 cache->maxentries = cache_size; 360 cache->numentries = 0; 361 cache->size = cache_size / 3; 362 if (cache->size < 64) cache->size = 64; 363 for (i = 0; primes[i] && primes[i] < cache->size; ++i) ; 364 cache->size = primes[i]? primes[i] : primes[i-1]; 365 366 cache->nodes = (util_cache_node_t **)util_ald_alloc(cache, cache->size * sizeof(util_cache_node_t *)); 367 if (!cache->nodes) { 368 /* This frees cache in the right way even if !APR_HAS_SHARED_MEMORY or !st->cache_rmm */ 369 util_ald_free(cache, cache); 370 return NULL; 371 } 372 373 for (i=0; i < cache->size; ++i) 374 cache->nodes[i] = NULL; 375 376 cache->hash = hashfunc; 377 cache->compare = comparefunc; 378 cache->copy = copyfunc; 379 cache->free = freefunc; 380 cache->display = displayfunc; 381 382 cache->fullmark = cache->maxentries / 4 * 3; 383 cache->marktime = 0; 384 cache->avg_purgetime = 0.0; 385 cache->numpurges = 0; 386 cache->last_purge = 0; 387 cache->npurged = 0; 388 389 cache->fetches = 0; 390 cache->hits = 0; 391 cache->inserts = 0; 392 cache->removes = 0; 393 394 return cache; 395} 396 397void util_ald_destroy_cache(util_ald_cache_t *cache) 398{ 399 unsigned long i; 400 util_cache_node_t *p, *q; 401 402 if (cache == NULL) 403 return; 404 405 for (i = 0; i < cache->size; ++i) { 406 p = cache->nodes[i]; 407 q = NULL; 408 while (p != NULL) { 409 q = p->next; 410 (*cache->free)(cache, p->payload); 411 util_ald_free(cache, p); 412 p = q; 413 } 414 } 415 util_ald_free(cache, cache->nodes); 416 util_ald_free(cache, cache); 417} 418 419void *util_ald_cache_fetch(util_ald_cache_t *cache, void *payload) 420{ 421 unsigned long hashval; 422 util_cache_node_t *p; 423 424 if (cache == NULL) 425 return NULL; 426 427 cache->fetches++; 428 429 hashval = (*cache->hash)(payload) % cache->size; 430 431 for (p = cache->nodes[hashval]; 432 p && !(*cache->compare)(p->payload, payload); 433 p = p->next) ; 434 435 if (p != NULL) { 436 cache->hits++; 437 return p->payload; 438 } 439 else { 440 return NULL; 441 } 442} 443 444/* 445 * Insert an item into the cache. 446 * *** Does not catch duplicates!!! *** 447 */ 448void *util_ald_cache_insert(util_ald_cache_t *cache, void *payload) 449{ 450 unsigned long hashval; 451 void *tmp_payload; 452 util_cache_node_t *node; 453 454 /* sanity check */ 455 if (cache == NULL || payload == NULL) { 456 return NULL; 457 } 458 459 /* check if we are full - if so, try purge */ 460 if (cache->numentries >= cache->maxentries) { 461 util_ald_cache_purge(cache); 462 if (cache->numentries >= cache->maxentries) { 463 /* if the purge was not effective, we leave now to avoid an overflow */ 464 ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, APLOGNO(01323) 465 "Purge of LDAP cache failed"); 466 return NULL; 467 } 468 } 469 470 node = (util_cache_node_t *)util_ald_alloc(cache, 471 sizeof(util_cache_node_t)); 472 if (node == NULL) { 473 /* 474 * XXX: The cache management should be rewritten to work 475 * properly when LDAPSharedCacheSize is too small. 476 */ 477 ap_log_error(APLOG_MARK, APLOG_WARNING, 0, NULL, APLOGNO(01324) 478 "LDAPSharedCacheSize is too small. Increase it or " 479 "reduce LDAPCacheEntries/LDAPOpCacheEntries!"); 480 if (cache->numentries < cache->fullmark) { 481 /* 482 * We have not even reached fullmark, trigger a complete purge. 483 * This is still better than not being able to add new entries 484 * at all. 485 */ 486 cache->marktime = apr_time_now(); 487 } 488 util_ald_cache_purge(cache); 489 node = (util_cache_node_t *)util_ald_alloc(cache, 490 sizeof(util_cache_node_t)); 491 if (node == NULL) { 492 ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, APLOGNO(01325) 493 "Could not allocate memory for LDAP cache entry"); 494 return NULL; 495 } 496 } 497 498 /* Take a copy of the payload before proceeeding. */ 499 tmp_payload = (*cache->copy)(cache, payload); 500 if (tmp_payload == NULL) { 501 /* 502 * XXX: The cache management should be rewritten to work 503 * properly when LDAPSharedCacheSize is too small. 504 */ 505 ap_log_error(APLOG_MARK, APLOG_WARNING, 0, NULL, APLOGNO(01326) 506 "LDAPSharedCacheSize is too small. Increase it or " 507 "reduce LDAPCacheEntries/LDAPOpCacheEntries!"); 508 if (cache->numentries < cache->fullmark) { 509 /* 510 * We have not even reached fullmark, trigger a complete purge. 511 * This is still better than not being able to add new entries 512 * at all. 513 */ 514 cache->marktime = apr_time_now(); 515 } 516 util_ald_cache_purge(cache); 517 tmp_payload = (*cache->copy)(cache, payload); 518 if (tmp_payload == NULL) { 519 ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, APLOGNO(01327) 520 "Could not allocate memory for LDAP cache value"); 521 util_ald_free(cache, node); 522 return NULL; 523 } 524 } 525 payload = tmp_payload; 526 527 /* populate the entry */ 528 cache->inserts++; 529 hashval = (*cache->hash)(payload) % cache->size; 530 node->add_time = apr_time_now(); 531 node->payload = payload; 532 node->next = cache->nodes[hashval]; 533 cache->nodes[hashval] = node; 534 535 /* if we reach the full mark, note the time we did so 536 * for the benefit of the purge function 537 */ 538 if (++cache->numentries == cache->fullmark) { 539 cache->marktime=apr_time_now(); 540 } 541 542 return node->payload; 543} 544 545void util_ald_cache_remove(util_ald_cache_t *cache, void *payload) 546{ 547 unsigned long hashval; 548 util_cache_node_t *p, *q; 549 550 if (cache == NULL) 551 return; 552 553 cache->removes++; 554 hashval = (*cache->hash)(payload) % cache->size; 555 for (p = cache->nodes[hashval], q=NULL; 556 p && !(*cache->compare)(p->payload, payload); 557 p = p->next) { 558 q = p; 559 } 560 561 /* If p is null, it means that we couldn't find the node, so just return */ 562 if (p == NULL) 563 return; 564 565 if (q == NULL) { 566 /* We found the node, and it's the first in the list */ 567 cache->nodes[hashval] = p->next; 568 } 569 else { 570 /* We found the node and it's not the first in the list */ 571 q->next = p->next; 572 } 573 (*cache->free)(cache, p->payload); 574 util_ald_free(cache, p); 575 cache->numentries--; 576} 577 578char *util_ald_cache_display_stats(request_rec *r, util_ald_cache_t *cache, char *name, char *id) 579{ 580 unsigned long i; 581 int totchainlen = 0; 582 int nchains = 0; 583 double chainlen; 584 util_cache_node_t *n; 585 char *buf, *buf2; 586 apr_pool_t *p = r->pool; 587 588 if (cache == NULL) { 589 return ""; 590 } 591 592 for (i=0; i < cache->size; ++i) { 593 if (cache->nodes[i] != NULL) { 594 nchains++; 595 for (n = cache->nodes[i]; 596 n != NULL && n != n->next; 597 n = n->next) { 598 totchainlen++; 599 } 600 } 601 } 602 chainlen = nchains? (double)totchainlen / (double)nchains : 0; 603 604 if (id) { 605 buf2 = apr_psprintf(p, 606 "<a href=\"%s?%s\">%s</a>", 607 ap_escape_html(r->pool, ap_escape_uri(r->pool, r->uri)), 608 id, 609 name); 610 } 611 else { 612 buf2 = name; 613 } 614 615 buf = apr_psprintf(p, 616 "<tr valign='top'>" 617 "<td nowrap>%s</td>" 618 "<td align='right' nowrap>%lu (%.0f%% full)</td>" 619 "<td align='right'>%.1f</td>" 620 "<td align='right'>%lu/%lu</td>" 621 "<td align='right'>%.0f%%</td>" 622 "<td align='right'>%lu/%lu</td>", 623 buf2, 624 cache->numentries, 625 (double)cache->numentries / (double)cache->maxentries * 100.0, 626 chainlen, 627 cache->hits, 628 cache->fetches, 629 (cache->fetches > 0 ? (double)(cache->hits) / (double)(cache->fetches) * 100.0 : 100.0), 630 cache->inserts, 631 cache->removes); 632 633 if (cache->numpurges) { 634 char str_ctime[APR_CTIME_LEN]; 635 636 apr_ctime(str_ctime, cache->last_purge); 637 buf = apr_psprintf(p, 638 "%s" 639 "<td align='right'>%lu</td>\n" 640 "<td align='right' nowrap>%s</td>\n", 641 buf, 642 cache->numpurges, 643 str_ctime); 644 } 645 else { 646 buf = apr_psprintf(p, 647 "%s<td colspan='2' align='center'>(none)</td>\n", 648 buf); 649 } 650 651 buf = apr_psprintf(p, "%s<td align='right'>%.2gms</td>\n</tr>", buf, cache->avg_purgetime); 652 653 return buf; 654} 655 656char *util_ald_cache_display(request_rec *r, util_ldap_state_t *st) 657{ 658 unsigned long i,j; 659 char *buf, *t1, *t2, *t3; 660 char *id1, *id2, *id3; 661 char *argfmt = "cache=%s&id=%d&off=%d"; 662 char *scanfmt = "cache=%4s&id=%u&off=%u%1s"; 663 apr_pool_t *pool = r->pool; 664 util_cache_node_t *p = NULL; 665 util_url_node_t *n = NULL; 666 667 util_ald_cache_t *util_ldap_cache = st->util_ldap_cache; 668 669 670 if (!util_ldap_cache) { 671 ap_rputs("<tr valign='top'><td nowrap colspan=7>Cache has not been enabled/initialised.</td></tr>", r); 672 return NULL; 673 } 674 675 if (r->args && strlen(r->args)) { 676 char cachetype[5], lint[2]; 677 unsigned int id, off; 678 char date_str[APR_CTIME_LEN]; 679 680 if ((3 == sscanf(r->args, scanfmt, cachetype, &id, &off, lint)) && 681 (id < util_ldap_cache->size)) { 682 683 if ((p = util_ldap_cache->nodes[id]) != NULL) { 684 n = (util_url_node_t *)p->payload; 685 buf = (char*)n->url; 686 } 687 else { 688 buf = ""; 689 } 690 691 ap_rprintf(r, 692 "<p>\n" 693 "<table border='0'>\n" 694 "<tr>\n" 695 "<td bgcolor='#000000'><font size='-1' face='Arial,Helvetica' color='#ffffff'><b>Cache Name:</b></font></td>" 696 "<td bgcolor='#ffffff'><font size='-1' face='Arial,Helvetica' color='#000000'><b>%s (%s)</b></font></td>" 697 "</tr>\n" 698 "</table>\n</p>\n", 699 buf, 700 cachetype[0] == 'm'? "Main" : 701 (cachetype[0] == 's' ? "Search" : 702 (cachetype[0] == 'c' ? "Compares" : "DNCompares"))); 703 704 switch (cachetype[0]) { 705 case 'm': 706 if (util_ldap_cache->marktime) { 707 apr_ctime(date_str, util_ldap_cache->marktime); 708 } 709 else 710 date_str[0] = 0; 711 712 ap_rprintf(r, 713 "<p>\n" 714 "<table border='0'>\n" 715 "<tr>\n" 716 "<td bgcolor='#000000'><font size='-1' face='Arial,Helvetica' color='#ffffff'><b>Size:</b></font></td>" 717 "<td bgcolor='#ffffff'><font size='-1' face='Arial,Helvetica' color='#000000'><b>%ld</b></font></td>" 718 "</tr>\n" 719 "<tr>\n" 720 "<td bgcolor='#000000'><font size='-1' face='Arial,Helvetica' color='#ffffff'><b>Max Entries:</b></font></td>" 721 "<td bgcolor='#ffffff'><font size='-1' face='Arial,Helvetica' color='#000000'><b>%ld</b></font></td>" 722 "</tr>\n" 723 "<tr>\n" 724 "<td bgcolor='#000000'><font size='-1' face='Arial,Helvetica' color='#ffffff'><b># Entries:</b></font></td>" 725 "<td bgcolor='#ffffff'><font size='-1' face='Arial,Helvetica' color='#000000'><b>%ld</b></font></td>" 726 "</tr>\n" 727 "<tr>\n" 728 "<td bgcolor='#000000'><font size='-1' face='Arial,Helvetica' color='#ffffff'><b>Full Mark:</b></font></td>" 729 "<td bgcolor='#ffffff'><font size='-1' face='Arial,Helvetica' color='#000000'><b>%ld</b></font></td>" 730 "</tr>\n" 731 "<tr>\n" 732 "<td bgcolor='#000000'><font size='-1' face='Arial,Helvetica' color='#ffffff'><b>Full Mark Time:</b></font></td>" 733 "<td bgcolor='#ffffff'><font size='-1' face='Arial,Helvetica' color='#000000'><b>%s</b></font></td>" 734 "</tr>\n" 735 "</table>\n</p>\n", 736 util_ldap_cache->size, 737 util_ldap_cache->maxentries, 738 util_ldap_cache->numentries, 739 util_ldap_cache->fullmark, 740 date_str); 741 742 ap_rputs("<p>\n" 743 "<table border='0'>\n" 744 "<tr bgcolor='#000000'>\n" 745 "<td><font size='-1' face='Arial,Helvetica' color='#ffffff'><b>LDAP URL</b></font></td>" 746 "<td><font size='-1' face='Arial,Helvetica' color='#ffffff'><b>Size</b></font></td>" 747 "<td><font size='-1' face='Arial,Helvetica' color='#ffffff'><b>Max Entries</b></font></td>" 748 "<td><font size='-1' face='Arial,Helvetica' color='#ffffff'><b># Entries</b></font></td>" 749 "<td><font size='-1' face='Arial,Helvetica' color='#ffffff'><b>Full Mark</b></font></td>" 750 "<td><font size='-1' face='Arial,Helvetica' color='#ffffff'><b>Full Mark Time</b></font></td>" 751 "</tr>\n", r 752 ); 753 for (i=0; i < util_ldap_cache->size; ++i) { 754 for (p = util_ldap_cache->nodes[i]; p != NULL; p = p->next) { 755 756 (*util_ldap_cache->display)(r, util_ldap_cache, p->payload); 757 } 758 } 759 ap_rputs("</table>\n</p>\n", r); 760 761 762 break; 763 case 's': 764 ap_rputs("<p>\n" 765 "<table border='0'>\n" 766 "<tr bgcolor='#000000'>\n" 767 "<td><font size='-1' face='Arial,Helvetica' color='#ffffff'><b>LDAP Filter</b></font></td>" 768 "<td><font size='-1' face='Arial,Helvetica' color='#ffffff'><b>User Name</b></font></td>" 769 "<td><font size='-1' face='Arial,Helvetica' color='#ffffff'><b>Last Bind</b></font></td>" 770 "</tr>\n", r 771 ); 772 if (n) { 773 for (i=0; i < n->search_cache->size; ++i) { 774 for (p = n->search_cache->nodes[i]; p != NULL; p = p->next) { 775 776 (*n->search_cache->display)(r, n->search_cache, p->payload); 777 } 778 } 779 } 780 ap_rputs("</table>\n</p>\n", r); 781 break; 782 case 'c': 783 ap_rputs("<p>\n" 784 "<table border='0'>\n" 785 "<tr bgcolor='#000000'>\n" 786 "<td><font size='-1' face='Arial,Helvetica' color='#ffffff'><b>DN</b></font></td>" 787 "<td><font size='-1' face='Arial,Helvetica' color='#ffffff'><b>Attribute</b></font></td>" 788 "<td><font size='-1' face='Arial,Helvetica' color='#ffffff'><b>Value</b></font></td>" 789 "<td><font size='-1' face='Arial,Helvetica' color='#ffffff'><b>Last Compare</b></font></td>" 790 "<td><font size='-1' face='Arial,Helvetica' color='#ffffff'><b>Result</b></font></td>" 791 "<td><font size='-1' face='Arial,Helvetica' color='#ffffff'><b>Sub-groups?</b></font></td>" 792 "<td><font size='-1' face='Arial,Helvetica' color='#ffffff'><b>S-G Checked?</b></font></td>" 793 "</tr>\n", r 794 ); 795 if (n) { 796 for (i=0; i < n->compare_cache->size; ++i) { 797 for (p = n->compare_cache->nodes[i]; p != NULL; p = p->next) { 798 799 (*n->compare_cache->display)(r, n->compare_cache, p->payload); 800 } 801 } 802 } 803 ap_rputs("</table>\n</p>\n", r); 804 break; 805 case 'd': 806 ap_rputs("<p>\n" 807 "<table border='0'>\n" 808 "<tr bgcolor='#000000'>\n" 809 "<td><font size='-1' face='Arial,Helvetica' color='#ffffff'><b>Require DN</b></font></td>" 810 "<td><font size='-1' face='Arial,Helvetica' color='#ffffff'><b>Actual DN</b></font></td>" 811 "</tr>\n", r 812 ); 813 if (n) { 814 for (i=0; i < n->dn_compare_cache->size; ++i) { 815 for (p = n->dn_compare_cache->nodes[i]; p != NULL; p = p->next) { 816 817 (*n->dn_compare_cache->display)(r, n->dn_compare_cache, p->payload); 818 } 819 } 820 } 821 ap_rputs("</table>\n</p>\n", r); 822 break; 823 default: 824 break; 825 } 826 827 } 828 else { 829 buf = ""; 830 } 831 } 832 else { 833 ap_rputs("<p>\n" 834 "<table border='0'>\n" 835 "<tr bgcolor='#000000'>\n" 836 "<td><font size='-1' face='Arial,Helvetica' color='#ffffff'><b>Cache Name</b></font></td>" 837 "<td><font size='-1' face='Arial,Helvetica' color='#ffffff'><b>Entries</b></font></td>" 838 "<td><font size='-1' face='Arial,Helvetica' color='#ffffff'><b>Avg. Chain Len.</b></font></td>" 839 "<td colspan='2'><font size='-1' face='Arial,Helvetica' color='#ffffff'><b>Hits</b></font></td>" 840 "<td><font size='-1' face='Arial,Helvetica' color='#ffffff'><b>Ins/Rem</b></font></td>" 841 "<td colspan='2'><font size='-1' face='Arial,Helvetica' color='#ffffff'><b>Purges</b></font></td>" 842 "<td><font size='-1' face='Arial,Helvetica' color='#ffffff'><b>Avg Purge Time</b></font></td>" 843 "</tr>\n", r 844 ); 845 846 847 id1 = apr_psprintf(pool, argfmt, "main", 0, 0); 848 buf = util_ald_cache_display_stats(r, st->util_ldap_cache, "LDAP URL Cache", id1); 849 850 for (i=0; i < util_ldap_cache->size; ++i) { 851 for (p = util_ldap_cache->nodes[i],j=0; p != NULL; p = p->next,j++) { 852 853 n = (util_url_node_t *)p->payload; 854 855 t1 = apr_psprintf(pool, "%s (Searches)", n->url); 856 t2 = apr_psprintf(pool, "%s (Compares)", n->url); 857 t3 = apr_psprintf(pool, "%s (DNCompares)", n->url); 858 id1 = apr_psprintf(pool, argfmt, "srch", i, j); 859 id2 = apr_psprintf(pool, argfmt, "cmpr", i, j); 860 id3 = apr_psprintf(pool, argfmt, "dncp", i, j); 861 862 buf = apr_psprintf(pool, "%s\n\n" 863 "%s\n\n" 864 "%s\n\n" 865 "%s\n\n", 866 buf, 867 util_ald_cache_display_stats(r, n->search_cache, t1, id1), 868 util_ald_cache_display_stats(r, n->compare_cache, t2, id2), 869 util_ald_cache_display_stats(r, n->dn_compare_cache, t3, id3) 870 ); 871 } 872 } 873 ap_rputs(buf, r); 874 ap_rputs("</table>\n</p>\n", r); 875 } 876 877 return buf; 878} 879 880#endif /* APR_HAS_LDAP */ 881