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