From: Pierangelo Masarati Date: Thu, 21 Apr 2005 03:17:31 +0000 (+0000) Subject: add basic support for retry; protect internal bind behind mutexes; rework search... X-Git-Tag: OPENLDAP_AC_BP~860 X-Git-Url: https://git.sur5r.net/?a=commitdiff_plain;h=08a6909f73ffb7c3ef7b1c108e93d44fd1d43d9f;p=openldap add basic support for retry; protect internal bind behind mutexes; rework search, review candidate selection; minor cleanup. Passes concurrency test036 --- diff --git a/servers/slapd/back-meta/add.c b/servers/slapd/back-meta/add.c index 870c92ef55..eec76d28af 100644 --- a/servers/slapd/back-meta/add.c +++ b/servers/slapd/back-meta/add.c @@ -36,13 +36,14 @@ int meta_back_add( Operation *op, SlapReply *rs ) { struct metainfo *li = ( struct metainfo * )op->o_bd->be_private; - struct metaconn *lc; + struct metaconn *mc; int i, candidate = -1; int isupdate; Attribute *a; LDAPMod **attrs; struct berval mdn = BER_BVNULL, mapped; dncookie dc; + int msgid, do_retry = 1; Debug(LDAP_DEBUG_ARGS, "==> meta_back_add: %s\n", op->o_req_dn.bv_val, 0, 0 ); @@ -50,12 +51,12 @@ meta_back_add( Operation *op, SlapReply *rs ) /* * get the current connection */ - lc = meta_back_getconn( op, rs, &candidate, LDAP_BACK_SENDERR ); - if ( !lc || !meta_back_dobind( lc, op, LDAP_BACK_SENDERR ) ) { + mc = meta_back_getconn( op, rs, &candidate, LDAP_BACK_SENDERR ); + if ( !mc || !meta_back_dobind( mc, op, LDAP_BACK_SENDERR ) ) { return rs->sr_err; } - if ( !meta_back_is_valid( lc, candidate ) ) { + if ( !meta_back_is_valid( mc, candidate ) ) { rs->sr_err = LDAP_UNAVAILABLE; send_ldap_result( op, rs ); return rs->sr_err; @@ -165,8 +166,21 @@ meta_back_add( Operation *op, SlapReply *rs ) } attrs[ i ] = NULL; - rs->sr_err = ldap_add_ext_s( lc->mc_conns[ candidate ].msc_ld, mdn.bv_val, +retry:; +#if 0 + rs->sr_err = ldap_add_ext( mc->mc_conns[ candidate ].msc_ld, mdn.bv_val, + attrs, op->o_ctrls, NULL, &msgid ); + rs->sr_err = meta_back_op_result( op, rs, &mc->mc_conns[ candidate ], msgid, LDAP_BACK_SENDERR ); +#endif + rs->sr_err = ldap_add_ext_s( mc->mc_conns[ candidate ].msc_ld, mdn.bv_val, attrs, op->o_ctrls, NULL ); + if ( rs->sr_err == LDAP_UNAVAILABLE && do_retry ) { + do_retry = 0; + if ( meta_back_retry( op, rs, mc, candidate, LDAP_BACK_SENDERR ) ) { + goto retry; + } + } + for ( --i; i >= 0; --i ) { free( attrs[ i ]->mod_bvalues ); free( attrs[ i ] ); @@ -177,6 +191,6 @@ meta_back_add( Operation *op, SlapReply *rs ) BER_BVZERO( &mdn ); } - return meta_back_op_result( lc, op, rs, candidate ); + return meta_back_op_result( mc, op, rs, candidate ); } diff --git a/servers/slapd/back-meta/back-meta.h b/servers/slapd/back-meta/back-meta.h index 78ab9ffdf3..84dd36d743 100644 --- a/servers/slapd/back-meta/back-meta.h +++ b/servers/slapd/back-meta/back-meta.h @@ -165,12 +165,13 @@ struct metasingleconn { struct metaconn { struct slap_conn *mc_conn; + ldap_pvt_thread_mutex_t mc_mutex; /* * means that the connection is bound; * of course only one target actually is ... */ - int mc_bound_target; + int mc_auth_target; #define META_BOUND_NONE (-1) #define META_BOUND_ALL (-2) /* supersedes the connection stuff */ @@ -237,47 +238,58 @@ meta_back_getconn( Operation *op, SlapReply *rs, int *candidate, - ldap_back_send_t sendok -); + ldap_back_send_t sendok ); + +extern int +meta_back_retry( + Operation *op, + SlapReply *rs, + struct metaconn *mc, + int candidate, + ldap_back_send_t sendok ); + +extern void +meta_back_conn_free( struct metaconn *mc ); extern int meta_back_dobind( struct metaconn *lc, Operation *op, - ldap_back_send_t sendok -); + ldap_back_send_t sendok ); + +int +meta_back_single_dobind( + Operation *op, + struct metasingleconn *msc, + ldap_back_send_t sendok, + int retries ); extern int meta_back_is_valid( struct metaconn *lc, - int candidate -); + int candidate ); extern int meta_back_op_result( struct metaconn *lc, Operation *op, SlapReply *rs, - int candidate -); + int candidate ); extern int back_meta_LTX_init_module( int argc, - char *argv[] -); + char *argv[] ); extern int meta_back_conn_cmp( const void *c1, - const void *c2 -); + const void *c2 ); extern int meta_back_conn_dup( void *c1, - void *c2 -); + void *c2 ); /* * Candidate stuff @@ -285,26 +297,23 @@ meta_back_conn_dup( extern int meta_back_is_candidate( struct berval *nsuffix, - struct berval *ndn -); + struct berval *ndn, + int scope ); extern int meta_back_select_unique_candidate( struct metainfo *li, - struct berval *ndn -); + struct berval *ndn ); extern int meta_clear_unused_candidates( Operation *op, struct metaconn *lc, - int candidate -); + int candidate ); extern int meta_clear_one_candidate( - struct metasingleconn *lc -); + struct metasingleconn *lc ); /* * Dn cache stuff (experimental) @@ -312,40 +321,33 @@ meta_clear_one_candidate( extern int meta_dncache_cmp( const void *c1, - const void *c2 -); + const void *c2 ); extern int meta_dncache_dup( void *c1, - void *c2 -); + void *c2 ); #define META_TARGET_NONE (-1) #define META_TARGET_MULTIPLE (-2) extern int meta_dncache_get_target( struct metadncache *cache, - struct berval *ndn -); + struct berval *ndn ); extern int meta_dncache_update_entry( struct metadncache *cache, struct berval *ndn, - int target -); + int target ); extern int meta_dncache_delete_entry( struct metadncache *cache, - struct berval *ndn -); + struct berval *ndn ); extern void -meta_dncache_free( - void *entry -); +meta_dncache_free( void *entry ); LDAP_END_DECL diff --git a/servers/slapd/back-meta/bind.c b/servers/slapd/back-meta/bind.c index 70968848b6..1fc44d8f94 100644 --- a/servers/slapd/back-meta/bind.c +++ b/servers/slapd/back-meta/bind.c @@ -36,21 +36,20 @@ static LDAP_REBIND_PROC meta_back_rebind; static int -meta_back_do_single_bind( - struct metaconn *lc, +meta_back_single_bind( Operation *op, SlapReply *rs, - int candidate -); + struct metaconn *mc, + int candidate ); int meta_back_bind( Operation *op, SlapReply *rs ) { struct metainfo *li = ( struct metainfo * )op->o_bd->be_private; - struct metaconn *lc; + struct metaconn *mc; int rc = LDAP_OTHER, - i, gotit = 0, ndnlen, isroot = 0; + i, gotit = 0, isroot = 0; char *candidates = meta_back_candidates_get( op ); @@ -67,8 +66,8 @@ meta_back_bind( Operation *op, SlapReply *rs ) /* we need meta_back_getconn() not send result even on error, * because we want to intercept the error and make it * invalidCredentials */ - lc = meta_back_getconn( op, rs, NULL, LDAP_BACK_DONTSEND ); - if ( !lc ) { + mc = meta_back_getconn( op, rs, NULL, LDAP_BACK_DONTSEND ); + if ( !mc ) { Debug( LDAP_DEBUG_ANY, "meta_back_bind: no target " "for dn \"%s\" (%d: %s).\n", @@ -90,15 +89,10 @@ meta_back_bind( Operation *op, SlapReply *rs ) /* * Each target is scanned ... */ - lc->mc_bound_target = META_BOUND_NONE; - ndnlen = op->o_req_ndn.bv_len; + mc->mc_auth_target = META_BOUND_NONE; for ( i = 0; i < li->mi_ntargets; i++ ) { int lerr; - struct berval orig_dn = op->o_req_dn; - struct berval orig_ndn = op->o_req_ndn; - struct berval orig_cred = op->orb_cred; - int orig_method = op->orb_method; - + Operation op2 = *op; /* * Skip non-candidates @@ -123,32 +117,24 @@ meta_back_bind( Operation *op, SlapReply *rs ) if ( isroot && !BER_BVISNULL( &li->mi_targets[ i ]->mt_pseudorootdn ) ) { - op->o_req_dn = li->mi_targets[ i ]->mt_pseudorootdn; - op->o_req_ndn = li->mi_targets[ i ]->mt_pseudorootdn; - op->orb_cred = li->mi_targets[ i ]->mt_pseudorootpw; - op->orb_method = LDAP_AUTH_SIMPLE; + op2.o_req_dn = li->mi_targets[ i ]->mt_pseudorootdn; + op2.o_req_ndn = li->mi_targets[ i ]->mt_pseudorootdn; + op2.orb_cred = li->mi_targets[ i ]->mt_pseudorootpw; + op2.orb_method = LDAP_AUTH_SIMPLE; } - lerr = meta_back_do_single_bind( lc, op, rs, i ); + lerr = meta_back_single_bind( &op2, rs, mc, i ); if ( lerr != LDAP_SUCCESS ) { rs->sr_err = lerr; candidates[ i ] = META_NOT_CANDIDATE; -#if 0 - ( void )meta_clear_one_candidate( &lc->mc_conns[ i ] ); -#endif } else { rc = LDAP_SUCCESS; } - - op->o_req_dn = orig_dn; - op->o_req_ndn = orig_ndn; - op->orb_cred = orig_cred; - op->orb_method = orig_method; } if ( isroot ) { - lc->mc_bound_target = META_BOUND_ALL; + mc->mc_auth_target = META_BOUND_ALL; } /* @@ -179,22 +165,22 @@ meta_back_bind( Operation *op, SlapReply *rs ) } /* - * meta_back_do_single_bind + * meta_back_single_bind * * attempts to perform a bind with creds */ static int -meta_back_do_single_bind( - struct metaconn *lc, +meta_back_single_bind( Operation *op, SlapReply *rs, + struct metaconn *mc, int candidate ) { struct metainfo *li = ( struct metainfo * )op->o_bd->be_private; struct berval mdn = BER_BVNULL; dncookie dc; - struct metasingleconn *lsc = &lc->mc_conns[ candidate ]; + struct metasingleconn *msc = &mc->mc_conns[ candidate ]; int msgid; /* @@ -215,37 +201,44 @@ meta_back_do_single_bind( * and more in case of failure ... */ /* FIXME: should be check if at least some of the op->o_ctrls * can/should be passed? */ - rs->sr_err = ldap_sasl_bind( lsc->msc_ld, mdn.bv_val, + rs->sr_err = ldap_sasl_bind( msc->msc_ld, mdn.bv_val, LDAP_SASL_SIMPLE, &op->orb_cred, op->o_ctrls, NULL, &msgid ); if ( rs->sr_err == LDAP_SUCCESS ) { LDAPMessage *res; struct timeval tv = { 0, 0 }; int rc; - int nretries = 0; + int nretries = META_BIND_NRETRIES; /* * handle response!!! */ retry:; - switch ( ldap_result( lsc->msc_ld, msgid, 0, &tv, &res ) ) { + switch ( ldap_result( msc->msc_ld, msgid, 0, &tv, &res ) ) { case 0: - if ( ++nretries <= META_BIND_NRETRIES ) { + if ( nretries > 0 ) { ldap_pvt_thread_yield(); tv.tv_sec = 0; tv.tv_usec = META_BIND_TIMEOUT; + nretries--; goto retry; } rs->sr_err = LDAP_BUSY; break; case -1: - ldap_get_option( lsc->msc_ld, LDAP_OPT_ERROR_NUMBER, + ldap_get_option( msc->msc_ld, LDAP_OPT_ERROR_NUMBER, &rs->sr_err ); + if ( rs->sr_err == LDAP_UNAVAILABLE && nretries > 0 ) { + nretries--; + if ( meta_back_retry( op, rs, mc, candidate, LDAP_BACK_SENDERR ) ) { + goto retry; + } + } break; default: - rc = ldap_parse_result( lsc->msc_ld, res, &rs->sr_err, + rc = ldap_parse_result( msc->msc_ld, res, &rs->sr_err, NULL, NULL, NULL, NULL, 1 ); if ( rc != LDAP_SUCCESS ) { rs->sr_err = rc; @@ -259,31 +252,23 @@ retry:; goto return_results; } - if ( !BER_BVISNULL( &lsc->msc_bound_ndn ) ) { - ber_memfree( lsc->msc_bound_ndn.bv_val ); - } - ber_dupbv( &lsc->msc_bound_ndn, &op->o_req_dn ); - lsc->msc_bound = META_BOUND; - lc->mc_bound_target = candidate; + ber_bvreplace( &msc->msc_bound_ndn, &op->o_req_dn ); + msc->msc_bound = META_BOUND; + mc->mc_auth_target = candidate; if ( LDAP_BACK_SAVECRED( li ) ) { - if ( !BER_BVISNULL( &lsc->msc_cred ) ) { - /* destroy sensitive data */ - memset( lsc->msc_cred.bv_val, 0, lsc->msc_cred.bv_len ); - ber_memfree( lsc->msc_cred.bv_val ); - } - ber_dupbv( &lsc->msc_cred, &op->orb_cred ); - ldap_set_rebind_proc( lsc->msc_ld, meta_back_rebind, lsc ); + ber_bvreplace( &msc->msc_cred, &op->orb_cred ); + ldap_set_rebind_proc( msc->msc_ld, meta_back_rebind, msc ); } if ( li->mi_cache.ttl != META_DNCACHE_DISABLED - && op->o_req_ndn.bv_len != 0 ) { + && op->o_req_ndn.bv_len != 0 ) + { ( void )meta_dncache_update_entry( &li->mi_cache, &op->o_req_ndn, candidate ); } return_results:; - if ( mdn.bv_val != op->o_req_dn.bv_val ) { free( mdn.bv_val ); } @@ -291,110 +276,127 @@ return_results:; return rs->sr_err; } +/* + * meta_back_single_dobind + */ +int +meta_back_single_dobind( + Operation *op, + struct metasingleconn *msc, + ldap_back_send_t sendok, + int retries ) +{ + int rc; + struct berval cred = BER_BVC( "" ); + int msgid; + + /* + * Otherwise an anonymous bind is performed + * (note: if the target was already bound, the anonymous + * bind clears the previous bind). + */ + if ( !BER_BVISNULL( &msc->msc_bound_ndn ) ) { + ber_memfree( msc->msc_bound_ndn.bv_val ); + BER_BVZERO( &msc->msc_bound_ndn ); + } + + if ( /* FIXME: need li ... li->savecred && */ + !BER_BVISNULL( &msc->msc_cred ) ) + { + /* destroy sensitive data */ + memset( msc->msc_cred.bv_val, 0, msc->msc_cred.bv_len ); + ber_memfree( msc->msc_cred.bv_val ); + BER_BVZERO( &msc->msc_cred ); + } + + /* FIXME: should we check if at least some of the op->o_ctrls + * can/should be passed? */ + rc = ldap_sasl_bind( msc->msc_ld, "", LDAP_SASL_SIMPLE, &cred, + NULL, NULL, &msgid ); + if ( rc == LDAP_SUCCESS ) { + LDAPMessage *res; + struct timeval tv = { 0, 0 }; + int err; + + /* + * handle response!!! + */ +retry:; + switch ( ldap_result( msc->msc_ld, msgid, 0, &tv, &res ) ) { + case 0: + if ( retries > 0 ) { + ldap_pvt_thread_yield(); + tv.tv_sec = 0; + tv.tv_usec = META_BIND_TIMEOUT; + retries--; + goto retry; + } + + rc = LDAP_BUSY; + break; + + case -1: + ldap_get_option( msc->msc_ld, + LDAP_OPT_ERROR_NUMBER, &rc ); + break; + + default: + rc = ldap_parse_result( msc->msc_ld, res, &err, + NULL, NULL, NULL, NULL, 1 ); + if ( rc == LDAP_SUCCESS ) { + rc = err; + } + break; + } + } + + return rc; +} + /* * meta_back_dobind */ int -meta_back_dobind( struct metaconn *lc, Operation *op, ldap_back_send_t sendok ) +meta_back_dobind( struct metaconn *mc, Operation *op, ldap_back_send_t sendok ) { - struct metasingleconn *lsc; + struct metasingleconn *msc; int bound = 0, i; - char *candidates = meta_back_candidates_get( op ); + char *candidates = meta_back_candidates_get( op ); + + ldap_pvt_thread_mutex_lock( &mc->mc_mutex ); /* * all the targets are bound as pseudoroot */ - if ( lc->mc_bound_target == META_BOUND_ALL ) { - return 1; + if ( mc->mc_auth_target == META_BOUND_ALL ) { + bound = 1; + goto done; } - for ( i = 0, lsc = &lc->mc_conns[ 0 ]; !META_LAST( lsc ); ++i, ++lsc ) { + for ( i = 0, msc = &mc->mc_conns[ 0 ]; !META_LAST( msc ); ++i, ++msc ) { int rc; - struct berval cred = BER_BVC(""); - int msgid; /* * Not a candidate or something wrong with this target ... */ - if ( lsc->msc_ld == NULL ) { + if ( msc->msc_ld == NULL ) { continue; } /* * If the target is already bound it is skipped */ - if ( lsc->msc_bound == META_BOUND && lc->mc_bound_target == i ) { + if ( msc->msc_bound == META_BOUND && mc->mc_auth_target == i ) { ++bound; continue; } - /* - * Otherwise an anonymous bind is performed - * (note: if the target was already bound, the anonymous - * bind clears the previous bind). - */ - if ( !BER_BVISNULL( &lsc->msc_bound_ndn ) ) { - ber_memfree( lsc->msc_bound_ndn.bv_val ); - BER_BVZERO( &lsc->msc_bound_ndn ); - } - - if ( /* FIXME: need li ... li->savecred && */ - !BER_BVISNULL( &lsc->msc_cred ) ) - { - /* destroy sensitive data */ - memset( lsc->msc_cred.bv_val, 0, lsc->msc_cred.bv_len ); - ber_memfree( lsc->msc_cred.bv_val ); - BER_BVZERO( &lsc->msc_cred ); - } - - /* FIXME: should we check if at least some of the op->o_ctrls - * can/should be passed? */ - rc = ldap_sasl_bind( lsc->msc_ld, "", LDAP_SASL_SIMPLE, &cred, - NULL, NULL, &msgid ); - if ( rc == LDAP_SUCCESS ) { - LDAPMessage *res; - struct timeval tv = { 0, 0 }; - int err; - int nretries = 0; - - /* - * handle response!!! - */ -retry:; - switch ( ldap_result( lsc->msc_ld, msgid, 0, &tv, &res ) ) { - case 0: - if ( ++nretries <= META_BIND_NRETRIES ) { - ldap_pvt_thread_yield(); - tv.tv_sec = 0; - tv.tv_usec = META_BIND_TIMEOUT; - goto retry; - } - - rc = LDAP_BUSY; - break; - - case -1: - ldap_get_option( lsc->msc_ld, LDAP_OPT_ERROR_NUMBER, - &rc ); - break; - - default: - rc = ldap_parse_result( lsc->msc_ld, res, &err, - NULL, NULL, NULL, NULL, 1 ); - if ( rc == LDAP_SUCCESS ) { - rc = err; - } - break; - } - } - + rc = meta_back_single_dobind( op, msc, sendok, META_BIND_NRETRIES ); if ( rc != LDAP_SUCCESS ) { - Debug( LDAP_DEBUG_ANY, - "==>meta_back_dobind: (anonymous)" - " bind failed" - " with error %d (%s)\n", - rc, ldap_err2string( rc ), 0 ); + Debug( LDAP_DEBUG_ANY, "%s meta_back_dobind[%d]: " + "(anonymous) err=%d\n", + op->o_log_prefix, i, rc ); /* * null cred bind should always succeed @@ -405,15 +407,19 @@ retry:; */ candidates[ i ] = META_NOT_CANDIDATE; #if 0 - ( void )meta_clear_one_candidate( lsc ); + ( void )meta_clear_one_candidate( msc ); #endif continue; } /* else */ - lsc->msc_bound = META_ANONYMOUS; + candidates[ i ] = META_CANDIDATE; + msc->msc_bound = META_ANONYMOUS; ++bound; } +done:; + ldap_pvt_thread_mutex_unlock( &mc->mc_mutex ); + return( bound > 0 ); } @@ -421,22 +427,22 @@ retry:; * */ int -meta_back_is_valid( struct metaconn *lc, int candidate ) +meta_back_is_valid( struct metaconn *mc, int candidate ) { - struct metasingleconn *lsc; + struct metasingleconn *msc; int i; - assert( lc ); + assert( mc ); if ( candidate < 0 ) { return 0; } - for ( i = 0, lsc = &lc->mc_conns[ 0 ]; !META_LAST( lsc ) && i < candidate; - ++i, ++lsc ); + for ( i = 0, msc = &mc->mc_conns[ 0 ]; !META_LAST( msc ) && i < candidate; + ++i, ++msc ); - if ( !META_LAST( lsc ) ) { - return ( lsc->msc_ld != NULL ); + if ( !META_LAST( msc ) ) { + return ( msc->msc_ld != NULL ); } return 0; @@ -452,10 +458,10 @@ static int meta_back_rebind( LDAP *ld, LDAP_CONST char *url, ber_tag_t request, ber_int_t msgid, void *params ) { - struct metasingleconn *lsc = params; + struct metasingleconn *msc = (struct metasingleconn *)params; - return ldap_sasl_bind_s( ld, lsc->msc_bound_ndn.bv_val, - LDAP_SASL_SIMPLE, &lsc->msc_cred, + return ldap_sasl_bind_s( ld, msc->msc_bound_ndn.bv_val, + LDAP_SASL_SIMPLE, &msc->msc_cred, NULL, NULL, NULL ); } @@ -464,25 +470,25 @@ meta_back_rebind( LDAP *ld, LDAP_CONST char *url, ber_tag_t request, */ int meta_back_op_result( - struct metaconn *lc, + struct metaconn *mc, Operation *op, SlapReply *rs, int candidate ) { int i, rerr = LDAP_SUCCESS; - struct metasingleconn *lsc; + struct metasingleconn *msc; char *rmsg = NULL; char *rmatch = NULL; int free_rmsg = 0, free_rmatch = 0; if ( candidate != META_TARGET_NONE ) { - lsc = &lc->mc_conns[ candidate ]; + msc = &mc->mc_conns[ candidate ]; rs->sr_err = LDAP_SUCCESS; - ldap_get_option( lsc->msc_ld, LDAP_OPT_ERROR_NUMBER, &rs->sr_err ); + ldap_get_option( msc->msc_ld, LDAP_OPT_ERROR_NUMBER, &rs->sr_err ); if ( rs->sr_err != LDAP_SUCCESS ) { /* * better check the type of error. In some cases @@ -490,9 +496,9 @@ meta_back_op_result( * success if at least one of the targets gave * positive result ... */ - ldap_get_option( lsc->msc_ld, + ldap_get_option( msc->msc_ld, LDAP_OPT_ERROR_STRING, &rmsg ); - ldap_get_option( lsc->msc_ld, + ldap_get_option( msc->msc_ld, LDAP_OPT_MATCHED_DN, &rmatch ); rerr = rs->sr_err = slap_map_api2result( rs ); @@ -512,13 +518,13 @@ meta_back_op_result( } } else { - for ( i = 0, lsc = &lc->mc_conns[ 0 ]; !META_LAST( lsc ); ++i, ++lsc ) { + for ( i = 0, msc = &mc->mc_conns[ 0 ]; !META_LAST( msc ); ++i, ++msc ) { char *msg = NULL; char *match = NULL; rs->sr_err = LDAP_SUCCESS; - ldap_get_option( lsc->msc_ld, LDAP_OPT_ERROR_NUMBER, &rs->sr_err ); + ldap_get_option( msc->msc_ld, LDAP_OPT_ERROR_NUMBER, &rs->sr_err ); if ( rs->sr_err != LDAP_SUCCESS ) { /* * better check the type of error. In some cases @@ -526,9 +532,9 @@ meta_back_op_result( * success if at least one of the targets gave * positive result ... */ - ldap_get_option( lsc->msc_ld, + ldap_get_option( msc->msc_ld, LDAP_OPT_ERROR_STRING, &msg ); - ldap_get_option( lsc->msc_ld, + ldap_get_option( msc->msc_ld, LDAP_OPT_MATCHED_DN, &match ); rs->sr_err = slap_map_api2result( rs ); diff --git a/servers/slapd/back-meta/candidates.c b/servers/slapd/back-meta/candidates.c index 96f0f22364..6e846ec172 100644 --- a/servers/slapd/back-meta/candidates.c +++ b/servers/slapd/back-meta/candidates.c @@ -50,12 +50,6 @@ * A possible extension will include the handling of multiple suffixes */ -static int -meta_back_count_candidates( - struct metainfo *li, - struct berval *ndn -); - static int meta_back_is_candidate_unique( struct metainfo *li, @@ -70,12 +64,17 @@ meta_back_is_candidate_unique( int meta_back_is_candidate( struct berval *nsuffix, - struct berval *ndn + struct berval *ndn, + int scope ) { - if ( dnIsSuffix( nsuffix, ndn ) || dnIsSuffix( ndn, nsuffix ) ) { + if ( dnIsSuffix( ndn, nsuffix ) ) { + return META_CANDIDATE; + } + + if ( scope == LDAP_SCOPE_SUBTREE && dnIsSuffix( nsuffix, ndn ) ) { /* - * suffix longer than dn + * suffix longer than dn, but common part matches */ return META_CANDIDATE; } @@ -83,39 +82,6 @@ meta_back_is_candidate( return META_NOT_CANDIDATE; } -/* - * meta_back_count_candidates - * - * returns a count of the possible candidate targets - * Note: dn MUST be normalized - */ - -static int -meta_back_count_candidates( - struct metainfo *li, - struct berval *ndn -) -{ - int i, cnt = 0; - - /* - * I know assertions should not check run-time values; - * at present I didn't find a place for such checks - * after config.c - */ - assert( li->mi_targets != NULL ); - assert( li->mi_ntargets != 0 ); - - for ( i = 0; i < li->mi_ntargets; ++i ) { - if ( meta_back_is_candidate( &li->mi_targets[ i ]->mt_nsuffix, ndn ) ) - { - ++cnt; - } - } - - return cnt; -} - /* * meta_back_is_candidate_unique * @@ -128,7 +94,13 @@ meta_back_is_candidate_unique( struct berval *ndn ) { - return ( meta_back_count_candidates( li, ndn ) == 1 ); + switch ( meta_back_select_unique_candidate( li, ndn ) ) { + case META_TARGET_MULTIPLE: + case META_TARGET_NONE: + return 0; + } + + return 1; } /* @@ -147,7 +119,7 @@ meta_back_select_unique_candidate( int i, candidate = META_TARGET_NONE; for ( i = 0; i < li->mi_ntargets; ++i ) { - if ( meta_back_is_candidate( &li->mi_targets[ i ]->mt_nsuffix, ndn ) ) + if ( meta_back_is_candidate( &li->mi_targets[ i ]->mt_nsuffix, ndn, LDAP_SCOPE_BASE ) ) { if ( candidate == META_TARGET_NONE ) { candidate = i; diff --git a/servers/slapd/back-meta/compare.c b/servers/slapd/back-meta/compare.c index 950562e1ad..b2c584ba99 100644 --- a/servers/slapd/back-meta/compare.c +++ b/servers/slapd/back-meta/compare.c @@ -174,23 +174,32 @@ meta_back_compare( Operation *op, SlapReply *rs ) for ( i = 0, lsc = &lc->mc_conns[ 0 ]; !META_LAST( lsc ); lsc++, i++ ) { int lrc; LDAPMessage *res = NULL; + struct timeval tv = { 0 }; + + tv.tv_sec = 0; + tv.tv_usec = 0; if ( msgid[ i ] == -1 ) { continue; } lrc = ldap_result( lsc->msc_ld, msgid[ i ], - 0, NULL, &res ); + 0, &tv, &res ); if ( lrc == 0 ) { - /* - * FIXME: should we yield? - */ - if ( res ) { - ldap_msgfree( res ); - } + assert( res == NULL ); continue; + } else if ( lrc == -1 ) { + /* we do not retry in this case; + * only for unique operations... */ + ldap_get_option( lsc->msc_ld, + LDAP_OPT_ERROR_NUMBER, &rs->sr_err ); + rres = slap_map_api2result( rs ); + rres = rc; + rc = -1; + goto finish; + } else if ( lrc == LDAP_RES_COMPARE ) { if ( count > 0 ) { rres = LDAP_OTHER; @@ -212,7 +221,7 @@ meta_back_compare( Operation *op, SlapReply *rs ) case LDAP_COMPARE_FALSE: /* - * true or flase, got it; + * true or false, got it; * sending to cache ... */ if ( li->mi_cache.ttl != META_DNCACHE_DISABLED ) { diff --git a/servers/slapd/back-meta/conn.c b/servers/slapd/back-meta/conn.c index d71a36be3f..eac32a6fba 100644 --- a/servers/slapd/back-meta/conn.c +++ b/servers/slapd/back-meta/conn.c @@ -47,13 +47,12 @@ int meta_back_conn_cmp( const void *c1, - const void *c2 - ) + const void *c2 ) { - struct metaconn *lc1 = ( struct metaconn * )c1; - struct metaconn *lc2 = ( struct metaconn * )c2; + struct metaconn *mc1 = ( struct metaconn * )c1; + struct metaconn *mc2 = ( struct metaconn * )c2; - return SLAP_PTRCMP( lc1->mc_conn, lc2->mc_conn ); + return SLAP_PTRCMP( mc1->mc_conn, mc2->mc_conn ); } /* @@ -65,13 +64,12 @@ meta_back_conn_cmp( int meta_back_conn_dup( void *c1, - void *c2 - ) + void *c2 ) { - struct metaconn *lc1 = ( struct metaconn * )c1; - struct metaconn *lc2 = ( struct metaconn * )c2; + struct metaconn *mc1 = ( struct metaconn * )c1; + struct metaconn *mc2 = ( struct metaconn * )c2; - return( ( lc1->mc_conn == lc2->mc_conn ) ? -1 : 0 ); + return( ( mc1->mc_conn == mc2->mc_conn ) ? -1 : 0 ); } /* @@ -124,73 +122,73 @@ myprint( Avlnode *root ) static struct metaconn * metaconn_alloc( int ntargets ) { - struct metaconn *lc; + struct metaconn *mc; assert( ntargets > 0 ); /* malloc once only; leave an extra one for one-past-end */ - lc = ch_malloc( sizeof( struct metaconn ) + mc = ch_malloc( sizeof( struct metaconn ) + sizeof( struct metasingleconn ) * ( ntargets + 1 ) ); - if ( lc == NULL ) { + if ( mc == NULL ) { return NULL; } - lc->mc_conns = (struct metasingleconn *)&lc[ 1 ]; + mc->mc_conns = (struct metasingleconn *)&mc[ 1 ]; /* FIXME: needed by META_LAST() */ - lc->mc_conns[ ntargets ].msc_candidate = META_LAST_CONN; + mc->mc_conns[ ntargets ].msc_candidate = META_LAST_CONN; for ( ; ntargets-- > 0; ) { - lc->mc_conns[ ntargets ].msc_ld = NULL; - BER_BVZERO( &lc->mc_conns[ ntargets ].msc_bound_ndn ); - BER_BVZERO( &lc->mc_conns[ ntargets ].msc_cred ); - lc->mc_conns[ ntargets ].msc_bound = META_UNBOUND; + mc->mc_conns[ ntargets ].msc_ld = NULL; + BER_BVZERO( &mc->mc_conns[ ntargets ].msc_bound_ndn ); + BER_BVZERO( &mc->mc_conns[ ntargets ].msc_cred ); + mc->mc_conns[ ntargets ].msc_bound = META_UNBOUND; } - lc->mc_bound_target = META_BOUND_NONE; + mc->mc_auth_target = META_BOUND_NONE; + ldap_pvt_thread_mutex_init( &mc->mc_mutex ); - return lc; + return mc; } /* - * metaconn_free + * meta_back_conn_free * * clears a metaconn */ -static void -metaconn_free( - struct metaconn *lc -) +void +meta_back_conn_free( struct metaconn *mc ) { - if ( !lc ) { + if ( mc == NULL ) { return; } + + ldap_pvt_thread_mutex_destroy( &mc->mc_mutex ); - free( lc ); + free( mc ); } /* - * init_one_conn + * meta_back_init_one_conn * * Initializes one connection */ static int -init_one_conn( +meta_back_init_one_conn( Operation *op, SlapReply *rs, struct metatarget *lt, - struct metasingleconn *lsc, - char *candidate, + struct metasingleconn *msc, ldap_back_send_t sendok ) { - struct metainfo *li = ( struct metainfo * )op->o_bd->be_private; + struct metainfo *mi = ( struct metainfo * )op->o_bd->be_private; int vers; dncookie dc; /* * Already init'ed */ - if ( lsc->msc_ld != NULL ) { + if ( msc->msc_ld != NULL ) { rs->sr_err = LDAP_SUCCESS; goto error_return; } @@ -198,7 +196,7 @@ init_one_conn( /* * Attempts to initialize the connection to the target ds */ - rs->sr_err = ldap_initialize( &lsc->msc_ld, lt->mt_uri ); + rs->sr_err = ldap_initialize( &msc->msc_ld, lt->mt_uri ); if ( rs->sr_err != LDAP_SUCCESS ) { goto error_return; } @@ -208,16 +206,16 @@ init_one_conn( * bound with a particular version, then so can we. */ vers = op->o_conn->c_protocol; - ldap_set_option( lsc->msc_ld, LDAP_OPT_PROTOCOL_VERSION, &vers ); + ldap_set_option( msc->msc_ld, LDAP_OPT_PROTOCOL_VERSION, &vers ); /* automatically chase referrals ("chase-referrals"/"dont-chase-referrals" statement) */ - if ( LDAP_BACK_CHASE_REFERRALS( li ) ) { - ldap_set_option( lsc->msc_ld, LDAP_OPT_REFERRALS, LDAP_OPT_ON ); + if ( LDAP_BACK_CHASE_REFERRALS( mi ) ) { + ldap_set_option( msc->msc_ld, LDAP_OPT_REFERRALS, LDAP_OPT_ON ); } #ifdef HAVE_TLS /* start TLS ("start-tls"/"try-start-tls" statements) */ - if ( ( LDAP_BACK_USE_TLS( li ) || ( op->o_conn->c_is_tls && LDAP_BACK_PROPAGATE_TLS( li ) ) ) + if ( ( LDAP_BACK_USE_TLS( mi ) || ( op->o_conn->c_is_tls && LDAP_BACK_PROPAGATE_TLS( mi ) ) ) && !ldap_is_ldaps_url( lt->mt_uri ) ) { #ifdef SLAP_STARTTLS_ASYNCHRONOUS @@ -227,14 +225,14 @@ init_one_conn( */ int msgid; - rs->sr_err = ldap_start_tls( lsc->msc_ld, NULL, NULL, &msgid ); + rs->sr_err = ldap_start_tls( msc->msc_ld, NULL, NULL, &msgid ); if ( rs->sr_err == LDAP_SUCCESS ) { LDAPMessage *res = NULL; int rc, retries = 1; struct timeval tv = { 0, 0 }; retry:; - rc = ldap_result( lsc->msc_ld, msgid, LDAP_MSG_ALL, &tv, &res ); + rc = ldap_result( msc->msc_ld, msgid, LDAP_MSG_ALL, &tv, &res ); if ( rc < 0 ) { rs->sr_err = LDAP_OTHER; @@ -250,10 +248,10 @@ retry:; } else if ( rc == LDAP_RES_EXTENDED ) { struct berval *data = NULL; - rs->sr_err = ldap_parse_extended_result( lsc->msc_ld, res, + rs->sr_err = ldap_parse_extended_result( msc->msc_ld, res, NULL, &data, 0 ); if ( rs->sr_err == LDAP_SUCCESS ) { - rs->sr_err = ldap_result2error( lsc->msc_ld, res, 1 ); + rs->sr_err = ldap_result2error( msc->msc_ld, res, 1 ); res = NULL; /* FIXME: in case a referral @@ -261,7 +259,7 @@ retry:; * using it instead of the * configured URI? */ if ( rs->sr_err == LDAP_SUCCESS ) { - ldap_install_tls( lsc->msc_ld ); + ldap_install_tls( msc->msc_ld ); } else if ( rs->sr_err == LDAP_REFERRAL ) { rs->sr_err = LDAP_OTHER; @@ -288,7 +286,7 @@ retry:; /* * use synchronous StartTLS */ - rs->sr_err = ldap_start_tls_s( lsc->msc_ld, NULL, NULL ); + rs->sr_err = ldap_start_tls_s( msc->msc_ld, NULL, NULL ); #endif /* ! SLAP_STARTTLS_ASYNCHRONOUS */ /* if StartTLS is requested, only attempt it if the URL @@ -296,9 +294,9 @@ retry:; * of misconfiguration, but also when used in the chain * overlay, where the "uri" can be parsed out of a referral */ if ( rs->sr_err == LDAP_SERVER_DOWN - || ( rs->sr_err != LDAP_SUCCESS && LDAP_BACK_TLS_CRITICAL( li ) ) ) + || ( rs->sr_err != LDAP_SUCCESS && LDAP_BACK_TLS_CRITICAL( mi ) ) ) { - ldap_unbind_ext_s( lsc->msc_ld, NULL, NULL ); + ldap_unbind_ext_s( msc->msc_ld, NULL, NULL ); goto error_return; } } @@ -307,13 +305,13 @@ retry:; /* * Set the network timeout if set */ - if ( li->mi_network_timeout != 0 ) { + if ( mi->mi_network_timeout != 0 ) { struct timeval network_timeout; network_timeout.tv_usec = 0; - network_timeout.tv_sec = li->mi_network_timeout; + network_timeout.tv_sec = mi->mi_network_timeout; - ldap_set_option( lsc->msc_ld, LDAP_OPT_NETWORK_TIMEOUT, + ldap_set_option( msc->msc_ld, LDAP_OPT_NETWORK_TIMEOUT, (void *)&network_timeout ); } @@ -335,23 +333,23 @@ retry:; * Rewrite the bind dn if needed */ if ( ldap_back_dn_massage( &dc, &op->o_conn->c_dn, - &lsc->msc_bound_ndn ) ) + &msc->msc_bound_ndn ) ) { goto error_return; } /* copy the DN idf needed */ - if ( lsc->msc_bound_ndn.bv_val == op->o_conn->c_dn.bv_val ) { - ber_dupbv( &lsc->msc_bound_ndn, &op->o_conn->c_dn ); + if ( msc->msc_bound_ndn.bv_val == op->o_conn->c_dn.bv_val ) { + ber_dupbv( &msc->msc_bound_ndn, &op->o_conn->c_dn ); } - assert( !BER_BVISNULL( &lsc->msc_bound_ndn ) ); + assert( !BER_BVISNULL( &msc->msc_bound_ndn ) ); } else { - ber_str2bv( "", 0, 1, &lsc->msc_bound_ndn ); + ber_str2bv( "", 0, 1, &msc->msc_bound_ndn ); } - lsc->msc_bound = META_UNBOUND; + msc->msc_bound = META_UNBOUND; error_return:; if ( rs->sr_err != LDAP_SUCCESS ) { @@ -360,18 +358,47 @@ error_return:; send_ldap_result( op, rs ); rs->sr_text = NULL; } - - } else { - - /* - * The candidate is activated - */ - *candidate = META_CANDIDATE; } return rs->sr_err; } +/* + * meta_back_retry + * + * Retries one connection + */ +int +meta_back_retry( + Operation *op, + SlapReply *rs, + struct metaconn *mc, + int candidate, + ldap_back_send_t sendok ) +{ + struct metainfo *mi = (struct metainfo *)op->o_bd->be_private; + struct metatarget *lt = mi->mi_targets[ candidate ]; + int rc; + struct metasingleconn *msc = &mc->mc_conns[ candidate ]; + + ldap_pvt_thread_mutex_lock( &mc->mc_mutex ); + + ldap_unbind_ext_s( msc->msc_ld, NULL, NULL ); + msc->msc_ld = NULL; + msc->msc_bound = 0; + + /* mc here must be the regular mc, reset and ready for init */ + rc = meta_back_init_one_conn( op, rs, lt, msc, sendok ); + + if ( rc == LDAP_SUCCESS ) { + rc = meta_back_single_dobind( op, msc, sendok, 0 ); + } + + ldap_pvt_thread_mutex_unlock( &mc->mc_mutex ); + + return rc == LDAP_SUCCESS ? 1 : 0; +} + /* * callback for unique candidate selection */ @@ -403,14 +430,14 @@ meta_back_get_candidate( SlapReply *rs, struct berval *ndn ) { - struct metainfo *li = ( struct metainfo * )op->o_bd->be_private; + struct metainfo *mi = ( struct metainfo * )op->o_bd->be_private; int candidate; /* * tries to get a unique candidate * (takes care of default target) */ - candidate = meta_back_select_unique_candidate( li, ndn ); + candidate = meta_back_select_unique_candidate( mi, ndn ); /* * if any is found, inits the connection @@ -460,10 +487,11 @@ meta_back_get_candidate( /* if multiple candidates can serve the operation, * and a default target is defined, and it is * a candidate, try using it (FIXME: YMMV) */ - if ( li->mi_defaulttarget != META_DEFAULT_TARGET_NONE - && meta_back_is_candidate( &li->mi_targets[ li->mi_defaulttarget ]->mt_nsuffix, ndn ) ) + if ( mi->mi_defaulttarget != META_DEFAULT_TARGET_NONE + && meta_back_is_candidate( &mi->mi_targets[ mi->mi_defaulttarget ]->mt_nsuffix, + ndn, op->o_tag == LDAP_REQ_SEARCH ? op->ors_scope : LDAP_SCOPE_BASE ) ) { - candidate = li->mi_defaulttarget; + candidate = mi->mi_defaulttarget; rs->sr_err = LDAP_SUCCESS; rs->sr_text = NULL; @@ -487,25 +515,25 @@ meta_back_candidate_keyfree( void *key, void *data ) char * meta_back_candidates_get( Operation *op ) { - struct metainfo *li = ( struct metainfo * )op->o_bd->be_private; + struct metainfo *mi = ( struct metainfo * )op->o_bd->be_private; void *data = NULL; if ( op->o_threadctx ) { ldap_pvt_thread_pool_getkey( op->o_threadctx, meta_back_candidate_keyfree, &data, NULL ); } else { - data = (void *)li->mi_candidates; + data = (void *)mi->mi_candidates; } if ( data == NULL ) { - data = ber_memalloc_x( sizeof( char ) * li->mi_ntargets, NULL ); + data = ber_memalloc_x( sizeof( char ) * mi->mi_ntargets, NULL ); if ( op->o_threadctx ) { ldap_pvt_thread_pool_setkey( op->o_threadctx, meta_back_candidate_keyfree, data, meta_back_candidate_keyfree ); } else { - li->mi_candidates = (char *)data; + mi->mi_candidates = (char *)data; } } @@ -552,8 +580,8 @@ meta_back_getconn( int *candidate, ldap_back_send_t sendok ) { - struct metainfo *li = ( struct metainfo * )op->o_bd->be_private; - struct metaconn *lc, lc_curr; + struct metainfo *mi = ( struct metainfo * )op->o_bd->be_private; + struct metaconn *mc, mc_curr; int cached = META_TARGET_NONE, i = META_TARGET_NONE, err = LDAP_SUCCESS, @@ -562,23 +590,24 @@ meta_back_getconn( meta_op_type op_type = META_OP_REQUIRE_SINGLE; int parent = 0, newparent = 0; - struct berval ndn = op->o_req_ndn; + struct berval ndn = op->o_req_ndn, + pndn; char *candidates = meta_back_candidates_get( op ); /* Searches for a metaconn in the avl tree */ - lc_curr.mc_conn = op->o_conn; - ldap_pvt_thread_mutex_lock( &li->mi_conn_mutex ); - lc = (struct metaconn *)avl_find( li->mi_conntree, - (caddr_t)&lc_curr, meta_back_conn_cmp ); - ldap_pvt_thread_mutex_unlock( &li->mi_conn_mutex ); + mc_curr.mc_conn = op->o_conn; + ldap_pvt_thread_mutex_lock( &mi->mi_conn_mutex ); + mc = (struct metaconn *)avl_find( mi->mi_conntree, + (caddr_t)&mc_curr, meta_back_conn_cmp ); + ldap_pvt_thread_mutex_unlock( &mi->mi_conn_mutex ); switch ( op->o_tag ) { case LDAP_REQ_ADD: /* if we go to selection, the entry must not exist, * and we must be able to resolve the parent */ parent = 1; - dnParent( &ndn, &ndn ); + dnParent( &ndn, &pndn ); break; case LDAP_REQ_MODRDN: @@ -619,22 +648,24 @@ meta_back_getconn( if ( op_type == META_OP_REQUIRE_ALL ) { /* Looks like we didn't get a bind. Open a new session... */ - if ( !lc ) { - lc = metaconn_alloc( li->mi_ntargets ); - lc->mc_conn = op->o_conn; + if ( !mc ) { + mc = metaconn_alloc( mi->mi_ntargets ); + mc->mc_conn = op->o_conn; new_conn = 1; } - for ( i = 0; i < li->mi_ntargets; i++ ) { + for ( i = 0; i < mi->mi_ntargets; i++ ) { /* * The target is activated; if needed, it is * also init'd */ - int lerr = init_one_conn( op, rs, li->mi_targets[ i ], - &lc->mc_conns[ i ], &candidates[ i ], - sendok ); - if ( lerr != LDAP_SUCCESS ) { + int lerr = meta_back_init_one_conn( op, rs, mi->mi_targets[ i ], + &mc->mc_conns[ i ], sendok ); + if ( lerr == LDAP_SUCCESS ) { + candidates[ i ] = META_CANDIDATE; + + } else { /* * FIXME: in case one target cannot @@ -642,9 +673,6 @@ meta_back_getconn( * be tried? */ candidates[ i ] = META_NOT_CANDIDATE; -#if 0 - ( void )meta_clear_one_candidate( &lc->mc_conns[ i ] ); -#endif err = lerr; continue; } @@ -655,13 +683,13 @@ meta_back_getconn( /* * looks in cache, if any */ - if ( li->mi_cache.ttl != META_DNCACHE_DISABLED ) { - cached = i = meta_dncache_get_target( &li->mi_cache, &op->o_req_ndn ); + if ( mi->mi_cache.ttl != META_DNCACHE_DISABLED ) { + cached = i = meta_dncache_get_target( &mi->mi_cache, &op->o_req_ndn ); } if ( op_type == META_OP_REQUIRE_SINGLE ) { - memset( candidates, META_NOT_CANDIDATE, sizeof( char ) * li->mi_ntargets ); + memset( candidates, META_NOT_CANDIDATE, sizeof( char ) * mi->mi_ntargets ); /* * tries to get a unique candidate @@ -670,6 +698,10 @@ meta_back_getconn( if ( i == META_TARGET_NONE ) { i = meta_back_get_candidate( op, rs, &ndn ); + if ( rs->sr_err == LDAP_NO_SUCH_OBJECT && parent ) { + i = meta_back_get_candidate( op, rs, &pndn ); + } + if ( rs->sr_err != LDAP_SUCCESS ) { if ( sendok & LDAP_BACK_SENDERR ) { send_ldap_result( op, rs ); @@ -695,33 +727,35 @@ meta_back_getconn( i, op->o_req_ndn.bv_val, 0 ); /* Retries searching for a metaconn in the avl tree */ - lc_curr.mc_conn = op->o_conn; - ldap_pvt_thread_mutex_lock( &li->mi_conn_mutex ); - lc = (struct metaconn *)avl_find( li->mi_conntree, - (caddr_t)&lc_curr, meta_back_conn_cmp ); - ldap_pvt_thread_mutex_unlock( &li->mi_conn_mutex ); + mc_curr.mc_conn = op->o_conn; + ldap_pvt_thread_mutex_lock( &mi->mi_conn_mutex ); + mc = (struct metaconn *)avl_find( mi->mi_conntree, + (caddr_t)&mc_curr, meta_back_conn_cmp ); + ldap_pvt_thread_mutex_unlock( &mi->mi_conn_mutex ); /* Looks like we didn't get a bind. Open a new session... */ - if ( !lc ) { - lc = metaconn_alloc( li->mi_ntargets ); - lc->mc_conn = op->o_conn; + if ( !mc ) { + mc = metaconn_alloc( mi->mi_ntargets ); + mc->mc_conn = op->o_conn; new_conn = 1; } /* * Clear all other candidates */ - ( void )meta_clear_unused_candidates( op, lc, i ); + ( void )meta_clear_unused_candidates( op, mc, i ); /* * The target is activated; if needed, it is - * also init'd. In case of error, init_one_conn + * also init'd. In case of error, meta_back_init_one_conn * sends the appropriate result. */ - err = init_one_conn( op, rs, li->mi_targets[ i ], - &lc->mc_conns[ i ], &candidates[ i ], - sendok ); - if ( err != LDAP_SUCCESS ) { + err = meta_back_init_one_conn( op, rs, mi->mi_targets[ i ], + &mc->mc_conns[ i ], sendok ); + if ( err == LDAP_SUCCESS ) { + candidates[ i ] = META_CANDIDATE; + + } else { /* * FIXME: in case one target cannot @@ -730,8 +764,8 @@ meta_back_getconn( */ candidates[ i ] = META_NOT_CANDIDATE; if ( new_conn ) { - ( void )meta_clear_one_candidate( &lc->mc_conns[ i ] ); - metaconn_free( lc ); + ( void )meta_clear_one_candidate( &mc->mc_conns[ i ] ); + meta_back_conn_free( mc ); } return NULL; } @@ -746,28 +780,29 @@ meta_back_getconn( } else { /* Looks like we didn't get a bind. Open a new session... */ - if ( !lc ) { - lc = metaconn_alloc( li->mi_ntargets ); - lc->mc_conn = op->o_conn; + if ( !mc ) { + mc = metaconn_alloc( mi->mi_ntargets ); + mc->mc_conn = op->o_conn; new_conn = 1; } - for ( i = 0; i < li->mi_ntargets; i++ ) { + for ( i = 0; i < mi->mi_ntargets; i++ ) { if ( i == cached - || meta_back_is_candidate( &li->mi_targets[ i ]->mt_nsuffix, - &op->o_req_ndn ) ) + || meta_back_is_candidate( &mi->mi_targets[ i ]->mt_nsuffix, + &op->o_req_ndn, LDAP_SCOPE_SUBTREE ) ) { /* * The target is activated; if needed, it is * also init'd */ - int lerr = init_one_conn( op, rs, - li->mi_targets[ i ], - &lc->mc_conns[ i ], - &candidates[ i ], - sendok ); - if ( lerr != LDAP_SUCCESS ) { + int lerr = meta_back_init_one_conn( op, rs, + mi->mi_targets[ i ], + &mc->mc_conns[ i ], sendok ); + if ( lerr == LDAP_SUCCESS ) { + candidates[ i ] = META_CANDIDATE; + + } else { /* * FIXME: in case one target cannot @@ -775,10 +810,11 @@ meta_back_getconn( * be tried? */ candidates[ i ] = META_NOT_CANDIDATE; -#if 0 - ( void )meta_clear_one_candidate( &lc->mc_conns[ i ] ); -#endif err = lerr; + + Debug( LDAP_DEBUG_ANY, "%s: meta_back_init_one_conn(%d) failed: %d\n", + op->o_log_prefix, i, lerr ); + continue; } @@ -789,7 +825,7 @@ meta_back_getconn( } done:; - /* clear out init_one_conn non-fatal errors */ + /* clear out meta_back_init_one_conn non-fatal errors */ rs->sr_err = LDAP_SUCCESS; rs->sr_text = NULL; @@ -798,19 +834,19 @@ done:; /* * Inserts the newly created metaconn in the avl tree */ - ldap_pvt_thread_mutex_lock( &li->mi_conn_mutex ); - err = avl_insert( &li->mi_conntree, ( caddr_t )lc, + ldap_pvt_thread_mutex_lock( &mi->mi_conn_mutex ); + err = avl_insert( &mi->mi_conntree, ( caddr_t )mc, meta_back_conn_cmp, meta_back_conn_dup ); #if PRINT_CONNTREE > 0 - myprint( li->mi_conntree ); + myprint( mi->mi_conntree ); #endif /* PRINT_CONNTREE */ - ldap_pvt_thread_mutex_unlock( &li->mi_conn_mutex ); + ldap_pvt_thread_mutex_unlock( &mi->mi_conn_mutex ); Debug( LDAP_DEBUG_TRACE, "=>meta_back_getconn: conn %ld inserted\n", - lc->mc_conn->c_connid, 0, 0 ); + mc->mc_conn->c_connid, 0, 0 ); /* * Err could be -1 in case a duplicate metaconn is inserted @@ -818,7 +854,7 @@ done:; if ( err != 0 ) { rs->sr_err = LDAP_OTHER; rs->sr_text = "Internal server error"; - metaconn_free( lc ); + meta_back_conn_free( mc ); if ( sendok & LDAP_BACK_SENDERR ) { send_ldap_result( op, rs ); rs->sr_text = NULL; @@ -829,9 +865,9 @@ done:; } else { Debug( LDAP_DEBUG_TRACE, "=>meta_back_getconn: conn %ld fetched\n", - lc->mc_conn->c_connid, 0, 0 ); + mc->mc_conn->c_connid, 0, 0 ); } - return lc; + return mc; } diff --git a/servers/slapd/back-meta/delete.c b/servers/slapd/back-meta/delete.c index a2387ea96c..3ee7ac8d5d 100644 --- a/servers/slapd/back-meta/delete.c +++ b/servers/slapd/back-meta/delete.c @@ -34,11 +34,12 @@ int meta_back_delete( Operation *op, SlapReply *rs ) { - struct metainfo *li = ( struct metainfo * )op->o_bd->be_private; - struct metaconn *lc; - int candidate = -1; - struct berval mdn = BER_BVNULL; - dncookie dc; + struct metainfo *li = ( struct metainfo * )op->o_bd->be_private; + struct metaconn *lc; + int candidate = -1; + struct berval mdn = BER_BVNULL; + dncookie dc; + int msgid, do_retry = 1; lc = meta_back_getconn( op, rs, &candidate, LDAP_BACK_SENDERR ); if ( !lc || !meta_back_dobind( lc, op, LDAP_BACK_SENDERR ) ) { @@ -64,8 +65,15 @@ meta_back_delete( Operation *op, SlapReply *rs ) return -1; } - (void)ldap_delete_ext_s( lc->mc_conns[ candidate ].msc_ld, mdn.bv_val, - op->o_ctrls, NULL ); +retry:; + rs->sr_err = ldap_delete_ext_s( lc->mc_conns[ candidate ].msc_ld, + mdn.bv_val, op->o_ctrls, NULL ); + if ( rs->sr_err == LDAP_UNAVAILABLE && do_retry ) { + do_retry = 0; + if ( meta_back_retry( op, rs, lc, candidate, LDAP_BACK_SENDERR ) ) { + goto retry; + } + } if ( mdn.bv_val != op->o_req_dn.bv_val ) { free( mdn.bv_val ); diff --git a/servers/slapd/back-meta/modify.c b/servers/slapd/back-meta/modify.c index 5177132f91..12c1d7107f 100644 --- a/servers/slapd/back-meta/modify.c +++ b/servers/slapd/back-meta/modify.c @@ -45,6 +45,7 @@ meta_back_modify( Operation *op, SlapReply *rs ) struct berval mdn = BER_BVNULL; struct berval mapped; dncookie dc; + int msgid, do_retry = 1; lc = meta_back_getconn( op, rs, &candidate, LDAP_BACK_SENDERR ); if ( !lc || !meta_back_dobind( lc, op, LDAP_BACK_SENDERR ) ) { @@ -174,8 +175,15 @@ meta_back_modify( Operation *op, SlapReply *rs ) } modv[ i ] = 0; +retry:; rs->sr_err = ldap_modify_ext_s( lc->mc_conns[ candidate ].msc_ld, mdn.bv_val, modv, op->o_ctrls, NULL ); + if ( rs->sr_err == LDAP_UNAVAILABLE && do_retry ) { + do_retry = 0; + if ( meta_back_retry( op, rs, lc, candidate, LDAP_BACK_SENDERR ) ) { + goto retry; + } + } cleanup:; if ( mdn.bv_val != op->o_req_dn.bv_val ) { diff --git a/servers/slapd/back-meta/modrdn.c b/servers/slapd/back-meta/modrdn.c index 6123fd2533..6276d19523 100644 --- a/servers/slapd/back-meta/modrdn.c +++ b/servers/slapd/back-meta/modrdn.c @@ -36,11 +36,11 @@ meta_back_modrdn( Operation *op, SlapReply *rs ) { struct metainfo *li = ( struct metainfo * )op->o_bd->be_private; struct metaconn *lc; - int rc = 0; int candidate = -1; struct berval mdn = BER_BVNULL, mnewSuperior = BER_BVNULL; dncookie dc; + int msgid, do_retry = 1; lc = meta_back_getconn( op, rs, &candidate, LDAP_BACK_SENDERR ); if ( !lc ) { @@ -95,7 +95,7 @@ meta_back_modrdn( Operation *op, SlapReply *rs ) dc.rwmap = &li->mi_targets[ candidate ]->mt_rwmap; dc.ctx = "newSuperiorDN"; if ( ldap_back_dn_massage( &dc, op->orr_newSup, &mnewSuperior ) ) { - rc = -1; + rs->sr_err = LDAP_OTHER; goto cleanup; } } @@ -106,15 +106,21 @@ meta_back_modrdn( Operation *op, SlapReply *rs ) dc.rwmap = &li->mi_targets[ candidate ]->mt_rwmap; dc.ctx = "modrDN"; if ( ldap_back_dn_massage( &dc, &op->o_req_dn, &mdn ) ) { - rc = -1; + rs->sr_err = LDAP_OTHER; goto cleanup; } - rc = ldap_rename_s( lc->mc_conns[ candidate ].msc_ld, mdn.bv_val, - op->orr_newrdn.bv_val, - mnewSuperior.bv_val, - op->orr_deleteoldrdn, - op->o_ctrls, NULL ) != LDAP_SUCCESS; +retry:; + rs->sr_err = ldap_rename_s( lc->mc_conns[ candidate ].msc_ld, + mdn.bv_val, op->orr_newrdn.bv_val, + mnewSuperior.bv_val, op->orr_deleteoldrdn, + op->o_ctrls, NULL ); + if ( rs->sr_err == LDAP_UNAVAILABLE && do_retry ) { + do_retry = 0; + if ( meta_back_retry( op, rs, lc, candidate, LDAP_BACK_SENDERR ) ) { + goto retry; + } + } cleanup:; if ( mdn.bv_val != op->o_req_dn.bv_val ) { @@ -129,13 +135,12 @@ cleanup:; BER_BVZERO( &mnewSuperior ); } - if ( rc == 0 ) { - return meta_back_op_result( lc, op, rs, candidate ) == LDAP_SUCCESS - ? 0 : 1; - } /* else */ + if ( rs->sr_err == LDAP_SUCCESS ) { + meta_back_op_result( lc, op, rs, candidate ); + } send_ldap_result( op, rs ); - return rc; + return rs->sr_err; } diff --git a/servers/slapd/back-meta/search.c b/servers/slapd/back-meta/search.c index e3bde3cdab..d88b1efc74 100644 --- a/servers/slapd/back-meta/search.c +++ b/servers/slapd/back-meta/search.c @@ -37,19 +37,194 @@ static int meta_send_entry( - Operation *op, - SlapReply *rs, - struct metaconn *lc, - int i, - LDAPMessage *e -); + Operation *op, + SlapReply *rs, + struct metaconn *lc, + int i, + LDAPMessage *e ); + +static int +meta_back_search_start( + Operation *op, + SlapReply *rs, + dncookie *dc, + struct metasingleconn *msc, + int candidate, + int *msgidp +) +{ + struct metainfo *mi = ( struct metainfo * )op->o_bd->be_private; + struct berval realbase = op->o_req_dn; + int realscope = op->ors_scope; + ber_len_t suffixlen = 0; + struct berval mbase = BER_BVNULL; + struct berval mfilter = BER_BVNULL; + char **mapped_attrs = NULL; + int rc; + + /* should we check return values? */ + if ( op->ors_deref != -1 ) { + ldap_set_option( msc->msc_ld, LDAP_OPT_DEREF, + ( void * )&op->ors_deref); + } + if ( op->ors_tlimit != SLAP_NO_LIMIT ) { + ldap_set_option( msc->msc_ld, LDAP_OPT_TIMELIMIT, + ( void * )&op->ors_tlimit); + } + if ( op->ors_slimit != SLAP_NO_LIMIT ) { + ldap_set_option( msc->msc_ld, LDAP_OPT_SIZELIMIT, + ( void * )&op->ors_slimit); + } + + dc->rwmap = &mi->mi_targets[ candidate ]->mt_rwmap; + + /* + * modifies the base according to the scope, if required + */ + suffixlen = mi->mi_targets[ candidate ]->mt_nsuffix.bv_len; + if ( suffixlen > op->o_req_ndn.bv_len ) { + switch ( op->ors_scope ) { + case LDAP_SCOPE_SUBTREE: + /* + * make the target suffix the new base + * FIXME: this is very forgiving, because + * "illegal" searchBases may be turned + * into the suffix of the target; however, + * the requested searchBase already passed + * thru the candidate analyzer... + */ + if ( dnIsSuffix( &mi->mi_targets[ candidate ]->mt_nsuffix, + &op->o_req_ndn ) ) + { + realbase = mi->mi_targets[ candidate ]->mt_nsuffix; + + } else { + /* + * this target is no longer candidate + */ + return 0; + } + break; + + case LDAP_SCOPE_ONELEVEL: + { + struct berval rdn = mi->mi_targets[ candidate ]->mt_nsuffix; + rdn.bv_len -= op->o_req_ndn.bv_len + STRLENOF( "," ); + if ( dnIsOneLevelRDN( &rdn ) + && dnIsSuffix( &mi->mi_targets[ candidate ]->mt_nsuffix, &op->o_req_ndn ) ) + { + /* + * if there is exactly one level, + * make the target suffix the new + * base, and make scope "base" + */ + realbase = mi->mi_targets[ candidate ]->mt_nsuffix; + realscope = LDAP_SCOPE_BASE; + break; + } /* else continue with the next case */ + } + + case LDAP_SCOPE_BASE: + /* + * this target is no longer candidate + */ + return 0; + } + } + + /* + * Rewrite the search base, if required + */ + dc->ctx = "searchBase"; + switch ( ldap_back_dn_massage( dc, &realbase, &mbase ) ) { + default: + break; + + case REWRITE_REGEXEC_UNWILLING: + rs->sr_err = LDAP_UNWILLING_TO_PERFORM; + rs->sr_text = "Operation not allowed"; + send_ldap_result( op, rs ); + return -1; + + case REWRITE_REGEXEC_ERR: + + /* + * this target is no longer candidate + */ + return 0; + } + + /* + * Maps filter + */ + rc = ldap_back_filter_map_rewrite( dc, op->ors_filter, + &mfilter, BACKLDAP_MAP ); + switch ( rc ) { + case LDAP_SUCCESS: + break; + + case LDAP_COMPARE_FALSE: + default: + /* + * this target is no longer candidate + */ + rc = 0; + goto done; + } + + /* + * Maps required attributes + */ + rc = ldap_back_map_attrs( &mi->mi_targets[ candidate ]->mt_rwmap.rwm_at, + op->ors_attrs, BACKLDAP_MAP, + &mapped_attrs ); + if ( rc != LDAP_SUCCESS ) { + /* + * this target is no longer candidate + */ + rc = 0; + goto done; + } + + /* + * Starts the search + */ + rc = ldap_search_ext( msc->msc_ld, + mbase.bv_val, realscope, mfilter.bv_val, + mapped_attrs, op->ors_attrsonly, + op->o_ctrls, NULL, + NULL, op->ors_slimit, msgidp ); + if ( rc == LDAP_SUCCESS ) { + rc = 1; + + } else { + *msgidp = -1; + rc = 0; + } + +done:; + if ( mapped_attrs ) { + free( mapped_attrs ); + mapped_attrs = NULL; + } + if ( mfilter.bv_val != op->ors_filterstr.bv_val ) { + free( mfilter.bv_val ); + BER_BVZERO( &mfilter ); + } + if ( mbase.bv_val != realbase.bv_val ) { + free( mbase.bv_val ); + BER_BVZERO( &mbase ); + } + + return rc; +} int meta_back_search( Operation *op, SlapReply *rs ) { - struct metainfo *li = ( struct metainfo * )op->o_bd->be_private; + struct metainfo *mi = ( struct metainfo * )op->o_bd->be_private; struct metaconn *lc; - struct metasingleconn *lsc; + struct metasingleconn *msc; struct timeval tv = { 0, 0 }; LDAPMessage *res = NULL, *e; int rc = 0, *msgid, sres = LDAP_SUCCESS; @@ -61,9 +236,7 @@ meta_back_search( Operation *op, SlapReply *rs ) initial_candidates = 0, candidate_match = 0; dncookie dc; - int is_scope = 0, - is_filter = 0, - is_ok = 0; + int is_ok = 0; void *savepriv; @@ -83,7 +256,7 @@ meta_back_search( Operation *op, SlapReply *rs ) /* * Array of message id of each target */ - msgid = ch_calloc( sizeof( int ), li->mi_ntargets ); + msgid = ch_calloc( sizeof( int ), mi->mi_ntargets ); if ( msgid == NULL ) { rs->sr_err = LDAP_OTHER; send_ldap_result( op, rs ); @@ -96,221 +269,81 @@ meta_back_search( Operation *op, SlapReply *rs ) /* * Inits searches */ - for ( i = 0, lsc = &lc->mc_conns[ 0 ]; !META_LAST( lsc ); ++i, ++lsc ) { - struct berval realbase = op->o_req_dn; - int realscope = op->ors_scope; - ber_len_t suffixlen = 0; - struct berval mbase = BER_BVNULL; - struct berval mfilter = BER_BVNULL; - char **mapped_attrs = NULL; + for ( i = 0, msc = &lc->mc_conns[ 0 ]; !META_LAST( msc ); ++i, ++msc ) { + msgid[ i ] = -1; if ( candidates[ i ] != META_CANDIDATE ) { - msgid[ i ] = -1; continue; } - /* should we check return values? */ - if ( op->ors_deref != -1 ) { - ldap_set_option( lsc->msc_ld, LDAP_OPT_DEREF, - ( void * )&op->ors_deref); - } - if ( op->ors_tlimit != SLAP_NO_LIMIT ) { - ldap_set_option( lsc->msc_ld, LDAP_OPT_TIMELIMIT, - ( void * )&op->ors_tlimit); - } - if ( op->ors_slimit != SLAP_NO_LIMIT ) { - ldap_set_option( lsc->msc_ld, LDAP_OPT_SIZELIMIT, - ( void * )&op->ors_slimit); - } - - dc.rwmap = &li->mi_targets[ i ]->mt_rwmap; - - /* - * modifies the base according to the scope, if required - */ - suffixlen = li->mi_targets[ i ]->mt_nsuffix.bv_len; - if ( suffixlen > op->o_req_ndn.bv_len ) { - switch ( op->ors_scope ) { - case LDAP_SCOPE_SUBTREE: - /* - * make the target suffix the new base - * FIXME: this is very forgiving, because - * illegal bases may be turned into - * the suffix of the target. - */ - if ( dnIsSuffix( &li->mi_targets[ i ]->mt_nsuffix, - &op->o_req_ndn ) ) { - realbase = li->mi_targets[ i ]->mt_nsuffix; - is_scope++; - - } else { - /* - * this target is no longer candidate - */ - msgid[ i ] = -1; - goto new_candidate; - } - break; - - case LDAP_SCOPE_ONELEVEL: - { - struct berval rdn = li->mi_targets[ i ]->mt_nsuffix; - rdn.bv_len -= op->o_req_ndn.bv_len + STRLENOF( "," ); - if ( dnIsOneLevelRDN( &rdn ) - && dnIsSuffix( &li->mi_targets[ i ]->mt_nsuffix, &op->o_req_ndn ) ) - { - /* - * if there is exactly one level, - * make the target suffix the new - * base, and make scope "base" - */ - realbase = li->mi_targets[ i ]->mt_nsuffix; - realscope = LDAP_SCOPE_BASE; - is_scope++; - break; - } /* else continue with the next case */ - } - - case LDAP_SCOPE_BASE: - /* - * this target is no longer candidate - */ - msgid[ i ] = -1; - goto new_candidate; - } - - } else { - is_scope++; - } - - /* - * Rewrite the search base, if required - */ - dc.ctx = "searchBase"; - switch ( ldap_back_dn_massage( &dc, &realbase, &mbase ) ) { - default: + switch ( meta_back_search_start( op, rs, &dc, msc, i, &msgid[ i ] ) ) + { + case 0: break; - case REWRITE_REGEXEC_UNWILLING: - rs->sr_err = LDAP_UNWILLING_TO_PERFORM; - rs->sr_text = "Operation not allowed"; - send_ldap_result( op, rs ); - rc = -1; - goto finish; + case 1: + ++ncandidates; + break; - case REWRITE_REGEXEC_ERR: -#if 0 - rs->sr_err = LDAP_OTHER; - rs->sr_text = "Rewrite error"; - send_ldap_result( op, rs ); + case -1: rc = -1; goto finish; -#endif - - /* - * this target is no longer candidate - */ - msgid[ i ] = -1; - goto new_candidate; } + } - /* - * Maps filter - */ - rc = ldap_back_filter_map_rewrite( &dc, - op->ors_filter, - &mfilter, BACKLDAP_MAP ); - switch ( rc ) { - case LDAP_SUCCESS: - is_filter++; - break; - - case LDAP_COMPARE_FALSE: - rc = 0; + initial_candidates = ncandidates; - default: - /* - * this target is no longer candidate - */ - msgid[ i ] = -1; - goto new_candidate; - } +#if 0 + { + char cnd[BUFSIZ]; + int i; - /* - * Maps required attributes - */ - rc = ldap_back_map_attrs( &li->mi_targets[ i ]->mt_rwmap.rwm_at, - op->ors_attrs, BACKLDAP_MAP, - &mapped_attrs ); - if ( rc != LDAP_SUCCESS ) { - /* - * this target is no longer candidate - */ - msgid[ i ] = -1; - goto new_candidate; + for ( i = 0; i < mi->mi_ntargets; i++ ) { + if ( candidates[ i ] == META_CANDIDATE ) { + cnd[ i ] = '*'; + } else { + cnd[ i ] = ' '; + } } + cnd[ i ] = '\0'; - /* - * Starts the search - */ - rc = ldap_search_ext( lsc->msc_ld, - mbase.bv_val, realscope, mfilter.bv_val, - mapped_attrs, op->ors_attrsonly, - op->o_ctrls, NULL, - NULL, op->ors_slimit, &msgid[ i ] ); - if ( mapped_attrs ) { - free( mapped_attrs ); - mapped_attrs = NULL; - } - if ( mfilter.bv_val != op->ors_filterstr.bv_val ) { - free( mfilter.bv_val ); - BER_BVZERO( &mfilter ); - } - if ( mbase.bv_val != realbase.bv_val ) { - free( mbase.bv_val ); - BER_BVZERO( &mbase ); - } + Debug( LDAP_DEBUG_ANY, "%s meta_back_search: ncandidates=%d " + "cnd=\"%s\"\n", op->o_log_prefix, ncandidates, cnd ); + } +#endif - if ( rc != LDAP_SUCCESS ) { - continue; - } - - ++ncandidates; + if ( initial_candidates == 0 ) { + send_ldap_error( op, rs, LDAP_NO_SUCH_OBJECT, NULL ); + /* FIXME: find a way to look up the best match */ -new_candidate:; + rc = LDAP_NO_SUCH_OBJECT; + goto finish; } - initial_candidates = ncandidates; - /* We pull apart the ber result, stuff it into a slapd entry, and * let send_search_entry stuff it back into ber format. Slow & ugly, * but this is necessary for version matching, and for ACL processing. */ - /* * In case there are no candidates, no cycle takes place... * - * FIXME: we might use a queue, to balance the load + * FIXME: we might use a queue, to better balance the load * among the candidates */ for ( rc = 0; ncandidates > 0; ) { - int ab, gotit = 0; + int gotit = 0; - /* check for abandon */ - ab = op->o_abandon; - - for ( i = 0, lsc = &lc->mc_conns[ 0 ]; !META_LAST( lsc ); lsc++, i++ ) { + for ( i = 0, msc = &lc->mc_conns[ 0 ]; !META_LAST( msc ); msc++, i++ ) { if ( msgid[ i ] == -1 ) { continue; } - - if ( ab ) { - ldap_abandon_ext( lsc->msc_ld, msgid[ i ], NULL, NULL ); - rc = SLAPD_ABANDON; + + /* check for abandon */ + if ( op->o_abandon ) { break; } - + if ( op->ors_slimit > 0 && rs->sr_nentries == op->ors_slimit ) { @@ -330,7 +363,7 @@ new_candidate:; * get a LDAP_TIMELIMIT_EXCEEDED from * one of them ... */ - rc = ldap_result( lsc->msc_ld, msgid[ i ], + rc = ldap_result( msc->msc_ld, msgid[ i ], 0, &tv, &res ); if ( rc == 0 ) { @@ -363,7 +396,7 @@ really_bad:; } else if ( rc == LDAP_RES_SEARCH_ENTRY ) { is_ok++; - e = ldap_first_entry( lsc->msc_ld, res ); + e = ldap_first_entry( msc->msc_ld, res ); savepriv = op->o_private; op->o_private = (void *)i; meta_send_entry( op, rs, lc, i, e ); @@ -395,7 +428,7 @@ really_bad:; is_ok++; - rc = ldap_parse_reference( lsc->msc_ld, res, + rc = ldap_parse_reference( msc->msc_ld, res, &references, &rs->sr_ctrls, 1 ); res = NULL; @@ -446,8 +479,10 @@ really_bad:; rs->sr_ctrls = NULL; } - } else { - if ( ldap_parse_result( lsc->msc_ld, res, + } else if ( rc == LDAP_RES_SEARCH_RESULT ) { + char buf[ SLAP_TEXT_BUFLEN ]; + + if ( ldap_parse_result( msc->msc_ld, res, &rs->sr_err, NULL, NULL, NULL, NULL, 1 ) ) { @@ -478,22 +513,25 @@ really_bad:; if ( err != NULL ) { free( err ); } - ldap_get_option( lsc->msc_ld, + ldap_get_option( msc->msc_ld, LDAP_OPT_ERROR_STRING, &err ); if ( !BER_BVISNULL( &match ) ) { free( match.bv_val ); BER_BVZERO( &match ); } - ldap_get_option( lsc->msc_ld, + ldap_get_option( msc->msc_ld, LDAP_OPT_MATCHED_DN, &match.bv_val ); if ( !BER_BVISNULL( &match ) ) { match.bv_len = strlen( match.bv_val ); } - Debug( LDAP_DEBUG_ANY, - "=>meta_back_search [%d] " + snprintf( buf, sizeof( buf ), + "%s meta_back_search[%d] " "match=\"%s\" err=\"%s\"\n", - i, match.bv_val, err ); + op->o_log_prefix, i, + match.bv_val, err ); + Debug( LDAP_DEBUG_ANY, "%s", buf, 0, 0 ); + candidate_match++; last = i; rc = 0; @@ -504,10 +542,20 @@ really_bad:; */ msgid[ i ] = -1; --ncandidates; + + } else { + assert( 0 ); + goto really_bad; } } - if ( ab ) { + /* check for abandon */ + if ( op->o_abandon ) { + for ( i = 0, msc = lc->mc_conns; !META_LAST( msc ); msc++, i++ ) { + ldap_abandon_ext( msc->msc_ld, msgid[ i ], NULL, NULL ); + } + + rc = SLAPD_ABANDON; goto finish; } @@ -524,7 +572,7 @@ really_bad:; if ( rc == -1 ) { /* - * FIXME: need a strategy to handle errors + * FIXME: need a better strategy to handle errors */ rc = meta_back_op_result( lc, op, rs, META_TARGET_NONE ); goto finish; @@ -539,7 +587,7 @@ really_bad:; && !BER_BVISNULL( &match ) && !BER_BVISEMPTY( &match ) ) { dc.ctx = "matchedDN"; - dc.rwmap = &li->mi_targets[ last ]->mt_rwmap; + dc.rwmap = &mi->mi_targets[ last ]->mt_rwmap; if ( ldap_back_dn_massage( &dc, &match, &mmatch ) ) { BER_BVZERO( &mmatch ); @@ -553,9 +601,28 @@ really_bad:; * FIXME: we should handle error codes and return the more * important/reasonable */ - if ( is_scope == 0 ) { - sres = LDAP_NO_SUCH_OBJECT; + +#if 0 + { + char buf[BUFSIZ]; + char cnd[BUFSIZ]; + int i; + + for ( i = 0; i < mi->mi_ntargets; i++ ) { + if ( candidates[ i ] == META_CANDIDATE ) { + cnd[ i ] = '*'; + } else { + cnd[ i ] = ' '; + } + } + cnd[ i ] = '\0'; + + snprintf( buf, sizeof( buf ), "%s meta_back_search: is_scope=%d is_ok=%d cnd=\"%s\"\n", + op->o_log_prefix, initial_candidates, is_ok, cnd ); + + Debug( LDAP_DEBUG_ANY, "%s", buf, 0, 0 ); } +#endif if ( sres == LDAP_SUCCESS && v2refs ) { sres = LDAP_REFERRAL; @@ -564,7 +631,7 @@ really_bad:; rs->sr_matched = mmatch.bv_val; rs->sr_v2ref = v2refs; savepriv = op->o_private; - op->o_private = (void *)i; + op->o_private = (void *)mi->mi_ntargets; send_ldap_result( op, rs ); op->o_private = savepriv; rs->sr_matched = NULL; @@ -593,16 +660,15 @@ finish:; static int meta_send_entry( - Operation *op, - SlapReply *rs, - struct metaconn *lc, - int target, - LDAPMessage *e -) + Operation *op, + SlapReply *rs, + struct metaconn *lc, + int target, + LDAPMessage *e ) { - struct metainfo *li = ( struct metainfo * )op->o_bd->be_private; + struct metainfo *mi = ( struct metainfo * )op->o_bd->be_private; struct berval a, mapped; - Entry ent = {0}; + Entry ent = { 0 }; BerElement ber = *e->lm_ber; Attribute *attr, **attrp; struct berval *bv, bdn; @@ -616,7 +682,7 @@ meta_send_entry( /* * Rewrite the dn of the result, if needed */ - dc.rwmap = &li->mi_targets[ target ]->mt_rwmap; + dc.rwmap = &mi->mi_targets[ target ]->mt_rwmap; dc.conn = op->o_conn; dc.rs = rs; dc.ctx = "searchResult"; @@ -642,8 +708,8 @@ meta_send_entry( /* * cache dn */ - if ( li->mi_cache.ttl != META_DNCACHE_DISABLED ) { - ( void )meta_dncache_update_entry( &li->mi_cache, + if ( mi->mi_cache.ttl != META_DNCACHE_DISABLED ) { + ( void )meta_dncache_update_entry( &mi->mi_cache, &ent.e_nname, target ); } @@ -653,7 +719,7 @@ meta_send_entry( while ( ber_scanf( &ber, "{m", &a ) != LBER_ERROR ) { int last = 0; - ldap_back_map( &li->mi_targets[ target ]->mt_rwmap.rwm_at, + ldap_back_map( &mi->mi_targets[ target ]->mt_rwmap.rwm_at, &a, &mapped, BACKLDAP_REMAP ); if ( BER_BVISNULL( &mapped ) || mapped.bv_val[0] == '\0' ) { continue; @@ -668,10 +734,17 @@ meta_send_entry( if ( slap_bv2ad( &mapped, &attr->a_desc, &text ) != LDAP_SUCCESS) { if ( slap_bv2undef_ad( &mapped, &attr->a_desc, &text ) - != LDAP_SUCCESS) { - Debug( LDAP_DEBUG_ANY, - "slap_bv2undef_ad(%s): " - "%s\n%s", mapped.bv_val, text, "" ); + != LDAP_SUCCESS ) + { + char buf[ SLAP_TEXT_BUFLEN ]; + + snprintf( buf, sizeof( buf ), + "%s meta_send_entry(\"%s\"): " + "slap_bv2undef_ad(%s): %s\n", + op->o_log_prefix, ent.e_name.bv_val, + mapped.bv_val, text ); + + Debug( LDAP_DEBUG_ANY, "%s", buf, 0, 0 ); ch_free( attr ); continue; } @@ -703,7 +776,7 @@ meta_send_entry( for ( last = 0; !BER_BVISNULL( &attr->a_vals[ last ] ); ++last ); for ( bv = attr->a_vals; !BER_BVISNULL( bv ); bv++ ) { - ldap_back_map( &li->mi_targets[ target ]->mt_rwmap.rwm_oc, + ldap_back_map( &mi->mi_targets[ target ]->mt_rwmap.rwm_oc, bv, &mapped, BACKLDAP_REMAP ); if ( BER_BVISNULL( &mapped ) || mapped.bv_val[0] == '\0') { free( bv->bv_val ); @@ -790,4 +863,3 @@ meta_send_entry( return LDAP_SUCCESS; } - diff --git a/servers/slapd/back-meta/unbind.c b/servers/slapd/back-meta/unbind.c index 8001da7dec..80e1050aa1 100644 --- a/servers/slapd/back-meta/unbind.c +++ b/servers/slapd/back-meta/unbind.c @@ -71,7 +71,7 @@ meta_back_conn_destroy( rewrite_session_delete( li->mi_targets[ i ]->mt_rwmap.rwm_rw, conn ); meta_clear_one_candidate( &lc->mc_conns[ i ] ); } - free( lc ); + meta_back_conn_free( lc ); } /* no response to unbind */