1/* $NetBSD: slapd-watcher.c,v 1.2 2021/08/14 16:15:03 christos Exp $ */ 2 3/* $OpenLDAP$ */ 4/* This work is part of OpenLDAP Software <http://www.openldap.org/>. 5 * 6 * Copyright 1999-2021 The OpenLDAP Foundation. 7 * All rights reserved. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted only as authorized by the OpenLDAP 11 * Public License. 12 * 13 * A copy of this license is available in file LICENSE in the 14 * top-level directory of the distribution or, alternatively, at 15 * <http://www.OpenLDAP.org/license.html>. 16 */ 17/* ACKNOWLEDGEMENTS: 18 * This work was initially developed by Howard Chu for inclusion 19 * in OpenLDAP Software. 20 */ 21 22#include <sys/cdefs.h> 23__RCSID("$NetBSD: slapd-watcher.c,v 1.2 2021/08/14 16:15:03 christos Exp $"); 24 25#include "portable.h" 26 27#include <stdio.h> 28 29#include "ac/signal.h" 30#include "ac/stdlib.h" 31#include "ac/time.h" 32 33#include "ac/ctype.h" 34#include "ac/param.h" 35#include "ac/socket.h" 36#include "ac/string.h" 37#include "ac/unistd.h" 38#include "ac/wait.h" 39#include "ac/time.h" 40 41#include "ldap.h" 42#include "lutil.h" 43#include "lutil_ldap.h" 44#include "lber_pvt.h" 45#include "ldap_pvt.h" 46 47#include "slapd-common.h" 48 49#define SLAP_SYNC_SID_MAX 4095 50 51#define HAS_MONITOR 1 52#define HAS_BASE 2 53#define HAS_ENTRIES 4 54#define HAS_SREPL 8 55#define HAS_ALL (HAS_MONITOR|HAS_BASE|HAS_ENTRIES|HAS_SREPL) 56 57 58#define WAS_LATE 0x100 59#define WAS_DOWN 0x200 60 61#define MONFILTER "(objectClass=monitorOperation)" 62 63static const char *default_monfilter = MONFILTER; 64 65typedef enum { 66 SLAP_OP_BIND = 0, 67 SLAP_OP_UNBIND, 68 SLAP_OP_SEARCH, 69 SLAP_OP_COMPARE, 70 SLAP_OP_MODIFY, 71 SLAP_OP_MODRDN, 72 SLAP_OP_ADD, 73 SLAP_OP_DELETE, 74 SLAP_OP_ABANDON, 75 SLAP_OP_EXTENDED, 76 SLAP_OP_LAST 77} slap_op_t; 78 79struct opname { 80 struct berval rdn; 81 char *display; 82} opnames[] = { 83 { BER_BVC("cn=Bind"), "Bind" }, 84 { BER_BVC("cn=Unbind"), "Unbind" }, 85 { BER_BVC("cn=Search"), "Search" }, 86 { BER_BVC("cn=Compare"), "Compare" }, 87 { BER_BVC("cn=Modify"), "Modify" }, 88 { BER_BVC("cn=Modrdn"), "ModDN" }, 89 { BER_BVC("cn=Add"), "Add" }, 90 { BER_BVC("cn=Delete"), "Delete" }, 91 { BER_BVC("cn=Abandon"), "Abandon" }, 92 { BER_BVC("cn=Extended"), "Extended" }, 93 { BER_BVNULL, NULL } 94}; 95 96typedef struct counters { 97 struct timeval time; 98 unsigned long entries; 99 unsigned long ops[SLAP_OP_LAST]; 100} counters; 101 102typedef struct csns { 103 struct berval *vals; 104 struct timeval *tvs; 105} csns; 106 107typedef struct activity { 108 time_t active; 109 time_t idle; 110 time_t maxlag; 111 time_t lag; 112} activity; 113 114typedef struct server { 115 char *url; 116 LDAP *ld; 117 int flags; 118 int sid; 119 struct berval monitorbase; 120 char *monitorfilter; 121 time_t late; 122 time_t down; 123 counters c_prev; 124 counters c_curr; 125 csns csn_prev; 126 csns csn_curr; 127 activity *times; 128} server; 129 130static void 131usage( char *name, char opt ) 132{ 133 if ( opt ) { 134 fprintf( stderr, "%s: unable to handle option \'%c\'\n\n", 135 name, opt ); 136 } 137 138 fprintf( stderr, "usage: %s " 139 "[-D <dn> [ -w <passwd> ]] " 140 "[-d <level>] " 141 "[-O <SASL secprops>] " 142 "[-R <SASL realm>] " 143 "[-U <SASL authcid> [-X <SASL authzid>]] " 144 "[-x | -Y <SASL mech>] " 145 "[-i <interval>] " 146 "[-s <sids>] " 147 "[-b <baseDN> ] URI[...]\n", 148 name ); 149 exit( EXIT_FAILURE ); 150} 151 152struct berval base; 153int interval = 10; 154int numservers; 155server *servers; 156char *monfilter; 157 158struct berval at_namingContexts = BER_BVC("namingContexts"); 159struct berval at_monitorOpCompleted = BER_BVC("monitorOpCompleted"); 160struct berval at_olmMDBEntries = BER_BVC("olmMDBEntries"); 161struct berval at_contextCSN = BER_BVC("contextCSN"); 162 163void timestamp(time_t *tt) 164{ 165 struct tm *tm = gmtime(tt); 166 printf("%d-%02d-%02d %02d:%02d:%02d", 167 tm->tm_year + 1900, tm->tm_mon+1, tm->tm_mday, 168 tm->tm_hour, tm->tm_min, tm->tm_sec); 169} 170 171void deltat(time_t *tt) 172{ 173 struct tm *tm = gmtime(tt); 174 if (tm->tm_mday-1) 175 printf("%02d+", tm->tm_mday-1); 176 printf("%02d:%02d:%02d", 177 tm->tm_hour, tm->tm_min, tm->tm_sec); 178} 179 180static char *clearscreen = "\033[H\033[2J"; 181 182void rotate_stats( server *sv ) 183{ 184 if ( sv->flags & HAS_MONITOR ) 185 sv->c_prev = sv->c_curr; 186 if ( sv->flags & HAS_BASE ) { 187 int i; 188 189 for (i=0; i<numservers; i++) { 190 if ( sv->csn_curr.vals[i].bv_len ) { 191 ber_bvreplace(&sv->csn_prev.vals[i], 192 &sv->csn_curr.vals[i]); 193 sv->csn_prev.tvs[i] = sv->csn_curr.tvs[i]; 194 } else { 195 if ( sv->csn_prev.vals[i].bv_val ) 196 sv->csn_prev.vals[i].bv_val[0] = '\0'; 197 } 198 } 199 } 200} 201 202void display() 203{ 204 int i, j; 205 struct timeval now; 206 time_t now_t; 207 208 gettimeofday(&now, NULL); 209 now_t = now.tv_sec; 210 printf("%s", clearscreen); 211 timestamp(&now_t); 212 printf("\n"); 213 214 for (i=0; i<numservers; i++) { 215 printf("\n%s", servers[i].url ); 216 if ( servers[i].flags & WAS_DOWN ) { 217 printf(", down@"); 218 timestamp( &servers[i].down ); 219 } 220 if ( servers[i].flags & WAS_LATE ) { 221 printf(", late@"); 222 timestamp( &servers[i].late ); 223 } 224 printf("\n"); 225 if ( servers[i].flags & HAS_MONITOR ) { 226 struct timeval tv; 227 double rate, duration; 228 long delta; 229 printf(" "); 230 if ( servers[i].flags & HAS_ENTRIES ) 231 printf(" Entries "); 232 for ( j = 0; j<SLAP_OP_LAST; j++ ) 233 printf(" %9s ", opnames[j].display); 234 printf("\n"); 235 printf("Num "); 236 if ( servers[i].flags & HAS_ENTRIES ) 237 printf("%10lu ", servers[i].c_curr.entries); 238 for ( j = 0; j<SLAP_OP_LAST; j++ ) 239 printf("%10lu ", servers[i].c_curr.ops[j]); 240 printf("\n"); 241 printf("Num/s "); 242 tv.tv_usec = now.tv_usec - servers[i].c_prev.time.tv_usec; 243 tv.tv_sec = now.tv_sec - servers[i].c_prev.time.tv_sec; 244 if ( tv.tv_usec < 0 ) { 245 tv.tv_usec += 1000000; 246 tv.tv_sec--; 247 } 248 duration = tv.tv_sec + (tv.tv_usec / (double)1000000); 249 if ( servers[i].flags & HAS_ENTRIES ) { 250 delta = servers[i].c_curr.entries - servers[i].c_prev.entries; 251 rate = delta / duration; 252 printf("%10.2f ", rate); 253 } 254 for ( j = 0; j<SLAP_OP_LAST; j++ ) { 255 delta = servers[i].c_curr.ops[j] - servers[i].c_prev.ops[j]; 256 rate = delta / duration; 257 printf("%10.2f ", rate); 258 } 259 printf("\n"); 260 } 261 if ( servers[i].flags & HAS_BASE ) { 262 for (j=0; j<numservers; j++) { 263 /* skip empty CSNs */ 264 if (!servers[i].csn_curr.vals[j].bv_len || 265 !servers[i].csn_curr.vals[j].bv_val[0]) 266 continue; 267 printf("contextCSN: %s", servers[i].csn_curr.vals[j].bv_val ); 268 if (ber_bvcmp(&servers[i].csn_curr.vals[j], 269 &servers[i].csn_prev.vals[j])) { 270 /* a difference */ 271 if (servers[i].times[j].idle) { 272 servers[i].times[j].idle = 0; 273 servers[i].times[j].active = 0; 274 servers[i].times[j].maxlag = 0; 275 servers[i].times[j].lag = 0; 276 } 277active: 278 if (!servers[i].times[j].active) 279 servers[i].times[j].active = now_t; 280 printf(" actv@"); 281 timestamp(&servers[i].times[j].active); 282 } else if ( servers[i].times[j].lag || ( servers[i].flags & WAS_LATE )) { 283 goto active; 284 } else { 285 if (servers[i].times[j].active && !servers[i].times[j].idle) 286 servers[i].times[j].idle = now_t; 287 if (servers[i].times[j].active) { 288 printf(" actv@"); 289 timestamp(&servers[i].times[j].active); 290 printf(", idle@"); 291 timestamp(&servers[i].times[j].idle); 292 } else { 293 printf(" idle"); 294 } 295 } 296 if (i != j) { 297 if (ber_bvcmp(&servers[i].csn_curr.vals[j], 298 &servers[j].csn_curr.vals[j])) { 299 struct timeval delta; 300 int ahead = 0; 301 time_t deltatt; 302 delta.tv_sec = servers[j].csn_curr.tvs[j].tv_sec - 303 servers[i].csn_curr.tvs[j].tv_sec; 304 delta.tv_usec = servers[j].csn_curr.tvs[j].tv_usec - 305 servers[i].csn_curr.tvs[j].tv_usec; 306 if (delta.tv_usec < 0) { 307 delta.tv_usec += 1000000; 308 delta.tv_sec--; 309 } 310 if (delta.tv_sec < 0) { 311 delta.tv_sec = -delta.tv_sec; 312 ahead = 1; 313 } 314 deltatt = delta.tv_sec; 315 if (ahead) 316 printf(", ahead "); 317 else 318 printf(", behind "); 319 deltat( &deltatt ); 320 servers[i].times[j].lag = deltatt; 321 if (deltatt > servers[i].times[j].maxlag) 322 servers[i].times[j].maxlag = deltatt; 323 } else { 324 servers[i].times[j].lag = 0; 325 printf(", sync'd"); 326 } 327 if (servers[i].times[j].maxlag) { 328 printf(", max delta "); 329 deltat( &servers[i].times[j].maxlag ); 330 } 331 } 332 printf("\n"); 333 } 334 } 335 if ( !( servers[i].flags & WAS_LATE )) 336 rotate_stats( &servers[i] ); 337 } 338} 339 340void get_counters( 341 LDAP *ld, 342 LDAPMessage *e, 343 BerElement *ber, 344 counters *c ) 345{ 346 int rc; 347 slap_op_t op = SLAP_OP_BIND; 348 struct berval dn, bv, *bvals, **bvp = &bvals; 349 350 do { 351 int done = 0; 352 for ( rc = ldap_get_attribute_ber( ld, e, ber, &bv, bvp ); 353 rc == LDAP_SUCCESS; 354 rc = ldap_get_attribute_ber( ld, e, ber, &bv, bvp )) { 355 356 if ( bv.bv_val == NULL ) break; 357 if ( !ber_bvcmp( &bv, &at_monitorOpCompleted ) && bvals ) { 358 c->ops[op] = strtoul( bvals[0].bv_val, NULL, 0 ); 359 done = 1; 360 } 361 if ( bvals ) { 362 ber_memfree( bvals ); 363 bvals = NULL; 364 } 365 if ( done ) 366 break; 367 } 368 ber_free( ber, 0 ); 369 e = ldap_next_entry( ld, e ); 370 if ( !e ) 371 break; 372 ldap_get_dn_ber( ld, e, &ber, &dn ); 373 op++; 374 } while ( op < SLAP_OP_LAST ); 375} 376 377int 378slap_parse_csn_sid( struct berval *csnp ) 379{ 380 char *p, *q; 381 struct berval csn = *csnp; 382 int i; 383 384 p = ber_bvchr( &csn, '#' ); 385 if ( !p ) 386 return -1; 387 p++; 388 csn.bv_len -= p - csn.bv_val; 389 csn.bv_val = p; 390 391 p = ber_bvchr( &csn, '#' ); 392 if ( !p ) 393 return -1; 394 p++; 395 csn.bv_len -= p - csn.bv_val; 396 csn.bv_val = p; 397 398 q = ber_bvchr( &csn, '#' ); 399 if ( !q ) 400 return -1; 401 402 csn.bv_len = q - p; 403 404 i = strtol( p, &q, 16 ); 405 if ( p == q || q != p + csn.bv_len || i < 0 || i > SLAP_SYNC_SID_MAX ) { 406 i = -1; 407 } 408 409 return i; 410} 411 412void get_csns( 413 csns *c, 414 struct berval *bvs 415) 416{ 417 int i, j; 418 419 /* clear old values if any */ 420 for (i=0; i<numservers; i++) 421 if ( c->vals[i].bv_val ) 422 c->vals[i].bv_val[0] = '\0'; 423 424 for (i=0; bvs[i].bv_val; i++) { 425 struct lutil_tm tm; 426 struct lutil_timet tt; 427 int sid = slap_parse_csn_sid( &bvs[i] ); 428 for (j=0; j<numservers; j++) 429 if (sid == servers[j].sid) break; 430 if (j < numservers) { 431 ber_bvreplace( &c->vals[j], &bvs[i] ); 432 lutil_parsetime(bvs[i].bv_val, &tm); 433 c->tvs[j].tv_usec = tm.tm_nsec / 1000; 434 lutil_tm2time( &tm, &tt ); 435 c->tvs[j].tv_sec = tt.tt_sec; 436 } 437 } 438} 439 440int 441setup_server( struct tester_conn_args *config, server *sv, int first ) 442{ 443 config->uri = sv->url; 444 tester_init_ld( &sv->ld, config, first ? 0 : TESTER_INIT_NOEXIT ); 445 if ( !sv->ld ) 446 return -1; 447 448 sv->flags &= ~HAS_ALL; 449 { 450 char *attrs[] = { at_namingContexts.bv_val, at_monitorOpCompleted.bv_val, 451 at_olmMDBEntries.bv_val, NULL }; 452 LDAPMessage *res = NULL, *e = NULL; 453 BerElement *ber = NULL; 454 LDAP *ld = sv->ld; 455 struct berval dn, bv, *bvals, **bvp = &bvals; 456 int j, rc; 457 458 rc = ldap_search_ext_s( ld, "cn=monitor", LDAP_SCOPE_SUBTREE, monfilter, 459 attrs, 0, NULL, NULL, NULL, LDAP_NO_LIMIT, &res ); 460 switch(rc) { 461 case LDAP_SIZELIMIT_EXCEEDED: 462 case LDAP_TIMELIMIT_EXCEEDED: 463 case LDAP_SUCCESS: 464 gettimeofday( &sv->c_curr.time, 0 ); 465 sv->flags |= HAS_MONITOR; 466 for ( e = ldap_first_entry( ld, res ); e; e = ldap_next_entry( ld, e )) { 467 ldap_get_dn_ber( ld, e, &ber, &dn ); 468 if ( !strncasecmp( dn.bv_val, "cn=Database", sizeof("cn=Database")-1 ) || 469 !strncasecmp( dn.bv_val, "cn=Frontend", sizeof("cn=Frontend")-1 )) { 470 int matched = 0; 471 for ( rc = ldap_get_attribute_ber( ld, e, ber, &bv, bvp ); 472 rc == LDAP_SUCCESS; 473 rc = ldap_get_attribute_ber( ld, e, ber, &bv, bvp )) { 474 if ( bv.bv_val == NULL ) break; 475 if (!ber_bvcmp( &bv, &at_namingContexts ) && bvals ) { 476 for (j=0; bvals[j].bv_val; j++) { 477 if ( !ber_bvstrcasecmp( &base, &bvals[j] )) { 478 matched = 1; 479 break; 480 } 481 } 482 if (!matched) { 483 ber_memfree( bvals ); 484 bvals = NULL; 485 break; 486 } 487 } 488 if (!ber_bvcmp( &bv, &at_olmMDBEntries )) { 489 ber_bvreplace( &sv->monitorbase, &dn ); 490 sv->flags |= HAS_ENTRIES; 491 sv->c_curr.entries = strtoul( bvals[0].bv_val, NULL, 0 ); 492 } 493 ber_memfree( bvals ); 494 bvals = NULL; 495 } 496 } else if (!strncasecmp( dn.bv_val, opnames[0].rdn.bv_val, 497 opnames[0].rdn.bv_len )) { 498 get_counters( ld, e, ber, &sv->c_curr ); 499 break; 500 } 501 if ( ber ) 502 ber_free( ber, 0 ); 503 } 504 break; 505 506 case LDAP_NO_SUCH_OBJECT: 507 /* no cn=monitor */ 508 break; 509 510 default: 511 tester_ldap_error( ld, "ldap_search_ext_s(cn=Monitor)", sv->url ); 512 if ( first ) 513 exit( EXIT_FAILURE ); 514 } 515 ldap_msgfree( res ); 516 517 if ( base.bv_val ) { 518 char *attr2[] = { at_contextCSN.bv_val, NULL }; 519 rc = ldap_search_ext_s( ld, base.bv_val, LDAP_SCOPE_BASE, "(objectClass=*)", 520 attr2, 0, NULL, NULL, NULL, LDAP_NO_LIMIT, &res ); 521 switch(rc) { 522 case LDAP_SUCCESS: 523 e = ldap_first_entry( ld, res ); 524 if ( e ) { 525 sv->flags |= HAS_BASE; 526 ldap_get_dn_ber( ld, e, &ber, &dn ); 527 for ( rc = ldap_get_attribute_ber( ld, e, ber, &bv, bvp ); 528 rc == LDAP_SUCCESS; 529 rc = ldap_get_attribute_ber( ld, e, ber, &bv, bvp )) { 530 int done = 0; 531 if ( bv.bv_val == NULL ) break; 532 if ( bvals ) { 533 if ( !ber_bvcmp( &bv, &at_contextCSN )) { 534 get_csns( &sv->csn_curr, bvals ); 535 done = 1; 536 } 537 ber_memfree( bvals ); 538 bvals = NULL; 539 if ( done ) 540 break; 541 } 542 } 543 } 544 ldap_msgfree( res ); 545 break; 546 547 default: 548 tester_ldap_error( ld, "ldap_search_ext_s(baseDN)", sv->url ); 549 if ( first ) 550 exit( EXIT_FAILURE ); 551 } 552 } 553 } 554 555 if ( sv->monitorfilter != default_monfilter ) 556 free( sv->monitorfilter ); 557 if ( sv->flags & HAS_ENTRIES ) { 558 int len = sv->monitorbase.bv_len + sizeof("(|(entryDN=)" MONFILTER ")"); 559 char *ptr = malloc(len); 560 sprintf(ptr, "(|(entryDN=%s)" MONFILTER ")", sv->monitorbase.bv_val ); 561 sv->monitorfilter = ptr; 562 } else if ( sv->flags & HAS_MONITOR ) { 563 sv->monitorfilter = (char *)default_monfilter; 564 } 565 if ( first ) 566 rotate_stats( sv ); 567 return 0; 568} 569 570int 571main( int argc, char **argv ) 572{ 573 int i, rc, *msg1, *msg2; 574 char **sids = NULL; 575 struct tester_conn_args *config; 576 int first = 1; 577 578 config = tester_init( "slapd-watcher", TESTER_TESTER ); 579 config->authmethod = LDAP_AUTH_SIMPLE; 580 581 while ( ( i = getopt( argc, argv, "D:O:R:U:X:Y:b:d:i:s:w:x" ) ) != EOF ) 582 { 583 switch ( i ) { 584 case 'b': /* base DN for contextCSN lookups */ 585 ber_str2bv( optarg, 0, 0, &base ); 586 break; 587 588 case 'i': 589 interval = atoi(optarg); 590 break; 591 592 case 's': 593 sids = ldap_str2charray( optarg, "," ); 594 break; 595 596 default: 597 if ( tester_config_opt( config, i, optarg ) == LDAP_SUCCESS ) 598 break; 599 600 usage( argv[0], i ); 601 break; 602 } 603 } 604 605 tester_config_finish( config ); 606#ifdef SIGPIPE 607 (void) SIGNAL(SIGPIPE, SIG_IGN); 608#endif 609 610 /* don't clear the screen if debug is enabled */ 611 if (debug) 612 clearscreen = "\n\n"; 613 614 numservers = argc - optind; 615 if ( !numservers ) 616 usage( argv[0], 0 ); 617 618 if ( sids ) { 619 for (i=0; sids[i]; i++ ); 620 if ( i != numservers ) { 621 fprintf(stderr, "Number of sids doesn't equal number of server URLs\n"); 622 exit( EXIT_FAILURE ); 623 } 624 } 625 626 argv += optind; 627 argc -= optind; 628 servers = calloc( numservers, sizeof(server)); 629 630 if ( base.bv_val ) { 631 monfilter = "(|(entryDN:dnOneLevelMatch:=cn=Databases,cn=Monitor)" MONFILTER ")"; 632 } else { 633 monfilter = MONFILTER; 634 } 635 636 if ( numservers > 1 ) { 637 for ( i=0; i<numservers; i++ ) 638 if ( sids ) 639 servers[i].sid = atoi(sids[i]); 640 else 641 servers[i].sid = i+1; 642 } 643 644 for ( i = 0; i < numservers; i++ ) { 645 servers[i].url = argv[i]; 646 servers[i].times = calloc( numservers, sizeof(activity)); 647 servers[i].csn_curr.vals = calloc( numservers, sizeof(struct berval)); 648 servers[i].csn_prev.vals = calloc( numservers, sizeof(struct berval)); 649 servers[i].csn_curr.tvs = calloc( numservers, sizeof(struct timeval)); 650 servers[i].csn_prev.tvs = calloc( numservers, sizeof(struct timeval)); 651 } 652 653 msg1 = malloc( numservers * 2 * sizeof(int)); 654 msg2 = msg1 + numservers; 655 656 for (;;) { 657 LDAPMessage *res = NULL, *e = NULL; 658 BerElement *ber = NULL; 659 struct berval dn, bv, *bvals, **bvp = &bvals; 660 struct timeval tv; 661 LDAP *ld; 662 663 for (i=0; i<numservers; i++) { 664 if ( !servers[i].ld || !(servers[i].flags & WAS_LATE )) { 665 msg1[i] = 0; 666 msg2[i] = 0; 667 } 668 if ( !servers[i].ld ) { 669 setup_server( config, &servers[i], first ); 670 } else { 671 ld = servers[i].ld; 672 rc = -1; 673 if ( servers[i].flags & WAS_DOWN ) 674 servers[i].flags ^= WAS_DOWN; 675 if (( servers[i].flags & HAS_MONITOR ) && !msg1[i] ) { 676 char *attrs[3] = { at_monitorOpCompleted.bv_val }; 677 if ( servers[i].flags & HAS_ENTRIES ) 678 attrs[1] = at_olmMDBEntries.bv_val; 679 rc = ldap_search_ext( ld, "cn=monitor", 680 LDAP_SCOPE_SUBTREE, servers[i].monitorfilter, 681 attrs, 0, NULL, NULL, NULL, LDAP_NO_LIMIT, &msg1[i] ); 682 if ( rc != LDAP_SUCCESS ) { 683 tester_ldap_error( ld, "ldap_search_ext(cn=Monitor)", servers[i].url ); 684 if ( first ) 685 exit( EXIT_FAILURE ); 686 else { 687server_down1: 688 ldap_unbind_ext( ld, NULL, NULL ); 689 servers[i].flags |= WAS_DOWN; 690 servers[i].ld = NULL; 691 gettimeofday( &tv, NULL ); 692 servers[i].down = tv.tv_sec; 693 msg1[i] = 0; 694 msg2[i] = 0; 695 continue; 696 } 697 } 698 } 699 if (( servers[i].flags & HAS_BASE ) && !msg2[i] ) { 700 char *attrs[2] = { at_contextCSN.bv_val }; 701 rc = ldap_search_ext( ld, base.bv_val, 702 LDAP_SCOPE_BASE, "(objectClass=*)", 703 attrs, 0, NULL, NULL, NULL, LDAP_NO_LIMIT, &msg2[i] ); 704 if ( rc != LDAP_SUCCESS ) { 705 tester_ldap_error( ld, "ldap_search_ext(baseDN)", servers[i].url ); 706 if ( first ) 707 exit( EXIT_FAILURE ); 708 else 709 goto server_down1; 710 } 711 } 712 if ( rc != -1 ) 713 gettimeofday( &servers[i].c_curr.time, 0 ); 714 } 715 } 716 717 for (i=0; i<numservers; i++) { 718 ld = servers[i].ld; 719 if ( msg1[i] ) { 720 tv.tv_sec = 0; 721 tv.tv_usec = 250000; 722 rc = ldap_result( ld, msg1[i], LDAP_MSG_ALL, &tv, &res ); 723 if ( rc < 0 ) { 724 tester_ldap_error( ld, "ldap_result(cn=Monitor)", servers[i].url ); 725 if ( first ) 726 exit( EXIT_FAILURE ); 727 else { 728server_down2: 729 ldap_unbind_ext( ld, NULL, NULL ); 730 servers[i].flags |= WAS_DOWN; 731 servers[i].ld = NULL; 732 servers[i].down = servers[i].c_curr.time.tv_sec; 733 msg1[i] = 0; 734 msg2[i] = 0; 735 continue; 736 } 737 } 738 if ( rc == 0 ) { 739 if ( !( servers[i].flags & WAS_LATE )) 740 servers[i].late = servers[i].c_curr.time.tv_sec; 741 servers[i].flags |= WAS_LATE; 742 continue; 743 } 744 if ( servers[i].flags & WAS_LATE ) 745 servers[i].flags ^= WAS_LATE; 746 for ( e = ldap_first_entry( ld, res ); e; e = ldap_next_entry( ld, e )) { 747 ldap_get_dn_ber( ld, e, &ber, &dn ); 748 if ( !strncasecmp( dn.bv_val, "cn=Database", sizeof("cn=Database")-1 ) || 749 !strncasecmp( dn.bv_val, "cn=Frontend", sizeof("cn=Frontend")-1 )) { 750 for ( rc = ldap_get_attribute_ber( ld, e, ber, &bv, bvp ); 751 rc == LDAP_SUCCESS; 752 rc = ldap_get_attribute_ber( ld, e, ber, &bv, bvp )) { 753 if ( bv.bv_val == NULL ) break; 754 if ( !ber_bvcmp( &bv, &at_olmMDBEntries )) { 755 if ( !BER_BVISNULL( &servers[i].monitorbase )) { 756 servers[i].c_curr.entries = strtoul( bvals[0].bv_val, NULL, 0 ); 757 } 758 } 759 ber_memfree( bvals ); 760 bvals = NULL; 761 } 762 } else if (!strncasecmp( dn.bv_val, opnames[0].rdn.bv_val, 763 opnames[0].rdn.bv_len )) { 764 get_counters( ld, e, ber, &servers[i].c_curr ); 765 break; 766 } 767 if ( ber ) 768 ber_free( ber, 0 ); 769 } 770 ldap_msgfree( res ); 771 } 772 if ( msg2[i] ) { 773 tv.tv_sec = 0; 774 tv.tv_usec = 250000; 775 rc = ldap_result( ld, msg2[i], LDAP_MSG_ALL, &tv, &res ); 776 if ( rc < 0 ) { 777 tester_ldap_error( ld, "ldap_result(baseDN)", servers[i].url ); 778 if ( first ) 779 exit( EXIT_FAILURE ); 780 else 781 goto server_down2; 782 } 783 if ( rc == 0 ) { 784 if ( !( servers[i].flags & WAS_LATE )) 785 servers[i].late = servers[i].c_curr.time.tv_sec; 786 servers[i].flags |= WAS_LATE; 787 continue; 788 } 789 if ( servers[i].flags & WAS_LATE ) 790 servers[i].flags ^= WAS_LATE; 791 e = ldap_first_entry( ld, res ); 792 if ( e ) { 793 ldap_get_dn_ber( ld, e, &ber, &dn ); 794 for ( rc = ldap_get_attribute_ber( ld, e, ber, &bv, bvp ); 795 rc == LDAP_SUCCESS; 796 rc = ldap_get_attribute_ber( ld, e, ber, &bv, bvp )) { 797 int done = 0; 798 if ( bv.bv_val == NULL ) break; 799 if ( bvals ) { 800 if ( !ber_bvcmp( &bv, &at_contextCSN )) { 801 get_csns( &servers[i].csn_curr, bvals ); 802 done = 1; 803 } 804 ber_memfree( bvals ); 805 bvals = NULL; 806 if ( done ) 807 break; 808 } 809 } 810 } 811 ldap_msgfree( res ); 812 } 813 } 814 display(); 815 sleep(interval); 816 first = 0; 817 } 818 819 exit( EXIT_SUCCESS ); 820} 821 822