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
63 static const char *default_monfilter = MONFILTER;
64
65 typedef 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
79 struct 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
96 typedef struct counters {
97 struct timeval time;
98 unsigned long entries;
99 unsigned long ops[SLAP_OP_LAST];
100 } counters;
101
102 typedef struct csns {
103 struct berval *vals;
104 struct timeval *tvs;
105 } csns;
106
107 typedef struct activity {
108 time_t active;
109 time_t idle;
110 time_t maxlag;
111 time_t lag;
112 } activity;
113
114 typedef 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
130 static void
usage(char * name,char opt)131 usage( 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
152 struct berval base;
153 int interval = 10;
154 int numservers;
155 server *servers;
156 char *monfilter;
157
158 struct berval at_namingContexts = BER_BVC("namingContexts");
159 struct berval at_monitorOpCompleted = BER_BVC("monitorOpCompleted");
160 struct berval at_olmMDBEntries = BER_BVC("olmMDBEntries");
161 struct berval at_contextCSN = BER_BVC("contextCSN");
162
timestamp(time_t * tt)163 void 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
deltat(time_t * tt)171 void 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
180 static char *clearscreen = "\033[H\033[2J";
181
rotate_stats(server * sv)182 void 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
display()202 void 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 }
277 active:
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
get_counters(LDAP * ld,LDAPMessage * e,BerElement * ber,counters * c)340 void 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
377 int
slap_parse_csn_sid(struct berval * csnp)378 slap_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
get_csns(csns * c,struct berval * bvs)412 void 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
440 int
setup_server(struct tester_conn_args * config,server * sv,int first)441 setup_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
570 int
main(int argc,char ** argv)571 main( 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 {
687 server_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 {
728 server_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