1*cf1d77f7Schristos /* $NetBSD: meta_result.c,v 1.2 2021/08/14 16:14:59 christos Exp $ */
292cfeba6Schristos
392cfeba6Schristos /* meta_result.c - target responses processing */
492cfeba6Schristos /* $OpenLDAP$ */
592cfeba6Schristos /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
692cfeba6Schristos *
792cfeba6Schristos * Copyright 2016-2021 The OpenLDAP Foundation.
892cfeba6Schristos * Portions Copyright 2016 Symas Corporation.
992cfeba6Schristos * All rights reserved.
1092cfeba6Schristos *
1192cfeba6Schristos * Redistribution and use in source and binary forms, with or without
1292cfeba6Schristos * modification, are permitted only as authorized by the OpenLDAP
1392cfeba6Schristos * Public License.
1492cfeba6Schristos *
1592cfeba6Schristos * A copy of this license is available in the file LICENSE in the
1692cfeba6Schristos * top-level directory of the distribution or, alternatively, at
1792cfeba6Schristos * <http://www.OpenLDAP.org/license.html>.
1892cfeba6Schristos */
1992cfeba6Schristos
2092cfeba6Schristos /* ACKNOWLEDGEMENTS:
2192cfeba6Schristos * This work was developed by Symas Corporation
2292cfeba6Schristos * based on back-meta module for inclusion in OpenLDAP Software.
2392cfeba6Schristos * This work was sponsored by Ericsson. */
2492cfeba6Schristos
2592cfeba6Schristos #include <sys/cdefs.h>
26*cf1d77f7Schristos __RCSID("$NetBSD: meta_result.c,v 1.2 2021/08/14 16:14:59 christos Exp $");
2792cfeba6Schristos
2892cfeba6Schristos #include "portable.h"
2992cfeba6Schristos
3092cfeba6Schristos #include <stdio.h>
3192cfeba6Schristos
3292cfeba6Schristos #include <ac/string.h>
3392cfeba6Schristos #include <ac/socket.h>
3492cfeba6Schristos
3592cfeba6Schristos #include "slap.h"
3692cfeba6Schristos #include "../back-ldap/back-ldap.h"
3792cfeba6Schristos #include "back-asyncmeta.h"
3892cfeba6Schristos #include "ldap_rq.h"
3992cfeba6Schristos #include "../../../libraries/liblber/lber-int.h"
4092cfeba6Schristos
4192cfeba6Schristos static void
asyncmeta_send_ldap_result(bm_context_t * bc,Operation * op,SlapReply * rs)4292cfeba6Schristos asyncmeta_send_ldap_result(bm_context_t *bc, Operation *op, SlapReply *rs)
4392cfeba6Schristos {
4492cfeba6Schristos if (bc->c_peer_name.bv_val == op->o_conn->c_peer_name.bv_val && !bc->op->o_abandon ) {
4592cfeba6Schristos send_ldap_result(&bc->copy_op, rs);
4692cfeba6Schristos bc->op->o_callback = bc->copy_op.o_callback;
4792cfeba6Schristos bc->op->o_extra = bc->copy_op.o_extra;
4892cfeba6Schristos bc->op->o_ctrls = bc->copy_op.o_ctrls;
4992cfeba6Schristos }
5092cfeba6Schristos }
5192cfeba6Schristos
5292cfeba6Schristos static int
asyncmeta_is_last_result(a_metaconn_t * mc,bm_context_t * bc,int candidate)5392cfeba6Schristos asyncmeta_is_last_result(a_metaconn_t *mc, bm_context_t *bc, int candidate)
5492cfeba6Schristos {
5592cfeba6Schristos a_metainfo_t *mi = mc->mc_info;
5692cfeba6Schristos int i;
5792cfeba6Schristos SlapReply *candidates = bc->candidates;
5892cfeba6Schristos for ( i = 0; i < mi->mi_ntargets; i++ ) {
5992cfeba6Schristos if ( !META_IS_CANDIDATE( &candidates[ i ] ) ) {
6092cfeba6Schristos continue;
6192cfeba6Schristos }
6292cfeba6Schristos if (candidates[ i ].sr_msgid != META_MSGID_IGNORE ||
6392cfeba6Schristos candidates[ i ].sr_type != REP_RESULT) {
6492cfeba6Schristos return 1;
6592cfeba6Schristos }
6692cfeba6Schristos }
6792cfeba6Schristos return 0;
6892cfeba6Schristos }
6992cfeba6Schristos
7092cfeba6Schristos meta_search_candidate_t
asyncmeta_dobind_result(a_metaconn_t * mc,int candidate,SlapReply * bind_result,LDAPMessage * res)7192cfeba6Schristos asyncmeta_dobind_result(
7292cfeba6Schristos a_metaconn_t *mc,
7392cfeba6Schristos int candidate,
7492cfeba6Schristos SlapReply *bind_result,
7592cfeba6Schristos LDAPMessage *res )
7692cfeba6Schristos {
7792cfeba6Schristos a_metainfo_t *mi = mc->mc_info;
7892cfeba6Schristos a_metatarget_t *mt = mi->mi_targets[ candidate ];
7992cfeba6Schristos a_metasingleconn_t *msc = &mc->mc_conns[ candidate ];
8092cfeba6Schristos
8192cfeba6Schristos meta_search_candidate_t retcode = META_SEARCH_NOT_CANDIDATE;
8292cfeba6Schristos int rc;
8392cfeba6Schristos
8492cfeba6Schristos assert( msc->msc_ldr != NULL );
8592cfeba6Schristos
8692cfeba6Schristos if ( mi->mi_idle_timeout != 0 ) {
8792cfeba6Schristos asyncmeta_set_msc_time(msc);
8892cfeba6Schristos }
8992cfeba6Schristos
9092cfeba6Schristos if ( LogTest( asyncmeta_debug ) ) {
9192cfeba6Schristos char time_buf[ SLAP_TEXT_BUFLEN ];
9292cfeba6Schristos asyncmeta_get_timestamp(time_buf);
9392cfeba6Schristos Debug( asyncmeta_debug, "[%x] [%s] asyncmeta_dobind_result msc: %p, "
9492cfeba6Schristos "msc->msc_binding_time: %x, msc->msc_flags:%x\n ",
9592cfeba6Schristos (unsigned int)slap_get_time(), time_buf, msc,
9692cfeba6Schristos (unsigned int)msc->msc_binding_time, msc->msc_mscflags );
9792cfeba6Schristos }
9892cfeba6Schristos /* FIXME: matched? referrals? response controls? */
9992cfeba6Schristos rc = ldap_parse_result( msc->msc_ldr, res,
10092cfeba6Schristos &(bind_result->sr_err),
10192cfeba6Schristos (char **)&(bind_result->sr_matched),
10292cfeba6Schristos (char **)&(bind_result->sr_text),
10392cfeba6Schristos NULL, NULL, 0 );
10492cfeba6Schristos
10592cfeba6Schristos if ( LogTest( asyncmeta_debug ) ) {
10692cfeba6Schristos char time_buf[ SLAP_TEXT_BUFLEN ];
10792cfeba6Schristos asyncmeta_get_timestamp(time_buf);
10892cfeba6Schristos Debug( asyncmeta_debug,
10992cfeba6Schristos "[%s] asyncmeta_dobind_result error=%d msc: %p\n",
11092cfeba6Schristos time_buf,bind_result->sr_err, msc );
11192cfeba6Schristos }
11292cfeba6Schristos
11392cfeba6Schristos if ( rc != LDAP_SUCCESS ) {
11492cfeba6Schristos bind_result->sr_err = rc;
11592cfeba6Schristos }
11692cfeba6Schristos rc = slap_map_api2result( bind_result );
11792cfeba6Schristos
11892cfeba6Schristos LDAP_BACK_CONN_BINDING_CLEAR( msc );
11992cfeba6Schristos if ( rc != LDAP_SUCCESS ) {
12092cfeba6Schristos bind_result->sr_err = rc;
12192cfeba6Schristos } else {
12292cfeba6Schristos /* FIXME: check if bound as idassert authcDN! */
12392cfeba6Schristos if ( BER_BVISNULL( &msc->msc_bound_ndn )
12492cfeba6Schristos || BER_BVISEMPTY( &msc->msc_bound_ndn ) )
12592cfeba6Schristos {
12692cfeba6Schristos LDAP_BACK_CONN_ISANON_SET( msc );
12792cfeba6Schristos if ( LogTest( asyncmeta_debug ) ) {
12892cfeba6Schristos char time_buf[ SLAP_TEXT_BUFLEN ];
12992cfeba6Schristos asyncmeta_get_timestamp(time_buf);
13092cfeba6Schristos Debug( asyncmeta_debug, "[%s] asyncmeta_dobind_result anonymous msc: %p\n",
13192cfeba6Schristos time_buf, msc );
13292cfeba6Schristos }
13392cfeba6Schristos
13492cfeba6Schristos } else {
13592cfeba6Schristos if ( META_BACK_TGT_SAVECRED( mt ) &&
13692cfeba6Schristos !BER_BVISNULL( &msc->msc_cred ) &&
13792cfeba6Schristos !BER_BVISEMPTY( &msc->msc_cred ) )
13892cfeba6Schristos {
13992cfeba6Schristos ldap_set_rebind_proc( msc->msc_ldr, mt->mt_rebind_f, msc );
14092cfeba6Schristos }
14192cfeba6Schristos if ( LogTest( asyncmeta_debug ) ) {
14292cfeba6Schristos char time_buf[ SLAP_TEXT_BUFLEN ];
14392cfeba6Schristos asyncmeta_get_timestamp(time_buf);
14492cfeba6Schristos Debug( asyncmeta_debug, "[%s] asyncmeta_dobind_result success msc: %p\n",
14592cfeba6Schristos time_buf, msc );
14692cfeba6Schristos }
14792cfeba6Schristos LDAP_BACK_CONN_ISBOUND_SET( msc );
14892cfeba6Schristos }
14992cfeba6Schristos retcode = META_SEARCH_CANDIDATE;
15092cfeba6Schristos }
15192cfeba6Schristos return retcode;
15292cfeba6Schristos }
15392cfeba6Schristos
15492cfeba6Schristos static int
asyncmeta_send_entry(Operation * op,SlapReply * rs,a_metaconn_t * mc,int target,LDAPMessage * e)15592cfeba6Schristos asyncmeta_send_entry(
15692cfeba6Schristos Operation *op,
15792cfeba6Schristos SlapReply *rs,
15892cfeba6Schristos a_metaconn_t *mc,
15992cfeba6Schristos int target,
16092cfeba6Schristos LDAPMessage *e )
16192cfeba6Schristos {
16292cfeba6Schristos a_metainfo_t *mi = mc->mc_info;
16392cfeba6Schristos struct berval a, mapped = BER_BVNULL;
16492cfeba6Schristos int check_sorted_attrs = 0;
16592cfeba6Schristos Entry ent = {0};
16692cfeba6Schristos BerElement ber = *ldap_get_message_ber( e );
16792cfeba6Schristos Attribute *attr, **attrp;
16892cfeba6Schristos struct berval bdn,
16992cfeba6Schristos dn = BER_BVNULL;
17092cfeba6Schristos const char *text;
17192cfeba6Schristos a_dncookie dc;
17292cfeba6Schristos ber_len_t len;
17392cfeba6Schristos int rc;
17492cfeba6Schristos void *mem_mark;
17592cfeba6Schristos
17692cfeba6Schristos mem_mark = slap_sl_mark( op->o_tmpmemctx );
17792cfeba6Schristos ber_set_option( &ber, LBER_OPT_BER_MEMCTX, &op->o_tmpmemctx );
17892cfeba6Schristos
17992cfeba6Schristos if ( ber_scanf( &ber, "l{", &len ) == LBER_ERROR ) {
18092cfeba6Schristos return LDAP_DECODING_ERROR;
18192cfeba6Schristos }
18292cfeba6Schristos
18392cfeba6Schristos if ( ber_set_option( &ber, LBER_OPT_REMAINING_BYTES, &len ) != LBER_OPT_SUCCESS ) {
18492cfeba6Schristos return LDAP_OTHER;
18592cfeba6Schristos }
18692cfeba6Schristos
18792cfeba6Schristos if ( ber_scanf( &ber, "m{", &bdn ) == LBER_ERROR ) {
18892cfeba6Schristos return LDAP_DECODING_ERROR;
18992cfeba6Schristos }
19092cfeba6Schristos
19192cfeba6Schristos /*
19292cfeba6Schristos * Rewrite the dn of the result, if needed
19392cfeba6Schristos */
19492cfeba6Schristos dc.op = op;
19592cfeba6Schristos dc.target = mi->mi_targets[ target ];
19692cfeba6Schristos dc.memctx = op->o_tmpmemctx;
19792cfeba6Schristos dc.to_from = MASSAGE_REP;
19892cfeba6Schristos asyncmeta_dn_massage( &dc, &bdn, &dn );
19992cfeba6Schristos
20092cfeba6Schristos /*
20192cfeba6Schristos * Note: this may fail if the target host(s) schema differs
20292cfeba6Schristos * from the one known to the meta, and a DN with unknown
20392cfeba6Schristos * attributes is returned.
20492cfeba6Schristos *
20592cfeba6Schristos * FIXME: should we log anything, or delegate to dnNormalize?
20692cfeba6Schristos */
20792cfeba6Schristos rc = dnPrettyNormal( NULL, &dn, &ent.e_name, &ent.e_nname,
20892cfeba6Schristos op->o_tmpmemctx );
20992cfeba6Schristos if ( dn.bv_val != bdn.bv_val ) {
21092cfeba6Schristos op->o_tmpfree( dn.bv_val, op->o_tmpmemctx );
21192cfeba6Schristos }
21292cfeba6Schristos BER_BVZERO( &dn );
21392cfeba6Schristos
21492cfeba6Schristos if ( rc != LDAP_SUCCESS ) {
21592cfeba6Schristos Debug( LDAP_DEBUG_ANY,
21692cfeba6Schristos "%s asyncmeta_send_entry(\"%s\"): "
21792cfeba6Schristos "invalid DN syntax\n",
21892cfeba6Schristos op->o_log_prefix, ent.e_name.bv_val );
21992cfeba6Schristos rc = LDAP_INVALID_DN_SYNTAX;
22092cfeba6Schristos goto done;
22192cfeba6Schristos }
22292cfeba6Schristos
22392cfeba6Schristos /*
22492cfeba6Schristos * cache dn
22592cfeba6Schristos */
22692cfeba6Schristos if ( mi->mi_cache.ttl != META_DNCACHE_DISABLED ) {
22792cfeba6Schristos ( void )asyncmeta_dncache_update_entry( &mi->mi_cache,
22892cfeba6Schristos &ent.e_nname, target );
22992cfeba6Schristos }
23092cfeba6Schristos
23192cfeba6Schristos attrp = &ent.e_attrs;
23292cfeba6Schristos
23392cfeba6Schristos while ( ber_scanf( &ber, "{m", &a ) != LBER_ERROR ) {
23492cfeba6Schristos int last = 0;
23592cfeba6Schristos slap_syntax_validate_func *validate;
23692cfeba6Schristos slap_syntax_transform_func *pretty;
23792cfeba6Schristos
23892cfeba6Schristos if ( ber_pvt_ber_remaining( &ber ) < 0 ) {
23992cfeba6Schristos Debug( LDAP_DEBUG_ANY,
24092cfeba6Schristos "%s asyncmeta_send_entry(\"%s\"): "
24192cfeba6Schristos "unable to parse attr \"%s\".\n",
24292cfeba6Schristos op->o_log_prefix, ent.e_name.bv_val, a.bv_val );
24392cfeba6Schristos
24492cfeba6Schristos rc = LDAP_OTHER;
24592cfeba6Schristos goto done;
24692cfeba6Schristos }
24792cfeba6Schristos
24892cfeba6Schristos if ( ber_pvt_ber_remaining( &ber ) == 0 ) {
24992cfeba6Schristos break;
25092cfeba6Schristos }
25192cfeba6Schristos
25292cfeba6Schristos attr = op->o_tmpcalloc( 1, sizeof(Attribute), op->o_tmpmemctx );
25392cfeba6Schristos if ( slap_bv2ad( &a, &attr->a_desc, &text )
25492cfeba6Schristos != LDAP_SUCCESS) {
25592cfeba6Schristos if ( slap_bv2undef_ad( &a, &attr->a_desc, &text,
25692cfeba6Schristos SLAP_AD_PROXIED ) != LDAP_SUCCESS )
25792cfeba6Schristos {
25892cfeba6Schristos Debug(LDAP_DEBUG_ANY,
25992cfeba6Schristos "%s meta_send_entry(\"%s\"): " "slap_bv2undef_ad(%s): %s\n",
26092cfeba6Schristos op->o_log_prefix, ent.e_name.bv_val,
26192cfeba6Schristos mapped.bv_val, text );
26292cfeba6Schristos ( void )ber_scanf( &ber, "x" /* [W] */ );
26392cfeba6Schristos op->o_tmpfree( attr, op->o_tmpmemctx );
26492cfeba6Schristos continue;
26592cfeba6Schristos }
26692cfeba6Schristos }
26792cfeba6Schristos
26892cfeba6Schristos if ( attr->a_desc->ad_type->sat_flags & SLAP_AT_SORTED_VAL )
26992cfeba6Schristos check_sorted_attrs = 1;
27092cfeba6Schristos
27192cfeba6Schristos /* no subschemaSubentry */
27292cfeba6Schristos if ( attr->a_desc == slap_schema.si_ad_subschemaSubentry
27392cfeba6Schristos || attr->a_desc == slap_schema.si_ad_entryDN )
27492cfeba6Schristos {
27592cfeba6Schristos
27692cfeba6Schristos /*
27792cfeba6Schristos * We eat target's subschemaSubentry because
27892cfeba6Schristos * a search for this value is likely not
27992cfeba6Schristos * to resolve to the appropriate backend;
28092cfeba6Schristos * later, the local subschemaSubentry is
28192cfeba6Schristos * added.
28292cfeba6Schristos *
28392cfeba6Schristos * We also eat entryDN because the frontend
28492cfeba6Schristos * will reattach it without checking if already
28592cfeba6Schristos * present...
28692cfeba6Schristos */
28792cfeba6Schristos ( void )ber_scanf( &ber, "x" /* [W] */ );
28892cfeba6Schristos op->o_tmpfree( attr, op->o_tmpmemctx );
28992cfeba6Schristos continue;
29092cfeba6Schristos }
29192cfeba6Schristos
29292cfeba6Schristos if ( ber_scanf( &ber, "[W]", &attr->a_vals ) == LBER_ERROR
29392cfeba6Schristos || attr->a_vals == NULL )
29492cfeba6Schristos {
29592cfeba6Schristos attr->a_vals = (struct berval *)&slap_dummy_bv;
29692cfeba6Schristos
29792cfeba6Schristos } else {
29892cfeba6Schristos for ( last = 0; !BER_BVISNULL( &attr->a_vals[ last ] ); ++last )
29992cfeba6Schristos ;
30092cfeba6Schristos }
30192cfeba6Schristos attr->a_numvals = last;
30292cfeba6Schristos
30392cfeba6Schristos validate = attr->a_desc->ad_type->sat_syntax->ssyn_validate;
30492cfeba6Schristos pretty = attr->a_desc->ad_type->sat_syntax->ssyn_pretty;
30592cfeba6Schristos
30692cfeba6Schristos if ( !validate && !pretty ) {
30792cfeba6Schristos ber_bvarray_free_x( attr->a_vals, op->o_tmpmemctx );
30892cfeba6Schristos op->o_tmpfree( attr, op->o_tmpmemctx );
30992cfeba6Schristos goto next_attr;
31092cfeba6Schristos }
31192cfeba6Schristos
31292cfeba6Schristos /*
31392cfeba6Schristos * It is necessary to try to rewrite attributes with
31492cfeba6Schristos * dn syntax because they might be used in ACLs as
31592cfeba6Schristos * members of groups; since ACLs are applied to the
31692cfeba6Schristos * rewritten stuff, no dn-based subecj clause could
31792cfeba6Schristos * be used at the ldap backend side (see
31892cfeba6Schristos * http://www.OpenLDAP.org/faq/data/cache/452.html)
31992cfeba6Schristos * The problem can be overcome by moving the dn-based
32092cfeba6Schristos * ACLs to the target directory server, and letting
32192cfeba6Schristos * everything pass thru the ldap backend.
32292cfeba6Schristos */
32392cfeba6Schristos {
32492cfeba6Schristos int i;
32592cfeba6Schristos
32692cfeba6Schristos if ( attr->a_desc->ad_type->sat_syntax ==
32792cfeba6Schristos slap_schema.si_syn_distinguishedName )
32892cfeba6Schristos {
32992cfeba6Schristos asyncmeta_dnattr_result_rewrite( &dc, attr->a_vals );
33092cfeba6Schristos
33192cfeba6Schristos } else if ( attr->a_desc == slap_schema.si_ad_ref ) {
33292cfeba6Schristos asyncmeta_referral_result_rewrite( &dc, attr->a_vals );
33392cfeba6Schristos
33492cfeba6Schristos }
33592cfeba6Schristos
33692cfeba6Schristos for ( i = 0; i < last; i++ ) {
33792cfeba6Schristos struct berval pval;
33892cfeba6Schristos int rc;
33992cfeba6Schristos
34092cfeba6Schristos if ( pretty ) {
34192cfeba6Schristos rc = ordered_value_pretty( attr->a_desc,
34292cfeba6Schristos &attr->a_vals[i], &pval, op->o_tmpmemctx );
34392cfeba6Schristos
34492cfeba6Schristos } else {
34592cfeba6Schristos rc = ordered_value_validate( attr->a_desc,
34692cfeba6Schristos &attr->a_vals[i], 0 );
34792cfeba6Schristos }
34892cfeba6Schristos
34992cfeba6Schristos if ( rc ) {
35092cfeba6Schristos ber_memfree_x( attr->a_vals[i].bv_val, op->o_tmpmemctx );
35192cfeba6Schristos if ( --last == i ) {
35292cfeba6Schristos BER_BVZERO( &attr->a_vals[ i ] );
35392cfeba6Schristos break;
35492cfeba6Schristos }
35592cfeba6Schristos attr->a_vals[i] = attr->a_vals[last];
35692cfeba6Schristos BER_BVZERO( &attr->a_vals[last] );
35792cfeba6Schristos i--;
35892cfeba6Schristos continue;
35992cfeba6Schristos }
36092cfeba6Schristos
36192cfeba6Schristos if ( pretty ) {
36292cfeba6Schristos ber_memfree_x( attr->a_vals[i].bv_val, op->o_tmpmemctx );
36392cfeba6Schristos attr->a_vals[i] = pval;
36492cfeba6Schristos }
36592cfeba6Schristos }
36692cfeba6Schristos
36792cfeba6Schristos if ( last == 0 && attr->a_vals != &slap_dummy_bv ) {
36892cfeba6Schristos ber_bvarray_free_x( attr->a_vals, op->o_tmpmemctx );
36992cfeba6Schristos op->o_tmpfree( attr, op->o_tmpmemctx );
37092cfeba6Schristos goto next_attr;
37192cfeba6Schristos }
37292cfeba6Schristos }
37392cfeba6Schristos
37492cfeba6Schristos if ( last && attr->a_desc->ad_type->sat_equality &&
37592cfeba6Schristos attr->a_desc->ad_type->sat_equality->smr_normalize )
37692cfeba6Schristos {
37792cfeba6Schristos int i;
37892cfeba6Schristos
37992cfeba6Schristos attr->a_nvals = op->o_tmpalloc( ( last + 1 ) * sizeof( struct berval ), op->o_tmpmemctx );
38092cfeba6Schristos for ( i = 0; i<last; i++ ) {
38192cfeba6Schristos /* if normalizer fails, drop this value */
38292cfeba6Schristos if ( ordered_value_normalize(
38392cfeba6Schristos SLAP_MR_VALUE_OF_ATTRIBUTE_SYNTAX,
38492cfeba6Schristos attr->a_desc,
38592cfeba6Schristos attr->a_desc->ad_type->sat_equality,
38692cfeba6Schristos &attr->a_vals[i], &attr->a_nvals[i],
38792cfeba6Schristos op->o_tmpmemctx )) {
38892cfeba6Schristos ber_memfree_x( attr->a_vals[i].bv_val, op->o_tmpmemctx );
38992cfeba6Schristos if ( --last == i ) {
39092cfeba6Schristos BER_BVZERO( &attr->a_vals[ i ] );
39192cfeba6Schristos break;
39292cfeba6Schristos }
39392cfeba6Schristos attr->a_vals[i] = attr->a_vals[last];
39492cfeba6Schristos BER_BVZERO( &attr->a_vals[last] );
39592cfeba6Schristos i--;
39692cfeba6Schristos }
39792cfeba6Schristos }
39892cfeba6Schristos BER_BVZERO( &attr->a_nvals[i] );
39992cfeba6Schristos if ( last == 0 ) {
40092cfeba6Schristos ber_bvarray_free_x( attr->a_vals, op->o_tmpmemctx );
40192cfeba6Schristos ber_bvarray_free_x( attr->a_nvals, op->o_tmpmemctx );
40292cfeba6Schristos op->o_tmpfree( attr, op->o_tmpmemctx );
40392cfeba6Schristos goto next_attr;
40492cfeba6Schristos }
40592cfeba6Schristos
40692cfeba6Schristos } else {
40792cfeba6Schristos attr->a_nvals = attr->a_vals;
40892cfeba6Schristos }
40992cfeba6Schristos
41092cfeba6Schristos attr->a_numvals = last;
41192cfeba6Schristos *attrp = attr;
41292cfeba6Schristos attrp = &attr->a_next;
41392cfeba6Schristos next_attr:;
41492cfeba6Schristos }
41592cfeba6Schristos
41692cfeba6Schristos /* Check for sorted attributes */
41792cfeba6Schristos if ( check_sorted_attrs ) {
41892cfeba6Schristos for ( attr = ent.e_attrs; attr; attr = attr->a_next ) {
41992cfeba6Schristos if ( attr->a_desc->ad_type->sat_flags & SLAP_AT_SORTED_VAL ) {
42092cfeba6Schristos while ( attr->a_numvals > 1 ) {
42192cfeba6Schristos int i;
42292cfeba6Schristos int rc = slap_sort_vals( (Modifications *)attr, &text, &i, op->o_tmpmemctx );
42392cfeba6Schristos if ( rc != LDAP_TYPE_OR_VALUE_EXISTS )
42492cfeba6Schristos break;
42592cfeba6Schristos
42692cfeba6Schristos /* Strip duplicate values */
42792cfeba6Schristos if ( attr->a_nvals != attr->a_vals )
42892cfeba6Schristos ber_memfree_x( attr->a_nvals[i].bv_val, op->o_tmpmemctx );
42992cfeba6Schristos ber_memfree_x( attr->a_vals[i].bv_val, op->o_tmpmemctx );
43092cfeba6Schristos attr->a_numvals--;
43192cfeba6Schristos if ( (unsigned)i < attr->a_numvals ) {
43292cfeba6Schristos attr->a_vals[i] = attr->a_vals[attr->a_numvals];
43392cfeba6Schristos if ( attr->a_nvals != attr->a_vals )
43492cfeba6Schristos attr->a_nvals[i] = attr->a_nvals[attr->a_numvals];
43592cfeba6Schristos }
43692cfeba6Schristos BER_BVZERO(&attr->a_vals[attr->a_numvals]);
43792cfeba6Schristos if ( attr->a_nvals != attr->a_vals )
43892cfeba6Schristos BER_BVZERO(&attr->a_nvals[attr->a_numvals]);
43992cfeba6Schristos }
44092cfeba6Schristos attr->a_flags |= SLAP_ATTR_SORTED_VALS;
44192cfeba6Schristos }
44292cfeba6Schristos }
44392cfeba6Schristos }
44492cfeba6Schristos Debug( LDAP_DEBUG_TRACE,
44592cfeba6Schristos "%s asyncmeta_send_entry(\"%s\"): "
44692cfeba6Schristos ".\n",
44792cfeba6Schristos op->o_log_prefix, ent.e_name.bv_val );
44892cfeba6Schristos ldap_get_entry_controls( mc->mc_conns[target].msc_ldr,
44992cfeba6Schristos e, &rs->sr_ctrls );
45092cfeba6Schristos rs->sr_entry = &ent;
45192cfeba6Schristos rs->sr_attrs = op->ors_attrs;
45292cfeba6Schristos rs->sr_operational_attrs = NULL;
45392cfeba6Schristos rs->sr_flags = mi->mi_targets[ target ]->mt_rep_flags;
45492cfeba6Schristos rs->sr_err = LDAP_SUCCESS;
45592cfeba6Schristos rc = send_search_entry( op, rs );
45692cfeba6Schristos switch ( rc ) {
45792cfeba6Schristos case LDAP_UNAVAILABLE:
45892cfeba6Schristos rc = LDAP_OTHER;
45992cfeba6Schristos break;
46092cfeba6Schristos }
46192cfeba6Schristos
46292cfeba6Schristos done:;
46392cfeba6Schristos if ( rs->sr_ctrls != NULL ) {
46492cfeba6Schristos ldap_controls_free( rs->sr_ctrls );
46592cfeba6Schristos rs->sr_ctrls = NULL;
46692cfeba6Schristos }
46792cfeba6Schristos #if 0
46892cfeba6Schristos while ( ent.e_attrs ) {
46992cfeba6Schristos attr = ent.e_attrs;
47092cfeba6Schristos ent.e_attrs = attr->a_next;
47192cfeba6Schristos if ( attr->a_nvals != attr->a_vals )
47292cfeba6Schristos ber_bvarray_free_x( attr->a_nvals, op->o_tmpmemctx );
47392cfeba6Schristos ber_bvarray_free_x( attr->a_vals, op->o_tmpmemctx );
47492cfeba6Schristos op->o_tmpfree( attr, op->o_tmpmemctx );
47592cfeba6Schristos }
47692cfeba6Schristos if (ent.e_name.bv_val != NULL) {
47792cfeba6Schristos op->o_tmpfree( ent.e_name.bv_val, op->o_tmpmemctx );
47892cfeba6Schristos }
47992cfeba6Schristos
48092cfeba6Schristos if (ent.e_nname.bv_val != NULL) {
48192cfeba6Schristos op->o_tmpfree( ent.e_nname.bv_val, op->o_tmpmemctx );
48292cfeba6Schristos }
48392cfeba6Schristos if (rs->sr_entry && rs->sr_entry != &ent) {
48492cfeba6Schristos entry_free( rs->sr_entry );
48592cfeba6Schristos }
48692cfeba6Schristos #endif
48792cfeba6Schristos slap_sl_release( mem_mark, op->o_tmpmemctx );
48892cfeba6Schristos rs->sr_entry = NULL;
48992cfeba6Schristos rs->sr_attrs = NULL;
49092cfeba6Schristos return rc;
49192cfeba6Schristos }
49292cfeba6Schristos
49392cfeba6Schristos static void
asyncmeta_search_last_result(a_metaconn_t * mc,bm_context_t * bc,int candidate,int sres)49492cfeba6Schristos asyncmeta_search_last_result(a_metaconn_t *mc, bm_context_t *bc, int candidate, int sres)
49592cfeba6Schristos {
49692cfeba6Schristos a_metainfo_t *mi = mc->mc_info;
49792cfeba6Schristos Operation *op = bc->op;
49892cfeba6Schristos SlapReply *rs = &bc->rs;
49992cfeba6Schristos int i;
50092cfeba6Schristos SlapReply *candidates = bc->candidates;
50192cfeba6Schristos char *matched = NULL;
50292cfeba6Schristos
50392cfeba6Schristos if ( bc->candidate_match > 0 ) {
50492cfeba6Schristos struct berval pmatched = BER_BVNULL;
50592cfeba6Schristos
50692cfeba6Schristos /* we use the first one */
50792cfeba6Schristos for ( i = 0; i < mi->mi_ntargets; i++ ) {
50892cfeba6Schristos if ( META_IS_CANDIDATE( &candidates[ i ] )
50992cfeba6Schristos && candidates[ i ].sr_matched != NULL )
51092cfeba6Schristos {
51192cfeba6Schristos struct berval bv, pbv;
51292cfeba6Schristos int rc;
51392cfeba6Schristos
51492cfeba6Schristos /* if we got success, and this target
51592cfeba6Schristos * returned noSuchObject, and its suffix
51692cfeba6Schristos * is a superior of the searchBase,
51792cfeba6Schristos * ignore the matchedDN */
51892cfeba6Schristos if ( sres == LDAP_SUCCESS
51992cfeba6Schristos && candidates[ i ].sr_err == LDAP_NO_SUCH_OBJECT
52092cfeba6Schristos && op->o_req_ndn.bv_len > mi->mi_targets[ i ]->mt_nsuffix.bv_len )
52192cfeba6Schristos {
52292cfeba6Schristos free( (char *)candidates[ i ].sr_matched );
52392cfeba6Schristos candidates[ i ].sr_matched = NULL;
52492cfeba6Schristos continue;
52592cfeba6Schristos }
52692cfeba6Schristos
52792cfeba6Schristos ber_str2bv( candidates[ i ].sr_matched, 0, 0, &bv );
52892cfeba6Schristos rc = dnPretty( NULL, &bv, &pbv, op->o_tmpmemctx );
52992cfeba6Schristos
53092cfeba6Schristos if ( rc == LDAP_SUCCESS ) {
53192cfeba6Schristos
53292cfeba6Schristos /* NOTE: if they all are superiors
53392cfeba6Schristos * of the baseDN, the shorter is also
53492cfeba6Schristos * superior of the longer... */
53592cfeba6Schristos if ( pbv.bv_len > pmatched.bv_len ) {
53692cfeba6Schristos if ( !BER_BVISNULL( &pmatched ) ) {
53792cfeba6Schristos op->o_tmpfree( pmatched.bv_val, op->o_tmpmemctx );
53892cfeba6Schristos }
53992cfeba6Schristos pmatched = pbv;
54092cfeba6Schristos
54192cfeba6Schristos } else {
54292cfeba6Schristos op->o_tmpfree( pbv.bv_val, op->o_tmpmemctx );
54392cfeba6Schristos }
54492cfeba6Schristos }
54592cfeba6Schristos
54692cfeba6Schristos if ( candidates[ i ].sr_matched != NULL ) {
54792cfeba6Schristos free( (char *)candidates[ i ].sr_matched );
54892cfeba6Schristos candidates[ i ].sr_matched = NULL;
54992cfeba6Schristos }
55092cfeba6Schristos }
55192cfeba6Schristos }
55292cfeba6Schristos
55392cfeba6Schristos if ( !BER_BVISNULL( &pmatched ) ) {
55492cfeba6Schristos matched = pmatched.bv_val;
55592cfeba6Schristos }
55692cfeba6Schristos
55792cfeba6Schristos } else if ( sres == LDAP_NO_SUCH_OBJECT ) {
55892cfeba6Schristos matched = mi->mi_suffix.bv_val;
55992cfeba6Schristos }
56092cfeba6Schristos
56192cfeba6Schristos /*
56292cfeba6Schristos * In case we returned at least one entry, we return LDAP_SUCCESS
56392cfeba6Schristos * otherwise, the latter error code we got
56492cfeba6Schristos */
56592cfeba6Schristos
56692cfeba6Schristos if ( sres == LDAP_SUCCESS ) {
56792cfeba6Schristos if ( rs->sr_v2ref ) {
56892cfeba6Schristos sres = LDAP_REFERRAL;
56992cfeba6Schristos }
57092cfeba6Schristos
57192cfeba6Schristos if ( META_BACK_ONERR_REPORT( mi ) ) {
57292cfeba6Schristos /*
57392cfeba6Schristos * Report errors, if any
57492cfeba6Schristos *
57592cfeba6Schristos * FIXME: we should handle error codes and return the more
57692cfeba6Schristos * important/reasonable
57792cfeba6Schristos */
57892cfeba6Schristos for ( i = 0; i < mi->mi_ntargets; i++ ) {
57992cfeba6Schristos if ( !META_IS_CANDIDATE( &candidates[ i ] ) ) {
58092cfeba6Schristos continue;
58192cfeba6Schristos }
58292cfeba6Schristos
58392cfeba6Schristos if ( candidates[ i ].sr_err != LDAP_SUCCESS
58492cfeba6Schristos && candidates[ i ].sr_err != LDAP_NO_SUCH_OBJECT )
58592cfeba6Schristos {
58692cfeba6Schristos sres = candidates[ i ].sr_err;
58792cfeba6Schristos break;
58892cfeba6Schristos }
58992cfeba6Schristos }
59092cfeba6Schristos }
59192cfeba6Schristos }
59292cfeba6Schristos Debug( LDAP_DEBUG_TRACE,
59392cfeba6Schristos "%s asyncmeta_search_last_result(\"%d\"): "
59492cfeba6Schristos ".\n",
59592cfeba6Schristos op->o_log_prefix, candidate );
59692cfeba6Schristos rs->sr_err = sres;
59792cfeba6Schristos rs->sr_matched = ( sres == LDAP_SUCCESS ? NULL : matched );
59892cfeba6Schristos rs->sr_text = ( sres == LDAP_SUCCESS ? NULL : candidates[candidate].sr_text );
59992cfeba6Schristos rs->sr_ref = ( sres == LDAP_REFERRAL ? rs->sr_v2ref : NULL );
60092cfeba6Schristos asyncmeta_send_ldap_result(bc, op, rs);
60192cfeba6Schristos rs->sr_text = NULL;
60292cfeba6Schristos rs->sr_matched = NULL;
60392cfeba6Schristos rs->sr_ref = NULL;
60492cfeba6Schristos }
60592cfeba6Schristos
60692cfeba6Schristos static meta_search_candidate_t
asyncmeta_send_pending_op(bm_context_t * bc,int candidate)60792cfeba6Schristos asyncmeta_send_pending_op(bm_context_t *bc, int candidate)
60892cfeba6Schristos {
60992cfeba6Schristos meta_search_candidate_t retcode;
61092cfeba6Schristos switch (bc->op->o_tag) {
61192cfeba6Schristos case LDAP_REQ_SEARCH:
61292cfeba6Schristos retcode = asyncmeta_back_search_start( &bc->copy_op, &bc->rs, bc->bc_mc, bc, candidate, NULL, 0 , 0);
61392cfeba6Schristos break;
61492cfeba6Schristos case LDAP_REQ_ADD:
61592cfeba6Schristos retcode = asyncmeta_back_add_start( &bc->copy_op, &bc->rs, bc->bc_mc, bc, candidate, 0);
61692cfeba6Schristos break;
61792cfeba6Schristos case LDAP_REQ_MODIFY:
61892cfeba6Schristos retcode = asyncmeta_back_modify_start( &bc->copy_op, &bc->rs, bc->bc_mc, bc, candidate, 0);
61992cfeba6Schristos break;
62092cfeba6Schristos case LDAP_REQ_MODRDN:
62192cfeba6Schristos retcode = asyncmeta_back_modrdn_start( &bc->copy_op, &bc->rs, bc->bc_mc, bc, candidate, 0);
62292cfeba6Schristos break;
62392cfeba6Schristos case LDAP_REQ_COMPARE:
62492cfeba6Schristos retcode = asyncmeta_back_compare_start( &bc->copy_op, &bc->rs, bc->bc_mc, bc, candidate, 0);
62592cfeba6Schristos break;
62692cfeba6Schristos case LDAP_REQ_DELETE:
62792cfeba6Schristos retcode = asyncmeta_back_delete_start( &bc->copy_op, &bc->rs, bc->bc_mc, bc, candidate, 0);
62892cfeba6Schristos break;
62992cfeba6Schristos default:
63092cfeba6Schristos retcode = META_SEARCH_NOT_CANDIDATE;
63192cfeba6Schristos }
63292cfeba6Schristos return retcode;
63392cfeba6Schristos }
63492cfeba6Schristos
63592cfeba6Schristos
63692cfeba6Schristos meta_search_candidate_t
asyncmeta_send_all_pending_ops(a_metaconn_t * mc,int candidate,void * ctx,int dolock)63792cfeba6Schristos asyncmeta_send_all_pending_ops(a_metaconn_t *mc, int candidate, void *ctx, int dolock)
63892cfeba6Schristos {
63992cfeba6Schristos a_metainfo_t *mi = mc->mc_info;
64092cfeba6Schristos bm_context_t *bc, *onext;
64192cfeba6Schristos a_metasingleconn_t *msc = &mc->mc_conns[candidate];
64292cfeba6Schristos
64392cfeba6Schristos if ( dolock )
64492cfeba6Schristos ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex );
64592cfeba6Schristos
64692cfeba6Schristos msc->msc_active++;
64792cfeba6Schristos for (bc = LDAP_STAILQ_FIRST(&mc->mc_om_list); bc; bc = onext) {
64892cfeba6Schristos meta_search_candidate_t ret;
64992cfeba6Schristos onext = LDAP_STAILQ_NEXT(bc, bc_next);
65092cfeba6Schristos if (bc->candidates[candidate].sr_msgid == META_MSGID_NEED_BIND)
65192cfeba6Schristos bc->candidates[candidate].sr_msgid = META_MSGID_GOT_BIND;
65292cfeba6Schristos if (bc->candidates[candidate].sr_msgid != META_MSGID_GOT_BIND || bc->bc_active > 0 || bc->op->o_abandon > 0) {
65392cfeba6Schristos continue;
65492cfeba6Schristos }
65592cfeba6Schristos bc->op->o_threadctx = ctx;
65692cfeba6Schristos bc->op->o_tid = ldap_pvt_thread_pool_tid( ctx );
65792cfeba6Schristos slap_sl_mem_setctx(ctx, bc->op->o_tmpmemctx);
65892cfeba6Schristos bc->bc_active++;
65992cfeba6Schristos ret = asyncmeta_send_pending_op(bc, candidate);
66092cfeba6Schristos if (ret != META_SEARCH_CANDIDATE) {
66192cfeba6Schristos bc->candidates[ candidate ].sr_msgid = META_MSGID_IGNORE;
66292cfeba6Schristos bc->candidates[ candidate ].sr_type = REP_RESULT;
66392cfeba6Schristos bc->candidates[ candidate ].sr_err = bc->rs.sr_err;
66492cfeba6Schristos if (bc->op->o_tag != LDAP_REQ_SEARCH || (META_BACK_ONERR_STOP( mi )) ||
66592cfeba6Schristos (asyncmeta_is_last_result(mc, bc, candidate) == 0)) {
66692cfeba6Schristos LDAP_STAILQ_REMOVE(&mc->mc_om_list, bc, bm_context_t, bc_next);
66792cfeba6Schristos mc->pending_ops--;
66892cfeba6Schristos asyncmeta_send_ldap_result(bc, bc->op, &bc->rs);
66992cfeba6Schristos asyncmeta_clear_bm_context(bc);
67092cfeba6Schristos }
67192cfeba6Schristos } else {
67292cfeba6Schristos bc->bc_active--;
67392cfeba6Schristos }
67492cfeba6Schristos }
67592cfeba6Schristos msc->msc_active--;
67692cfeba6Schristos
67792cfeba6Schristos if ( dolock )
67892cfeba6Schristos ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex );
67992cfeba6Schristos
68092cfeba6Schristos return META_SEARCH_CANDIDATE;
68192cfeba6Schristos }
68292cfeba6Schristos
68392cfeba6Schristos meta_search_candidate_t
asyncmeta_return_bind_errors(a_metaconn_t * mc,int candidate,SlapReply * bind_result,void * ctx,int dolock)68492cfeba6Schristos asyncmeta_return_bind_errors(a_metaconn_t *mc, int candidate, SlapReply *bind_result, void *ctx, int dolock)
68592cfeba6Schristos {
68692cfeba6Schristos a_metainfo_t *mi = mc->mc_info;
68792cfeba6Schristos bm_context_t *bc, *onext;
68892cfeba6Schristos
68992cfeba6Schristos if ( dolock )
69092cfeba6Schristos ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex );
69192cfeba6Schristos
69292cfeba6Schristos for (bc = LDAP_STAILQ_FIRST(&mc->mc_om_list); bc; bc = onext) {
69392cfeba6Schristos onext = LDAP_STAILQ_NEXT(bc, bc_next);
69492cfeba6Schristos if (bc->candidates[candidate].sr_msgid != META_MSGID_NEED_BIND
69592cfeba6Schristos || bc->bc_active > 0 || bc->op->o_abandon > 0) {
69692cfeba6Schristos continue;
69792cfeba6Schristos }
69892cfeba6Schristos bc->candidates[ candidate ].sr_msgid = META_MSGID_IGNORE;
69992cfeba6Schristos bc->candidates[ candidate ].sr_type = REP_RESULT;
70092cfeba6Schristos bc->candidates[ candidate ].sr_err = bind_result->sr_err;
70192cfeba6Schristos if (bc->op->o_tag != LDAP_REQ_SEARCH || (META_BACK_ONERR_STOP( mi )) ||
70292cfeba6Schristos (asyncmeta_is_last_result(mc, bc, candidate) == 0)) {
70392cfeba6Schristos LDAP_STAILQ_REMOVE(&mc->mc_om_list, bc, bm_context_t, bc_next);
70492cfeba6Schristos bc->op->o_threadctx = ctx;
70592cfeba6Schristos bc->op->o_tid = ldap_pvt_thread_pool_tid( ctx );
70692cfeba6Schristos slap_sl_mem_setctx(ctx, bc->op->o_tmpmemctx);
70792cfeba6Schristos bc->rs.sr_err = bind_result->sr_err;
70892cfeba6Schristos bc->rs.sr_text = bind_result->sr_text;
70992cfeba6Schristos mc->pending_ops--;
71092cfeba6Schristos asyncmeta_send_ldap_result(bc, bc->op, &bc->rs);
71192cfeba6Schristos asyncmeta_clear_bm_context(bc);
71292cfeba6Schristos }
71392cfeba6Schristos }
71492cfeba6Schristos
71592cfeba6Schristos if ( dolock )
71692cfeba6Schristos ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex );
71792cfeba6Schristos
71892cfeba6Schristos return META_SEARCH_CANDIDATE;
71992cfeba6Schristos }
72092cfeba6Schristos
72192cfeba6Schristos static meta_search_candidate_t
asyncmeta_handle_bind_result(LDAPMessage * msg,a_metaconn_t * mc,int candidate,void * ctx)72292cfeba6Schristos asyncmeta_handle_bind_result(LDAPMessage *msg, a_metaconn_t *mc, int candidate, void *ctx)
72392cfeba6Schristos {
72492cfeba6Schristos meta_search_candidate_t retcode;
72592cfeba6Schristos SlapReply bind_result = {0};
72692cfeba6Schristos /* could modify the msc, safer to lock it */
72792cfeba6Schristos ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex );
72892cfeba6Schristos retcode = asyncmeta_dobind_result( mc, candidate, &bind_result, msg );
72992cfeba6Schristos ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex );
73092cfeba6Schristos if ( retcode == META_SEARCH_CANDIDATE ) {
73192cfeba6Schristos /* send the remaining pending ops */
73292cfeba6Schristos asyncmeta_send_all_pending_ops(mc, candidate, ctx, 1);
73392cfeba6Schristos } else {
73492cfeba6Schristos asyncmeta_return_bind_errors(mc, candidate, &bind_result, ctx, 1);
73592cfeba6Schristos }
73692cfeba6Schristos return retcode;
73792cfeba6Schristos }
73892cfeba6Schristos
73992cfeba6Schristos int
asyncmeta_handle_search_msg(LDAPMessage * res,a_metaconn_t * mc,bm_context_t * bc,int candidate)74092cfeba6Schristos asyncmeta_handle_search_msg(LDAPMessage *res, a_metaconn_t *mc, bm_context_t *bc, int candidate)
74192cfeba6Schristos {
74292cfeba6Schristos a_metainfo_t *mi;
74392cfeba6Schristos a_metatarget_t *mt;
74492cfeba6Schristos a_metasingleconn_t *msc;
74592cfeba6Schristos Operation *op = bc->op;
74692cfeba6Schristos SlapReply *rs;
74792cfeba6Schristos int i, rc = LDAP_SUCCESS, sres;
74892cfeba6Schristos SlapReply *candidates;
74992cfeba6Schristos char **references = NULL;
75092cfeba6Schristos LDAPControl **ctrls = NULL;
75192cfeba6Schristos a_dncookie dc;
75292cfeba6Schristos LDAPMessage *msg;
75392cfeba6Schristos ber_int_t id;
75492cfeba6Schristos
75592cfeba6Schristos rs = &bc->rs;
75692cfeba6Schristos mi = mc->mc_info;
75792cfeba6Schristos mt = mi->mi_targets[ candidate ];
75892cfeba6Schristos msc = &mc->mc_conns[ candidate ];
75992cfeba6Schristos dc.op = op;
76092cfeba6Schristos dc.target = mt;
76192cfeba6Schristos dc.to_from = MASSAGE_REP;
76292cfeba6Schristos id = ldap_msgid(res);
76392cfeba6Schristos
76492cfeba6Schristos
76592cfeba6Schristos candidates = bc->candidates;
76692cfeba6Schristos i = candidate;
76792cfeba6Schristos
76892cfeba6Schristos while (res && !META_BACK_CONN_INVALID(msc)) {
76992cfeba6Schristos for (msg = ldap_first_message(msc->msc_ldr, res); msg; msg = ldap_next_message(msc->msc_ldr, msg)) {
77092cfeba6Schristos switch(ldap_msgtype(msg)) {
77192cfeba6Schristos case LDAP_RES_SEARCH_ENTRY:
77292cfeba6Schristos Debug( LDAP_DEBUG_TRACE,
77392cfeba6Schristos "%s asyncmeta_handle_search_msg: msc %p entry\n",
77492cfeba6Schristos op->o_log_prefix, msc );
77592cfeba6Schristos if ( candidates[ i ].sr_type == REP_INTERMEDIATE ) {
77692cfeba6Schristos /* don't retry any more... */
77792cfeba6Schristos candidates[ i ].sr_type = REP_RESULT;
77892cfeba6Schristos }
77992cfeba6Schristos /* count entries returned by target */
78092cfeba6Schristos candidates[ i ].sr_nentries++;
78192cfeba6Schristos if (bc->c_peer_name.bv_val == op->o_conn->c_peer_name.bv_val && !op->o_abandon) {
78292cfeba6Schristos rs->sr_err = asyncmeta_send_entry( &bc->copy_op, rs, mc, i, msg );
78392cfeba6Schristos } else {
78492cfeba6Schristos goto err_cleanup;
78592cfeba6Schristos }
78692cfeba6Schristos switch ( rs->sr_err ) {
78792cfeba6Schristos case LDAP_SIZELIMIT_EXCEEDED:
78892cfeba6Schristos asyncmeta_send_ldap_result(bc, op, rs);
78992cfeba6Schristos rs->sr_err = LDAP_SUCCESS;
79092cfeba6Schristos goto err_cleanup;
79192cfeba6Schristos case LDAP_UNAVAILABLE:
79292cfeba6Schristos rs->sr_err = LDAP_OTHER;
79392cfeba6Schristos break;
79492cfeba6Schristos default:
79592cfeba6Schristos break;
79692cfeba6Schristos }
79792cfeba6Schristos bc->is_ok++;
79892cfeba6Schristos break;
79992cfeba6Schristos
80092cfeba6Schristos case LDAP_RES_SEARCH_REFERENCE:
80192cfeba6Schristos if ( META_BACK_TGT_NOREFS( mt ) ) {
80292cfeba6Schristos rs->sr_err = LDAP_OTHER;
80392cfeba6Schristos asyncmeta_send_ldap_result(bc, op, rs);
80492cfeba6Schristos goto err_cleanup;
80592cfeba6Schristos }
80692cfeba6Schristos if ( candidates[ i ].sr_type == REP_INTERMEDIATE ) {
80792cfeba6Schristos /* don't retry any more... */
80892cfeba6Schristos candidates[ i ].sr_type = REP_RESULT;
80992cfeba6Schristos }
81092cfeba6Schristos bc->is_ok++;
81192cfeba6Schristos rc = ldap_parse_reference( msc->msc_ldr, msg,
81292cfeba6Schristos &references, &rs->sr_ctrls, 0 );
81392cfeba6Schristos
81492cfeba6Schristos if ( rc != LDAP_SUCCESS || references == NULL ) {
81592cfeba6Schristos rs->sr_err = LDAP_OTHER;
81692cfeba6Schristos asyncmeta_send_ldap_result(bc, op, rs);
81792cfeba6Schristos goto err_cleanup;
81892cfeba6Schristos }
81992cfeba6Schristos
82092cfeba6Schristos /* FIXME: merge all and return at the end */
82192cfeba6Schristos
82292cfeba6Schristos {
82392cfeba6Schristos int cnt;
82492cfeba6Schristos for ( cnt = 0; references[ cnt ]; cnt++ )
82592cfeba6Schristos ;
82692cfeba6Schristos
82792cfeba6Schristos rs->sr_ref = op->o_tmpalloc( sizeof( struct berval ) * ( cnt + 1 ),
82892cfeba6Schristos op->o_tmpmemctx );
82992cfeba6Schristos
83092cfeba6Schristos for ( cnt = 0; references[ cnt ]; cnt++ ) {
83192cfeba6Schristos ber_str2bv_x( references[ cnt ], 0, 1, &rs->sr_ref[ cnt ],
83292cfeba6Schristos op->o_tmpmemctx );
83392cfeba6Schristos }
83492cfeba6Schristos BER_BVZERO( &rs->sr_ref[ cnt ] );
83592cfeba6Schristos }
83692cfeba6Schristos
83792cfeba6Schristos {
83892cfeba6Schristos dc.memctx = op->o_tmpmemctx;
83992cfeba6Schristos ( void )asyncmeta_referral_result_rewrite( &dc, rs->sr_ref );
84092cfeba6Schristos }
84192cfeba6Schristos
84292cfeba6Schristos if ( rs->sr_ref != NULL ) {
84392cfeba6Schristos if (!BER_BVISNULL( &rs->sr_ref[ 0 ] ) ) {
84492cfeba6Schristos /* ignore return value by now */
84592cfeba6Schristos ( void )send_search_reference( op, rs );
84692cfeba6Schristos }
84792cfeba6Schristos
84892cfeba6Schristos ber_bvarray_free_x( rs->sr_ref, op->o_tmpmemctx );
84992cfeba6Schristos rs->sr_ref = NULL;
85092cfeba6Schristos }
85192cfeba6Schristos
85292cfeba6Schristos /* cleanup */
85392cfeba6Schristos if ( references ) {
85492cfeba6Schristos ber_memvfree( (void **)references );
85592cfeba6Schristos }
85692cfeba6Schristos
85792cfeba6Schristos if ( rs->sr_ctrls ) {
85892cfeba6Schristos ldap_controls_free( rs->sr_ctrls );
85992cfeba6Schristos rs->sr_ctrls = NULL;
86092cfeba6Schristos }
86192cfeba6Schristos break;
86292cfeba6Schristos
86392cfeba6Schristos case LDAP_RES_INTERMEDIATE:
86492cfeba6Schristos if ( candidates[ i ].sr_type == REP_INTERMEDIATE ) {
86592cfeba6Schristos /* don't retry any more... */
86692cfeba6Schristos candidates[ i ].sr_type = REP_RESULT;
86792cfeba6Schristos }
86892cfeba6Schristos bc->is_ok++;
86992cfeba6Schristos
87092cfeba6Schristos /* FIXME: response controls
87192cfeba6Schristos * are passed without checks */
87292cfeba6Schristos rs->sr_err = ldap_parse_intermediate( msc->msc_ldr,
87392cfeba6Schristos msg,
87492cfeba6Schristos (char **)&rs->sr_rspoid,
87592cfeba6Schristos &rs->sr_rspdata,
87692cfeba6Schristos &rs->sr_ctrls,
87792cfeba6Schristos 0 );
87892cfeba6Schristos if ( rs->sr_err != LDAP_SUCCESS ) {
87992cfeba6Schristos candidates[ i ].sr_type = REP_RESULT;
88092cfeba6Schristos rs->sr_err = LDAP_OTHER;
88192cfeba6Schristos asyncmeta_send_ldap_result(bc, op, rs);
88292cfeba6Schristos goto err_cleanup;
88392cfeba6Schristos }
88492cfeba6Schristos
88592cfeba6Schristos slap_send_ldap_intermediate( op, rs );
88692cfeba6Schristos
88792cfeba6Schristos if ( rs->sr_rspoid != NULL ) {
88892cfeba6Schristos ber_memfree( (char *)rs->sr_rspoid );
88992cfeba6Schristos rs->sr_rspoid = NULL;
89092cfeba6Schristos }
89192cfeba6Schristos
89292cfeba6Schristos if ( rs->sr_rspdata != NULL ) {
89392cfeba6Schristos ber_bvfree( rs->sr_rspdata );
89492cfeba6Schristos rs->sr_rspdata = NULL;
89592cfeba6Schristos }
89692cfeba6Schristos
89792cfeba6Schristos if ( rs->sr_ctrls != NULL ) {
89892cfeba6Schristos ldap_controls_free( rs->sr_ctrls );
89992cfeba6Schristos rs->sr_ctrls = NULL;
90092cfeba6Schristos }
90192cfeba6Schristos break;
90292cfeba6Schristos
90392cfeba6Schristos case LDAP_RES_SEARCH_RESULT:
90492cfeba6Schristos if ( mi->mi_idle_timeout != 0 ) {
90592cfeba6Schristos asyncmeta_set_msc_time(msc);
90692cfeba6Schristos }
90792cfeba6Schristos Debug( LDAP_DEBUG_TRACE,
90892cfeba6Schristos "%s asyncmeta_handle_search_msg: msc %p result\n",
90992cfeba6Schristos op->o_log_prefix, msc );
91092cfeba6Schristos candidates[ i ].sr_type = REP_RESULT;
91192cfeba6Schristos candidates[ i ].sr_msgid = META_MSGID_IGNORE;
91292cfeba6Schristos /* NOTE: ignores response controls
91392cfeba6Schristos * (and intermediate response controls
91492cfeba6Schristos * as well, except for those with search
91592cfeba6Schristos * references); this may not be correct,
91692cfeba6Schristos * but if they're not ignored then
91792cfeba6Schristos * back-meta would need to merge them
91892cfeba6Schristos * consistently (think of pagedResults...)
91992cfeba6Schristos */
92092cfeba6Schristos /* FIXME: response controls? */
92192cfeba6Schristos rs->sr_err = ldap_parse_result( msc->msc_ldr,
92292cfeba6Schristos msg,
92392cfeba6Schristos &candidates[ i ].sr_err,
92492cfeba6Schristos (char **)&candidates[ i ].sr_matched,
92592cfeba6Schristos (char **)&candidates[ i ].sr_text,
92692cfeba6Schristos &references,
92792cfeba6Schristos &ctrls /* &candidates[ i ].sr_ctrls (unused) */ ,
92892cfeba6Schristos 0 );
92992cfeba6Schristos if ( rs->sr_err != LDAP_SUCCESS ) {
93092cfeba6Schristos candidates[ i ].sr_err = rs->sr_err;
93192cfeba6Schristos sres = slap_map_api2result( &candidates[ i ] );
93292cfeba6Schristos candidates[ i ].sr_type = REP_RESULT;
93392cfeba6Schristos goto finish;
93492cfeba6Schristos }
93592cfeba6Schristos
93692cfeba6Schristos rs->sr_err = candidates[ i ].sr_err;
93792cfeba6Schristos
93892cfeba6Schristos /* massage matchedDN if need be */
93992cfeba6Schristos if ( candidates[ i ].sr_matched != NULL ) {
94092cfeba6Schristos struct berval match, mmatch;
94192cfeba6Schristos
94292cfeba6Schristos ber_str2bv( candidates[ i ].sr_matched,
94392cfeba6Schristos 0, 0, &match );
94492cfeba6Schristos candidates[ i ].sr_matched = NULL;
94592cfeba6Schristos
94692cfeba6Schristos dc.memctx = NULL;
94792cfeba6Schristos asyncmeta_dn_massage( &dc, &match, &mmatch );
94892cfeba6Schristos if ( mmatch.bv_val == match.bv_val ) {
94992cfeba6Schristos candidates[ i ].sr_matched
95092cfeba6Schristos = ch_strdup( mmatch.bv_val );
95192cfeba6Schristos
95292cfeba6Schristos } else {
95392cfeba6Schristos candidates[ i ].sr_matched = mmatch.bv_val;
95492cfeba6Schristos }
95592cfeba6Schristos
95692cfeba6Schristos bc->candidate_match++;
95792cfeba6Schristos ldap_memfree( match.bv_val );
95892cfeba6Schristos }
95992cfeba6Schristos
96092cfeba6Schristos /* add references to array */
96192cfeba6Schristos /* RFC 4511: referrals can only appear
96292cfeba6Schristos * if result code is LDAP_REFERRAL */
96392cfeba6Schristos if ( references != NULL
96492cfeba6Schristos && references[ 0 ] != NULL
96592cfeba6Schristos && references[ 0 ][ 0 ] != '\0' )
96692cfeba6Schristos {
96792cfeba6Schristos if ( rs->sr_err != LDAP_REFERRAL ) {
96892cfeba6Schristos Debug( LDAP_DEBUG_ANY,
96992cfeba6Schristos "%s asncmeta_search_result[%d]: "
97092cfeba6Schristos "got referrals with err=%d\n",
97192cfeba6Schristos op->o_log_prefix,
97292cfeba6Schristos i, rs->sr_err );
97392cfeba6Schristos
97492cfeba6Schristos } else {
97592cfeba6Schristos BerVarray sr_ref;
97692cfeba6Schristos int cnt;
97792cfeba6Schristos
97892cfeba6Schristos for ( cnt = 0; references[ cnt ]; cnt++ )
97992cfeba6Schristos ;
98092cfeba6Schristos
98192cfeba6Schristos sr_ref = op->o_tmpalloc( sizeof( struct berval ) * ( cnt + 1 ),
98292cfeba6Schristos op->o_tmpmemctx );
98392cfeba6Schristos
98492cfeba6Schristos for ( cnt = 0; references[ cnt ]; cnt++ ) {
98592cfeba6Schristos ber_str2bv_x( references[ cnt ], 0, 1, &sr_ref[ cnt ],
98692cfeba6Schristos op->o_tmpmemctx );
98792cfeba6Schristos }
98892cfeba6Schristos BER_BVZERO( &sr_ref[ cnt ] );
98992cfeba6Schristos
99092cfeba6Schristos dc.memctx = op->o_tmpmemctx;
99192cfeba6Schristos ( void )asyncmeta_referral_result_rewrite( &dc, sr_ref );
99292cfeba6Schristos
99392cfeba6Schristos if ( rs->sr_v2ref == NULL ) {
99492cfeba6Schristos rs->sr_v2ref = sr_ref;
99592cfeba6Schristos
99692cfeba6Schristos } else {
99792cfeba6Schristos for ( cnt = 0; !BER_BVISNULL( &sr_ref[ cnt ] ); cnt++ ) {
99892cfeba6Schristos ber_bvarray_add_x( &rs->sr_v2ref, &sr_ref[ cnt ],
99992cfeba6Schristos op->o_tmpmemctx );
100092cfeba6Schristos }
100192cfeba6Schristos ber_memfree_x( sr_ref, op->o_tmpmemctx );
100292cfeba6Schristos }
100392cfeba6Schristos }
100492cfeba6Schristos
100592cfeba6Schristos } else if ( rs->sr_err == LDAP_REFERRAL ) {
100692cfeba6Schristos Debug( LDAP_DEBUG_TRACE,
100792cfeba6Schristos "%s asyncmeta_search_result[%d]: "
100892cfeba6Schristos "got err=%d with null "
100992cfeba6Schristos "or empty referrals\n",
101092cfeba6Schristos op->o_log_prefix,
101192cfeba6Schristos i, rs->sr_err );
101292cfeba6Schristos
101392cfeba6Schristos rs->sr_err = LDAP_NO_SUCH_OBJECT;
101492cfeba6Schristos }
101592cfeba6Schristos
101692cfeba6Schristos /* cleanup */
101792cfeba6Schristos ber_memvfree( (void **)references );
101892cfeba6Schristos
101992cfeba6Schristos sres = slap_map_api2result( rs );
102092cfeba6Schristos
102192cfeba6Schristos if ( candidates[ i ].sr_err == LDAP_SUCCESS ) {
102292cfeba6Schristos Debug( LDAP_DEBUG_TRACE, "%s asyncmeta_search_result[%d] "
102392cfeba6Schristos "match=\"%s\" err=%ld\n",
102492cfeba6Schristos op->o_log_prefix, i,
102592cfeba6Schristos candidates[ i ].sr_matched ? candidates[ i ].sr_matched : "",
102692cfeba6Schristos (long) candidates[ i ].sr_err );
102792cfeba6Schristos } else {
102892cfeba6Schristos Debug( LDAP_DEBUG_ANY, "%s asyncmeta_search_result[%d] "
102992cfeba6Schristos "match=\"%s\" err=%ld (%s)\n",
103092cfeba6Schristos op->o_log_prefix, i,
103192cfeba6Schristos candidates[ i ].sr_matched ? candidates[ i ].sr_matched : "",
103292cfeba6Schristos (long) candidates[ i ].sr_err, ldap_err2string( candidates[ i ].sr_err ) );
103392cfeba6Schristos }
103492cfeba6Schristos
103592cfeba6Schristos switch ( sres ) {
103692cfeba6Schristos case LDAP_NO_SUCH_OBJECT:
103792cfeba6Schristos /* is_ok is touched any time a valid
103892cfeba6Schristos * (even intermediate) result is
103992cfeba6Schristos * returned; as a consequence, if
104092cfeba6Schristos * a candidate returns noSuchObject
104192cfeba6Schristos * it is ignored and the candidate
104292cfeba6Schristos * is simply demoted. */
104392cfeba6Schristos if ( bc->is_ok ) {
104492cfeba6Schristos sres = LDAP_SUCCESS;
104592cfeba6Schristos }
104692cfeba6Schristos break;
104792cfeba6Schristos
104892cfeba6Schristos case LDAP_SUCCESS:
104992cfeba6Schristos if ( ctrls != NULL && ctrls[0] != NULL ) {
105092cfeba6Schristos #ifdef SLAPD_META_CLIENT_PR
105192cfeba6Schristos LDAPControl *pr_c;
105292cfeba6Schristos
105392cfeba6Schristos pr_c = ldap_control_find( LDAP_CONTROL_PAGEDRESULTS, ctrls, NULL );
105492cfeba6Schristos if ( pr_c != NULL ) {
105592cfeba6Schristos BerElementBuffer berbuf;
105692cfeba6Schristos BerElement *ber = (BerElement *)&berbuf;
105792cfeba6Schristos ber_tag_t tag;
105892cfeba6Schristos ber_int_t prsize;
105992cfeba6Schristos struct berval prcookie;
106092cfeba6Schristos
106192cfeba6Schristos /* unsolicited, do not accept */
106292cfeba6Schristos if ( mt->mt_ps == 0 ) {
106392cfeba6Schristos rs->sr_err = LDAP_OTHER;
106492cfeba6Schristos goto err_pr;
106592cfeba6Schristos }
106692cfeba6Schristos
106792cfeba6Schristos ber_init2( ber, &pr_c->ldctl_value, LBER_USE_DER );
106892cfeba6Schristos
106992cfeba6Schristos tag = ber_scanf( ber, "{im}", &prsize, &prcookie );
107092cfeba6Schristos if ( tag == LBER_ERROR ) {
107192cfeba6Schristos rs->sr_err = LDAP_OTHER;
107292cfeba6Schristos goto err_pr;
107392cfeba6Schristos }
107492cfeba6Schristos
107592cfeba6Schristos /* more pages? new search request */
107692cfeba6Schristos if ( !BER_BVISNULL( &prcookie ) && !BER_BVISEMPTY( &prcookie ) ) {
107792cfeba6Schristos if ( mt->mt_ps > 0 ) {
107892cfeba6Schristos /* ignore size if specified */
107992cfeba6Schristos prsize = 0;
108092cfeba6Schristos
108192cfeba6Schristos } else if ( prsize == 0 ) {
108292cfeba6Schristos /* guess the page size from the entries returned so far */
108392cfeba6Schristos prsize = candidates[ i ].sr_nentries;
108492cfeba6Schristos }
108592cfeba6Schristos
108692cfeba6Schristos candidates[ i ].sr_nentries = 0;
108792cfeba6Schristos candidates[ i ].sr_msgid = META_MSGID_IGNORE;
108892cfeba6Schristos candidates[ i ].sr_type = REP_INTERMEDIATE;
108992cfeba6Schristos
109092cfeba6Schristos assert( candidates[ i ].sr_matched == NULL );
109192cfeba6Schristos assert( candidates[ i ].sr_text == NULL );
109292cfeba6Schristos assert( candidates[ i ].sr_ref == NULL );
109392cfeba6Schristos
109492cfeba6Schristos switch ( asyncmeta_back_search_start( &bc->copy_op, rs, mc, bc, i, &prcookie, prsize, 1 ) )
109592cfeba6Schristos {
109692cfeba6Schristos case META_SEARCH_CANDIDATE:
109792cfeba6Schristos assert( candidates[ i ].sr_msgid >= 0 );
109892cfeba6Schristos ldap_controls_free( ctrls );
109992cfeba6Schristos // goto free_message;
110092cfeba6Schristos
110192cfeba6Schristos case META_SEARCH_ERR:
110292cfeba6Schristos case META_SEARCH_NEED_BIND:
110392cfeba6Schristos err_pr:;
110492cfeba6Schristos candidates[ i ].sr_err = rs->sr_err;
110592cfeba6Schristos candidates[ i ].sr_type = REP_RESULT;
110692cfeba6Schristos if ( META_BACK_ONERR_STOP( mi ) ) {
110792cfeba6Schristos asyncmeta_send_ldap_result(bc, op, rs);
110892cfeba6Schristos ldap_controls_free( ctrls );
110992cfeba6Schristos goto err_cleanup;
111092cfeba6Schristos }
111192cfeba6Schristos /* fallthru */
111292cfeba6Schristos
111392cfeba6Schristos case META_SEARCH_NOT_CANDIDATE:
111492cfeba6Schristos /* means that asyncmeta_back_search_start()
111592cfeba6Schristos * failed but onerr == continue */
111692cfeba6Schristos candidates[ i ].sr_msgid = META_MSGID_IGNORE;
111792cfeba6Schristos candidates[ i ].sr_type = REP_RESULT;
111892cfeba6Schristos break;
111992cfeba6Schristos
112092cfeba6Schristos default:
112192cfeba6Schristos /* impossible */
112292cfeba6Schristos assert( 0 );
112392cfeba6Schristos break;
112492cfeba6Schristos }
112592cfeba6Schristos break;
112692cfeba6Schristos }
112792cfeba6Schristos }
112892cfeba6Schristos #endif /* SLAPD_META_CLIENT_PR */
112992cfeba6Schristos
113092cfeba6Schristos ldap_controls_free( ctrls );
113192cfeba6Schristos }
113292cfeba6Schristos /* fallthru */
113392cfeba6Schristos
113492cfeba6Schristos case LDAP_REFERRAL:
113592cfeba6Schristos bc->is_ok++;
113692cfeba6Schristos break;
113792cfeba6Schristos
113892cfeba6Schristos case LDAP_SIZELIMIT_EXCEEDED:
113992cfeba6Schristos /* if a target returned sizelimitExceeded
114092cfeba6Schristos * and the entry count is equal to the
114192cfeba6Schristos * proxy's limit, the target would have
114292cfeba6Schristos * returned more, and the error must be
114392cfeba6Schristos * propagated to the client; otherwise,
114492cfeba6Schristos * the target enforced a limit lower
114592cfeba6Schristos * than what requested by the proxy;
114692cfeba6Schristos * ignore it */
114792cfeba6Schristos candidates[ i ].sr_err = rs->sr_err;
114892cfeba6Schristos if ( rs->sr_nentries == op->ors_slimit
114992cfeba6Schristos || META_BACK_ONERR_STOP( mi ) )
115092cfeba6Schristos {
115192cfeba6Schristos const char *save_text;
115292cfeba6Schristos got_err:
115392cfeba6Schristos save_text = rs->sr_text;
115492cfeba6Schristos rs->sr_text = candidates[ i ].sr_text;
115592cfeba6Schristos asyncmeta_send_ldap_result(bc, op, rs);
115692cfeba6Schristos if (candidates[ i ].sr_text != NULL) {
115792cfeba6Schristos ch_free( (char *)candidates[ i ].sr_text );
115892cfeba6Schristos candidates[ i ].sr_text = NULL;
115992cfeba6Schristos }
116092cfeba6Schristos rs->sr_text = save_text;
116192cfeba6Schristos ldap_controls_free( ctrls );
116292cfeba6Schristos goto err_cleanup;
116392cfeba6Schristos }
116492cfeba6Schristos break;
116592cfeba6Schristos
116692cfeba6Schristos default:
116792cfeba6Schristos candidates[ i ].sr_err = rs->sr_err;
116892cfeba6Schristos if ( META_BACK_ONERR_STOP( mi ) ) {
116992cfeba6Schristos goto got_err;
117092cfeba6Schristos }
117192cfeba6Schristos break;
117292cfeba6Schristos }
117392cfeba6Schristos /* if this is the last result we will ever receive, send it back */
117492cfeba6Schristos rc = rs->sr_err;
117592cfeba6Schristos if (asyncmeta_is_last_result(mc, bc, i) == 0) {
117692cfeba6Schristos Debug( LDAP_DEBUG_TRACE,
117792cfeba6Schristos "%s asyncmeta_handle_search_msg: msc %p last result\n",
117892cfeba6Schristos op->o_log_prefix, msc );
117992cfeba6Schristos asyncmeta_search_last_result(mc, bc, i, sres);
118092cfeba6Schristos err_cleanup:
118192cfeba6Schristos rc = rs->sr_err;
118292cfeba6Schristos ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex );
118392cfeba6Schristos asyncmeta_drop_bc( mc, bc);
118492cfeba6Schristos asyncmeta_clear_bm_context(bc);
118592cfeba6Schristos ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex );
118692cfeba6Schristos ldap_msgfree(res);
118792cfeba6Schristos return rc;
118892cfeba6Schristos }
118992cfeba6Schristos finish:
119092cfeba6Schristos break;
119192cfeba6Schristos
119292cfeba6Schristos default:
119392cfeba6Schristos continue;
119492cfeba6Schristos }
119592cfeba6Schristos }
119692cfeba6Schristos ldap_msgfree(res);
119792cfeba6Schristos res = NULL;
119892cfeba6Schristos if (candidates[ i ].sr_type != REP_RESULT) {
119992cfeba6Schristos struct timeval tv = {0};
120092cfeba6Schristos rc = ldap_result( msc->msc_ldr, id, LDAP_MSG_RECEIVED, &tv, &res );
120192cfeba6Schristos if (res != NULL) {
120292cfeba6Schristos msc->msc_result_time = slap_get_time();
120392cfeba6Schristos }
120492cfeba6Schristos }
120592cfeba6Schristos }
120692cfeba6Schristos ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex );
120792cfeba6Schristos bc->bc_active--;
120892cfeba6Schristos ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex );
120992cfeba6Schristos
121092cfeba6Schristos return rc;
121192cfeba6Schristos }
121292cfeba6Schristos
121392cfeba6Schristos /* handles the received result for add, modify, modrdn, compare and delete ops */
121492cfeba6Schristos
asyncmeta_handle_common_result(LDAPMessage * msg,a_metaconn_t * mc,bm_context_t * bc,int candidate)121592cfeba6Schristos int asyncmeta_handle_common_result(LDAPMessage *msg, a_metaconn_t *mc, bm_context_t *bc, int candidate)
121692cfeba6Schristos {
121792cfeba6Schristos a_metainfo_t *mi;
121892cfeba6Schristos a_metatarget_t *mt;
121992cfeba6Schristos a_metasingleconn_t *msc;
122092cfeba6Schristos const char *save_text = NULL,
122192cfeba6Schristos *save_matched = NULL;
122292cfeba6Schristos BerVarray save_ref = NULL;
122392cfeba6Schristos LDAPControl **save_ctrls = NULL;
122492cfeba6Schristos void *matched_ctx = NULL;
122592cfeba6Schristos
122692cfeba6Schristos char *matched = NULL;
122792cfeba6Schristos char *text = NULL;
122892cfeba6Schristos char **refs = NULL;
122992cfeba6Schristos LDAPControl **ctrls = NULL;
123092cfeba6Schristos Operation *op;
123192cfeba6Schristos SlapReply *rs;
123292cfeba6Schristos int rc;
123392cfeba6Schristos
123492cfeba6Schristos mi = mc->mc_info;
123592cfeba6Schristos mt = mi->mi_targets[ candidate ];
123692cfeba6Schristos msc = &mc->mc_conns[ candidate ];
123792cfeba6Schristos
123892cfeba6Schristos op = bc->op;
123992cfeba6Schristos rs = &bc->rs;
124092cfeba6Schristos save_text = rs->sr_text,
124192cfeba6Schristos save_matched = rs->sr_matched;
124292cfeba6Schristos save_ref = rs->sr_ref;
124392cfeba6Schristos save_ctrls = rs->sr_ctrls;
124492cfeba6Schristos rs->sr_text = NULL;
124592cfeba6Schristos rs->sr_matched = NULL;
124692cfeba6Schristos rs->sr_ref = NULL;
124792cfeba6Schristos rs->sr_ctrls = NULL;
124892cfeba6Schristos
124992cfeba6Schristos /* only touch when activity actually took place... */
125092cfeba6Schristos if ( mi->mi_idle_timeout != 0 ) {
125192cfeba6Schristos asyncmeta_set_msc_time(msc);
125292cfeba6Schristos }
125392cfeba6Schristos
125492cfeba6Schristos rc = ldap_parse_result( msc->msc_ldr, msg, &rs->sr_err,
125592cfeba6Schristos &matched, &text, &refs, &ctrls, 0 );
125692cfeba6Schristos
125792cfeba6Schristos if ( rc == LDAP_SUCCESS ) {
125892cfeba6Schristos rs->sr_text = text;
125992cfeba6Schristos } else {
126092cfeba6Schristos rs->sr_err = rc;
126192cfeba6Schristos }
126292cfeba6Schristos rs->sr_err = slap_map_api2result( rs );
126392cfeba6Schristos
126492cfeba6Schristos /* RFC 4511: referrals can only appear
126592cfeba6Schristos * if result code is LDAP_REFERRAL */
126692cfeba6Schristos if ( refs != NULL
126792cfeba6Schristos && refs[ 0 ] != NULL
126892cfeba6Schristos && refs[ 0 ][ 0 ] != '\0' )
126992cfeba6Schristos {
127092cfeba6Schristos if ( rs->sr_err != LDAP_REFERRAL ) {
127192cfeba6Schristos Debug( LDAP_DEBUG_ANY,
127292cfeba6Schristos "%s asyncmeta_handle_common_result[%d]: "
127392cfeba6Schristos "got referrals with err=%d\n",
127492cfeba6Schristos op->o_log_prefix,
127592cfeba6Schristos candidate, rs->sr_err );
127692cfeba6Schristos
127792cfeba6Schristos } else {
127892cfeba6Schristos int i;
127992cfeba6Schristos
128092cfeba6Schristos for ( i = 0; refs[ i ] != NULL; i++ )
128192cfeba6Schristos /* count */ ;
128292cfeba6Schristos rs->sr_ref = op->o_tmpalloc( sizeof( struct berval ) * ( i + 1 ),
128392cfeba6Schristos op->o_tmpmemctx );
128492cfeba6Schristos for ( i = 0; refs[ i ] != NULL; i++ ) {
128592cfeba6Schristos ber_str2bv( refs[ i ], 0, 0, &rs->sr_ref[ i ] );
128692cfeba6Schristos }
128792cfeba6Schristos BER_BVZERO( &rs->sr_ref[ i ] );
128892cfeba6Schristos }
128992cfeba6Schristos
129092cfeba6Schristos } else if ( rs->sr_err == LDAP_REFERRAL ) {
129192cfeba6Schristos Debug( LDAP_DEBUG_ANY,
129292cfeba6Schristos "%s asyncmeta_handle_common_result[%d]: "
129392cfeba6Schristos "got err=%d with null "
129492cfeba6Schristos "or empty referrals\n",
129592cfeba6Schristos op->o_log_prefix,
129692cfeba6Schristos candidate, rs->sr_err );
129792cfeba6Schristos
129892cfeba6Schristos rs->sr_err = LDAP_NO_SUCH_OBJECT;
129992cfeba6Schristos }
130092cfeba6Schristos
130192cfeba6Schristos if ( ctrls != NULL ) {
130292cfeba6Schristos rs->sr_ctrls = ctrls;
130392cfeba6Schristos }
130492cfeba6Schristos
130592cfeba6Schristos /* if the error in the reply structure is not
130692cfeba6Schristos * LDAP_SUCCESS, try to map it from client
130792cfeba6Schristos * to server error */
130892cfeba6Schristos if ( !LDAP_ERR_OK( rs->sr_err ) ) {
130992cfeba6Schristos rs->sr_err = slap_map_api2result( rs );
131092cfeba6Schristos
131192cfeba6Schristos /* internal ops ( op->o_conn == NULL )
131292cfeba6Schristos * must not reply to client */
131392cfeba6Schristos if ( op->o_conn && !op->o_do_not_cache && matched ) {
131492cfeba6Schristos
131592cfeba6Schristos /* record the (massaged) matched
131692cfeba6Schristos * DN into the reply structure */
131792cfeba6Schristos rs->sr_matched = matched;
131892cfeba6Schristos }
131992cfeba6Schristos }
132092cfeba6Schristos
132192cfeba6Schristos if ( META_BACK_TGT_QUARANTINE( mt ) ) {
132292cfeba6Schristos asyncmeta_quarantine( op, mi, rs, candidate );
132392cfeba6Schristos }
132492cfeba6Schristos
132592cfeba6Schristos if ( matched != NULL ) {
132692cfeba6Schristos struct berval dn, pdn;
132792cfeba6Schristos
132892cfeba6Schristos ber_str2bv( matched, 0, 0, &dn );
132992cfeba6Schristos if ( dnPretty( NULL, &dn, &pdn, op->o_tmpmemctx ) == LDAP_SUCCESS ) {
133092cfeba6Schristos ldap_memfree( matched );
133192cfeba6Schristos matched_ctx = op->o_tmpmemctx;
133292cfeba6Schristos matched = pdn.bv_val;
133392cfeba6Schristos }
133492cfeba6Schristos rs->sr_matched = matched;
133592cfeba6Schristos }
133692cfeba6Schristos
133792cfeba6Schristos if ( rs->sr_err == LDAP_UNAVAILABLE || rs->sr_err == LDAP_SERVER_DOWN ) {
133892cfeba6Schristos if ( rs->sr_text == NULL ) {
133992cfeba6Schristos rs->sr_text = "Target is unavailable";
134092cfeba6Schristos }
134192cfeba6Schristos }
134292cfeba6Schristos
134392cfeba6Schristos ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex );
134492cfeba6Schristos asyncmeta_drop_bc( mc, bc);
134592cfeba6Schristos ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex );
134692cfeba6Schristos
134792cfeba6Schristos if ( op->o_conn ) {
134892cfeba6Schristos asyncmeta_send_ldap_result(bc, op, rs);
134992cfeba6Schristos }
135092cfeba6Schristos
135192cfeba6Schristos if ( matched ) {
135292cfeba6Schristos op->o_tmpfree( (char *)rs->sr_matched, matched_ctx );
135392cfeba6Schristos }
135492cfeba6Schristos if ( text ) {
135592cfeba6Schristos ldap_memfree( text );
135692cfeba6Schristos }
135792cfeba6Schristos if ( rs->sr_ref ) {
135892cfeba6Schristos op->o_tmpfree( rs->sr_ref, op->o_tmpmemctx );
135992cfeba6Schristos rs->sr_ref = NULL;
136092cfeba6Schristos }
136192cfeba6Schristos if ( refs ) {
136292cfeba6Schristos ber_memvfree( (void **)refs );
136392cfeba6Schristos }
136492cfeba6Schristos if ( ctrls ) {
136592cfeba6Schristos assert( rs->sr_ctrls != NULL );
136692cfeba6Schristos ldap_controls_free( ctrls );
136792cfeba6Schristos }
136892cfeba6Schristos
136992cfeba6Schristos rs->sr_text = save_text;
137092cfeba6Schristos rs->sr_matched = save_matched;
137192cfeba6Schristos rs->sr_ref = save_ref;
137292cfeba6Schristos rs->sr_ctrls = save_ctrls;
137392cfeba6Schristos rc = (LDAP_ERR_OK( rs->sr_err ) ? LDAP_SUCCESS : rs->sr_err);
137492cfeba6Schristos ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex );
137592cfeba6Schristos asyncmeta_clear_bm_context(bc);
137692cfeba6Schristos ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex );
137792cfeba6Schristos return rc;
137892cfeba6Schristos }
137992cfeba6Schristos
138092cfeba6Schristos /* This takes care to clean out the outbound queue in case we have a read error
138192cfeba6Schristos * sending back responses to the client */
138292cfeba6Schristos int
asyncmeta_op_read_error(a_metaconn_t * mc,int candidate,int error,void * ctx)138392cfeba6Schristos asyncmeta_op_read_error(a_metaconn_t *mc, int candidate, int error, void* ctx)
138492cfeba6Schristos {
138592cfeba6Schristos bm_context_t *bc, *onext;
138692cfeba6Schristos int cleanup;
138792cfeba6Schristos Operation *op;
138892cfeba6Schristos SlapReply *rs;
138992cfeba6Schristos SlapReply *candidates;
139092cfeba6Schristos
139192cfeba6Schristos /* no outstanding ops, nothing to do but log */
139292cfeba6Schristos Debug( LDAP_DEBUG_TRACE,
139392cfeba6Schristos "asyncmeta_op_read_error: ldr=%p, err=%d\n",
139492cfeba6Schristos mc->mc_conns[candidate].msc_ldr, error );
139592cfeba6Schristos
139692cfeba6Schristos ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex );
139792cfeba6Schristos /*someone may be trying to write */
139892cfeba6Schristos if (mc->mc_conns[candidate].msc_active <= 1) {
139992cfeba6Schristos asyncmeta_clear_one_msc(NULL, mc, candidate, 0, __FUNCTION__);
140092cfeba6Schristos } else {
140192cfeba6Schristos META_BACK_CONN_INVALID_SET(&mc->mc_conns[candidate]);
140292cfeba6Schristos }
140392cfeba6Schristos
140492cfeba6Schristos if (mc->pending_ops <= 0) {
140592cfeba6Schristos ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex );
140692cfeba6Schristos return LDAP_SUCCESS;
140792cfeba6Schristos }
140892cfeba6Schristos
140992cfeba6Schristos for (bc = LDAP_STAILQ_FIRST(&mc->mc_om_list); bc; bc = onext) {
141092cfeba6Schristos onext = LDAP_STAILQ_NEXT(bc, bc_next);
141192cfeba6Schristos cleanup = 0;
141292cfeba6Schristos candidates = bc->candidates;
141392cfeba6Schristos /* was this op affected? */
141492cfeba6Schristos if ( !META_IS_CANDIDATE( &candidates[ candidate ] ) )
141592cfeba6Schristos continue;
141692cfeba6Schristos
141792cfeba6Schristos if (bc->op->o_abandon) {
141892cfeba6Schristos bc->bc_invalid = 1;
141992cfeba6Schristos continue;
142092cfeba6Schristos }
142192cfeba6Schristos
142292cfeba6Schristos if (bc->bc_active > 0) {
142392cfeba6Schristos bc->bc_invalid = 1;
142492cfeba6Schristos continue;
142592cfeba6Schristos }
142692cfeba6Schristos
142792cfeba6Schristos bc->op->o_threadctx = ctx;
142892cfeba6Schristos bc->op->o_tid = ldap_pvt_thread_pool_tid( ctx );
142992cfeba6Schristos slap_sl_mem_setctx(ctx, bc->op->o_tmpmemctx);
143092cfeba6Schristos
143192cfeba6Schristos op = bc->op;
143292cfeba6Schristos rs = &bc->rs;
143392cfeba6Schristos switch (op->o_tag) {
143492cfeba6Schristos case LDAP_REQ_ADD:
143592cfeba6Schristos case LDAP_REQ_MODIFY:
143692cfeba6Schristos case LDAP_REQ_MODRDN:
143792cfeba6Schristos case LDAP_REQ_COMPARE:
143892cfeba6Schristos case LDAP_REQ_DELETE:
143992cfeba6Schristos rs->sr_err = LDAP_UNAVAILABLE;
144092cfeba6Schristos rs->sr_text = "Read error on connection to target";
144192cfeba6Schristos asyncmeta_send_ldap_result( bc, op, rs );
144292cfeba6Schristos cleanup = 1;
144392cfeba6Schristos break;
144492cfeba6Schristos case LDAP_REQ_SEARCH:
144592cfeba6Schristos {
144692cfeba6Schristos a_metainfo_t *mi = mc->mc_info;
144792cfeba6Schristos rs->sr_err = LDAP_UNAVAILABLE;
144892cfeba6Schristos rs->sr_text = "Read error on connection to target";
144992cfeba6Schristos candidates[ candidate ].sr_msgid = META_MSGID_IGNORE;
145092cfeba6Schristos candidates[ candidate ].sr_type = REP_RESULT;
145192cfeba6Schristos if ( (META_BACK_ONERR_STOP( mi ) ||
145292cfeba6Schristos asyncmeta_is_last_result(mc, bc, candidate)) && op->o_conn) {
145392cfeba6Schristos asyncmeta_send_ldap_result( bc, op, rs );
145492cfeba6Schristos cleanup = 1;
145592cfeba6Schristos }
145692cfeba6Schristos }
145792cfeba6Schristos break;
145892cfeba6Schristos default:
145992cfeba6Schristos break;
146092cfeba6Schristos }
146192cfeba6Schristos
146292cfeba6Schristos if (cleanup) {
146392cfeba6Schristos int j;
146492cfeba6Schristos a_metainfo_t *mi = mc->mc_info;
146592cfeba6Schristos for (j=0; j<mi->mi_ntargets; j++) {
146692cfeba6Schristos if (j != candidate && bc->candidates[j].sr_msgid >= 0
146792cfeba6Schristos && mc->mc_conns[j].msc_ld != NULL) {
146892cfeba6Schristos asyncmeta_back_cancel( mc, op,
146992cfeba6Schristos bc->candidates[ j ].sr_msgid, j );
147092cfeba6Schristos }
147192cfeba6Schristos }
147292cfeba6Schristos LDAP_STAILQ_REMOVE(&mc->mc_om_list, bc, bm_context_t, bc_next);
147392cfeba6Schristos mc->pending_ops--;
147492cfeba6Schristos asyncmeta_clear_bm_context(bc);
147592cfeba6Schristos }
147692cfeba6Schristos }
147792cfeba6Schristos ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex );
147892cfeba6Schristos return LDAP_SUCCESS;
147992cfeba6Schristos }
148092cfeba6Schristos
148192cfeba6Schristos void *
asyncmeta_op_handle_result(void * ctx,void * arg)148292cfeba6Schristos asyncmeta_op_handle_result(void *ctx, void *arg)
148392cfeba6Schristos {
148492cfeba6Schristos a_metaconn_t *mc = arg;
148592cfeba6Schristos int i, j, rc, ntargets;
148692cfeba6Schristos struct timeval tv = {0};
148792cfeba6Schristos LDAPMessage *msg;
148892cfeba6Schristos a_metasingleconn_t *msc;
148992cfeba6Schristos bm_context_t *bc;
149092cfeba6Schristos void *oldctx;
149192cfeba6Schristos
149292cfeba6Schristos ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex );
149392cfeba6Schristos rc = ++mc->mc_active;
149492cfeba6Schristos ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex );
149592cfeba6Schristos if (rc > 1)
149692cfeba6Schristos return NULL;
149792cfeba6Schristos
149892cfeba6Schristos ntargets = mc->mc_info->mi_ntargets;
149992cfeba6Schristos i = ntargets;
150092cfeba6Schristos oldctx = slap_sl_mem_create(SLAP_SLAB_SIZE, SLAP_SLAB_STACK, ctx, 0); /* get existing memctx */
150192cfeba6Schristos
150292cfeba6Schristos again:
150392cfeba6Schristos for (j=0; j<ntargets; j++) {
150492cfeba6Schristos i++;
150592cfeba6Schristos if (i >= ntargets) i = 0;
150692cfeba6Schristos msc = &mc->mc_conns[i];
150792cfeba6Schristos ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex );
150892cfeba6Schristos if (!mc->mc_conns[i].msc_ldr ||
150992cfeba6Schristos META_BACK_CONN_CREATING( &mc->mc_conns[i] ) ||
151092cfeba6Schristos META_BACK_CONN_INVALID(&mc->mc_conns[i])) {
151192cfeba6Schristos ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex );
151292cfeba6Schristos continue;
151392cfeba6Schristos }
151492cfeba6Schristos
151592cfeba6Schristos msc->msc_active++;
151692cfeba6Schristos ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex );
151792cfeba6Schristos
151892cfeba6Schristos rc = ldap_result( mc->mc_conns[i].msc_ldr, LDAP_RES_ANY, LDAP_MSG_RECEIVED, &tv, &msg );
151992cfeba6Schristos if (rc < 1) {
152092cfeba6Schristos if (rc < 0) {
152192cfeba6Schristos ldap_get_option( mc->mc_conns[i].msc_ldr, LDAP_OPT_ERROR_NUMBER, &rc);
152292cfeba6Schristos META_BACK_CONN_INVALID_SET(&mc->mc_conns[i]);
152392cfeba6Schristos asyncmeta_op_read_error(mc, i, rc, ctx);
152492cfeba6Schristos }
152592cfeba6Schristos ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex );
152692cfeba6Schristos msc->msc_active--;
152792cfeba6Schristos ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex );
152892cfeba6Schristos continue;
152992cfeba6Schristos }
153092cfeba6Schristos rc = ldap_msgtype( msg );
153192cfeba6Schristos if (rc == LDAP_RES_BIND) {
153292cfeba6Schristos if ( LogTest( asyncmeta_debug ) ) {
153392cfeba6Schristos char time_buf[ SLAP_TEXT_BUFLEN ];
153492cfeba6Schristos asyncmeta_get_timestamp(time_buf);
153592cfeba6Schristos Debug( asyncmeta_debug, "[%s] asyncmeta_op_handle_result received bind msgid=%d msc: %p\n",
153692cfeba6Schristos time_buf, ldap_msgid(msg), msc );
153792cfeba6Schristos }
153892cfeba6Schristos asyncmeta_handle_bind_result(msg, mc, i, ctx);
153992cfeba6Schristos mc->mc_info->mi_targets[i]->mt_timeout_ops = 0;
154092cfeba6Schristos ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex );
154192cfeba6Schristos msc->msc_result_time = slap_get_time();
154292cfeba6Schristos msc->msc_active--;
154392cfeba6Schristos ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex );
154492cfeba6Schristos if (msg)
154592cfeba6Schristos ldap_msgfree(msg);
154692cfeba6Schristos
154792cfeba6Schristos continue;
154892cfeba6Schristos }
154992cfeba6Schristos retry_bc:
155092cfeba6Schristos ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex );
155192cfeba6Schristos bc = asyncmeta_find_message(ldap_msgid(msg), mc, i);
155292cfeba6Schristos /* The sender might not be yet done with the context. On error it might also remove it
155392cfeba6Schristos * so it's best to try and find it again after a wait */
155492cfeba6Schristos if (bc && bc->bc_active > 0) {
155592cfeba6Schristos ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex );
155692cfeba6Schristos ldap_pvt_thread_yield();
155792cfeba6Schristos goto retry_bc;
155892cfeba6Schristos }
155992cfeba6Schristos if (bc) {
156092cfeba6Schristos bc->bc_active++;
156192cfeba6Schristos }
156292cfeba6Schristos
156392cfeba6Schristos msc->msc_result_time = slap_get_time();
156492cfeba6Schristos msc->msc_active--;
156592cfeba6Schristos ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex );
156692cfeba6Schristos if (!bc) {
156792cfeba6Schristos Debug( asyncmeta_debug,
156892cfeba6Schristos "asyncmeta_op_handle_result: Unable to find bc for msguid %d, msc: %p\n", ldap_msgid(msg), msc );
156992cfeba6Schristos ldap_msgfree(msg);
157092cfeba6Schristos continue;
157192cfeba6Schristos }
157292cfeba6Schristos
157392cfeba6Schristos /* set our memctx */
157492cfeba6Schristos bc->op->o_threadctx = ctx;
157592cfeba6Schristos bc->op->o_tid = ldap_pvt_thread_pool_tid( ctx );
157692cfeba6Schristos slap_sl_mem_setctx(ctx, bc->op->o_tmpmemctx);
157792cfeba6Schristos if (bc->op->o_abandon) {
157892cfeba6Schristos ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex );
157992cfeba6Schristos asyncmeta_drop_bc( mc, bc);
158092cfeba6Schristos if ( bc->op->o_tag == LDAP_REQ_SEARCH ) {
158192cfeba6Schristos int j;
158292cfeba6Schristos for (j=0; j<ntargets; j++) {
158392cfeba6Schristos if (bc->candidates[j].sr_msgid >= 0) {
158492cfeba6Schristos a_metasingleconn_t *tmp_msc = &mc->mc_conns[j];
158592cfeba6Schristos tmp_msc->msc_active++;
158692cfeba6Schristos asyncmeta_back_cancel( mc, bc->op,
158792cfeba6Schristos bc->candidates[ j ].sr_msgid, j );
158892cfeba6Schristos tmp_msc->msc_active--;
158992cfeba6Schristos }
159092cfeba6Schristos }
159192cfeba6Schristos }
159292cfeba6Schristos asyncmeta_clear_bm_context(bc);
159392cfeba6Schristos ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex );
159492cfeba6Schristos if (msg)
159592cfeba6Schristos ldap_msgfree(msg);
159692cfeba6Schristos continue;
159792cfeba6Schristos }
159892cfeba6Schristos
159992cfeba6Schristos switch (rc) {
160092cfeba6Schristos case LDAP_RES_SEARCH_ENTRY:
160192cfeba6Schristos case LDAP_RES_SEARCH_REFERENCE:
160292cfeba6Schristos case LDAP_RES_SEARCH_RESULT:
160392cfeba6Schristos case LDAP_RES_INTERMEDIATE:
160492cfeba6Schristos asyncmeta_handle_search_msg(msg, mc, bc, i);
160592cfeba6Schristos mc->mc_info->mi_targets[i]->mt_timeout_ops = 0;
160692cfeba6Schristos msg = NULL;
160792cfeba6Schristos break;
160892cfeba6Schristos case LDAP_RES_ADD:
160992cfeba6Schristos case LDAP_RES_DELETE:
161092cfeba6Schristos case LDAP_RES_MODDN:
161192cfeba6Schristos case LDAP_RES_COMPARE:
161292cfeba6Schristos case LDAP_RES_MODIFY:
161392cfeba6Schristos rc = asyncmeta_handle_common_result(msg, mc, bc, i);
161492cfeba6Schristos mc->mc_info->mi_targets[i]->mt_timeout_ops = 0;
161592cfeba6Schristos break;
161692cfeba6Schristos default:
161792cfeba6Schristos {
161892cfeba6Schristos Debug( asyncmeta_debug,
161992cfeba6Schristos "asyncmeta_op_handle_result: "
162092cfeba6Schristos "unrecognized response message tag=%d\n",
162192cfeba6Schristos rc );
162292cfeba6Schristos
162392cfeba6Schristos }
162492cfeba6Schristos }
162592cfeba6Schristos if (msg)
162692cfeba6Schristos ldap_msgfree(msg);
162792cfeba6Schristos }
162892cfeba6Schristos
162992cfeba6Schristos ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex );
163092cfeba6Schristos rc = --mc->mc_active;
163192cfeba6Schristos if (rc) {
163292cfeba6Schristos i++;
163392cfeba6Schristos ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex );
163492cfeba6Schristos goto again;
163592cfeba6Schristos }
163692cfeba6Schristos slap_sl_mem_setctx(ctx, oldctx);
163792cfeba6Schristos if (mc->mc_conns) {
163892cfeba6Schristos for (i=0; i<ntargets; i++) {
163992cfeba6Schristos if (!slapd_shutdown && !META_BACK_CONN_INVALID(msc)
164092cfeba6Schristos && mc->mc_conns[i].msc_ldr && mc->mc_conns[i].conn) {
164192cfeba6Schristos connection_client_enable(mc->mc_conns[i].conn);
164292cfeba6Schristos }
164392cfeba6Schristos }
164492cfeba6Schristos }
164592cfeba6Schristos ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex );
164692cfeba6Schristos return NULL;
164792cfeba6Schristos }
164892cfeba6Schristos
asyncmeta_set_msc_time(a_metasingleconn_t * msc)164992cfeba6Schristos void asyncmeta_set_msc_time(a_metasingleconn_t *msc)
165092cfeba6Schristos {
165192cfeba6Schristos msc->msc_time = slap_get_time();
165292cfeba6Schristos }
165392cfeba6Schristos
asyncmeta_timeout_loop(void * ctx,void * arg)165492cfeba6Schristos void* asyncmeta_timeout_loop(void *ctx, void *arg)
165592cfeba6Schristos {
165692cfeba6Schristos struct re_s* rtask = arg;
165792cfeba6Schristos a_metainfo_t *mi = rtask->arg;
165892cfeba6Schristos bm_context_t *bc, *onext;
165992cfeba6Schristos time_t current_time = slap_get_time();
166092cfeba6Schristos int i, j;
166192cfeba6Schristos LDAP_STAILQ_HEAD(BCList, bm_context_t) timeout_list;
166292cfeba6Schristos LDAP_STAILQ_INIT( &timeout_list );
166392cfeba6Schristos
166492cfeba6Schristos Debug( asyncmeta_debug, "asyncmeta_timeout_loop[%p] start at [%ld] \n", rtask, current_time );
166592cfeba6Schristos void *oldctx = slap_sl_mem_create(SLAP_SLAB_SIZE, SLAP_SLAB_STACK, ctx, 0);
166692cfeba6Schristos for (i=0; i<mi->mi_num_conns; i++) {
166792cfeba6Schristos a_metaconn_t * mc= &mi->mi_conns[i];
166892cfeba6Schristos ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex );
166992cfeba6Schristos for (bc = LDAP_STAILQ_FIRST(&mc->mc_om_list); bc; bc = onext) {
167092cfeba6Schristos onext = LDAP_STAILQ_NEXT(bc, bc_next);
167192cfeba6Schristos if (bc->bc_active > 0) {
167292cfeba6Schristos continue;
167392cfeba6Schristos }
167492cfeba6Schristos
167592cfeba6Schristos if (bc->op->o_abandon ) {
167692cfeba6Schristos /* set our memctx */
167792cfeba6Schristos bc->op->o_threadctx = ctx;
167892cfeba6Schristos bc->op->o_tid = ldap_pvt_thread_pool_tid( ctx );
167992cfeba6Schristos slap_sl_mem_setctx(ctx, bc->op->o_tmpmemctx);
168092cfeba6Schristos Operation *op = bc->op;
168192cfeba6Schristos
168292cfeba6Schristos LDAP_STAILQ_REMOVE(&mc->mc_om_list, bc, bm_context_t, bc_next);
168392cfeba6Schristos mc->pending_ops--;
168492cfeba6Schristos for (j=0; j<mi->mi_ntargets; j++) {
168592cfeba6Schristos if (bc->candidates[j].sr_msgid >= 0) {
168692cfeba6Schristos a_metasingleconn_t *msc = &mc->mc_conns[j];
168792cfeba6Schristos if ( op->o_tag == LDAP_REQ_SEARCH ) {
168892cfeba6Schristos msc->msc_active++;
168992cfeba6Schristos asyncmeta_back_cancel( mc, op,
169092cfeba6Schristos bc->candidates[ j ].sr_msgid, j );
169192cfeba6Schristos msc->msc_active--;
169292cfeba6Schristos }
169392cfeba6Schristos }
169492cfeba6Schristos }
169592cfeba6Schristos asyncmeta_clear_bm_context(bc);
169692cfeba6Schristos continue;
169792cfeba6Schristos }
169892cfeba6Schristos if (bc->bc_invalid) {
169992cfeba6Schristos LDAP_STAILQ_REMOVE(&mc->mc_om_list, bc, bm_context_t, bc_next);
170092cfeba6Schristos mc->pending_ops--;
170192cfeba6Schristos LDAP_STAILQ_INSERT_TAIL( &timeout_list, bc, bc_next);
170292cfeba6Schristos continue;
170392cfeba6Schristos }
170492cfeba6Schristos
170592cfeba6Schristos if (bc->timeout && bc->stoptime < current_time) {
170692cfeba6Schristos Operation *op = bc->op;
170792cfeba6Schristos LDAP_STAILQ_REMOVE(&mc->mc_om_list, bc, bm_context_t, bc_next);
170892cfeba6Schristos mc->pending_ops--;
170992cfeba6Schristos LDAP_STAILQ_INSERT_TAIL( &timeout_list, bc, bc_next);
171092cfeba6Schristos for (j=0; j<mi->mi_ntargets; j++) {
171192cfeba6Schristos if (bc->candidates[j].sr_msgid >= 0) {
171292cfeba6Schristos a_metasingleconn_t *msc = &mc->mc_conns[j];
171392cfeba6Schristos asyncmeta_set_msc_time(msc);
171492cfeba6Schristos if ( op->o_tag == LDAP_REQ_SEARCH ) {
171592cfeba6Schristos msc->msc_active++;
171692cfeba6Schristos asyncmeta_back_cancel( mc, op,
171792cfeba6Schristos bc->candidates[ j ].sr_msgid, j );
171892cfeba6Schristos msc->msc_active--;
171992cfeba6Schristos }
172092cfeba6Schristos }
172192cfeba6Schristos }
172292cfeba6Schristos }
172392cfeba6Schristos }
172492cfeba6Schristos ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex );
172592cfeba6Schristos
172692cfeba6Schristos for (bc = LDAP_STAILQ_FIRST(&timeout_list); bc; bc = onext) {
172792cfeba6Schristos Operation *op = bc->op;
172892cfeba6Schristos SlapReply *rs = &bc->rs;
172992cfeba6Schristos int timeout_err;
173092cfeba6Schristos const char *timeout_text;
173192cfeba6Schristos
173292cfeba6Schristos onext = LDAP_STAILQ_NEXT(bc, bc_next);
173392cfeba6Schristos LDAP_STAILQ_REMOVE(&timeout_list, bc, bm_context_t, bc_next);
173492cfeba6Schristos /* set our memctx */
173592cfeba6Schristos bc->op->o_threadctx = ctx;
173692cfeba6Schristos bc->op->o_tid = ldap_pvt_thread_pool_tid( ctx );
173792cfeba6Schristos slap_sl_mem_setctx(ctx, bc->op->o_tmpmemctx);
173892cfeba6Schristos
173992cfeba6Schristos if (bc->searchtime) {
174092cfeba6Schristos timeout_err = LDAP_TIMELIMIT_EXCEEDED;
174192cfeba6Schristos } else {
174292cfeba6Schristos timeout_err = op->o_protocol >= LDAP_VERSION3 ?
174392cfeba6Schristos LDAP_ADMINLIMIT_EXCEEDED : LDAP_OTHER;
174492cfeba6Schristos }
174592cfeba6Schristos
174692cfeba6Schristos if ( bc->bc_invalid ) {
174792cfeba6Schristos timeout_text = "Operation is invalid - target connection has been reset";
174892cfeba6Schristos } else {
174992cfeba6Schristos a_metasingleconn_t *log_msc = &mc->mc_conns[0];
175092cfeba6Schristos Debug( asyncmeta_debug,
175192cfeba6Schristos "asyncmeta_timeout_loop:Timeout op %s loop[%p], "
175292cfeba6Schristos "current_time:%ld, op->o_time:%ld msc: %p, "
175392cfeba6Schristos "msc->msc_binding_time: %x, msc->msc_flags:%x \n",
175492cfeba6Schristos bc->op->o_log_prefix, rtask, current_time, bc->op->o_time,
175592cfeba6Schristos log_msc, (unsigned int)log_msc->msc_binding_time, log_msc->msc_mscflags );
175692cfeba6Schristos
175792cfeba6Schristos if (bc->searchtime) {
175892cfeba6Schristos timeout_text = NULL;
175992cfeba6Schristos } else {
176092cfeba6Schristos timeout_text = "Operation timed out";
176192cfeba6Schristos }
176292cfeba6Schristos
176392cfeba6Schristos for (j=0; j<mi->mi_ntargets; j++) {
176492cfeba6Schristos if (bc->candidates[j].sr_msgid >= 0) {
176592cfeba6Schristos a_metatarget_t *mt = mi->mi_targets[j];
176692cfeba6Schristos if (!META_BACK_TGT_QUARANTINE( mt ) ||
176792cfeba6Schristos bc->candidates[j].sr_type == REP_RESULT) {
176892cfeba6Schristos continue;
176992cfeba6Schristos }
177092cfeba6Schristos
177192cfeba6Schristos if (mt->mt_isquarantined > LDAP_BACK_FQ_NO) {
177292cfeba6Schristos timeout_err = LDAP_UNAVAILABLE;
177392cfeba6Schristos } else {
177492cfeba6Schristos mt->mt_timeout_ops++;
177592cfeba6Schristos if ((mi->mi_max_timeout_ops > 0) &&
177692cfeba6Schristos (mt->mt_timeout_ops > mi->mi_max_timeout_ops)) {
177792cfeba6Schristos timeout_err = LDAP_UNAVAILABLE;
177892cfeba6Schristos rs->sr_err = timeout_err;
177992cfeba6Schristos if (mt->mt_isquarantined == LDAP_BACK_FQ_NO)
178092cfeba6Schristos asyncmeta_quarantine(op, mi, rs, j);
178192cfeba6Schristos }
178292cfeba6Schristos }
178392cfeba6Schristos }
178492cfeba6Schristos }
178592cfeba6Schristos }
178692cfeba6Schristos rs->sr_err = timeout_err;
178792cfeba6Schristos rs->sr_text = timeout_text;
178892cfeba6Schristos if (!bc->op->o_abandon ) {
178992cfeba6Schristos asyncmeta_send_ldap_result( bc, bc->op, &bc->rs );
179092cfeba6Schristos }
179192cfeba6Schristos asyncmeta_clear_bm_context(bc);
179292cfeba6Schristos }
179392cfeba6Schristos
179492cfeba6Schristos ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex );
179592cfeba6Schristos if (mi->mi_idle_timeout) {
179692cfeba6Schristos for (j=0; j<mi->mi_ntargets; j++) {
179792cfeba6Schristos a_metasingleconn_t *msc = &mc->mc_conns[j];
179892cfeba6Schristos if ( msc->msc_active > 0 ) {
179992cfeba6Schristos continue;
180092cfeba6Schristos }
180192cfeba6Schristos if (mc->pending_ops > 0) {
180292cfeba6Schristos continue;
180392cfeba6Schristos }
180492cfeba6Schristos current_time = slap_get_time();
180592cfeba6Schristos if (msc->msc_ld && msc->msc_time > 0 && msc->msc_time + mi->mi_idle_timeout < current_time) {
180692cfeba6Schristos asyncmeta_clear_one_msc(NULL, mc, j, 1, __FUNCTION__);
180792cfeba6Schristos }
180892cfeba6Schristos }
180992cfeba6Schristos }
181092cfeba6Schristos ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex );
181192cfeba6Schristos }
181292cfeba6Schristos
181392cfeba6Schristos slap_sl_mem_setctx(ctx, oldctx);
181492cfeba6Schristos current_time = slap_get_time();
181592cfeba6Schristos Debug( asyncmeta_debug, "asyncmeta_timeout_loop[%p] stop at [%ld] \n", rtask, current_time );
181692cfeba6Schristos ldap_pvt_thread_mutex_lock( &slapd_rq.rq_mutex );
181792cfeba6Schristos if ( ldap_pvt_runqueue_isrunning( &slapd_rq, rtask )) {
181892cfeba6Schristos ldap_pvt_runqueue_stoptask( &slapd_rq, rtask );
181992cfeba6Schristos }
182092cfeba6Schristos ldap_pvt_thread_mutex_unlock( &slapd_rq.rq_mutex );
182192cfeba6Schristos return NULL;
182292cfeba6Schristos }
182392cfeba6Schristos
1824