int asyncmeta_handle_common_result(LDAPMessage *msg, a_metaconn_t *mc, bm_context_t *bc, int candidate) { a_metainfo_t *mi; a_metatarget_t *mt; a_metasingleconn_t *msc; const char *save_text = NULL, *save_matched = NULL; BerVarray save_ref = NULL; LDAPControl **save_ctrls = NULL; void *matched_ctx = NULL; char *matched = NULL; char *text = NULL; char **refs = NULL; LDAPControl **ctrls = NULL; Operation *op; SlapReply *rs; int rc; mi = mc->mc_info; mt = mi->mi_targets[ candidate ]; msc = &mc->mc_conns[ candidate ]; op = bc->op; rs = &bc->rs; save_text = rs->sr_text, save_matched = rs->sr_matched; save_ref = rs->sr_ref; save_ctrls = rs->sr_ctrls; rs->sr_text = NULL; rs->sr_matched = NULL; rs->sr_ref = NULL; rs->sr_ctrls = NULL; /* only touch when activity actually took place... */ if ( mi->mi_idle_timeout != 0 ) { asyncmeta_set_msc_time(msc); } rc = ldap_parse_result( msc->msc_ldr, msg, &rs->sr_err, &matched, &text, &refs, &ctrls, 0 ); if ( rc == LDAP_SUCCESS ) { rs->sr_text = text; } else { rs->sr_err = rc; } rs->sr_err = slap_map_api2result( rs ); /* RFC 4511: referrals can only appear * if result code is LDAP_REFERRAL */ if ( refs != NULL && refs[ 0 ] != NULL && refs[ 0 ][ 0 ] != '\0' ) { if ( rs->sr_err != LDAP_REFERRAL ) { Debug( LDAP_DEBUG_ANY, "%s asyncmeta_handle_common_result[%d]: " "got referrals with err=%d\n", op->o_log_prefix, candidate, rs->sr_err ); } else { int i; for ( i = 0; refs[ i ] != NULL; i++ ) /* count */ ; rs->sr_ref = op->o_tmpalloc( sizeof( struct berval ) * ( i + 1 ), op->o_tmpmemctx ); for ( i = 0; refs[ i ] != NULL; i++ ) { ber_str2bv( refs[ i ], 0, 0, &rs->sr_ref[ i ] ); } BER_BVZERO( &rs->sr_ref[ i ] ); } } else if ( rs->sr_err == LDAP_REFERRAL ) { Debug( LDAP_DEBUG_ANY, "%s asyncmeta_handle_common_result[%d]: " "got err=%d with null " "or empty referrals\n", op->o_log_prefix, candidate, rs->sr_err ); rs->sr_err = LDAP_NO_SUCH_OBJECT; } if ( ctrls != NULL ) { rs->sr_ctrls = ctrls; } /* if the error in the reply structure is not * LDAP_SUCCESS, try to map it from client * to server error */ if ( !LDAP_ERR_OK( rs->sr_err ) ) { rs->sr_err = slap_map_api2result( rs ); /* internal ops ( op->o_conn == NULL ) * must not reply to client */ if ( op->o_conn && !op->o_do_not_cache && matched ) { /* record the (massaged) matched * DN into the reply structure */ rs->sr_matched = matched; } } if ( META_BACK_TGT_QUARANTINE( mt ) ) { asyncmeta_quarantine( op, mi, rs, candidate ); } if ( matched != NULL ) { struct berval dn, pdn; ber_str2bv( matched, 0, 0, &dn ); if ( dnPretty( NULL, &dn, &pdn, op->o_tmpmemctx ) == LDAP_SUCCESS ) { ldap_memfree( matched ); matched_ctx = op->o_tmpmemctx; matched = pdn.bv_val; } rs->sr_matched = matched; } if ( rs->sr_err == LDAP_UNAVAILABLE || rs->sr_err == LDAP_SERVER_DOWN ) { if ( rs->sr_text == NULL ) { rs->sr_text = "Target is unavailable"; } } ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex ); asyncmeta_drop_bc( mc, bc); ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex ); if ( op->o_conn ) { asyncmeta_send_ldap_result(bc, op, rs); } if ( matched ) { op->o_tmpfree( (char *)rs->sr_matched, matched_ctx ); } if ( text ) { ldap_memfree( text ); } if ( rs->sr_ref ) { op->o_tmpfree( rs->sr_ref, op->o_tmpmemctx ); rs->sr_ref = NULL; } if ( refs ) { ber_memvfree( (void **)refs ); } if ( ctrls ) { assert( rs->sr_ctrls != NULL ); ldap_controls_free( ctrls ); } rs->sr_text = save_text; rs->sr_matched = save_matched; rs->sr_ref = save_ref; rs->sr_ctrls = save_ctrls; rc = (LDAP_ERR_OK( rs->sr_err ) ? LDAP_SUCCESS : rs->sr_err); ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex ); asyncmeta_clear_bm_context(bc); ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex ); return rc; }
/* * FIXME: error return must be handled in a cleaner way ... */ int meta_back_op_result( metaconn_t *mc, Operation *op, SlapReply *rs, int candidate, ber_int_t msgid, time_t timeout, ldap_back_send_t sendok ) { metainfo_t *mi = ( metainfo_t * )op->o_bd->be_private; const char *save_text = rs->sr_text, *save_matched = rs->sr_matched; BerVarray save_ref = rs->sr_ref; LDAPControl **save_ctrls = rs->sr_ctrls; void *matched_ctx = NULL; char *matched = NULL; char *text = NULL; char **refs = NULL; LDAPControl **ctrls = NULL; assert( mc != NULL ); rs->sr_text = NULL; rs->sr_matched = NULL; rs->sr_ref = NULL; rs->sr_ctrls = NULL; if ( candidate != META_TARGET_NONE ) { metatarget_t *mt = mi->mi_targets[ candidate ]; metasingleconn_t *msc = &mc->mc_conns[ candidate ]; if ( LDAP_ERR_OK( rs->sr_err ) ) { int rc; struct timeval tv; LDAPMessage *res = NULL; time_t stoptime = (time_t)(-1); int timeout_err = op->o_protocol >= LDAP_VERSION3 ? LDAP_ADMINLIMIT_EXCEEDED : LDAP_OTHER; const char *timeout_text = "Operation timed out"; /* if timeout is not specified, compute and use * the one specific to the ongoing operation */ if ( timeout == (time_t)(-1) ) { slap_op_t opidx = slap_req2op( op->o_tag ); if ( opidx == SLAP_OP_SEARCH ) { if ( op->ors_tlimit <= 0 ) { timeout = 0; } else { timeout = op->ors_tlimit; timeout_err = LDAP_TIMELIMIT_EXCEEDED; timeout_text = NULL; } } else { timeout = mt->mt_timeout[ opidx ]; } } /* better than nothing :) */ if ( timeout == 0 ) { if ( mi->mi_idle_timeout ) { timeout = mi->mi_idle_timeout; } else if ( mi->mi_conn_ttl ) { timeout = mi->mi_conn_ttl; } } if ( timeout ) { stoptime = op->o_time + timeout; } LDAP_BACK_TV_SET( &tv ); retry:; rc = ldap_result( msc->msc_ld, msgid, LDAP_MSG_ALL, &tv, &res ); switch ( rc ) { case 0: if ( timeout && slap_get_time() > stoptime ) { (void)meta_back_cancel( mc, op, rs, msgid, candidate, sendok ); rs->sr_err = timeout_err; rs->sr_text = timeout_text; break; } LDAP_BACK_TV_SET( &tv ); ldap_pvt_thread_yield(); goto retry; case -1: ldap_get_option( msc->msc_ld, LDAP_OPT_RESULT_CODE, &rs->sr_err ); break; /* otherwise get the result; if it is not * LDAP_SUCCESS, record it in the reply * structure (this includes * LDAP_COMPARE_{TRUE|FALSE}) */ default: /* only touch when activity actually took place... */ if ( mi->mi_idle_timeout != 0 && msc->msc_time < op->o_time ) { msc->msc_time = op->o_time; } rc = ldap_parse_result( msc->msc_ld, res, &rs->sr_err, &matched, &text, &refs, &ctrls, 1 ); res = NULL; if ( rc == LDAP_SUCCESS ) { rs->sr_text = text; } else { rs->sr_err = rc; } rs->sr_err = slap_map_api2result( rs ); /* RFC 4511: referrals can only appear * if result code is LDAP_REFERRAL */ if ( refs != NULL && refs[ 0 ] != NULL && refs[ 0 ][ 0 ] != '\0' ) { if ( rs->sr_err != LDAP_REFERRAL ) { Debug( LDAP_DEBUG_ANY, "%s meta_back_op_result[%d]: " "got referrals with err=%d\n", op->o_log_prefix, candidate, rs->sr_err ); } else { int i; for ( i = 0; refs[ i ] != NULL; i++ ) /* count */ ; rs->sr_ref = op->o_tmpalloc( sizeof( struct berval ) * ( i + 1 ), op->o_tmpmemctx ); for ( i = 0; refs[ i ] != NULL; i++ ) { ber_str2bv( refs[ i ], 0, 0, &rs->sr_ref[ i ] ); } BER_BVZERO( &rs->sr_ref[ i ] ); } } else if ( rs->sr_err == LDAP_REFERRAL ) { Debug( LDAP_DEBUG_ANY, "%s meta_back_op_result[%d]: " "got err=%d with null " "or empty referrals\n", op->o_log_prefix, candidate, rs->sr_err ); rs->sr_err = LDAP_NO_SUCH_OBJECT; } if ( ctrls != NULL ) { rs->sr_ctrls = ctrls; } } assert( res == NULL ); } /* if the error in the reply structure is not * LDAP_SUCCESS, try to map it from client * to server error */ if ( !LDAP_ERR_OK( rs->sr_err ) ) { rs->sr_err = slap_map_api2result( rs ); /* internal ops ( op->o_conn == NULL ) * must not reply to client */ if ( op->o_conn && !op->o_do_not_cache && matched ) { /* record the (massaged) matched * DN into the reply structure */ rs->sr_matched = matched; } } if ( META_BACK_TGT_QUARANTINE( mt ) ) { meta_back_quarantine( op, rs, candidate ); } } else { int i, err = rs->sr_err; for ( i = 0; i < mi->mi_ntargets; i++ ) { metasingleconn_t *msc = &mc->mc_conns[ i ]; char *xtext = NULL; char *xmatched = NULL; if ( msc->msc_ld == NULL ) { continue; } rs->sr_err = LDAP_SUCCESS; ldap_get_option( msc->msc_ld, LDAP_OPT_RESULT_CODE, &rs->sr_err ); if ( rs->sr_err != LDAP_SUCCESS ) { /* * better check the type of error. In some cases * (search ?) it might be better to return a * success if at least one of the targets gave * positive result ... */ ldap_get_option( msc->msc_ld, LDAP_OPT_DIAGNOSTIC_MESSAGE, &xtext ); if ( xtext != NULL && xtext [ 0 ] == '\0' ) { ldap_memfree( xtext ); xtext = NULL; } ldap_get_option( msc->msc_ld, LDAP_OPT_MATCHED_DN, &xmatched ); if ( xmatched != NULL && xmatched[ 0 ] == '\0' ) { ldap_memfree( xmatched ); xmatched = NULL; } rs->sr_err = slap_map_api2result( rs ); if ( LogTest( LDAP_DEBUG_ANY ) ) { char buf[ SLAP_TEXT_BUFLEN ]; snprintf( buf, sizeof( buf ), "meta_back_op_result[%d] " "err=%d text=\"%s\" matched=\"%s\"", i, rs->sr_err, ( xtext ? xtext : "" ), ( xmatched ? xmatched : "" ) ); Debug( LDAP_DEBUG_ANY, "%s %s.\n", op->o_log_prefix, buf ); } /* * FIXME: need to rewrite "match" (need rwinfo) */ switch ( rs->sr_err ) { default: err = rs->sr_err; if ( xtext != NULL ) { if ( text ) { ldap_memfree( text ); } text = xtext; xtext = NULL; } if ( xmatched != NULL ) { if ( matched ) { ldap_memfree( matched ); } matched = xmatched; xmatched = NULL; } break; } if ( xtext ) { ldap_memfree( xtext ); } if ( xmatched ) { ldap_memfree( xmatched ); } } if ( META_BACK_TGT_QUARANTINE( mi->mi_targets[ i ] ) ) { meta_back_quarantine( op, rs, i ); } } if ( err != LDAP_SUCCESS ) { rs->sr_err = err; } } if ( matched != NULL ) { struct berval dn, pdn; ber_str2bv( matched, 0, 0, &dn ); if ( dnPretty( NULL, &dn, &pdn, op->o_tmpmemctx ) == LDAP_SUCCESS ) { ldap_memfree( matched ); matched_ctx = op->o_tmpmemctx; matched = pdn.bv_val; } rs->sr_matched = matched; } if ( rs->sr_err == LDAP_UNAVAILABLE ) { if ( !( sendok & LDAP_BACK_RETRYING ) ) { if ( op->o_conn && ( sendok & LDAP_BACK_SENDERR ) ) { if ( rs->sr_text == NULL ) rs->sr_text = "Proxy operation retry failed"; send_ldap_result( op, rs ); } } } else if ( op->o_conn && ( ( ( sendok & LDAP_BACK_SENDOK ) && LDAP_ERR_OK( rs->sr_err ) ) || ( ( sendok & LDAP_BACK_SENDERR ) && !LDAP_ERR_OK( rs->sr_err ) ) ) ) { send_ldap_result( op, rs ); } if ( matched ) { op->o_tmpfree( (char *)rs->sr_matched, matched_ctx ); } if ( text ) { ldap_memfree( text ); } if ( rs->sr_ref ) { op->o_tmpfree( rs->sr_ref, op->o_tmpmemctx ); rs->sr_ref = NULL; } if ( refs ) { ber_memvfree( (void **)refs ); } if ( ctrls ) { assert( rs->sr_ctrls != NULL ); ldap_controls_free( ctrls ); } rs->sr_text = save_text; rs->sr_matched = save_matched; rs->sr_ref = save_ref; rs->sr_ctrls = save_ctrls; return( LDAP_ERR_OK( rs->sr_err ) ? LDAP_SUCCESS : rs->sr_err ); }