From 1748ec59a6913d6a25b898faa893661a19018359 Mon Sep 17 00:00:00 2001 From: Howard Chu Date: Sun, 6 Sep 2020 16:09:35 +0100 Subject: [PATCH] ITS#9339 Add syncrepl status to cn=monitor Shows connection address, refresh/persist state, time of last connect attempt and received data, and last sent and received cookies per consumer. --- servers/slapd/backend.c | 5 + servers/slapd/daemon.c | 118 ++++++---- servers/slapd/proto-slap.h | 1 + servers/slapd/slap.h | 8 + servers/slapd/syncrepl.c | 466 ++++++++++++++++++++++++++++++++++++- 5 files changed, 555 insertions(+), 43 deletions(-) diff --git a/servers/slapd/backend.c b/servers/slapd/backend.c index f4d9c53b35..f15ee9e815 100644 --- a/servers/slapd/backend.c +++ b/servers/slapd/backend.c @@ -78,6 +78,8 @@ backend_init_controls( BackendInfo *bi ) return 0; } +extern int syncrepl_monitor_init(void); + int backend_init(void) { int rc = -1; @@ -114,6 +116,9 @@ int backend_init(void) LDAP_STAILQ_INSERT_TAIL(&backendInfo, bi, bi_next); } + /* HACK: need schema defined in deterministic order */ + syncrepl_monitor_init(); + if ( nBackendInfo > 0) { return 0; diff --git a/servers/slapd/daemon.c b/servers/slapd/daemon.c index 48d502136e..dc132754c6 100644 --- a/servers/slapd/daemon.c +++ b/servers/slapd/daemon.c @@ -2121,6 +2121,78 @@ destroy_listeners( void ) slap_listeners = NULL; } +void +slap_sockaddrstr( Sockaddr *sa, struct berval *addrbuf ) +{ + char *addr; + switch( sa->sa_addr.sa_family ) { +#ifdef LDAP_PF_LOCAL + case AF_LOCAL: + addrbuf->bv_len = snprintf( addrbuf->bv_val, addrbuf->bv_len, + "PATH=%s", sa->sa_un_addr.sun_path ); + break; +#endif +#ifdef LDAP_PF_INET6 + case AF_INET6: + strcpy(addrbuf->bv_val, "IP="); + if ( IN6_IS_ADDR_V4MAPPED(&sa->sa_in6_addr.sin6_addr) ) { +#if defined( HAVE_GETADDRINFO ) && defined( HAVE_INET_NTOP ) + addr = inet_ntop( AF_INET, + ((struct in_addr *)&sa->sa_in6_addr.sin6_addr.s6_addr[12]), + addrbuf->bv_val+3, addrbuf->bv_len-3 ); +#else /* ! HAVE_GETADDRINFO || ! HAVE_INET_NTOP */ + addr = inet_ntoa( *((struct in_addr *) + &sa->sa_in6_addr.sin6_addr.s6_addr[12]) ); +#endif /* ! HAVE_GETADDRINFO || ! HAVE_INET_NTOP */ + if ( !addr ) addr = SLAP_STRING_UNKNOWN; + if ( addr != addrbuf->bv_val+3 ) { + addrbuf->bv_len = sprintf( addrbuf->bv_val+3, "%s:%d", addr, + (unsigned) ntohs( sa->sa_in6_addr.sin6_port ) ) + 3; + } else { + int len = strlen( addr ); + addrbuf->bv_len = sprintf( addr+len, ":%d", + (unsigned) ntohs( sa->sa_in6_addr.sin6_port ) ) + len + 3; + } + } else { + addr = inet_ntop( AF_INET6, + &sa->sa_in6_addr.sin6_addr, + addrbuf->bv_val+4, addrbuf->bv_len-4 ); + if ( !addr ) addr = SLAP_STRING_UNKNOWN; + if ( addr != addrbuf->bv_val+4 ) { + addrbuf->bv_len = sprintf( addrbuf->bv_val+3, "[%s]:%d", addr, + (unsigned) ntohs( sa->sa_in6_addr.sin6_port ) ) + 3; + } else { + int len = strlen( addr ); + addrbuf->bv_val[3] = '['; + addrbuf->bv_len = sprintf( addr+len, "]:%d", + (unsigned) ntohs( sa->sa_in6_addr.sin6_port ) ) + len + 4; + } + } + break; +#endif /* LDAP_PF_INET6 */ + case AF_INET: + strcpy(addrbuf->bv_val, "IP="); +#if defined( HAVE_GETADDRINFO ) && defined( HAVE_INET_NTOP ) + addr = inet_ntop( AF_INET, &sa->sa_in_addr.sin_addr, + addrbuf->bv_val+3, addrbuf->bv_len-3 ); +#else /* ! HAVE_GETADDRINFO || ! HAVE_INET_NTOP */ + addr = inet_ntoa( sa->sa_in_addr.sin_addr ); +#endif /* ! HAVE_GETADDRINFO || ! HAVE_INET_NTOP */ + if ( !addr ) addr = SLAP_STRING_UNKNOWN; + if ( addr != addrbuf->bv_val+3 ) { + addrbuf->bv_len = sprintf( addrbuf->bv_val+3, "%s:%d", addr, + (unsigned) ntohs( sa->sa_in_addr.sin_port ) ) + 3; + } else { + int len = strlen( addr ); + addrbuf->bv_len = sprintf( addr+len, ":%d", + (unsigned) ntohs( sa->sa_in_addr.sin_port ) ) + len + 3; + } + break; + default: + addrbuf->bv_val[0] = '\0'; + } +} + static int slap_listener( Listener *sl ) @@ -2139,18 +2211,12 @@ slap_listener( char *dnsname = NULL; const char *peeraddr = NULL; /* we assume INET6_ADDRSTRLEN > INET_ADDRSTRLEN */ - char addr[INET6_ADDRSTRLEN]; -#ifdef LDAP_PF_LOCAL - char peername[MAXPATHLEN + sizeof("PATH=")]; + char peername[SLAP_ADDRLEN]; + struct berval peerbv = BER_BVC(peername); #ifdef LDAP_PF_LOCAL_SENDMSG char peerbuf[8]; struct berval peerbv = BER_BVNULL; #endif -#elif defined(LDAP_PF_INET6) - char peername[sizeof("IP=[ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff]:65535")]; -#else /* ! LDAP_PF_LOCAL && ! LDAP_PF_INET6 */ - char peername[sizeof("IP=255.255.255.255:65336")]; -#endif /* LDAP_PF_LOCAL */ int cflag; int tid; @@ -2315,40 +2381,10 @@ slap_listener( # ifdef LDAP_PF_INET6 case AF_INET6: - if ( IN6_IS_ADDR_V4MAPPED(&from.sa_in6_addr.sin6_addr) ) { -#if defined( HAVE_GETADDRINFO ) && defined( HAVE_INET_NTOP ) - peeraddr = inet_ntop( AF_INET, - ((struct in_addr *)&from.sa_in6_addr.sin6_addr.s6_addr[12]), - addr, sizeof(addr) ); -#else /* ! HAVE_GETADDRINFO || ! HAVE_INET_NTOP */ - peeraddr = inet_ntoa( *((struct in_addr *) - &from.sa_in6_addr.sin6_addr.s6_addr[12]) ); -#endif /* ! HAVE_GETADDRINFO || ! HAVE_INET_NTOP */ - if ( !peeraddr ) peeraddr = SLAP_STRING_UNKNOWN; - sprintf( peername, "IP=%s:%d", peeraddr, - (unsigned) ntohs( from.sa_in6_addr.sin6_port ) ); - } else { - peeraddr = inet_ntop( AF_INET6, - &from.sa_in6_addr.sin6_addr, - addr, sizeof addr ); - if ( !peeraddr ) peeraddr = SLAP_STRING_UNKNOWN; - sprintf( peername, "IP=[%s]:%d", peeraddr, - (unsigned) ntohs( from.sa_in6_addr.sin6_port ) ); - } - break; # endif /* LDAP_PF_INET6 */ - - case AF_INET: { -#if defined( HAVE_GETADDRINFO ) && defined( HAVE_INET_NTOP ) - peeraddr = inet_ntop( AF_INET, &from.sa_in_addr.sin_addr, - addr, sizeof(addr) ); -#else /* ! HAVE_GETADDRINFO || ! HAVE_INET_NTOP */ - peeraddr = inet_ntoa( from.sa_in_addr.sin_addr ); -#endif /* ! HAVE_GETADDRINFO || ! HAVE_INET_NTOP */ - if ( !peeraddr ) peeraddr = SLAP_STRING_UNKNOWN; - sprintf( peername, "IP=%s:%d", peeraddr, - (unsigned) ntohs( from.sa_in_addr.sin_port ) ); - } break; + case AF_INET: + slap_sockaddrstr( &from, &peerbv ); + break; default: slapd_close(sfd); diff --git a/servers/slapd/proto-slap.h b/servers/slapd/proto-slap.h index 470ebf31c5..cd509ccfa3 100644 --- a/servers/slapd/proto-slap.h +++ b/servers/slapd/proto-slap.h @@ -893,6 +893,7 @@ LDAP_SLAPD_F (void) slap_resume_listeners LDAP_P((void)); LDAP_SLAPD_F (int) slap_pause_server LDAP_P((void)); LDAP_SLAPD_F (int) slap_unpause_server LDAP_P((void)); +LDAP_SLAPD_F (void) slap_sockaddrstr LDAP_P((Sockaddr *sa, struct berval *)); LDAP_SLAPD_F (void) slapd_set_write LDAP_P((ber_socket_t s, int wake)); LDAP_SLAPD_F (void) slapd_clr_write LDAP_P((ber_socket_t s, int wake)); diff --git a/servers/slapd/slap.h b/servers/slapd/slap.h index 69ee0338a5..73f1ed37b8 100644 --- a/servers/slapd/slap.h +++ b/servers/slapd/slap.h @@ -2858,6 +2858,14 @@ typedef void (SEND_LDAP_INTERMEDIATE)( typedef struct Listener Listener; +#ifdef LDAP_PF_LOCAL +#define SLAP_ADDRLEN (MAXPATHLEN + sizeof("PATH=")) +#elif defined(LDAP_PF_INET6) +#define SLAP_ADDRLEN sizeof("IP=[ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff]:65535") +#else +#define SLAP_ADDRLEN sizeof("IP=255.255.255.255:65336") +#endif + /* * represents a connection from an ldap client */ diff --git a/servers/slapd/syncrepl.c b/servers/slapd/syncrepl.c index eb3eb2a07b..62d345aacd 100644 --- a/servers/slapd/syncrepl.c +++ b/servers/slapd/syncrepl.c @@ -32,6 +32,9 @@ #include "ldap_rq.h" #include "rewrite.h" + +#include "back-monitor/back-monitor.h" + #define SUFFIXM_CTX "" #ifdef LDAP_CONTROL_X_DIRSYNC @@ -152,8 +155,19 @@ typedef struct syncinfo_s { #ifdef LDAP_CONTROL_X_DIRSYNC struct berval si_dirSyncCookie; #endif - unsigned long si_prevchange;; + unsigned long si_prevchange; unsigned long si_lastchange; + + /* monitor info */ + int si_monitorInited; + time_t si_lastconnect; + time_t si_lastcontact; + struct berval *si_connaddr; + struct berval si_lastCookieRcvd; + struct berval si_lastCookieSent; + struct berval si_monitor_ndn; + + ldap_pvt_thread_mutex_t si_monitor_mutex; ldap_pvt_thread_mutex_t si_mutex; } syncinfo_t; @@ -912,6 +926,8 @@ do_syncrep1( void *ssl; #endif + si->si_lastconnect = slap_get_time(); + si->si_refreshDone = 0; rc = slap_client_connect( &si->si_ld, &si->si_bindconf ); if ( rc != LDAP_SUCCESS ) { goto done; @@ -1069,10 +1085,13 @@ do_syncrep1( } - si->si_refreshDone = 0; Debug( LDAP_DEBUG_SYNC, "do_syncrep1: %s starting refresh (sending cookie=%s)\n", si->si_ridtxt, si->si_syncCookie.octet_str.bv_val ); + ldap_pvt_thread_mutex_lock( &si->si_monitor_mutex ); + ber_bvreplace( &si->si_lastCookieSent, &si->si_syncCookie.octet_str ); + ldap_pvt_thread_mutex_unlock( &si->si_monitor_mutex ); + rc = ldap_sync_search( si, op->o_tmpmemctx ); if( rc != LDAP_SUCCESS ) { @@ -1241,6 +1260,7 @@ do_syncrep2( rc = SYNC_SHUTDOWN; goto done; } + si->si_lastcontact = slap_get_time(); switch( ldap_msgtype( msg ) ) { case LDAP_RES_SEARCH_ENTRY: #ifdef LDAP_CONTROL_X_DIRSYNC @@ -1357,6 +1377,10 @@ do_syncrep2( if ( !BER_BVISNULL( &cookie ) ) { ch_free( syncCookie.octet_str.bv_val ); ber_dupbv( &syncCookie.octet_str, &cookie ); + + ldap_pvt_thread_mutex_lock( &si->si_monitor_mutex ); + ber_bvreplace( &si->si_lastCookieRcvd, &cookie ); + ldap_pvt_thread_mutex_unlock( &si->si_monitor_mutex ); } if ( !BER_BVISNULL( &syncCookie.octet_str ) ) { @@ -1571,6 +1595,10 @@ logerr: if ( !BER_BVISNULL( &cookie ) ) { ch_free( syncCookie.octet_str.bv_val ); ber_dupbv( &syncCookie.octet_str, &cookie); + + ldap_pvt_thread_mutex_lock( &si->si_monitor_mutex ); + ber_bvreplace( &si->si_lastCookieRcvd, &cookie ); + ldap_pvt_thread_mutex_unlock( &si->si_monitor_mutex ); } if ( !BER_BVISNULL( &syncCookie.octet_str ) ) { @@ -1656,6 +1684,10 @@ logerr: if ( !BER_BVISNULL( &cookie ) ) { ch_free( syncCookie.octet_str.bv_val ); ber_dupbv( &syncCookie.octet_str, &cookie ); + + ldap_pvt_thread_mutex_lock( &si->si_monitor_mutex ); + ber_bvreplace( &si->si_lastCookieRcvd, &cookie ); + ldap_pvt_thread_mutex_unlock( &si->si_monitor_mutex ); } if (!BER_BVISNULL( &syncCookie.octet_str ) ) { slap_parse_sync_cookie( &syncCookie, NULL ); @@ -1687,6 +1719,10 @@ logerr: if ( !BER_BVISNULL( &cookie ) ) { ch_free( syncCookie.octet_str.bv_val ); ber_dupbv( &syncCookie.octet_str, &cookie ); + + ldap_pvt_thread_mutex_lock( &si->si_monitor_mutex ); + ber_bvreplace( &si->si_lastCookieRcvd, &cookie ); + ldap_pvt_thread_mutex_unlock( &si->si_monitor_mutex ); } if ( !BER_BVISNULL( &syncCookie.octet_str ) ) { @@ -1728,6 +1764,10 @@ logerr: if ( !BER_BVISNULL( &cookie ) ) { ch_free( syncCookie.octet_str.bv_val ); ber_dupbv( &syncCookie.octet_str, &cookie ); + + ldap_pvt_thread_mutex_lock( &si->si_monitor_mutex ); + ber_bvreplace( &si->si_lastCookieRcvd, &cookie ); + ldap_pvt_thread_mutex_unlock( &si->si_monitor_mutex ); } if ( !BER_BVISNULL( &syncCookie.octet_str ) ) { @@ -1868,6 +1908,12 @@ done: return rc; } +static int +syncrepl_monitor_add( syncinfo_t *si ); + +static int +syncrepl_monitor_del( syncinfo_t *si ); + static void * do_syncrepl( void *ctx, @@ -1889,6 +1935,11 @@ do_syncrepl( if ( slapd_shutdown ) return NULL; + if ( !si->si_monitorInited ) { + syncrepl_monitor_add( si ); + si->si_monitorInited = 1; + } + Debug( LDAP_DEBUG_TRACE, "=>do_syncrepl %s\n", si->si_ridtxt ); /* Don't get stuck here while a pause is initiated */ @@ -1994,6 +2045,15 @@ reload: if ( rc == LDAP_SUCCESS ) { ldap_get_option( si->si_ld, LDAP_OPT_DESC, &s ); + if ( si->si_connaddr ) { + Sockaddr addr; + socklen_t len = sizeof( addr ); + if ( !getsockname( s, &addr.sa_addr, &len )) { + si->si_connaddr->bv_len = SLAP_ADDRLEN; + slap_sockaddrstr( &addr, si->si_connaddr ); + } + } + /* use current DB */ op->o_bd = be; op->o_dn = op->o_bd->be_rootdn; @@ -5673,6 +5733,10 @@ syncinfo_free( syncinfo_t *sie, int free_all ) do { si_next = sie->si_next; + if ( !BER_BVISEMPTY( &sie->si_monitor_ndn )) { + syncrepl_monitor_del( sie ); + } + if ( sie->si_ld ) { if ( sie->si_conn ) { connection_client_stop( sie->si_conn ); @@ -5693,6 +5757,7 @@ syncinfo_free( syncinfo_t *sie, int free_all ) } ldap_pvt_thread_mutex_destroy( &sie->si_mutex ); + ldap_pvt_thread_mutex_destroy( &sie->si_monitor_mutex ); bindconf_free( &sie->si_bindconf ); @@ -6462,6 +6527,402 @@ parse_syncrepl_line( return 0; } +/* monitor entry contains: + provider URLs + timestamp of last contact + cookievals + */ + +static ObjectClass *oc_olmSyncRepl; +static AttributeDescription *ad_olmProviderURIList, + *ad_olmConnection, *ad_olmSyncPhase, + *ad_olmNextConnect, *ad_olmLastConnect, *ad_olmLastContact, + *ad_olmLastCookieRcvd, *ad_olmLastCookieSent; + +static struct { + char *name; + char *oid; +} s_oid[] = { + { "olmSyncReplAttributes", "olmOverlayAttributes:1" }, + { "olmSyncReplObjectClasses", "olmOverlayObjectClasses:1" }, + { NULL } +}; + +static struct { + char *desc; + AttributeDescription **ad; +} s_at[] = { + { "( olmSyncReplAttributes:1 " + "NAME ( 'olmSRProviderURIList' ) " + "DESC 'List of provider URIs for this consumer instance' " + "SUP monitoredInfo " + "NO-USER-MODIFICATION " + "USAGE dSAOperation )", + &ad_olmProviderURIList }, + { "( olmSyncReplAttributes:2 " + "NAME ( 'olmSRConnection' ) " + "DESC 'Local address:port of connection to provider' " + "SUP monitoredInfo " + "SINGLE-VALUE " + "NO-USER-MODIFICATION " + "USAGE dSAOperation )", + &ad_olmConnection }, + { "( olmSyncReplAttributes:3 " + "NAME ( 'olmSRSyncPhase' ) " + "DESC 'Current syncrepl mode' " + "SUP monitoredInfo " + "SINGLE-VALUE " + "NO-USER-MODIFICATION " + "USAGE dSAOperation )", + &ad_olmSyncPhase }, + { "( olmSyncReplAttributes:4 " + "NAME ( 'olmSRNextConnect' ) " + "DESC 'Scheduled time of next connection attempt' " + "SUP monitorTimestamp " + "SINGLE-VALUE " + "NO-USER-MODIFICATION " + "USAGE dSAOperation )", + &ad_olmNextConnect }, + { "( olmSyncReplAttributes:5 " + "NAME ( 'olmSRLastConnect' ) " + "DESC 'Time last connected to provider' " + "SUP monitorTimestamp " + "SINGLE-VALUE " + "NO-USER-MODIFICATION " + "USAGE dSAOperation )", + &ad_olmLastConnect }, + { "( olmSyncReplAttributes:6 " + "NAME ( 'olmSRLastContact' ) " + "DESC 'Time last message received from provider' " + "SUP monitorTimestamp " + "SINGLE-VALUE " + "NO-USER-MODIFICATION " + "USAGE dSAOperation )", + &ad_olmLastContact }, + { "( olmSyncReplAttributes:7 " + "NAME ( 'olmSRLastCookieRcvd' ) " + "DESC 'Last sync cookie received from provider' " + "SUP monitoredInfo " + "NO-USER-MODIFICATION " + "USAGE dSAOperation )", + &ad_olmLastCookieRcvd }, + { "( olmSyncReplAttributes:8 " + "NAME ( 'olmSRLastCookieSent' ) " + "DESC 'Last sync cookie sent to provider' " + "SUP monitoredInfo " + "NO-USER-MODIFICATION " + "USAGE dSAOperation )", + &ad_olmLastCookieSent }, + { NULL } +}; + +static struct { + char *desc; + ObjectClass **oc; +} s_oc[] = { + { "( olmSyncReplObjectClasses:1 " + "NAME ( 'olmSyncReplInstance' ) " + "SUP monitoredObject STRUCTURAL " + "MAY ( " + "olmSRProviderURIList " + "$ olmSRConnection " + "$ olmSRSyncPhase " + "$ olmSRNextConnect " + "$ olmSRLastConnect " + "$ olmSRLastContact " + "$ olmSRLastCookieRcvd " + "$ olmSRLastCookieSent " + ") )", + &oc_olmSyncRepl }, + { NULL } +}; + +static int +syncrepl_monitor_initialized; + +int +syncrepl_monitor_init( void ) +{ + int i, code; + + if ( syncrepl_monitor_initialized ) + return 0; + + if ( backend_info( "monitor" ) == NULL ) + return -1; + + { + ConfigArgs c; + char *argv[3]; + + argv[ 0 ] = "syncrepl monitor"; + c.argv = argv; + c.argc = 2; + c.fname = argv[0]; + for ( i=0; s_oid[i].name; i++ ) { + argv[1] = s_oid[i].name; + argv[2] = s_oid[i].oid; + if ( parse_oidm( &c, 0, NULL )) { + Debug( LDAP_DEBUG_ANY, + "syncrepl_monitor_init: unable to add " + "objectIdentifier \"%s=%s\"\n", + s_oid[i].name, s_oid[i].oid ); + return 2; + } + } + } + + for ( i=0; s_at[i].desc != NULL; i++ ) { + code = register_at( s_at[i].desc, s_at[i].ad, 1 ); + if ( code != LDAP_SUCCESS ) { + Debug( LDAP_DEBUG_ANY, + "syncrepl_monitor_init: register_at failed for attributeType (%s)\n", + s_at[i].desc ); + return 3; + } else { + (*s_at[i].ad)->ad_type->sat_flags |= SLAP_AT_HIDE; + } + } + + for ( i=0; s_oc[i].desc != NULL; i++ ) { + code = register_oc( s_oc[i].desc, s_oc[i].oc, 1 ); + if ( code != LDAP_SUCCESS ) { + Debug( LDAP_DEBUG_ANY, + "syncrepl_monitor_init: register_oc failed for objectClass (%s)\n", + s_oc[i].desc ); + return 4; + } else { + (*s_oc[i].oc)->soc_flags |= SLAP_OC_HIDE; + } + } + syncrepl_monitor_initialized = 1; + + return 0; +} + +static const struct berval zerotime = BER_BVC("00000101000000Z"); + +static int +syncrepl_monitor_update( + Operation *op, + SlapReply *rs, + Entry *e, + void *priv ) +{ + syncinfo_t *si = (syncinfo_t *)priv; + Attribute *a; + int isConnected = 0; + + a = attr_find( e->e_attrs, ad_olmConnection ); + if ( !a ) + return SLAP_CB_CONTINUE; + if ( si->si_ld ) { + isConnected = 1; + } else { + a->a_vals[0].bv_val[0] = '\0'; + a->a_vals[0].bv_len = 0; + } + + a = a->a_next; + if ( a->a_desc != ad_olmSyncPhase ) + return SLAP_CB_CONTINUE; + + if ( si->si_refreshDone ) { + struct berval bv = BER_BVC("Persist"); + ber_bvreplace( &a->a_vals[0], &bv ); + } else { + if ( si->si_syncdata && si->si_logstate == SYNCLOG_FALLBACK ) { + struct berval bv = BER_BVC("Fallback Refresh"); + ber_bvreplace( &a->a_vals[0], &bv ); + } else { + struct berval bv = BER_BVC("Refresh"); + ber_bvreplace( &a->a_vals[0], &bv ); + } + } + + { + struct tm tm; + char tmbuf[ LDAP_LUTIL_GENTIME_BUFSIZE ]; + ber_len_t len; + + a = a->a_next; + if ( a->a_desc != ad_olmNextConnect ) + return SLAP_CB_CONTINUE; + + if ( !isConnected && si->si_re && si->si_re->next_sched.tv_sec ) { + time_t next_sched = si->si_re->next_sched.tv_sec; + ldap_pvt_gmtime( &next_sched, &tm ); + lutil_gentime( tmbuf, sizeof( tmbuf ), &tm ); + len = strlen( tmbuf ); + assert( len == a->a_vals[0].bv_len ); + AC_MEMCPY( a->a_vals[0].bv_val, tmbuf, len ); + } else { + AC_MEMCPY( a->a_vals[0].bv_val, zerotime.bv_val, zerotime.bv_len ); + } + + a = a->a_next; + if ( a->a_desc != ad_olmLastConnect ) + return SLAP_CB_CONTINUE; + + if ( si->si_lastconnect ) { + ldap_pvt_gmtime( &si->si_lastconnect, &tm ); + lutil_gentime( tmbuf, sizeof( tmbuf ), &tm ); + len = strlen( tmbuf ); + assert( len == a->a_vals[0].bv_len ); + AC_MEMCPY( a->a_vals[0].bv_val, tmbuf, len ); + } + + a = a->a_next; + if ( a->a_desc != ad_olmLastContact ) + return SLAP_CB_CONTINUE; + + if ( si->si_lastcontact ) { + ldap_pvt_gmtime( &si->si_lastcontact, &tm ); + lutil_gentime( tmbuf, sizeof( tmbuf ), &tm ); + len = strlen( tmbuf ); + assert( len == a->a_vals[0].bv_len ); + AC_MEMCPY( a->a_vals[0].bv_val, tmbuf, len ); + } + } + + a = a->a_next; + if ( a->a_desc != ad_olmLastCookieRcvd ) + return SLAP_CB_CONTINUE; + + ldap_pvt_thread_mutex_lock( &si->si_monitor_mutex ); + if ( !BER_BVISEMPTY( &si->si_lastCookieRcvd ) && + !bvmatch( &a->a_vals[0], &si->si_lastCookieRcvd )) + ber_bvreplace( &a->a_vals[0], &si->si_lastCookieRcvd ); + + a = a->a_next; + if ( a->a_desc != ad_olmLastCookieSent ) { + ldap_pvt_thread_mutex_unlock( &si->si_monitor_mutex ); + return SLAP_CB_CONTINUE; + } + + if ( !BER_BVISEMPTY( &si->si_lastCookieSent ) && + !bvmatch( &a->a_vals[0], &si->si_lastCookieSent )) + ber_bvreplace( &a->a_vals[0], &si->si_lastCookieSent ); + ldap_pvt_thread_mutex_unlock( &si->si_monitor_mutex ); + + return SLAP_CB_CONTINUE; +} + +static int +syncrepl_monitor_add( + syncinfo_t *si +) +{ + BackendInfo *mi; + monitor_extra_t *mbe; + struct berval pndn, pdn, rdn, bv; + char rdnbuf[sizeof("cn=Consumer 999")]; + Entry *e, *p; + int rc; + + if ( !syncrepl_monitor_initialized ) + return -1; + + mi = backend_info( "monitor" ); + if ( !mi || !mi->bi_extra ) { + SLAP_DBFLAGS( si->si_be ) ^= SLAP_DBFLAG_MONITORING; + return 0; + } + mbe = mi->bi_extra; + + if ( !mbe->is_configured() ) { + return 0; + } + + rc = mbe->register_database( si->si_be, &pndn ); + if ( rc ) { + Debug( LDAP_DEBUG_ANY, "syncrepl_monitor_add: " + "failed to register the database with back-monitor\n" ); + return rc; + } + rdn.bv_len = sprintf(rdnbuf, "cn=Consumer %03d", si->si_rid ); + rdn.bv_val = rdnbuf; + p = mbe->entry_get_unlocked( &pndn ); + if ( p ) { + pdn = p->e_name; + } else { + pdn = pndn; + } + + e = mbe->entry_stub( &pdn, &pndn, &rdn, + oc_olmSyncRepl, NULL, NULL ); + if ( e == NULL ) { + Debug( LDAP_DEBUG_ANY, + "syncrepl_monitor_add: " + "unable to create entry \"%s,%s\"\n", + rdn.bv_val, pndn.bv_val ); + return -1; + } + + attr_merge_normalize_one( e, ad_olmProviderURIList, + &si->si_bindconf.sb_uri, NULL ); + + { + char addrbuf[SLAP_ADDRLEN]; + struct berval bv = BER_BVC(addrbuf); + addrbuf[0] = '\0'; + attr_merge_normalize_one( e, ad_olmConnection, &bv, NULL ); + } + { + struct berval bv = BER_BVC("Refresh"); + attr_merge_normalize_one( e, ad_olmSyncPhase, &bv, NULL ); + } + { + attr_merge_normalize_one( e, ad_olmNextConnect, (struct berval *)&zerotime, NULL ); + attr_merge_normalize_one( e, ad_olmLastConnect, (struct berval *)&zerotime, NULL ); + attr_merge_normalize_one( e, ad_olmLastContact, (struct berval *)&zerotime, NULL ); + } + { + struct berval bv = BER_BVC(""); + attr_merge_normalize_one( e, ad_olmLastCookieRcvd, &bv, NULL ); + attr_merge_normalize_one( e, ad_olmLastCookieSent, &bv, NULL ); + } + { + monitor_callback_t *cb = ch_calloc( sizeof( monitor_callback_t ), 1 ); + cb->mc_update = syncrepl_monitor_update; + cb->mc_private = si; + rc = mbe->register_entry( e, cb, NULL, 0 ); + } + + p = mbe->entry_get_unlocked( &e->e_nname ); + if ( p ) { + Attribute *a = attr_find( p->e_attrs, ad_olmConnection ); + if ( a ) { + si->si_connaddr = &a->a_vals[0]; + a->a_vals[0].bv_len = 0; + } + } + + si->si_monitor_ndn = e->e_nname; + BER_BVZERO( &e->e_nname ); + entry_free( e ); + + return rc; +} + +static int +syncrepl_monitor_del( + syncinfo_t *si +) +{ + BackendInfo *mi; + + mi = backend_info( "monitor" ); + if ( mi && mi->bi_extra ) { + monitor_extra_t *mbe = mi->bi_extra; + mbe->unregister_entry( &si->si_monitor_ndn ); + } + ch_free( si->si_lastCookieSent.bv_val ); + ch_free( si->si_lastCookieRcvd.bv_val ); + ch_free( si->si_monitor_ndn.bv_val ); + return 0; +} + static int add_syncrepl( ConfigArgs *c ) @@ -6512,6 +6973,7 @@ add_syncrepl( si->si_presentlist = NULL; LDAP_LIST_INIT( &si->si_nonpresentlist ); + ldap_pvt_thread_mutex_init( &si->si_monitor_mutex ); ldap_pvt_thread_mutex_init( &si->si_mutex ); rc = parse_syncrepl_line( c, si );