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