From 5ea77a75dd2d2158401331879f3c8f47940a732c Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sun, 7 Apr 2024 18:35:32 +0200 Subject: Adding upstream version 2.5.13+dfsg. Signed-off-by: Daniel Baumann --- tests/progs/slapd-watcher.c | 823 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 823 insertions(+) create mode 100644 tests/progs/slapd-watcher.c (limited to 'tests/progs/slapd-watcher.c') diff --git a/tests/progs/slapd-watcher.c b/tests/progs/slapd-watcher.c new file mode 100644 index 0000000..0fed11f --- /dev/null +++ b/tests/progs/slapd-watcher.c @@ -0,0 +1,823 @@ +/* $OpenLDAP$ */ +/* This work is part of OpenLDAP Software . + * + * Copyright 1999-2022 The OpenLDAP Foundation. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted only as authorized by the OpenLDAP + * Public License. + * + * A copy of this license is available in file LICENSE in the + * top-level directory of the distribution or, alternatively, at + * . + */ +/* ACKNOWLEDGEMENTS: + * This work was initially developed by Howard Chu for inclusion + * in OpenLDAP Software. + */ + +#include "portable.h" + +#include + +#include "ac/signal.h" +#include "ac/stdlib.h" +#include "ac/time.h" + +#include "ac/ctype.h" +#include "ac/param.h" +#include "ac/socket.h" +#include "ac/string.h" +#include "ac/unistd.h" +#include "ac/wait.h" +#include "ac/time.h" + +#include "ldap.h" +#include "lutil.h" +#include "lutil_ldap.h" +#include "lber_pvt.h" +#include "ldap_pvt.h" + +#include "slapd-common.h" + +#define SLAP_SYNC_SID_MAX 4095 + +#define HAS_MONITOR 1 +#define HAS_BASE 2 +#define HAS_ENTRIES 4 +#define HAS_SREPL 8 +#define HAS_ALL (HAS_MONITOR|HAS_BASE|HAS_ENTRIES|HAS_SREPL) + + +#define WAS_LATE 0x100 +#define WAS_DOWN 0x200 + +#define MONFILTER "(objectClass=monitorOperation)" + +static const char *default_monfilter = MONFILTER; + +typedef enum { + SLAP_OP_BIND = 0, + SLAP_OP_UNBIND, + SLAP_OP_SEARCH, + SLAP_OP_COMPARE, + SLAP_OP_MODIFY, + SLAP_OP_MODRDN, + SLAP_OP_ADD, + SLAP_OP_DELETE, + SLAP_OP_ABANDON, + SLAP_OP_EXTENDED, + SLAP_OP_LAST +} slap_op_t; + +struct opname { + struct berval rdn; + char *display; +} opnames[] = { + { BER_BVC("cn=Bind"), "Bind" }, + { BER_BVC("cn=Unbind"), "Unbind" }, + { BER_BVC("cn=Search"), "Search" }, + { BER_BVC("cn=Compare"), "Compare" }, + { BER_BVC("cn=Modify"), "Modify" }, + { BER_BVC("cn=Modrdn"), "ModDN" }, + { BER_BVC("cn=Add"), "Add" }, + { BER_BVC("cn=Delete"), "Delete" }, + { BER_BVC("cn=Abandon"), "Abandon" }, + { BER_BVC("cn=Extended"), "Extended" }, + { BER_BVNULL, NULL } +}; + +typedef struct counters { + struct timeval time; + unsigned long entries; + unsigned long ops[SLAP_OP_LAST]; +} counters; + +typedef struct csns { + struct berval *vals; + struct timeval *tvs; +} csns; + +typedef struct activity { + time_t active; + time_t idle; + time_t maxlag; + time_t lag; +} activity; + +typedef struct server { + char *url; + LDAP *ld; + int flags; + int sid; + struct berval monitorbase; + char *monitorfilter; + time_t late; + time_t down; + counters c_prev; + counters c_curr; + csns csn_prev; + csns csn_curr; + activity *times; +} server; + +static void +usage( char *name, char opt ) +{ + if ( opt ) { + fprintf( stderr, "%s: unable to handle option \'%c\'\n\n", + name, opt ); + } + + fprintf( stderr, "usage: %s " + "[-D [ -w ]] " + "[-d ] " + "[-O ] " + "[-R ] " + "[-U [-X ]] " + "[-x | -Y ] " + "[-i ] " + "[-s ] " + "[-c ] " + "[-b ] URI[...]\n", + name ); + exit( EXIT_FAILURE ); +} + +struct berval base, cbase; +int interval = 10; +int numservers; +server *servers; +char *monfilter; + +struct berval at_namingContexts = BER_BVC("namingContexts"); +struct berval at_monitorOpCompleted = BER_BVC("monitorOpCompleted"); +struct berval at_olmMDBEntries = BER_BVC("olmMDBEntries"); +struct berval at_contextCSN = BER_BVC("contextCSN"); + +void timestamp(time_t *tt) +{ + struct tm *tm = gmtime(tt); + printf("%d-%02d-%02d %02d:%02d:%02d", + tm->tm_year + 1900, tm->tm_mon+1, tm->tm_mday, + tm->tm_hour, tm->tm_min, tm->tm_sec); +} + +void deltat(time_t *tt) +{ + struct tm *tm = gmtime(tt); + if (tm->tm_mday-1) + printf("%02d+", tm->tm_mday-1); + printf("%02d:%02d:%02d", + tm->tm_hour, tm->tm_min, tm->tm_sec); +} + +static char *clearscreen = "\033[H\033[2J"; + +void rotate_stats( server *sv ) +{ + if ( sv->flags & HAS_MONITOR ) + sv->c_prev = sv->c_curr; + if ( sv->flags & HAS_BASE ) { + int i; + + for (i=0; icsn_curr.vals[i].bv_len ) { + ber_bvreplace(&sv->csn_prev.vals[i], + &sv->csn_curr.vals[i]); + sv->csn_prev.tvs[i] = sv->csn_curr.tvs[i]; + } else { + if ( sv->csn_prev.vals[i].bv_val ) + sv->csn_prev.vals[i].bv_val[0] = '\0'; + } + } + } +} + +void display() +{ + int i, j; + struct timeval now; + time_t now_t; + + gettimeofday(&now, NULL); + now_t = now.tv_sec; + printf("%s", clearscreen); + timestamp(&now_t); + printf("\n"); + + for (i=0; i servers[i].times[j].maxlag) + servers[i].times[j].maxlag = deltatt; + } else { + servers[i].times[j].lag = 0; + printf(", sync'd"); + } + if (servers[i].times[j].maxlag) { + printf(", max delta "); + deltat( &servers[i].times[j].maxlag ); + } + } + printf("\n"); + } + } + if ( !( servers[i].flags & WAS_LATE )) + rotate_stats( &servers[i] ); + } +} + +void get_counters( + LDAP *ld, + LDAPMessage *e, + BerElement *ber, + counters *c ) +{ + int rc; + slap_op_t op = SLAP_OP_BIND; + struct berval dn, bv, *bvals, **bvp = &bvals; + + do { + int done = 0; + for ( rc = ldap_get_attribute_ber( ld, e, ber, &bv, bvp ); + rc == LDAP_SUCCESS; + rc = ldap_get_attribute_ber( ld, e, ber, &bv, bvp )) { + + if ( bv.bv_val == NULL ) break; + if ( !ber_bvcmp( &bv, &at_monitorOpCompleted ) && bvals ) { + c->ops[op] = strtoul( bvals[0].bv_val, NULL, 0 ); + done = 1; + } + if ( bvals ) { + ber_memfree( bvals ); + bvals = NULL; + } + if ( done ) + break; + } + ber_free( ber, 0 ); + e = ldap_next_entry( ld, e ); + if ( !e ) + break; + ldap_get_dn_ber( ld, e, &ber, &dn ); + op++; + } while ( op < SLAP_OP_LAST ); +} + +int +slap_parse_csn_sid( struct berval *csnp ) +{ + char *p, *q; + struct berval csn = *csnp; + int i; + + p = ber_bvchr( &csn, '#' ); + if ( !p ) + return -1; + p++; + csn.bv_len -= p - csn.bv_val; + csn.bv_val = p; + + p = ber_bvchr( &csn, '#' ); + if ( !p ) + return -1; + p++; + csn.bv_len -= p - csn.bv_val; + csn.bv_val = p; + + q = ber_bvchr( &csn, '#' ); + if ( !q ) + return -1; + + csn.bv_len = q - p; + + i = strtol( p, &q, 16 ); + if ( p == q || q != p + csn.bv_len || i < 0 || i > SLAP_SYNC_SID_MAX ) { + i = -1; + } + + return i; +} + +void get_csns( + csns *c, + struct berval *bvs +) +{ + int i, j; + + /* clear old values if any */ + for (i=0; ivals[i].bv_val ) + c->vals[i].bv_val[0] = '\0'; + + for (i=0; bvs[i].bv_val; i++) { + struct lutil_tm tm; + struct lutil_timet tt; + int sid = slap_parse_csn_sid( &bvs[i] ); + for (j=0; jvals[j], &bvs[i] ); + lutil_parsetime(bvs[i].bv_val, &tm); + c->tvs[j].tv_usec = tm.tm_nsec / 1000; + lutil_tm2time( &tm, &tt ); + c->tvs[j].tv_sec = tt.tt_sec; + } + } +} + +int +setup_server( struct tester_conn_args *config, server *sv, int first ) +{ + config->uri = sv->url; + tester_init_ld( &sv->ld, config, first ? 0 : TESTER_INIT_NOEXIT ); + if ( !sv->ld ) + return -1; + + sv->flags &= ~HAS_ALL; + { + char *attrs[] = { at_namingContexts.bv_val, at_monitorOpCompleted.bv_val, + at_olmMDBEntries.bv_val, NULL }; + LDAPMessage *res = NULL, *e = NULL; + BerElement *ber = NULL; + LDAP *ld = sv->ld; + struct berval dn, bv, *bvals, **bvp = &bvals; + int j, rc; + + rc = ldap_search_ext_s( ld, "cn=monitor", LDAP_SCOPE_SUBTREE, monfilter, + attrs, 0, NULL, NULL, NULL, LDAP_NO_LIMIT, &res ); + switch(rc) { + case LDAP_SIZELIMIT_EXCEEDED: + case LDAP_TIMELIMIT_EXCEEDED: + case LDAP_SUCCESS: + gettimeofday( &sv->c_curr.time, 0 ); + sv->flags |= HAS_MONITOR; + for ( e = ldap_first_entry( ld, res ); e; e = ldap_next_entry( ld, e )) { + ldap_get_dn_ber( ld, e, &ber, &dn ); + if ( !strncasecmp( dn.bv_val, "cn=Database", sizeof("cn=Database")-1 ) || + !strncasecmp( dn.bv_val, "cn=Frontend", sizeof("cn=Frontend")-1 )) { + int matched = 0; + for ( rc = ldap_get_attribute_ber( ld, e, ber, &bv, bvp ); + rc == LDAP_SUCCESS; + rc = ldap_get_attribute_ber( ld, e, ber, &bv, bvp )) { + if ( bv.bv_val == NULL ) break; + if (!ber_bvcmp( &bv, &at_namingContexts ) && bvals ) { + for (j=0; bvals[j].bv_val; j++) { + if ( !ber_bvstrcasecmp( &base, &bvals[j] )) { + matched = 1; + break; + } + } + if (!matched) { + ber_memfree( bvals ); + bvals = NULL; + break; + } + } + if (!ber_bvcmp( &bv, &at_olmMDBEntries )) { + ber_bvreplace( &sv->monitorbase, &dn ); + sv->flags |= HAS_ENTRIES; + sv->c_curr.entries = strtoul( bvals[0].bv_val, NULL, 0 ); + } + ber_memfree( bvals ); + bvals = NULL; + } + } else if (!strncasecmp( dn.bv_val, opnames[0].rdn.bv_val, + opnames[0].rdn.bv_len )) { + get_counters( ld, e, ber, &sv->c_curr ); + break; + } + if ( ber ) + ber_free( ber, 0 ); + } + break; + + case LDAP_NO_SUCH_OBJECT: + /* no cn=monitor */ + break; + + default: + tester_ldap_error( ld, "ldap_search_ext_s(cn=Monitor)", sv->url ); + if ( first ) + exit( EXIT_FAILURE ); + } + ldap_msgfree( res ); + + if ( cbase.bv_val ) { + char *attr2[] = { at_contextCSN.bv_val, NULL }; + rc = ldap_search_ext_s( ld, cbase.bv_val, LDAP_SCOPE_BASE, "(objectClass=*)", + attr2, 0, NULL, NULL, NULL, LDAP_NO_LIMIT, &res ); + switch(rc) { + case LDAP_SUCCESS: + e = ldap_first_entry( ld, res ); + if ( e ) { + sv->flags |= HAS_BASE; + ldap_get_dn_ber( ld, e, &ber, &dn ); + for ( rc = ldap_get_attribute_ber( ld, e, ber, &bv, bvp ); + rc == LDAP_SUCCESS; + rc = ldap_get_attribute_ber( ld, e, ber, &bv, bvp )) { + int done = 0; + if ( bv.bv_val == NULL ) break; + if ( bvals ) { + if ( !ber_bvcmp( &bv, &at_contextCSN )) { + get_csns( &sv->csn_curr, bvals ); + done = 1; + } + ber_memfree( bvals ); + bvals = NULL; + if ( done ) + break; + } + } + } + ldap_msgfree( res ); + break; + + default: + tester_ldap_error( ld, "ldap_search_ext_s(baseDN)", sv->url ); + if ( first ) + exit( EXIT_FAILURE ); + } + } + } + + if ( sv->monitorfilter != default_monfilter ) + free( sv->monitorfilter ); + if ( sv->flags & HAS_ENTRIES ) { + int len = sv->monitorbase.bv_len + sizeof("(|(entryDN=)" MONFILTER ")"); + char *ptr = malloc(len); + sprintf(ptr, "(|(entryDN=%s)" MONFILTER ")", sv->monitorbase.bv_val ); + sv->monitorfilter = ptr; + } else if ( sv->flags & HAS_MONITOR ) { + sv->monitorfilter = (char *)default_monfilter; + } + if ( first ) + rotate_stats( sv ); + return 0; +} + +int +main( int argc, char **argv ) +{ + int i, rc, *msg1, *msg2; + char **sids = NULL; + struct tester_conn_args *config; + int first = 1; + + config = tester_init( "slapd-watcher", TESTER_TESTER ); + config->authmethod = LDAP_AUTH_SIMPLE; + + while ( ( i = getopt( argc, argv, "D:O:R:U:X:Y:b:c:d:i:s:w:x" ) ) != EOF ) + { + switch ( i ) { + case 'b': /* base DN for DB entrycount lookups */ + ber_str2bv( optarg, 0, 0, &base ); + if ( !cbase.bv_val ) + cbase = base; + break; + + case 'c': /* base DN for contextCSN lookups */ + ber_str2bv( optarg, 0, 0, &cbase ); + break; + + case 'i': + interval = atoi(optarg); + break; + + case 's': + sids = ldap_str2charray( optarg, "," ); + break; + + default: + if ( tester_config_opt( config, i, optarg ) == LDAP_SUCCESS ) + break; + + usage( argv[0], i ); + break; + } + } + + tester_config_finish( config ); +#ifdef SIGPIPE + (void) SIGNAL(SIGPIPE, SIG_IGN); +#endif + + /* don't clear the screen if debug is enabled */ + if (debug) + clearscreen = "\n\n"; + + numservers = argc - optind; + if ( !numservers ) + usage( argv[0], 0 ); + + if ( sids ) { + for (i=0; sids[i]; i++ ); + if ( i != numservers ) { + fprintf(stderr, "Number of sids doesn't equal number of server URLs\n"); + exit( EXIT_FAILURE ); + } + } + + argv += optind; + argc -= optind; + servers = calloc( numservers, sizeof(server)); + + if ( base.bv_val ) { + monfilter = "(|(entryDN:dnOneLevelMatch:=cn=Databases,cn=Monitor)" MONFILTER ")"; + } else { + monfilter = MONFILTER; + } + + if ( sids || numservers > 1 ) { + for ( i=0; i