1 1.1 christos /* $NetBSD: meta_result.c,v 1.3 2025/09/05 21:16:26 christos Exp $ */ 2 1.1 christos 3 1.1 christos /* meta_result.c - target responses processing */ 4 1.1 christos /* $OpenLDAP$ */ 5 1.1 christos /* This work is part of OpenLDAP Software <http://www.openldap.org/>. 6 1.1 christos * 7 1.3 christos * Copyright 2016-2024 The OpenLDAP Foundation. 8 1.1 christos * Portions Copyright 2016 Symas Corporation. 9 1.1 christos * All rights reserved. 10 1.1 christos * 11 1.1 christos * Redistribution and use in source and binary forms, with or without 12 1.1 christos * modification, are permitted only as authorized by the OpenLDAP 13 1.1 christos * Public License. 14 1.1 christos * 15 1.1 christos * A copy of this license is available in the file LICENSE in the 16 1.1 christos * top-level directory of the distribution or, alternatively, at 17 1.1 christos * <http://www.OpenLDAP.org/license.html>. 18 1.1 christos */ 19 1.1 christos 20 1.1 christos /* ACKNOWLEDGEMENTS: 21 1.1 christos * This work was developed by Symas Corporation 22 1.1 christos * based on back-meta module for inclusion in OpenLDAP Software. 23 1.1 christos * This work was sponsored by Ericsson. */ 24 1.1 christos 25 1.1 christos #include <sys/cdefs.h> 26 1.1 christos __RCSID("$NetBSD: meta_result.c,v 1.3 2025/09/05 21:16:26 christos Exp $"); 27 1.1 christos 28 1.1 christos #include "portable.h" 29 1.1 christos 30 1.1 christos #include <stdio.h> 31 1.1 christos 32 1.1 christos #include <ac/string.h> 33 1.1 christos #include <ac/socket.h> 34 1.1 christos 35 1.1 christos #include "slap.h" 36 1.1 christos #include "../back-ldap/back-ldap.h" 37 1.1 christos #include "back-asyncmeta.h" 38 1.1 christos #include "ldap_rq.h" 39 1.1 christos #include "../../../libraries/liblber/lber-int.h" 40 1.1 christos 41 1.1 christos static void 42 1.1 christos asyncmeta_send_ldap_result(bm_context_t *bc, Operation *op, SlapReply *rs) 43 1.1 christos { 44 1.1 christos if (bc->c_peer_name.bv_val == op->o_conn->c_peer_name.bv_val && !bc->op->o_abandon ) { 45 1.1 christos send_ldap_result(&bc->copy_op, rs); 46 1.1 christos bc->op->o_callback = bc->copy_op.o_callback; 47 1.1 christos bc->op->o_extra = bc->copy_op.o_extra; 48 1.1 christos bc->op->o_ctrls = bc->copy_op.o_ctrls; 49 1.1 christos } 50 1.1 christos } 51 1.1 christos 52 1.1 christos static int 53 1.1 christos asyncmeta_is_last_result(a_metaconn_t *mc, bm_context_t *bc, int candidate) 54 1.1 christos { 55 1.1 christos a_metainfo_t *mi = mc->mc_info; 56 1.1 christos int i; 57 1.1 christos SlapReply *candidates = bc->candidates; 58 1.1 christos for ( i = 0; i < mi->mi_ntargets; i++ ) { 59 1.1 christos if ( !META_IS_CANDIDATE( &candidates[ i ] ) ) { 60 1.1 christos continue; 61 1.1 christos } 62 1.1 christos if (candidates[ i ].sr_msgid != META_MSGID_IGNORE || 63 1.1 christos candidates[ i ].sr_type != REP_RESULT) { 64 1.1 christos return 1; 65 1.1 christos } 66 1.1 christos } 67 1.1 christos return 0; 68 1.1 christos } 69 1.1 christos 70 1.1 christos meta_search_candidate_t 71 1.1 christos asyncmeta_dobind_result( 72 1.1 christos a_metaconn_t *mc, 73 1.1 christos int candidate, 74 1.1 christos SlapReply *bind_result, 75 1.1 christos LDAPMessage *res ) 76 1.1 christos { 77 1.1 christos a_metainfo_t *mi = mc->mc_info; 78 1.1 christos a_metatarget_t *mt = mi->mi_targets[ candidate ]; 79 1.1 christos a_metasingleconn_t *msc = &mc->mc_conns[ candidate ]; 80 1.1 christos 81 1.1 christos meta_search_candidate_t retcode = META_SEARCH_NOT_CANDIDATE; 82 1.1 christos int rc; 83 1.1 christos 84 1.1 christos assert( msc->msc_ldr != NULL ); 85 1.1 christos 86 1.1 christos if ( mi->mi_idle_timeout != 0 ) { 87 1.1 christos asyncmeta_set_msc_time(msc); 88 1.1 christos } 89 1.1 christos 90 1.1 christos if ( LogTest( asyncmeta_debug ) ) { 91 1.1 christos char time_buf[ SLAP_TEXT_BUFLEN ]; 92 1.1 christos asyncmeta_get_timestamp(time_buf); 93 1.1 christos Debug( asyncmeta_debug, "[%x] [%s] asyncmeta_dobind_result msc: %p, " 94 1.1 christos "msc->msc_binding_time: %x, msc->msc_flags:%x\n ", 95 1.1 christos (unsigned int)slap_get_time(), time_buf, msc, 96 1.1 christos (unsigned int)msc->msc_binding_time, msc->msc_mscflags ); 97 1.1 christos } 98 1.1 christos /* FIXME: matched? referrals? response controls? */ 99 1.1 christos rc = ldap_parse_result( msc->msc_ldr, res, 100 1.1 christos &(bind_result->sr_err), 101 1.1 christos (char **)&(bind_result->sr_matched), 102 1.1 christos (char **)&(bind_result->sr_text), 103 1.1 christos NULL, NULL, 0 ); 104 1.1 christos 105 1.1 christos if ( LogTest( asyncmeta_debug ) ) { 106 1.1 christos char time_buf[ SLAP_TEXT_BUFLEN ]; 107 1.1 christos asyncmeta_get_timestamp(time_buf); 108 1.1 christos Debug( asyncmeta_debug, 109 1.1 christos "[%s] asyncmeta_dobind_result error=%d msc: %p\n", 110 1.1 christos time_buf,bind_result->sr_err, msc ); 111 1.1 christos } 112 1.1 christos 113 1.1 christos if ( rc != LDAP_SUCCESS ) { 114 1.1 christos bind_result->sr_err = rc; 115 1.1 christos } 116 1.1 christos rc = slap_map_api2result( bind_result ); 117 1.1 christos 118 1.1 christos LDAP_BACK_CONN_BINDING_CLEAR( msc ); 119 1.1 christos if ( rc != LDAP_SUCCESS ) { 120 1.1 christos bind_result->sr_err = rc; 121 1.1 christos } else { 122 1.1 christos /* FIXME: check if bound as idassert authcDN! */ 123 1.1 christos if ( BER_BVISNULL( &msc->msc_bound_ndn ) 124 1.1 christos || BER_BVISEMPTY( &msc->msc_bound_ndn ) ) 125 1.1 christos { 126 1.1 christos LDAP_BACK_CONN_ISANON_SET( msc ); 127 1.1 christos if ( LogTest( asyncmeta_debug ) ) { 128 1.1 christos char time_buf[ SLAP_TEXT_BUFLEN ]; 129 1.1 christos asyncmeta_get_timestamp(time_buf); 130 1.1 christos Debug( asyncmeta_debug, "[%s] asyncmeta_dobind_result anonymous msc: %p\n", 131 1.1 christos time_buf, msc ); 132 1.1 christos } 133 1.1 christos 134 1.1 christos } else { 135 1.1 christos if ( META_BACK_TGT_SAVECRED( mt ) && 136 1.1 christos !BER_BVISNULL( &msc->msc_cred ) && 137 1.1 christos !BER_BVISEMPTY( &msc->msc_cred ) ) 138 1.1 christos { 139 1.1 christos ldap_set_rebind_proc( msc->msc_ldr, mt->mt_rebind_f, msc ); 140 1.1 christos } 141 1.1 christos if ( LogTest( asyncmeta_debug ) ) { 142 1.1 christos char time_buf[ SLAP_TEXT_BUFLEN ]; 143 1.1 christos asyncmeta_get_timestamp(time_buf); 144 1.1 christos Debug( asyncmeta_debug, "[%s] asyncmeta_dobind_result success msc: %p\n", 145 1.1 christos time_buf, msc ); 146 1.1 christos } 147 1.1 christos LDAP_BACK_CONN_ISBOUND_SET( msc ); 148 1.1 christos } 149 1.1 christos retcode = META_SEARCH_CANDIDATE; 150 1.1 christos } 151 1.1 christos return retcode; 152 1.1 christos } 153 1.1 christos 154 1.1 christos static int 155 1.1 christos asyncmeta_send_entry( 156 1.1 christos Operation *op, 157 1.1 christos SlapReply *rs, 158 1.1 christos a_metaconn_t *mc, 159 1.1 christos int target, 160 1.1 christos LDAPMessage *e ) 161 1.1 christos { 162 1.1 christos a_metainfo_t *mi = mc->mc_info; 163 1.1 christos struct berval a, mapped = BER_BVNULL; 164 1.1 christos int check_sorted_attrs = 0; 165 1.1 christos Entry ent = {0}; 166 1.1 christos BerElement ber = *ldap_get_message_ber( e ); 167 1.1 christos Attribute *attr, **attrp; 168 1.1 christos struct berval bdn, 169 1.1 christos dn = BER_BVNULL; 170 1.1 christos const char *text; 171 1.1 christos a_dncookie dc; 172 1.1 christos ber_len_t len; 173 1.1 christos int rc; 174 1.1 christos void *mem_mark; 175 1.1 christos 176 1.1 christos mem_mark = slap_sl_mark( op->o_tmpmemctx ); 177 1.1 christos ber_set_option( &ber, LBER_OPT_BER_MEMCTX, &op->o_tmpmemctx ); 178 1.1 christos 179 1.1 christos if ( ber_scanf( &ber, "l{", &len ) == LBER_ERROR ) { 180 1.1 christos return LDAP_DECODING_ERROR; 181 1.1 christos } 182 1.1 christos 183 1.1 christos if ( ber_set_option( &ber, LBER_OPT_REMAINING_BYTES, &len ) != LBER_OPT_SUCCESS ) { 184 1.1 christos return LDAP_OTHER; 185 1.1 christos } 186 1.1 christos 187 1.1 christos if ( ber_scanf( &ber, "m{", &bdn ) == LBER_ERROR ) { 188 1.1 christos return LDAP_DECODING_ERROR; 189 1.1 christos } 190 1.1 christos 191 1.1 christos /* 192 1.1 christos * Rewrite the dn of the result, if needed 193 1.1 christos */ 194 1.1 christos dc.op = op; 195 1.1 christos dc.target = mi->mi_targets[ target ]; 196 1.1 christos dc.memctx = op->o_tmpmemctx; 197 1.1 christos dc.to_from = MASSAGE_REP; 198 1.1 christos asyncmeta_dn_massage( &dc, &bdn, &dn ); 199 1.1 christos 200 1.1 christos /* 201 1.1 christos * Note: this may fail if the target host(s) schema differs 202 1.1 christos * from the one known to the meta, and a DN with unknown 203 1.1 christos * attributes is returned. 204 1.1 christos * 205 1.1 christos * FIXME: should we log anything, or delegate to dnNormalize? 206 1.1 christos */ 207 1.1 christos rc = dnPrettyNormal( NULL, &dn, &ent.e_name, &ent.e_nname, 208 1.1 christos op->o_tmpmemctx ); 209 1.1 christos if ( dn.bv_val != bdn.bv_val ) { 210 1.1 christos op->o_tmpfree( dn.bv_val, op->o_tmpmemctx ); 211 1.1 christos } 212 1.1 christos BER_BVZERO( &dn ); 213 1.1 christos 214 1.1 christos if ( rc != LDAP_SUCCESS ) { 215 1.1 christos Debug( LDAP_DEBUG_ANY, 216 1.1 christos "%s asyncmeta_send_entry(\"%s\"): " 217 1.1 christos "invalid DN syntax\n", 218 1.1 christos op->o_log_prefix, ent.e_name.bv_val ); 219 1.1 christos rc = LDAP_INVALID_DN_SYNTAX; 220 1.1 christos goto done; 221 1.1 christos } 222 1.1 christos 223 1.1 christos /* 224 1.1 christos * cache dn 225 1.1 christos */ 226 1.1 christos if ( mi->mi_cache.ttl != META_DNCACHE_DISABLED ) { 227 1.1 christos ( void )asyncmeta_dncache_update_entry( &mi->mi_cache, 228 1.1 christos &ent.e_nname, target ); 229 1.1 christos } 230 1.1 christos 231 1.1 christos attrp = &ent.e_attrs; 232 1.1 christos 233 1.1 christos while ( ber_scanf( &ber, "{m", &a ) != LBER_ERROR ) { 234 1.1 christos int last = 0; 235 1.1 christos slap_syntax_validate_func *validate; 236 1.1 christos slap_syntax_transform_func *pretty; 237 1.1 christos 238 1.1 christos if ( ber_pvt_ber_remaining( &ber ) < 0 ) { 239 1.1 christos Debug( LDAP_DEBUG_ANY, 240 1.1 christos "%s asyncmeta_send_entry(\"%s\"): " 241 1.1 christos "unable to parse attr \"%s\".\n", 242 1.1 christos op->o_log_prefix, ent.e_name.bv_val, a.bv_val ); 243 1.1 christos 244 1.1 christos rc = LDAP_OTHER; 245 1.1 christos goto done; 246 1.1 christos } 247 1.1 christos 248 1.1 christos if ( ber_pvt_ber_remaining( &ber ) == 0 ) { 249 1.1 christos break; 250 1.1 christos } 251 1.1 christos 252 1.1 christos attr = op->o_tmpcalloc( 1, sizeof(Attribute), op->o_tmpmemctx ); 253 1.1 christos if ( slap_bv2ad( &a, &attr->a_desc, &text ) 254 1.1 christos != LDAP_SUCCESS) { 255 1.1 christos if ( slap_bv2undef_ad( &a, &attr->a_desc, &text, 256 1.1 christos SLAP_AD_PROXIED ) != LDAP_SUCCESS ) 257 1.1 christos { 258 1.1 christos Debug(LDAP_DEBUG_ANY, 259 1.1 christos "%s meta_send_entry(\"%s\"): " "slap_bv2undef_ad(%s): %s\n", 260 1.1 christos op->o_log_prefix, ent.e_name.bv_val, 261 1.1 christos mapped.bv_val, text ); 262 1.1 christos ( void )ber_scanf( &ber, "x" /* [W] */ ); 263 1.1 christos op->o_tmpfree( attr, op->o_tmpmemctx ); 264 1.1 christos continue; 265 1.1 christos } 266 1.1 christos } 267 1.1 christos 268 1.1 christos if ( attr->a_desc->ad_type->sat_flags & SLAP_AT_SORTED_VAL ) 269 1.1 christos check_sorted_attrs = 1; 270 1.1 christos 271 1.1 christos /* no subschemaSubentry */ 272 1.1 christos if ( attr->a_desc == slap_schema.si_ad_subschemaSubentry 273 1.1 christos || attr->a_desc == slap_schema.si_ad_entryDN ) 274 1.1 christos { 275 1.1 christos 276 1.1 christos /* 277 1.1 christos * We eat target's subschemaSubentry because 278 1.1 christos * a search for this value is likely not 279 1.1 christos * to resolve to the appropriate backend; 280 1.1 christos * later, the local subschemaSubentry is 281 1.1 christos * added. 282 1.1 christos * 283 1.1 christos * We also eat entryDN because the frontend 284 1.1 christos * will reattach it without checking if already 285 1.1 christos * present... 286 1.1 christos */ 287 1.1 christos ( void )ber_scanf( &ber, "x" /* [W] */ ); 288 1.1 christos op->o_tmpfree( attr, op->o_tmpmemctx ); 289 1.1 christos continue; 290 1.1 christos } 291 1.1 christos 292 1.1 christos if ( ber_scanf( &ber, "[W]", &attr->a_vals ) == LBER_ERROR 293 1.1 christos || attr->a_vals == NULL ) 294 1.1 christos { 295 1.1 christos attr->a_vals = (struct berval *)&slap_dummy_bv; 296 1.1 christos 297 1.1 christos } else { 298 1.1 christos for ( last = 0; !BER_BVISNULL( &attr->a_vals[ last ] ); ++last ) 299 1.1 christos ; 300 1.1 christos } 301 1.1 christos attr->a_numvals = last; 302 1.1 christos 303 1.1 christos validate = attr->a_desc->ad_type->sat_syntax->ssyn_validate; 304 1.1 christos pretty = attr->a_desc->ad_type->sat_syntax->ssyn_pretty; 305 1.1 christos 306 1.1 christos if ( !validate && !pretty ) { 307 1.1 christos ber_bvarray_free_x( attr->a_vals, op->o_tmpmemctx ); 308 1.1 christos op->o_tmpfree( attr, op->o_tmpmemctx ); 309 1.1 christos goto next_attr; 310 1.1 christos } 311 1.1 christos 312 1.1 christos /* 313 1.1 christos * It is necessary to try to rewrite attributes with 314 1.1 christos * dn syntax because they might be used in ACLs as 315 1.1 christos * members of groups; since ACLs are applied to the 316 1.1 christos * rewritten stuff, no dn-based subecj clause could 317 1.1 christos * be used at the ldap backend side (see 318 1.1 christos * http://www.OpenLDAP.org/faq/data/cache/452.html) 319 1.1 christos * The problem can be overcome by moving the dn-based 320 1.1 christos * ACLs to the target directory server, and letting 321 1.1 christos * everything pass thru the ldap backend. 322 1.1 christos */ 323 1.1 christos { 324 1.1 christos int i; 325 1.1 christos 326 1.1 christos if ( attr->a_desc->ad_type->sat_syntax == 327 1.1 christos slap_schema.si_syn_distinguishedName ) 328 1.1 christos { 329 1.1 christos asyncmeta_dnattr_result_rewrite( &dc, attr->a_vals ); 330 1.1 christos 331 1.1 christos } else if ( attr->a_desc == slap_schema.si_ad_ref ) { 332 1.1 christos asyncmeta_referral_result_rewrite( &dc, attr->a_vals ); 333 1.1 christos 334 1.1 christos } 335 1.1 christos 336 1.1 christos for ( i = 0; i < last; i++ ) { 337 1.1 christos struct berval pval; 338 1.1 christos int rc; 339 1.1 christos 340 1.1 christos if ( pretty ) { 341 1.1 christos rc = ordered_value_pretty( attr->a_desc, 342 1.1 christos &attr->a_vals[i], &pval, op->o_tmpmemctx ); 343 1.1 christos 344 1.1 christos } else { 345 1.1 christos rc = ordered_value_validate( attr->a_desc, 346 1.1 christos &attr->a_vals[i], 0 ); 347 1.1 christos } 348 1.1 christos 349 1.1 christos if ( rc ) { 350 1.1 christos ber_memfree_x( attr->a_vals[i].bv_val, op->o_tmpmemctx ); 351 1.1 christos if ( --last == i ) { 352 1.1 christos BER_BVZERO( &attr->a_vals[ i ] ); 353 1.1 christos break; 354 1.1 christos } 355 1.1 christos attr->a_vals[i] = attr->a_vals[last]; 356 1.1 christos BER_BVZERO( &attr->a_vals[last] ); 357 1.1 christos i--; 358 1.1 christos continue; 359 1.1 christos } 360 1.1 christos 361 1.1 christos if ( pretty ) { 362 1.1 christos ber_memfree_x( attr->a_vals[i].bv_val, op->o_tmpmemctx ); 363 1.1 christos attr->a_vals[i] = pval; 364 1.1 christos } 365 1.1 christos } 366 1.1 christos 367 1.1 christos if ( last == 0 && attr->a_vals != &slap_dummy_bv ) { 368 1.1 christos ber_bvarray_free_x( attr->a_vals, op->o_tmpmemctx ); 369 1.1 christos op->o_tmpfree( attr, op->o_tmpmemctx ); 370 1.1 christos goto next_attr; 371 1.1 christos } 372 1.1 christos } 373 1.1 christos 374 1.1 christos if ( last && attr->a_desc->ad_type->sat_equality && 375 1.1 christos attr->a_desc->ad_type->sat_equality->smr_normalize ) 376 1.1 christos { 377 1.1 christos int i; 378 1.1 christos 379 1.1 christos attr->a_nvals = op->o_tmpalloc( ( last + 1 ) * sizeof( struct berval ), op->o_tmpmemctx ); 380 1.1 christos for ( i = 0; i<last; i++ ) { 381 1.1 christos /* if normalizer fails, drop this value */ 382 1.1 christos if ( ordered_value_normalize( 383 1.1 christos SLAP_MR_VALUE_OF_ATTRIBUTE_SYNTAX, 384 1.1 christos attr->a_desc, 385 1.1 christos attr->a_desc->ad_type->sat_equality, 386 1.1 christos &attr->a_vals[i], &attr->a_nvals[i], 387 1.1 christos op->o_tmpmemctx )) { 388 1.1 christos ber_memfree_x( attr->a_vals[i].bv_val, op->o_tmpmemctx ); 389 1.1 christos if ( --last == i ) { 390 1.1 christos BER_BVZERO( &attr->a_vals[ i ] ); 391 1.1 christos break; 392 1.1 christos } 393 1.1 christos attr->a_vals[i] = attr->a_vals[last]; 394 1.1 christos BER_BVZERO( &attr->a_vals[last] ); 395 1.1 christos i--; 396 1.1 christos } 397 1.1 christos } 398 1.1 christos BER_BVZERO( &attr->a_nvals[i] ); 399 1.1 christos if ( last == 0 ) { 400 1.1 christos ber_bvarray_free_x( attr->a_vals, op->o_tmpmemctx ); 401 1.1 christos ber_bvarray_free_x( attr->a_nvals, op->o_tmpmemctx ); 402 1.1 christos op->o_tmpfree( attr, op->o_tmpmemctx ); 403 1.1 christos goto next_attr; 404 1.1 christos } 405 1.1 christos 406 1.1 christos } else { 407 1.1 christos attr->a_nvals = attr->a_vals; 408 1.1 christos } 409 1.1 christos 410 1.1 christos attr->a_numvals = last; 411 1.1 christos *attrp = attr; 412 1.1 christos attrp = &attr->a_next; 413 1.1 christos next_attr:; 414 1.1 christos } 415 1.1 christos 416 1.1 christos /* Check for sorted attributes */ 417 1.1 christos if ( check_sorted_attrs ) { 418 1.1 christos for ( attr = ent.e_attrs; attr; attr = attr->a_next ) { 419 1.1 christos if ( attr->a_desc->ad_type->sat_flags & SLAP_AT_SORTED_VAL ) { 420 1.1 christos while ( attr->a_numvals > 1 ) { 421 1.1 christos int i; 422 1.1 christos int rc = slap_sort_vals( (Modifications *)attr, &text, &i, op->o_tmpmemctx ); 423 1.1 christos if ( rc != LDAP_TYPE_OR_VALUE_EXISTS ) 424 1.1 christos break; 425 1.1 christos 426 1.1 christos /* Strip duplicate values */ 427 1.1 christos if ( attr->a_nvals != attr->a_vals ) 428 1.1 christos ber_memfree_x( attr->a_nvals[i].bv_val, op->o_tmpmemctx ); 429 1.1 christos ber_memfree_x( attr->a_vals[i].bv_val, op->o_tmpmemctx ); 430 1.1 christos attr->a_numvals--; 431 1.1 christos if ( (unsigned)i < attr->a_numvals ) { 432 1.1 christos attr->a_vals[i] = attr->a_vals[attr->a_numvals]; 433 1.1 christos if ( attr->a_nvals != attr->a_vals ) 434 1.1 christos attr->a_nvals[i] = attr->a_nvals[attr->a_numvals]; 435 1.1 christos } 436 1.1 christos BER_BVZERO(&attr->a_vals[attr->a_numvals]); 437 1.1 christos if ( attr->a_nvals != attr->a_vals ) 438 1.1 christos BER_BVZERO(&attr->a_nvals[attr->a_numvals]); 439 1.1 christos } 440 1.1 christos attr->a_flags |= SLAP_ATTR_SORTED_VALS; 441 1.1 christos } 442 1.1 christos } 443 1.1 christos } 444 1.1 christos Debug( LDAP_DEBUG_TRACE, 445 1.1 christos "%s asyncmeta_send_entry(\"%s\"): " 446 1.1 christos ".\n", 447 1.1 christos op->o_log_prefix, ent.e_name.bv_val ); 448 1.1 christos ldap_get_entry_controls( mc->mc_conns[target].msc_ldr, 449 1.1 christos e, &rs->sr_ctrls ); 450 1.1 christos rs->sr_entry = &ent; 451 1.1 christos rs->sr_attrs = op->ors_attrs; 452 1.1 christos rs->sr_operational_attrs = NULL; 453 1.1 christos rs->sr_flags = mi->mi_targets[ target ]->mt_rep_flags; 454 1.1 christos rs->sr_err = LDAP_SUCCESS; 455 1.1 christos rc = send_search_entry( op, rs ); 456 1.1 christos switch ( rc ) { 457 1.1 christos case LDAP_UNAVAILABLE: 458 1.1 christos rc = LDAP_OTHER; 459 1.1 christos break; 460 1.1 christos } 461 1.1 christos 462 1.1 christos done:; 463 1.1 christos if ( rs->sr_ctrls != NULL ) { 464 1.1 christos ldap_controls_free( rs->sr_ctrls ); 465 1.1 christos rs->sr_ctrls = NULL; 466 1.1 christos } 467 1.1 christos #if 0 468 1.1 christos while ( ent.e_attrs ) { 469 1.1 christos attr = ent.e_attrs; 470 1.1 christos ent.e_attrs = attr->a_next; 471 1.1 christos if ( attr->a_nvals != attr->a_vals ) 472 1.1 christos ber_bvarray_free_x( attr->a_nvals, op->o_tmpmemctx ); 473 1.1 christos ber_bvarray_free_x( attr->a_vals, op->o_tmpmemctx ); 474 1.1 christos op->o_tmpfree( attr, op->o_tmpmemctx ); 475 1.1 christos } 476 1.1 christos if (ent.e_name.bv_val != NULL) { 477 1.1 christos op->o_tmpfree( ent.e_name.bv_val, op->o_tmpmemctx ); 478 1.1 christos } 479 1.1 christos 480 1.1 christos if (ent.e_nname.bv_val != NULL) { 481 1.1 christos op->o_tmpfree( ent.e_nname.bv_val, op->o_tmpmemctx ); 482 1.1 christos } 483 1.1 christos if (rs->sr_entry && rs->sr_entry != &ent) { 484 1.1 christos entry_free( rs->sr_entry ); 485 1.1 christos } 486 1.1 christos #endif 487 1.1 christos slap_sl_release( mem_mark, op->o_tmpmemctx ); 488 1.1 christos rs->sr_entry = NULL; 489 1.1 christos rs->sr_attrs = NULL; 490 1.1 christos return rc; 491 1.1 christos } 492 1.1 christos 493 1.1 christos static void 494 1.1 christos asyncmeta_search_last_result(a_metaconn_t *mc, bm_context_t *bc, int candidate, int sres) 495 1.1 christos { 496 1.1 christos a_metainfo_t *mi = mc->mc_info; 497 1.1 christos Operation *op = bc->op; 498 1.1 christos SlapReply *rs = &bc->rs; 499 1.1 christos int i; 500 1.1 christos SlapReply *candidates = bc->candidates; 501 1.1 christos char *matched = NULL; 502 1.1 christos 503 1.1 christos if ( bc->candidate_match > 0 ) { 504 1.1 christos struct berval pmatched = BER_BVNULL; 505 1.1 christos 506 1.1 christos /* we use the first one */ 507 1.1 christos for ( i = 0; i < mi->mi_ntargets; i++ ) { 508 1.1 christos if ( META_IS_CANDIDATE( &candidates[ i ] ) 509 1.1 christos && candidates[ i ].sr_matched != NULL ) 510 1.1 christos { 511 1.1 christos struct berval bv, pbv; 512 1.1 christos int rc; 513 1.1 christos 514 1.1 christos /* if we got success, and this target 515 1.1 christos * returned noSuchObject, and its suffix 516 1.1 christos * is a superior of the searchBase, 517 1.1 christos * ignore the matchedDN */ 518 1.1 christos if ( sres == LDAP_SUCCESS 519 1.1 christos && candidates[ i ].sr_err == LDAP_NO_SUCH_OBJECT 520 1.1 christos && op->o_req_ndn.bv_len > mi->mi_targets[ i ]->mt_nsuffix.bv_len ) 521 1.1 christos { 522 1.1 christos free( (char *)candidates[ i ].sr_matched ); 523 1.1 christos candidates[ i ].sr_matched = NULL; 524 1.1 christos continue; 525 1.1 christos } 526 1.1 christos 527 1.1 christos ber_str2bv( candidates[ i ].sr_matched, 0, 0, &bv ); 528 1.1 christos rc = dnPretty( NULL, &bv, &pbv, op->o_tmpmemctx ); 529 1.1 christos 530 1.1 christos if ( rc == LDAP_SUCCESS ) { 531 1.1 christos 532 1.1 christos /* NOTE: if they all are superiors 533 1.1 christos * of the baseDN, the shorter is also 534 1.1 christos * superior of the longer... */ 535 1.1 christos if ( pbv.bv_len > pmatched.bv_len ) { 536 1.1 christos if ( !BER_BVISNULL( &pmatched ) ) { 537 1.1 christos op->o_tmpfree( pmatched.bv_val, op->o_tmpmemctx ); 538 1.1 christos } 539 1.1 christos pmatched = pbv; 540 1.1 christos 541 1.1 christos } else { 542 1.1 christos op->o_tmpfree( pbv.bv_val, op->o_tmpmemctx ); 543 1.1 christos } 544 1.1 christos } 545 1.1 christos 546 1.1 christos if ( candidates[ i ].sr_matched != NULL ) { 547 1.1 christos free( (char *)candidates[ i ].sr_matched ); 548 1.1 christos candidates[ i ].sr_matched = NULL; 549 1.1 christos } 550 1.1 christos } 551 1.1 christos } 552 1.1 christos 553 1.1 christos if ( !BER_BVISNULL( &pmatched ) ) { 554 1.1 christos matched = pmatched.bv_val; 555 1.1 christos } 556 1.1 christos 557 1.1 christos } else if ( sres == LDAP_NO_SUCH_OBJECT ) { 558 1.1 christos matched = mi->mi_suffix.bv_val; 559 1.1 christos } 560 1.1 christos 561 1.1 christos /* 562 1.1 christos * In case we returned at least one entry, we return LDAP_SUCCESS 563 1.1 christos * otherwise, the latter error code we got 564 1.1 christos */ 565 1.1 christos 566 1.1 christos if ( sres == LDAP_SUCCESS ) { 567 1.1 christos if ( rs->sr_v2ref ) { 568 1.1 christos sres = LDAP_REFERRAL; 569 1.1 christos } 570 1.1 christos 571 1.1 christos if ( META_BACK_ONERR_REPORT( mi ) ) { 572 1.1 christos /* 573 1.1 christos * Report errors, if any 574 1.1 christos * 575 1.1 christos * FIXME: we should handle error codes and return the more 576 1.1 christos * important/reasonable 577 1.1 christos */ 578 1.1 christos for ( i = 0; i < mi->mi_ntargets; i++ ) { 579 1.1 christos if ( !META_IS_CANDIDATE( &candidates[ i ] ) ) { 580 1.1 christos continue; 581 1.1 christos } 582 1.1 christos 583 1.1 christos if ( candidates[ i ].sr_err != LDAP_SUCCESS 584 1.1 christos && candidates[ i ].sr_err != LDAP_NO_SUCH_OBJECT ) 585 1.1 christos { 586 1.1 christos sres = candidates[ i ].sr_err; 587 1.1 christos break; 588 1.1 christos } 589 1.1 christos } 590 1.1 christos } 591 1.1 christos } 592 1.1 christos Debug( LDAP_DEBUG_TRACE, 593 1.1 christos "%s asyncmeta_search_last_result(\"%d\"): " 594 1.1 christos ".\n", 595 1.1 christos op->o_log_prefix, candidate ); 596 1.1 christos rs->sr_err = sres; 597 1.1 christos rs->sr_matched = ( sres == LDAP_SUCCESS ? NULL : matched ); 598 1.1 christos rs->sr_text = ( sres == LDAP_SUCCESS ? NULL : candidates[candidate].sr_text ); 599 1.1 christos rs->sr_ref = ( sres == LDAP_REFERRAL ? rs->sr_v2ref : NULL ); 600 1.1 christos asyncmeta_send_ldap_result(bc, op, rs); 601 1.1 christos rs->sr_text = NULL; 602 1.1 christos rs->sr_matched = NULL; 603 1.1 christos rs->sr_ref = NULL; 604 1.1 christos } 605 1.1 christos 606 1.1 christos static meta_search_candidate_t 607 1.1 christos asyncmeta_send_pending_op(bm_context_t *bc, int candidate) 608 1.1 christos { 609 1.1 christos meta_search_candidate_t retcode; 610 1.1 christos switch (bc->op->o_tag) { 611 1.1 christos case LDAP_REQ_SEARCH: 612 1.1 christos retcode = asyncmeta_back_search_start( &bc->copy_op, &bc->rs, bc->bc_mc, bc, candidate, NULL, 0 , 0); 613 1.1 christos break; 614 1.1 christos case LDAP_REQ_ADD: 615 1.1 christos retcode = asyncmeta_back_add_start( &bc->copy_op, &bc->rs, bc->bc_mc, bc, candidate, 0); 616 1.1 christos break; 617 1.1 christos case LDAP_REQ_MODIFY: 618 1.1 christos retcode = asyncmeta_back_modify_start( &bc->copy_op, &bc->rs, bc->bc_mc, bc, candidate, 0); 619 1.1 christos break; 620 1.1 christos case LDAP_REQ_MODRDN: 621 1.1 christos retcode = asyncmeta_back_modrdn_start( &bc->copy_op, &bc->rs, bc->bc_mc, bc, candidate, 0); 622 1.1 christos break; 623 1.1 christos case LDAP_REQ_COMPARE: 624 1.1 christos retcode = asyncmeta_back_compare_start( &bc->copy_op, &bc->rs, bc->bc_mc, bc, candidate, 0); 625 1.1 christos break; 626 1.1 christos case LDAP_REQ_DELETE: 627 1.1 christos retcode = asyncmeta_back_delete_start( &bc->copy_op, &bc->rs, bc->bc_mc, bc, candidate, 0); 628 1.1 christos break; 629 1.1 christos default: 630 1.1 christos retcode = META_SEARCH_NOT_CANDIDATE; 631 1.1 christos } 632 1.1 christos return retcode; 633 1.1 christos } 634 1.1 christos 635 1.1 christos 636 1.1 christos meta_search_candidate_t 637 1.1 christos asyncmeta_send_all_pending_ops(a_metaconn_t *mc, int candidate, void *ctx, int dolock) 638 1.1 christos { 639 1.1 christos a_metainfo_t *mi = mc->mc_info; 640 1.1 christos bm_context_t *bc, *onext; 641 1.1 christos a_metasingleconn_t *msc = &mc->mc_conns[candidate]; 642 1.1 christos 643 1.1 christos if ( dolock ) 644 1.1 christos ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex ); 645 1.1 christos 646 1.1 christos msc->msc_active++; 647 1.1 christos for (bc = LDAP_STAILQ_FIRST(&mc->mc_om_list); bc; bc = onext) { 648 1.1 christos meta_search_candidate_t ret; 649 1.1 christos onext = LDAP_STAILQ_NEXT(bc, bc_next); 650 1.1 christos if (bc->candidates[candidate].sr_msgid == META_MSGID_NEED_BIND) 651 1.1 christos bc->candidates[candidate].sr_msgid = META_MSGID_GOT_BIND; 652 1.1 christos if (bc->candidates[candidate].sr_msgid != META_MSGID_GOT_BIND || bc->bc_active > 0 || bc->op->o_abandon > 0) { 653 1.1 christos continue; 654 1.1 christos } 655 1.1 christos bc->op->o_threadctx = ctx; 656 1.1 christos bc->op->o_tid = ldap_pvt_thread_pool_tid( ctx ); 657 1.1 christos slap_sl_mem_setctx(ctx, bc->op->o_tmpmemctx); 658 1.3 christos operation_counter_init( bc->op, ctx ); 659 1.1 christos bc->bc_active++; 660 1.1 christos ret = asyncmeta_send_pending_op(bc, candidate); 661 1.1 christos if (ret != META_SEARCH_CANDIDATE) { 662 1.1 christos bc->candidates[ candidate ].sr_msgid = META_MSGID_IGNORE; 663 1.1 christos bc->candidates[ candidate ].sr_type = REP_RESULT; 664 1.1 christos bc->candidates[ candidate ].sr_err = bc->rs.sr_err; 665 1.1 christos if (bc->op->o_tag != LDAP_REQ_SEARCH || (META_BACK_ONERR_STOP( mi )) || 666 1.1 christos (asyncmeta_is_last_result(mc, bc, candidate) == 0)) { 667 1.1 christos LDAP_STAILQ_REMOVE(&mc->mc_om_list, bc, bm_context_t, bc_next); 668 1.1 christos mc->pending_ops--; 669 1.1 christos asyncmeta_send_ldap_result(bc, bc->op, &bc->rs); 670 1.1 christos asyncmeta_clear_bm_context(bc); 671 1.1 christos } 672 1.1 christos } else { 673 1.1 christos bc->bc_active--; 674 1.1 christos } 675 1.1 christos } 676 1.1 christos msc->msc_active--; 677 1.1 christos 678 1.1 christos if ( dolock ) 679 1.1 christos ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex ); 680 1.1 christos 681 1.1 christos return META_SEARCH_CANDIDATE; 682 1.1 christos } 683 1.1 christos 684 1.1 christos meta_search_candidate_t 685 1.1 christos asyncmeta_return_bind_errors(a_metaconn_t *mc, int candidate, SlapReply *bind_result, void *ctx, int dolock) 686 1.1 christos { 687 1.1 christos a_metainfo_t *mi = mc->mc_info; 688 1.1 christos bm_context_t *bc, *onext; 689 1.1 christos 690 1.1 christos if ( dolock ) 691 1.1 christos ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex ); 692 1.1 christos 693 1.1 christos for (bc = LDAP_STAILQ_FIRST(&mc->mc_om_list); bc; bc = onext) { 694 1.1 christos onext = LDAP_STAILQ_NEXT(bc, bc_next); 695 1.1 christos if (bc->candidates[candidate].sr_msgid != META_MSGID_NEED_BIND 696 1.1 christos || bc->bc_active > 0 || bc->op->o_abandon > 0) { 697 1.1 christos continue; 698 1.1 christos } 699 1.1 christos bc->candidates[ candidate ].sr_msgid = META_MSGID_IGNORE; 700 1.1 christos bc->candidates[ candidate ].sr_type = REP_RESULT; 701 1.1 christos bc->candidates[ candidate ].sr_err = bind_result->sr_err; 702 1.1 christos if (bc->op->o_tag != LDAP_REQ_SEARCH || (META_BACK_ONERR_STOP( mi )) || 703 1.1 christos (asyncmeta_is_last_result(mc, bc, candidate) == 0)) { 704 1.1 christos LDAP_STAILQ_REMOVE(&mc->mc_om_list, bc, bm_context_t, bc_next); 705 1.1 christos bc->op->o_threadctx = ctx; 706 1.1 christos bc->op->o_tid = ldap_pvt_thread_pool_tid( ctx ); 707 1.1 christos slap_sl_mem_setctx(ctx, bc->op->o_tmpmemctx); 708 1.3 christos operation_counter_init( bc->op, ctx ); 709 1.1 christos bc->rs.sr_err = bind_result->sr_err; 710 1.1 christos bc->rs.sr_text = bind_result->sr_text; 711 1.1 christos mc->pending_ops--; 712 1.1 christos asyncmeta_send_ldap_result(bc, bc->op, &bc->rs); 713 1.1 christos asyncmeta_clear_bm_context(bc); 714 1.1 christos } 715 1.1 christos } 716 1.1 christos 717 1.1 christos if ( dolock ) 718 1.1 christos ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex ); 719 1.1 christos 720 1.1 christos return META_SEARCH_CANDIDATE; 721 1.1 christos } 722 1.1 christos 723 1.1 christos static meta_search_candidate_t 724 1.1 christos asyncmeta_handle_bind_result(LDAPMessage *msg, a_metaconn_t *mc, int candidate, void *ctx) 725 1.1 christos { 726 1.1 christos meta_search_candidate_t retcode; 727 1.1 christos SlapReply bind_result = {0}; 728 1.1 christos /* could modify the msc, safer to lock it */ 729 1.1 christos ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex ); 730 1.1 christos retcode = asyncmeta_dobind_result( mc, candidate, &bind_result, msg ); 731 1.1 christos ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex ); 732 1.1 christos if ( retcode == META_SEARCH_CANDIDATE ) { 733 1.1 christos /* send the remaining pending ops */ 734 1.1 christos asyncmeta_send_all_pending_ops(mc, candidate, ctx, 1); 735 1.1 christos } else { 736 1.1 christos asyncmeta_return_bind_errors(mc, candidate, &bind_result, ctx, 1); 737 1.1 christos } 738 1.1 christos return retcode; 739 1.1 christos } 740 1.1 christos 741 1.1 christos int 742 1.1 christos asyncmeta_handle_search_msg(LDAPMessage *res, a_metaconn_t *mc, bm_context_t *bc, int candidate) 743 1.1 christos { 744 1.1 christos a_metainfo_t *mi; 745 1.1 christos a_metatarget_t *mt; 746 1.1 christos a_metasingleconn_t *msc; 747 1.1 christos Operation *op = bc->op; 748 1.1 christos SlapReply *rs; 749 1.1 christos int i, rc = LDAP_SUCCESS, sres; 750 1.1 christos SlapReply *candidates; 751 1.1 christos char **references = NULL; 752 1.1 christos LDAPControl **ctrls = NULL; 753 1.1 christos a_dncookie dc; 754 1.1 christos LDAPMessage *msg; 755 1.1 christos ber_int_t id; 756 1.1 christos 757 1.1 christos rs = &bc->rs; 758 1.1 christos mi = mc->mc_info; 759 1.1 christos mt = mi->mi_targets[ candidate ]; 760 1.1 christos msc = &mc->mc_conns[ candidate ]; 761 1.1 christos dc.op = op; 762 1.1 christos dc.target = mt; 763 1.1 christos dc.to_from = MASSAGE_REP; 764 1.1 christos id = ldap_msgid(res); 765 1.1 christos 766 1.1 christos 767 1.1 christos candidates = bc->candidates; 768 1.1 christos i = candidate; 769 1.1 christos 770 1.1 christos while (res && !META_BACK_CONN_INVALID(msc)) { 771 1.1 christos for (msg = ldap_first_message(msc->msc_ldr, res); msg; msg = ldap_next_message(msc->msc_ldr, msg)) { 772 1.1 christos switch(ldap_msgtype(msg)) { 773 1.1 christos case LDAP_RES_SEARCH_ENTRY: 774 1.1 christos Debug( LDAP_DEBUG_TRACE, 775 1.1 christos "%s asyncmeta_handle_search_msg: msc %p entry\n", 776 1.1 christos op->o_log_prefix, msc ); 777 1.1 christos if ( candidates[ i ].sr_type == REP_INTERMEDIATE ) { 778 1.1 christos /* don't retry any more... */ 779 1.1 christos candidates[ i ].sr_type = REP_RESULT; 780 1.1 christos } 781 1.1 christos /* count entries returned by target */ 782 1.1 christos candidates[ i ].sr_nentries++; 783 1.1 christos if (bc->c_peer_name.bv_val == op->o_conn->c_peer_name.bv_val && !op->o_abandon) { 784 1.1 christos rs->sr_err = asyncmeta_send_entry( &bc->copy_op, rs, mc, i, msg ); 785 1.1 christos } else { 786 1.1 christos goto err_cleanup; 787 1.1 christos } 788 1.1 christos switch ( rs->sr_err ) { 789 1.1 christos case LDAP_SIZELIMIT_EXCEEDED: 790 1.1 christos asyncmeta_send_ldap_result(bc, op, rs); 791 1.1 christos rs->sr_err = LDAP_SUCCESS; 792 1.1 christos goto err_cleanup; 793 1.1 christos case LDAP_UNAVAILABLE: 794 1.1 christos rs->sr_err = LDAP_OTHER; 795 1.1 christos break; 796 1.1 christos default: 797 1.1 christos break; 798 1.1 christos } 799 1.1 christos bc->is_ok++; 800 1.1 christos break; 801 1.1 christos 802 1.1 christos case LDAP_RES_SEARCH_REFERENCE: 803 1.1 christos if ( META_BACK_TGT_NOREFS( mt ) ) { 804 1.1 christos rs->sr_err = LDAP_OTHER; 805 1.1 christos asyncmeta_send_ldap_result(bc, op, rs); 806 1.1 christos goto err_cleanup; 807 1.1 christos } 808 1.1 christos if ( candidates[ i ].sr_type == REP_INTERMEDIATE ) { 809 1.1 christos /* don't retry any more... */ 810 1.1 christos candidates[ i ].sr_type = REP_RESULT; 811 1.1 christos } 812 1.1 christos bc->is_ok++; 813 1.1 christos rc = ldap_parse_reference( msc->msc_ldr, msg, 814 1.1 christos &references, &rs->sr_ctrls, 0 ); 815 1.1 christos 816 1.1 christos if ( rc != LDAP_SUCCESS || references == NULL ) { 817 1.1 christos rs->sr_err = LDAP_OTHER; 818 1.1 christos asyncmeta_send_ldap_result(bc, op, rs); 819 1.1 christos goto err_cleanup; 820 1.1 christos } 821 1.1 christos 822 1.1 christos /* FIXME: merge all and return at the end */ 823 1.1 christos 824 1.1 christos { 825 1.1 christos int cnt; 826 1.1 christos for ( cnt = 0; references[ cnt ]; cnt++ ) 827 1.1 christos ; 828 1.1 christos 829 1.1 christos rs->sr_ref = op->o_tmpalloc( sizeof( struct berval ) * ( cnt + 1 ), 830 1.1 christos op->o_tmpmemctx ); 831 1.1 christos 832 1.1 christos for ( cnt = 0; references[ cnt ]; cnt++ ) { 833 1.1 christos ber_str2bv_x( references[ cnt ], 0, 1, &rs->sr_ref[ cnt ], 834 1.1 christos op->o_tmpmemctx ); 835 1.1 christos } 836 1.1 christos BER_BVZERO( &rs->sr_ref[ cnt ] ); 837 1.1 christos } 838 1.1 christos 839 1.1 christos { 840 1.1 christos dc.memctx = op->o_tmpmemctx; 841 1.1 christos ( void )asyncmeta_referral_result_rewrite( &dc, rs->sr_ref ); 842 1.1 christos } 843 1.1 christos 844 1.1 christos if ( rs->sr_ref != NULL ) { 845 1.1 christos if (!BER_BVISNULL( &rs->sr_ref[ 0 ] ) ) { 846 1.1 christos /* ignore return value by now */ 847 1.1 christos ( void )send_search_reference( op, rs ); 848 1.1 christos } 849 1.1 christos 850 1.1 christos ber_bvarray_free_x( rs->sr_ref, op->o_tmpmemctx ); 851 1.1 christos rs->sr_ref = NULL; 852 1.1 christos } 853 1.1 christos 854 1.1 christos /* cleanup */ 855 1.1 christos if ( references ) { 856 1.1 christos ber_memvfree( (void **)references ); 857 1.1 christos } 858 1.1 christos 859 1.1 christos if ( rs->sr_ctrls ) { 860 1.1 christos ldap_controls_free( rs->sr_ctrls ); 861 1.1 christos rs->sr_ctrls = NULL; 862 1.1 christos } 863 1.1 christos break; 864 1.1 christos 865 1.1 christos case LDAP_RES_INTERMEDIATE: 866 1.1 christos if ( candidates[ i ].sr_type == REP_INTERMEDIATE ) { 867 1.1 christos /* don't retry any more... */ 868 1.1 christos candidates[ i ].sr_type = REP_RESULT; 869 1.1 christos } 870 1.1 christos bc->is_ok++; 871 1.1 christos 872 1.1 christos /* FIXME: response controls 873 1.1 christos * are passed without checks */ 874 1.1 christos rs->sr_err = ldap_parse_intermediate( msc->msc_ldr, 875 1.1 christos msg, 876 1.1 christos (char **)&rs->sr_rspoid, 877 1.1 christos &rs->sr_rspdata, 878 1.1 christos &rs->sr_ctrls, 879 1.1 christos 0 ); 880 1.1 christos if ( rs->sr_err != LDAP_SUCCESS ) { 881 1.1 christos candidates[ i ].sr_type = REP_RESULT; 882 1.1 christos rs->sr_err = LDAP_OTHER; 883 1.1 christos asyncmeta_send_ldap_result(bc, op, rs); 884 1.1 christos goto err_cleanup; 885 1.1 christos } 886 1.1 christos 887 1.1 christos slap_send_ldap_intermediate( op, rs ); 888 1.1 christos 889 1.1 christos if ( rs->sr_rspoid != NULL ) { 890 1.1 christos ber_memfree( (char *)rs->sr_rspoid ); 891 1.1 christos rs->sr_rspoid = NULL; 892 1.1 christos } 893 1.1 christos 894 1.1 christos if ( rs->sr_rspdata != NULL ) { 895 1.1 christos ber_bvfree( rs->sr_rspdata ); 896 1.1 christos rs->sr_rspdata = NULL; 897 1.1 christos } 898 1.1 christos 899 1.1 christos if ( rs->sr_ctrls != NULL ) { 900 1.1 christos ldap_controls_free( rs->sr_ctrls ); 901 1.1 christos rs->sr_ctrls = NULL; 902 1.1 christos } 903 1.1 christos break; 904 1.1 christos 905 1.1 christos case LDAP_RES_SEARCH_RESULT: 906 1.1 christos if ( mi->mi_idle_timeout != 0 ) { 907 1.1 christos asyncmeta_set_msc_time(msc); 908 1.1 christos } 909 1.1 christos Debug( LDAP_DEBUG_TRACE, 910 1.1 christos "%s asyncmeta_handle_search_msg: msc %p result\n", 911 1.1 christos op->o_log_prefix, msc ); 912 1.1 christos candidates[ i ].sr_type = REP_RESULT; 913 1.1 christos candidates[ i ].sr_msgid = META_MSGID_IGNORE; 914 1.1 christos /* NOTE: ignores response controls 915 1.1 christos * (and intermediate response controls 916 1.1 christos * as well, except for those with search 917 1.1 christos * references); this may not be correct, 918 1.1 christos * but if they're not ignored then 919 1.1 christos * back-meta would need to merge them 920 1.1 christos * consistently (think of pagedResults...) 921 1.1 christos */ 922 1.1 christos /* FIXME: response controls? */ 923 1.1 christos rs->sr_err = ldap_parse_result( msc->msc_ldr, 924 1.1 christos msg, 925 1.1 christos &candidates[ i ].sr_err, 926 1.1 christos (char **)&candidates[ i ].sr_matched, 927 1.1 christos (char **)&candidates[ i ].sr_text, 928 1.1 christos &references, 929 1.1 christos &ctrls /* &candidates[ i ].sr_ctrls (unused) */ , 930 1.1 christos 0 ); 931 1.1 christos if ( rs->sr_err != LDAP_SUCCESS ) { 932 1.1 christos candidates[ i ].sr_err = rs->sr_err; 933 1.1 christos sres = slap_map_api2result( &candidates[ i ] ); 934 1.1 christos candidates[ i ].sr_type = REP_RESULT; 935 1.1 christos goto finish; 936 1.1 christos } 937 1.1 christos 938 1.1 christos rs->sr_err = candidates[ i ].sr_err; 939 1.1 christos 940 1.1 christos /* massage matchedDN if need be */ 941 1.1 christos if ( candidates[ i ].sr_matched != NULL ) { 942 1.1 christos struct berval match, mmatch; 943 1.1 christos 944 1.1 christos ber_str2bv( candidates[ i ].sr_matched, 945 1.1 christos 0, 0, &match ); 946 1.1 christos candidates[ i ].sr_matched = NULL; 947 1.1 christos 948 1.1 christos dc.memctx = NULL; 949 1.1 christos asyncmeta_dn_massage( &dc, &match, &mmatch ); 950 1.1 christos if ( mmatch.bv_val == match.bv_val ) { 951 1.1 christos candidates[ i ].sr_matched 952 1.1 christos = ch_strdup( mmatch.bv_val ); 953 1.1 christos 954 1.1 christos } else { 955 1.1 christos candidates[ i ].sr_matched = mmatch.bv_val; 956 1.1 christos } 957 1.1 christos 958 1.1 christos bc->candidate_match++; 959 1.1 christos ldap_memfree( match.bv_val ); 960 1.1 christos } 961 1.1 christos 962 1.1 christos /* add references to array */ 963 1.1 christos /* RFC 4511: referrals can only appear 964 1.1 christos * if result code is LDAP_REFERRAL */ 965 1.1 christos if ( references != NULL 966 1.1 christos && references[ 0 ] != NULL 967 1.1 christos && references[ 0 ][ 0 ] != '\0' ) 968 1.1 christos { 969 1.1 christos if ( rs->sr_err != LDAP_REFERRAL ) { 970 1.1 christos Debug( LDAP_DEBUG_ANY, 971 1.1 christos "%s asncmeta_search_result[%d]: " 972 1.1 christos "got referrals with err=%d\n", 973 1.1 christos op->o_log_prefix, 974 1.1 christos i, rs->sr_err ); 975 1.1 christos 976 1.1 christos } else { 977 1.1 christos BerVarray sr_ref; 978 1.1 christos int cnt; 979 1.1 christos 980 1.1 christos for ( cnt = 0; references[ cnt ]; cnt++ ) 981 1.1 christos ; 982 1.1 christos 983 1.1 christos sr_ref = op->o_tmpalloc( sizeof( struct berval ) * ( cnt + 1 ), 984 1.1 christos op->o_tmpmemctx ); 985 1.1 christos 986 1.1 christos for ( cnt = 0; references[ cnt ]; cnt++ ) { 987 1.1 christos ber_str2bv_x( references[ cnt ], 0, 1, &sr_ref[ cnt ], 988 1.1 christos op->o_tmpmemctx ); 989 1.1 christos } 990 1.1 christos BER_BVZERO( &sr_ref[ cnt ] ); 991 1.1 christos 992 1.1 christos dc.memctx = op->o_tmpmemctx; 993 1.1 christos ( void )asyncmeta_referral_result_rewrite( &dc, sr_ref ); 994 1.1 christos 995 1.1 christos if ( rs->sr_v2ref == NULL ) { 996 1.1 christos rs->sr_v2ref = sr_ref; 997 1.1 christos 998 1.1 christos } else { 999 1.1 christos for ( cnt = 0; !BER_BVISNULL( &sr_ref[ cnt ] ); cnt++ ) { 1000 1.1 christos ber_bvarray_add_x( &rs->sr_v2ref, &sr_ref[ cnt ], 1001 1.1 christos op->o_tmpmemctx ); 1002 1.1 christos } 1003 1.1 christos ber_memfree_x( sr_ref, op->o_tmpmemctx ); 1004 1.1 christos } 1005 1.1 christos } 1006 1.1 christos 1007 1.1 christos } else if ( rs->sr_err == LDAP_REFERRAL ) { 1008 1.1 christos Debug( LDAP_DEBUG_TRACE, 1009 1.1 christos "%s asyncmeta_search_result[%d]: " 1010 1.1 christos "got err=%d with null " 1011 1.1 christos "or empty referrals\n", 1012 1.1 christos op->o_log_prefix, 1013 1.1 christos i, rs->sr_err ); 1014 1.1 christos 1015 1.1 christos rs->sr_err = LDAP_NO_SUCH_OBJECT; 1016 1.1 christos } 1017 1.1 christos 1018 1.1 christos /* cleanup */ 1019 1.1 christos ber_memvfree( (void **)references ); 1020 1.1 christos 1021 1.1 christos sres = slap_map_api2result( rs ); 1022 1.1 christos 1023 1.1 christos if ( candidates[ i ].sr_err == LDAP_SUCCESS ) { 1024 1.1 christos Debug( LDAP_DEBUG_TRACE, "%s asyncmeta_search_result[%d] " 1025 1.1 christos "match=\"%s\" err=%ld\n", 1026 1.1 christos op->o_log_prefix, i, 1027 1.1 christos candidates[ i ].sr_matched ? candidates[ i ].sr_matched : "", 1028 1.1 christos (long) candidates[ i ].sr_err ); 1029 1.1 christos } else { 1030 1.1 christos Debug( LDAP_DEBUG_ANY, "%s asyncmeta_search_result[%d] " 1031 1.1 christos "match=\"%s\" err=%ld (%s)\n", 1032 1.1 christos op->o_log_prefix, i, 1033 1.1 christos candidates[ i ].sr_matched ? candidates[ i ].sr_matched : "", 1034 1.1 christos (long) candidates[ i ].sr_err, ldap_err2string( candidates[ i ].sr_err ) ); 1035 1.1 christos } 1036 1.1 christos 1037 1.1 christos switch ( sres ) { 1038 1.1 christos case LDAP_NO_SUCH_OBJECT: 1039 1.1 christos /* is_ok is touched any time a valid 1040 1.1 christos * (even intermediate) result is 1041 1.1 christos * returned; as a consequence, if 1042 1.1 christos * a candidate returns noSuchObject 1043 1.1 christos * it is ignored and the candidate 1044 1.1 christos * is simply demoted. */ 1045 1.1 christos if ( bc->is_ok ) { 1046 1.1 christos sres = LDAP_SUCCESS; 1047 1.1 christos } 1048 1.1 christos break; 1049 1.1 christos 1050 1.1 christos case LDAP_SUCCESS: 1051 1.1 christos if ( ctrls != NULL && ctrls[0] != NULL ) { 1052 1.1 christos #ifdef SLAPD_META_CLIENT_PR 1053 1.1 christos LDAPControl *pr_c; 1054 1.1 christos 1055 1.1 christos pr_c = ldap_control_find( LDAP_CONTROL_PAGEDRESULTS, ctrls, NULL ); 1056 1.1 christos if ( pr_c != NULL ) { 1057 1.1 christos BerElementBuffer berbuf; 1058 1.1 christos BerElement *ber = (BerElement *)&berbuf; 1059 1.1 christos ber_tag_t tag; 1060 1.1 christos ber_int_t prsize; 1061 1.1 christos struct berval prcookie; 1062 1.1 christos 1063 1.1 christos /* unsolicited, do not accept */ 1064 1.1 christos if ( mt->mt_ps == 0 ) { 1065 1.1 christos rs->sr_err = LDAP_OTHER; 1066 1.1 christos goto err_pr; 1067 1.1 christos } 1068 1.1 christos 1069 1.1 christos ber_init2( ber, &pr_c->ldctl_value, LBER_USE_DER ); 1070 1.1 christos 1071 1.1 christos tag = ber_scanf( ber, "{im}", &prsize, &prcookie ); 1072 1.1 christos if ( tag == LBER_ERROR ) { 1073 1.1 christos rs->sr_err = LDAP_OTHER; 1074 1.1 christos goto err_pr; 1075 1.1 christos } 1076 1.1 christos 1077 1.1 christos /* more pages? new search request */ 1078 1.1 christos if ( !BER_BVISNULL( &prcookie ) && !BER_BVISEMPTY( &prcookie ) ) { 1079 1.1 christos if ( mt->mt_ps > 0 ) { 1080 1.1 christos /* ignore size if specified */ 1081 1.1 christos prsize = 0; 1082 1.1 christos 1083 1.1 christos } else if ( prsize == 0 ) { 1084 1.1 christos /* guess the page size from the entries returned so far */ 1085 1.1 christos prsize = candidates[ i ].sr_nentries; 1086 1.1 christos } 1087 1.1 christos 1088 1.1 christos candidates[ i ].sr_nentries = 0; 1089 1.1 christos candidates[ i ].sr_msgid = META_MSGID_IGNORE; 1090 1.1 christos candidates[ i ].sr_type = REP_INTERMEDIATE; 1091 1.1 christos 1092 1.1 christos assert( candidates[ i ].sr_matched == NULL ); 1093 1.1 christos assert( candidates[ i ].sr_text == NULL ); 1094 1.1 christos assert( candidates[ i ].sr_ref == NULL ); 1095 1.1 christos 1096 1.1 christos switch ( asyncmeta_back_search_start( &bc->copy_op, rs, mc, bc, i, &prcookie, prsize, 1 ) ) 1097 1.1 christos { 1098 1.1 christos case META_SEARCH_CANDIDATE: 1099 1.1 christos assert( candidates[ i ].sr_msgid >= 0 ); 1100 1.1 christos ldap_controls_free( ctrls ); 1101 1.1 christos // goto free_message; 1102 1.1 christos 1103 1.1 christos case META_SEARCH_ERR: 1104 1.1 christos case META_SEARCH_NEED_BIND: 1105 1.1 christos err_pr:; 1106 1.1 christos candidates[ i ].sr_err = rs->sr_err; 1107 1.1 christos candidates[ i ].sr_type = REP_RESULT; 1108 1.1 christos if ( META_BACK_ONERR_STOP( mi ) ) { 1109 1.1 christos asyncmeta_send_ldap_result(bc, op, rs); 1110 1.1 christos ldap_controls_free( ctrls ); 1111 1.1 christos goto err_cleanup; 1112 1.1 christos } 1113 1.1 christos /* fallthru */ 1114 1.1 christos 1115 1.1 christos case META_SEARCH_NOT_CANDIDATE: 1116 1.1 christos /* means that asyncmeta_back_search_start() 1117 1.1 christos * failed but onerr == continue */ 1118 1.1 christos candidates[ i ].sr_msgid = META_MSGID_IGNORE; 1119 1.1 christos candidates[ i ].sr_type = REP_RESULT; 1120 1.1 christos break; 1121 1.1 christos 1122 1.1 christos default: 1123 1.1 christos /* impossible */ 1124 1.1 christos assert( 0 ); 1125 1.1 christos break; 1126 1.1 christos } 1127 1.1 christos break; 1128 1.1 christos } 1129 1.1 christos } 1130 1.1 christos #endif /* SLAPD_META_CLIENT_PR */ 1131 1.1 christos 1132 1.1 christos ldap_controls_free( ctrls ); 1133 1.1 christos } 1134 1.1 christos /* fallthru */ 1135 1.1 christos 1136 1.1 christos case LDAP_REFERRAL: 1137 1.1 christos bc->is_ok++; 1138 1.1 christos break; 1139 1.1 christos 1140 1.1 christos case LDAP_SIZELIMIT_EXCEEDED: 1141 1.1 christos /* if a target returned sizelimitExceeded 1142 1.1 christos * and the entry count is equal to the 1143 1.1 christos * proxy's limit, the target would have 1144 1.1 christos * returned more, and the error must be 1145 1.1 christos * propagated to the client; otherwise, 1146 1.1 christos * the target enforced a limit lower 1147 1.1 christos * than what requested by the proxy; 1148 1.1 christos * ignore it */ 1149 1.1 christos candidates[ i ].sr_err = rs->sr_err; 1150 1.1 christos if ( rs->sr_nentries == op->ors_slimit 1151 1.1 christos || META_BACK_ONERR_STOP( mi ) ) 1152 1.1 christos { 1153 1.1 christos const char *save_text; 1154 1.1 christos got_err: 1155 1.1 christos save_text = rs->sr_text; 1156 1.1 christos rs->sr_text = candidates[ i ].sr_text; 1157 1.1 christos asyncmeta_send_ldap_result(bc, op, rs); 1158 1.1 christos if (candidates[ i ].sr_text != NULL) { 1159 1.1 christos ch_free( (char *)candidates[ i ].sr_text ); 1160 1.1 christos candidates[ i ].sr_text = NULL; 1161 1.1 christos } 1162 1.1 christos rs->sr_text = save_text; 1163 1.1 christos ldap_controls_free( ctrls ); 1164 1.1 christos goto err_cleanup; 1165 1.1 christos } 1166 1.1 christos break; 1167 1.1 christos 1168 1.1 christos default: 1169 1.1 christos candidates[ i ].sr_err = rs->sr_err; 1170 1.1 christos if ( META_BACK_ONERR_STOP( mi ) ) { 1171 1.1 christos goto got_err; 1172 1.1 christos } 1173 1.1 christos break; 1174 1.1 christos } 1175 1.1 christos /* if this is the last result we will ever receive, send it back */ 1176 1.1 christos rc = rs->sr_err; 1177 1.1 christos if (asyncmeta_is_last_result(mc, bc, i) == 0) { 1178 1.1 christos Debug( LDAP_DEBUG_TRACE, 1179 1.1 christos "%s asyncmeta_handle_search_msg: msc %p last result\n", 1180 1.1 christos op->o_log_prefix, msc ); 1181 1.1 christos asyncmeta_search_last_result(mc, bc, i, sres); 1182 1.1 christos err_cleanup: 1183 1.1 christos rc = rs->sr_err; 1184 1.1 christos ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex ); 1185 1.1 christos asyncmeta_drop_bc( mc, bc); 1186 1.1 christos asyncmeta_clear_bm_context(bc); 1187 1.1 christos ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex ); 1188 1.1 christos ldap_msgfree(res); 1189 1.1 christos return rc; 1190 1.1 christos } 1191 1.1 christos finish: 1192 1.1 christos break; 1193 1.1 christos 1194 1.1 christos default: 1195 1.1 christos continue; 1196 1.1 christos } 1197 1.1 christos } 1198 1.1 christos ldap_msgfree(res); 1199 1.1 christos res = NULL; 1200 1.1 christos if (candidates[ i ].sr_type != REP_RESULT) { 1201 1.1 christos struct timeval tv = {0}; 1202 1.1 christos rc = ldap_result( msc->msc_ldr, id, LDAP_MSG_RECEIVED, &tv, &res ); 1203 1.1 christos if (res != NULL) { 1204 1.1 christos msc->msc_result_time = slap_get_time(); 1205 1.1 christos } 1206 1.1 christos } 1207 1.1 christos } 1208 1.1 christos ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex ); 1209 1.1 christos bc->bc_active--; 1210 1.1 christos ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex ); 1211 1.1 christos 1212 1.1 christos return rc; 1213 1.1 christos } 1214 1.1 christos 1215 1.1 christos /* handles the received result for add, modify, modrdn, compare and delete ops */ 1216 1.1 christos 1217 1.1 christos int asyncmeta_handle_common_result(LDAPMessage *msg, a_metaconn_t *mc, bm_context_t *bc, int candidate) 1218 1.1 christos { 1219 1.1 christos a_metainfo_t *mi; 1220 1.1 christos a_metatarget_t *mt; 1221 1.1 christos a_metasingleconn_t *msc; 1222 1.1 christos const char *save_text = NULL, 1223 1.1 christos *save_matched = NULL; 1224 1.1 christos BerVarray save_ref = NULL; 1225 1.1 christos LDAPControl **save_ctrls = NULL; 1226 1.1 christos void *matched_ctx = NULL; 1227 1.1 christos 1228 1.1 christos char *matched = NULL; 1229 1.1 christos char *text = NULL; 1230 1.1 christos char **refs = NULL; 1231 1.1 christos LDAPControl **ctrls = NULL; 1232 1.1 christos Operation *op; 1233 1.1 christos SlapReply *rs; 1234 1.1 christos int rc; 1235 1.1 christos 1236 1.1 christos mi = mc->mc_info; 1237 1.1 christos mt = mi->mi_targets[ candidate ]; 1238 1.1 christos msc = &mc->mc_conns[ candidate ]; 1239 1.1 christos 1240 1.1 christos op = bc->op; 1241 1.1 christos rs = &bc->rs; 1242 1.1 christos save_text = rs->sr_text, 1243 1.1 christos save_matched = rs->sr_matched; 1244 1.1 christos save_ref = rs->sr_ref; 1245 1.1 christos save_ctrls = rs->sr_ctrls; 1246 1.1 christos rs->sr_text = NULL; 1247 1.1 christos rs->sr_matched = NULL; 1248 1.1 christos rs->sr_ref = NULL; 1249 1.1 christos rs->sr_ctrls = NULL; 1250 1.1 christos 1251 1.1 christos /* only touch when activity actually took place... */ 1252 1.1 christos if ( mi->mi_idle_timeout != 0 ) { 1253 1.1 christos asyncmeta_set_msc_time(msc); 1254 1.1 christos } 1255 1.1 christos 1256 1.1 christos rc = ldap_parse_result( msc->msc_ldr, msg, &rs->sr_err, 1257 1.1 christos &matched, &text, &refs, &ctrls, 0 ); 1258 1.1 christos 1259 1.1 christos if ( rc == LDAP_SUCCESS ) { 1260 1.1 christos rs->sr_text = text; 1261 1.1 christos } else { 1262 1.1 christos rs->sr_err = rc; 1263 1.1 christos } 1264 1.1 christos rs->sr_err = slap_map_api2result( rs ); 1265 1.1 christos 1266 1.1 christos /* RFC 4511: referrals can only appear 1267 1.1 christos * if result code is LDAP_REFERRAL */ 1268 1.1 christos if ( refs != NULL 1269 1.1 christos && refs[ 0 ] != NULL 1270 1.1 christos && refs[ 0 ][ 0 ] != '\0' ) 1271 1.1 christos { 1272 1.1 christos if ( rs->sr_err != LDAP_REFERRAL ) { 1273 1.1 christos Debug( LDAP_DEBUG_ANY, 1274 1.1 christos "%s asyncmeta_handle_common_result[%d]: " 1275 1.1 christos "got referrals with err=%d\n", 1276 1.1 christos op->o_log_prefix, 1277 1.1 christos candidate, rs->sr_err ); 1278 1.1 christos 1279 1.1 christos } else { 1280 1.1 christos int i; 1281 1.1 christos 1282 1.1 christos for ( i = 0; refs[ i ] != NULL; i++ ) 1283 1.1 christos /* count */ ; 1284 1.1 christos rs->sr_ref = op->o_tmpalloc( sizeof( struct berval ) * ( i + 1 ), 1285 1.1 christos op->o_tmpmemctx ); 1286 1.1 christos for ( i = 0; refs[ i ] != NULL; i++ ) { 1287 1.1 christos ber_str2bv( refs[ i ], 0, 0, &rs->sr_ref[ i ] ); 1288 1.1 christos } 1289 1.1 christos BER_BVZERO( &rs->sr_ref[ i ] ); 1290 1.1 christos } 1291 1.1 christos 1292 1.1 christos } else if ( rs->sr_err == LDAP_REFERRAL ) { 1293 1.1 christos Debug( LDAP_DEBUG_ANY, 1294 1.1 christos "%s asyncmeta_handle_common_result[%d]: " 1295 1.1 christos "got err=%d with null " 1296 1.1 christos "or empty referrals\n", 1297 1.1 christos op->o_log_prefix, 1298 1.1 christos candidate, rs->sr_err ); 1299 1.1 christos 1300 1.1 christos rs->sr_err = LDAP_NO_SUCH_OBJECT; 1301 1.1 christos } 1302 1.1 christos 1303 1.1 christos if ( ctrls != NULL ) { 1304 1.1 christos rs->sr_ctrls = ctrls; 1305 1.1 christos } 1306 1.1 christos 1307 1.1 christos /* if the error in the reply structure is not 1308 1.1 christos * LDAP_SUCCESS, try to map it from client 1309 1.1 christos * to server error */ 1310 1.1 christos if ( !LDAP_ERR_OK( rs->sr_err ) ) { 1311 1.1 christos rs->sr_err = slap_map_api2result( rs ); 1312 1.1 christos 1313 1.1 christos /* internal ops ( op->o_conn == NULL ) 1314 1.1 christos * must not reply to client */ 1315 1.1 christos if ( op->o_conn && !op->o_do_not_cache && matched ) { 1316 1.1 christos 1317 1.1 christos /* record the (massaged) matched 1318 1.1 christos * DN into the reply structure */ 1319 1.1 christos rs->sr_matched = matched; 1320 1.1 christos } 1321 1.1 christos } 1322 1.1 christos 1323 1.1 christos if ( META_BACK_TGT_QUARANTINE( mt ) ) { 1324 1.1 christos asyncmeta_quarantine( op, mi, rs, candidate ); 1325 1.1 christos } 1326 1.1 christos 1327 1.1 christos if ( matched != NULL ) { 1328 1.1 christos struct berval dn, pdn; 1329 1.1 christos 1330 1.1 christos ber_str2bv( matched, 0, 0, &dn ); 1331 1.1 christos if ( dnPretty( NULL, &dn, &pdn, op->o_tmpmemctx ) == LDAP_SUCCESS ) { 1332 1.1 christos ldap_memfree( matched ); 1333 1.1 christos matched_ctx = op->o_tmpmemctx; 1334 1.1 christos matched = pdn.bv_val; 1335 1.1 christos } 1336 1.1 christos rs->sr_matched = matched; 1337 1.1 christos } 1338 1.1 christos 1339 1.1 christos if ( rs->sr_err == LDAP_UNAVAILABLE || rs->sr_err == LDAP_SERVER_DOWN ) { 1340 1.1 christos if ( rs->sr_text == NULL ) { 1341 1.1 christos rs->sr_text = "Target is unavailable"; 1342 1.1 christos } 1343 1.1 christos } 1344 1.1 christos 1345 1.1 christos ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex ); 1346 1.1 christos asyncmeta_drop_bc( mc, bc); 1347 1.1 christos ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex ); 1348 1.1 christos 1349 1.1 christos if ( op->o_conn ) { 1350 1.1 christos asyncmeta_send_ldap_result(bc, op, rs); 1351 1.1 christos } 1352 1.1 christos 1353 1.1 christos if ( matched ) { 1354 1.1 christos op->o_tmpfree( (char *)rs->sr_matched, matched_ctx ); 1355 1.1 christos } 1356 1.1 christos if ( text ) { 1357 1.1 christos ldap_memfree( text ); 1358 1.1 christos } 1359 1.1 christos if ( rs->sr_ref ) { 1360 1.1 christos op->o_tmpfree( rs->sr_ref, op->o_tmpmemctx ); 1361 1.1 christos rs->sr_ref = NULL; 1362 1.1 christos } 1363 1.1 christos if ( refs ) { 1364 1.1 christos ber_memvfree( (void **)refs ); 1365 1.1 christos } 1366 1.1 christos if ( ctrls ) { 1367 1.1 christos assert( rs->sr_ctrls != NULL ); 1368 1.1 christos ldap_controls_free( ctrls ); 1369 1.1 christos } 1370 1.1 christos 1371 1.1 christos rs->sr_text = save_text; 1372 1.1 christos rs->sr_matched = save_matched; 1373 1.1 christos rs->sr_ref = save_ref; 1374 1.1 christos rs->sr_ctrls = save_ctrls; 1375 1.1 christos rc = (LDAP_ERR_OK( rs->sr_err ) ? LDAP_SUCCESS : rs->sr_err); 1376 1.1 christos ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex ); 1377 1.1 christos asyncmeta_clear_bm_context(bc); 1378 1.1 christos ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex ); 1379 1.1 christos return rc; 1380 1.1 christos } 1381 1.1 christos 1382 1.1 christos /* This takes care to clean out the outbound queue in case we have a read error 1383 1.1 christos * sending back responses to the client */ 1384 1.1 christos int 1385 1.1 christos asyncmeta_op_read_error(a_metaconn_t *mc, int candidate, int error, void* ctx) 1386 1.1 christos { 1387 1.1 christos bm_context_t *bc, *onext; 1388 1.1 christos int cleanup; 1389 1.1 christos Operation *op; 1390 1.1 christos SlapReply *rs; 1391 1.1 christos SlapReply *candidates; 1392 1.1 christos 1393 1.1 christos /* no outstanding ops, nothing to do but log */ 1394 1.1 christos Debug( LDAP_DEBUG_TRACE, 1395 1.1 christos "asyncmeta_op_read_error: ldr=%p, err=%d\n", 1396 1.1 christos mc->mc_conns[candidate].msc_ldr, error ); 1397 1.1 christos 1398 1.1 christos ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex ); 1399 1.1 christos /*someone may be trying to write */ 1400 1.1 christos if (mc->mc_conns[candidate].msc_active <= 1) { 1401 1.1 christos asyncmeta_clear_one_msc(NULL, mc, candidate, 0, __FUNCTION__); 1402 1.1 christos } else { 1403 1.1 christos META_BACK_CONN_INVALID_SET(&mc->mc_conns[candidate]); 1404 1.1 christos } 1405 1.1 christos 1406 1.1 christos if (mc->pending_ops <= 0) { 1407 1.1 christos ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex ); 1408 1.1 christos return LDAP_SUCCESS; 1409 1.1 christos } 1410 1.1 christos 1411 1.1 christos for (bc = LDAP_STAILQ_FIRST(&mc->mc_om_list); bc; bc = onext) { 1412 1.1 christos onext = LDAP_STAILQ_NEXT(bc, bc_next); 1413 1.1 christos cleanup = 0; 1414 1.1 christos candidates = bc->candidates; 1415 1.1 christos /* was this op affected? */ 1416 1.1 christos if ( !META_IS_CANDIDATE( &candidates[ candidate ] ) ) 1417 1.1 christos continue; 1418 1.1 christos 1419 1.1 christos if (bc->op->o_abandon) { 1420 1.1 christos bc->bc_invalid = 1; 1421 1.1 christos continue; 1422 1.1 christos } 1423 1.1 christos 1424 1.1 christos if (bc->bc_active > 0) { 1425 1.1 christos bc->bc_invalid = 1; 1426 1.1 christos continue; 1427 1.1 christos } 1428 1.1 christos 1429 1.1 christos bc->op->o_threadctx = ctx; 1430 1.1 christos bc->op->o_tid = ldap_pvt_thread_pool_tid( ctx ); 1431 1.1 christos slap_sl_mem_setctx(ctx, bc->op->o_tmpmemctx); 1432 1.3 christos operation_counter_init( bc->op, ctx ); 1433 1.1 christos 1434 1.1 christos op = bc->op; 1435 1.1 christos rs = &bc->rs; 1436 1.1 christos switch (op->o_tag) { 1437 1.1 christos case LDAP_REQ_ADD: 1438 1.1 christos case LDAP_REQ_MODIFY: 1439 1.1 christos case LDAP_REQ_MODRDN: 1440 1.1 christos case LDAP_REQ_COMPARE: 1441 1.1 christos case LDAP_REQ_DELETE: 1442 1.1 christos rs->sr_err = LDAP_UNAVAILABLE; 1443 1.1 christos rs->sr_text = "Read error on connection to target"; 1444 1.1 christos asyncmeta_send_ldap_result( bc, op, rs ); 1445 1.1 christos cleanup = 1; 1446 1.1 christos break; 1447 1.1 christos case LDAP_REQ_SEARCH: 1448 1.1 christos { 1449 1.1 christos a_metainfo_t *mi = mc->mc_info; 1450 1.1 christos rs->sr_err = LDAP_UNAVAILABLE; 1451 1.1 christos rs->sr_text = "Read error on connection to target"; 1452 1.1 christos candidates[ candidate ].sr_msgid = META_MSGID_IGNORE; 1453 1.1 christos candidates[ candidate ].sr_type = REP_RESULT; 1454 1.1 christos if ( (META_BACK_ONERR_STOP( mi ) || 1455 1.1 christos asyncmeta_is_last_result(mc, bc, candidate)) && op->o_conn) { 1456 1.1 christos asyncmeta_send_ldap_result( bc, op, rs ); 1457 1.1 christos cleanup = 1; 1458 1.1 christos } 1459 1.1 christos } 1460 1.1 christos break; 1461 1.1 christos default: 1462 1.1 christos break; 1463 1.1 christos } 1464 1.1 christos 1465 1.1 christos if (cleanup) { 1466 1.1 christos int j; 1467 1.1 christos a_metainfo_t *mi = mc->mc_info; 1468 1.1 christos for (j=0; j<mi->mi_ntargets; j++) { 1469 1.1 christos if (j != candidate && bc->candidates[j].sr_msgid >= 0 1470 1.1 christos && mc->mc_conns[j].msc_ld != NULL) { 1471 1.1 christos asyncmeta_back_cancel( mc, op, 1472 1.1 christos bc->candidates[ j ].sr_msgid, j ); 1473 1.1 christos } 1474 1.1 christos } 1475 1.1 christos LDAP_STAILQ_REMOVE(&mc->mc_om_list, bc, bm_context_t, bc_next); 1476 1.1 christos mc->pending_ops--; 1477 1.1 christos asyncmeta_clear_bm_context(bc); 1478 1.1 christos } 1479 1.1 christos } 1480 1.1 christos ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex ); 1481 1.1 christos return LDAP_SUCCESS; 1482 1.1 christos } 1483 1.1 christos 1484 1.1 christos void * 1485 1.1 christos asyncmeta_op_handle_result(void *ctx, void *arg) 1486 1.1 christos { 1487 1.1 christos a_metaconn_t *mc = arg; 1488 1.1 christos int i, j, rc, ntargets; 1489 1.1 christos struct timeval tv = {0}; 1490 1.1 christos LDAPMessage *msg; 1491 1.1 christos a_metasingleconn_t *msc; 1492 1.1 christos bm_context_t *bc; 1493 1.1 christos void *oldctx; 1494 1.1 christos 1495 1.3 christos /* exit if the database is disabled, this will let timeout_loop 1496 1.3 christos * do it's job faster */ 1497 1.3 christos if ( mc->mc_info->mi_disabled > 0 ) 1498 1.3 christos return NULL; 1499 1.3 christos 1500 1.1 christos ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex ); 1501 1.1 christos rc = ++mc->mc_active; 1502 1.1 christos ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex ); 1503 1.1 christos if (rc > 1) 1504 1.1 christos return NULL; 1505 1.1 christos 1506 1.1 christos ntargets = mc->mc_info->mi_ntargets; 1507 1.1 christos i = ntargets; 1508 1.1 christos oldctx = slap_sl_mem_create(SLAP_SLAB_SIZE, SLAP_SLAB_STACK, ctx, 0); /* get existing memctx */ 1509 1.1 christos 1510 1.1 christos again: 1511 1.1 christos for (j=0; j<ntargets; j++) { 1512 1.1 christos i++; 1513 1.1 christos if (i >= ntargets) i = 0; 1514 1.1 christos msc = &mc->mc_conns[i]; 1515 1.1 christos ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex ); 1516 1.1 christos if (!mc->mc_conns[i].msc_ldr || 1517 1.1 christos META_BACK_CONN_CREATING( &mc->mc_conns[i] ) || 1518 1.1 christos META_BACK_CONN_INVALID(&mc->mc_conns[i])) { 1519 1.1 christos ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex ); 1520 1.1 christos continue; 1521 1.1 christos } 1522 1.1 christos 1523 1.1 christos msc->msc_active++; 1524 1.1 christos ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex ); 1525 1.1 christos 1526 1.1 christos rc = ldap_result( mc->mc_conns[i].msc_ldr, LDAP_RES_ANY, LDAP_MSG_RECEIVED, &tv, &msg ); 1527 1.1 christos if (rc < 1) { 1528 1.1 christos if (rc < 0) { 1529 1.1 christos ldap_get_option( mc->mc_conns[i].msc_ldr, LDAP_OPT_ERROR_NUMBER, &rc); 1530 1.1 christos META_BACK_CONN_INVALID_SET(&mc->mc_conns[i]); 1531 1.1 christos asyncmeta_op_read_error(mc, i, rc, ctx); 1532 1.1 christos } 1533 1.1 christos ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex ); 1534 1.1 christos msc->msc_active--; 1535 1.1 christos ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex ); 1536 1.1 christos continue; 1537 1.1 christos } 1538 1.1 christos rc = ldap_msgtype( msg ); 1539 1.1 christos if (rc == LDAP_RES_BIND) { 1540 1.1 christos if ( LogTest( asyncmeta_debug ) ) { 1541 1.1 christos char time_buf[ SLAP_TEXT_BUFLEN ]; 1542 1.1 christos asyncmeta_get_timestamp(time_buf); 1543 1.1 christos Debug( asyncmeta_debug, "[%s] asyncmeta_op_handle_result received bind msgid=%d msc: %p\n", 1544 1.1 christos time_buf, ldap_msgid(msg), msc ); 1545 1.1 christos } 1546 1.1 christos asyncmeta_handle_bind_result(msg, mc, i, ctx); 1547 1.1 christos mc->mc_info->mi_targets[i]->mt_timeout_ops = 0; 1548 1.1 christos ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex ); 1549 1.1 christos msc->msc_result_time = slap_get_time(); 1550 1.1 christos msc->msc_active--; 1551 1.1 christos ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex ); 1552 1.1 christos if (msg) 1553 1.1 christos ldap_msgfree(msg); 1554 1.1 christos 1555 1.1 christos continue; 1556 1.1 christos } 1557 1.1 christos retry_bc: 1558 1.1 christos ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex ); 1559 1.1 christos bc = asyncmeta_find_message(ldap_msgid(msg), mc, i); 1560 1.1 christos /* The sender might not be yet done with the context. On error it might also remove it 1561 1.1 christos * so it's best to try and find it again after a wait */ 1562 1.1 christos if (bc && bc->bc_active > 0) { 1563 1.1 christos ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex ); 1564 1.1 christos ldap_pvt_thread_yield(); 1565 1.1 christos goto retry_bc; 1566 1.1 christos } 1567 1.1 christos if (bc) { 1568 1.1 christos bc->bc_active++; 1569 1.1 christos } 1570 1.1 christos 1571 1.1 christos msc->msc_result_time = slap_get_time(); 1572 1.1 christos msc->msc_active--; 1573 1.1 christos ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex ); 1574 1.1 christos if (!bc) { 1575 1.1 christos Debug( asyncmeta_debug, 1576 1.1 christos "asyncmeta_op_handle_result: Unable to find bc for msguid %d, msc: %p\n", ldap_msgid(msg), msc ); 1577 1.1 christos ldap_msgfree(msg); 1578 1.1 christos continue; 1579 1.1 christos } 1580 1.1 christos 1581 1.1 christos /* set our memctx */ 1582 1.1 christos bc->op->o_threadctx = ctx; 1583 1.1 christos bc->op->o_tid = ldap_pvt_thread_pool_tid( ctx ); 1584 1.1 christos slap_sl_mem_setctx(ctx, bc->op->o_tmpmemctx); 1585 1.3 christos operation_counter_init( bc->op, ctx ); 1586 1.1 christos if (bc->op->o_abandon) { 1587 1.1 christos ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex ); 1588 1.1 christos asyncmeta_drop_bc( mc, bc); 1589 1.1 christos if ( bc->op->o_tag == LDAP_REQ_SEARCH ) { 1590 1.1 christos int j; 1591 1.1 christos for (j=0; j<ntargets; j++) { 1592 1.1 christos if (bc->candidates[j].sr_msgid >= 0) { 1593 1.1 christos a_metasingleconn_t *tmp_msc = &mc->mc_conns[j]; 1594 1.1 christos tmp_msc->msc_active++; 1595 1.1 christos asyncmeta_back_cancel( mc, bc->op, 1596 1.1 christos bc->candidates[ j ].sr_msgid, j ); 1597 1.1 christos tmp_msc->msc_active--; 1598 1.1 christos } 1599 1.1 christos } 1600 1.1 christos } 1601 1.1 christos asyncmeta_clear_bm_context(bc); 1602 1.1 christos ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex ); 1603 1.1 christos if (msg) 1604 1.1 christos ldap_msgfree(msg); 1605 1.1 christos continue; 1606 1.1 christos } 1607 1.1 christos 1608 1.1 christos switch (rc) { 1609 1.1 christos case LDAP_RES_SEARCH_ENTRY: 1610 1.1 christos case LDAP_RES_SEARCH_REFERENCE: 1611 1.1 christos case LDAP_RES_SEARCH_RESULT: 1612 1.1 christos case LDAP_RES_INTERMEDIATE: 1613 1.1 christos asyncmeta_handle_search_msg(msg, mc, bc, i); 1614 1.1 christos mc->mc_info->mi_targets[i]->mt_timeout_ops = 0; 1615 1.1 christos msg = NULL; 1616 1.1 christos break; 1617 1.1 christos case LDAP_RES_ADD: 1618 1.1 christos case LDAP_RES_DELETE: 1619 1.1 christos case LDAP_RES_MODDN: 1620 1.1 christos case LDAP_RES_COMPARE: 1621 1.1 christos case LDAP_RES_MODIFY: 1622 1.1 christos rc = asyncmeta_handle_common_result(msg, mc, bc, i); 1623 1.1 christos mc->mc_info->mi_targets[i]->mt_timeout_ops = 0; 1624 1.1 christos break; 1625 1.1 christos default: 1626 1.1 christos { 1627 1.1 christos Debug( asyncmeta_debug, 1628 1.1 christos "asyncmeta_op_handle_result: " 1629 1.1 christos "unrecognized response message tag=%d\n", 1630 1.1 christos rc ); 1631 1.1 christos 1632 1.1 christos } 1633 1.1 christos } 1634 1.1 christos if (msg) 1635 1.1 christos ldap_msgfree(msg); 1636 1.1 christos } 1637 1.1 christos 1638 1.1 christos ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex ); 1639 1.1 christos rc = --mc->mc_active; 1640 1.1 christos if (rc) { 1641 1.1 christos i++; 1642 1.1 christos ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex ); 1643 1.1 christos goto again; 1644 1.1 christos } 1645 1.1 christos slap_sl_mem_setctx(ctx, oldctx); 1646 1.1 christos if (mc->mc_conns) { 1647 1.1 christos for (i=0; i<ntargets; i++) { 1648 1.1 christos if (!slapd_shutdown && !META_BACK_CONN_INVALID(msc) 1649 1.1 christos && mc->mc_conns[i].msc_ldr && mc->mc_conns[i].conn) { 1650 1.1 christos connection_client_enable(mc->mc_conns[i].conn); 1651 1.1 christos } 1652 1.1 christos } 1653 1.1 christos } 1654 1.1 christos ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex ); 1655 1.1 christos return NULL; 1656 1.1 christos } 1657 1.1 christos 1658 1.1 christos void asyncmeta_set_msc_time(a_metasingleconn_t *msc) 1659 1.1 christos { 1660 1.1 christos msc->msc_time = slap_get_time(); 1661 1.1 christos } 1662 1.1 christos 1663 1.1 christos void* asyncmeta_timeout_loop(void *ctx, void *arg) 1664 1.1 christos { 1665 1.1 christos struct re_s* rtask = arg; 1666 1.1 christos a_metainfo_t *mi = rtask->arg; 1667 1.1 christos bm_context_t *bc, *onext; 1668 1.1 christos time_t current_time = slap_get_time(); 1669 1.1 christos int i, j; 1670 1.1 christos LDAP_STAILQ_HEAD(BCList, bm_context_t) timeout_list; 1671 1.1 christos LDAP_STAILQ_INIT( &timeout_list ); 1672 1.1 christos 1673 1.1 christos Debug( asyncmeta_debug, "asyncmeta_timeout_loop[%p] start at [%ld] \n", rtask, current_time ); 1674 1.3 christos if ( mi->mi_disabled > 0 && asyncmeta_db_has_pending_ops( mi ) == 0 ) { 1675 1.3 christos Debug( asyncmeta_debug, "asyncmeta_timeout_loop[%p] database disabled, clearing connections [%ld] \n", rtask, current_time ); 1676 1.3 christos ldap_pvt_thread_mutex_lock( &mi->mi_mc_mutex ); 1677 1.3 christos asyncmeta_back_clear_miconns( mi ); 1678 1.3 christos mi->mi_task = NULL; 1679 1.3 christos ldap_pvt_thread_mutex_unlock( &mi->mi_mc_mutex ); 1680 1.3 christos return NULL; 1681 1.3 christos } 1682 1.1 christos void *oldctx = slap_sl_mem_create(SLAP_SLAB_SIZE, SLAP_SLAB_STACK, ctx, 0); 1683 1.1 christos for (i=0; i<mi->mi_num_conns; i++) { 1684 1.1 christos a_metaconn_t * mc= &mi->mi_conns[i]; 1685 1.1 christos ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex ); 1686 1.1 christos for (bc = LDAP_STAILQ_FIRST(&mc->mc_om_list); bc; bc = onext) { 1687 1.1 christos onext = LDAP_STAILQ_NEXT(bc, bc_next); 1688 1.1 christos if (bc->bc_active > 0) { 1689 1.1 christos continue; 1690 1.1 christos } 1691 1.1 christos 1692 1.3 christos if (mi->mi_disabled > 0) { 1693 1.3 christos bc->bc_invalid = 1; 1694 1.3 christos } 1695 1.3 christos 1696 1.1 christos if (bc->op->o_abandon ) { 1697 1.1 christos Operation *op = bc->op; 1698 1.1 christos 1699 1.3 christos /* set our memctx */ 1700 1.3 christos op->o_threadctx = ctx; 1701 1.3 christos op->o_tid = ldap_pvt_thread_pool_tid( ctx ); 1702 1.3 christos slap_sl_mem_setctx(ctx, op->o_tmpmemctx); 1703 1.3 christos operation_counter_init( op, ctx ); 1704 1.3 christos 1705 1.1 christos LDAP_STAILQ_REMOVE(&mc->mc_om_list, bc, bm_context_t, bc_next); 1706 1.1 christos mc->pending_ops--; 1707 1.1 christos for (j=0; j<mi->mi_ntargets; j++) { 1708 1.1 christos if (bc->candidates[j].sr_msgid >= 0) { 1709 1.1 christos a_metasingleconn_t *msc = &mc->mc_conns[j]; 1710 1.1 christos if ( op->o_tag == LDAP_REQ_SEARCH ) { 1711 1.1 christos msc->msc_active++; 1712 1.1 christos asyncmeta_back_cancel( mc, op, 1713 1.1 christos bc->candidates[ j ].sr_msgid, j ); 1714 1.1 christos msc->msc_active--; 1715 1.1 christos } 1716 1.1 christos } 1717 1.1 christos } 1718 1.1 christos asyncmeta_clear_bm_context(bc); 1719 1.1 christos continue; 1720 1.1 christos } 1721 1.1 christos if (bc->bc_invalid) { 1722 1.1 christos LDAP_STAILQ_REMOVE(&mc->mc_om_list, bc, bm_context_t, bc_next); 1723 1.1 christos mc->pending_ops--; 1724 1.1 christos LDAP_STAILQ_INSERT_TAIL( &timeout_list, bc, bc_next); 1725 1.1 christos continue; 1726 1.1 christos } 1727 1.1 christos 1728 1.1 christos if (bc->timeout && bc->stoptime < current_time) { 1729 1.1 christos Operation *op = bc->op; 1730 1.1 christos LDAP_STAILQ_REMOVE(&mc->mc_om_list, bc, bm_context_t, bc_next); 1731 1.1 christos mc->pending_ops--; 1732 1.1 christos LDAP_STAILQ_INSERT_TAIL( &timeout_list, bc, bc_next); 1733 1.1 christos for (j=0; j<mi->mi_ntargets; j++) { 1734 1.1 christos if (bc->candidates[j].sr_msgid >= 0) { 1735 1.1 christos a_metasingleconn_t *msc = &mc->mc_conns[j]; 1736 1.1 christos asyncmeta_set_msc_time(msc); 1737 1.1 christos if ( op->o_tag == LDAP_REQ_SEARCH ) { 1738 1.1 christos msc->msc_active++; 1739 1.1 christos asyncmeta_back_cancel( mc, op, 1740 1.1 christos bc->candidates[ j ].sr_msgid, j ); 1741 1.1 christos msc->msc_active--; 1742 1.1 christos } 1743 1.1 christos } 1744 1.1 christos } 1745 1.1 christos } 1746 1.1 christos } 1747 1.1 christos ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex ); 1748 1.1 christos 1749 1.1 christos for (bc = LDAP_STAILQ_FIRST(&timeout_list); bc; bc = onext) { 1750 1.1 christos Operation *op = bc->op; 1751 1.1 christos SlapReply *rs = &bc->rs; 1752 1.1 christos int timeout_err; 1753 1.1 christos const char *timeout_text; 1754 1.1 christos 1755 1.1 christos onext = LDAP_STAILQ_NEXT(bc, bc_next); 1756 1.1 christos LDAP_STAILQ_REMOVE(&timeout_list, bc, bm_context_t, bc_next); 1757 1.1 christos /* set our memctx */ 1758 1.1 christos bc->op->o_threadctx = ctx; 1759 1.1 christos bc->op->o_tid = ldap_pvt_thread_pool_tid( ctx ); 1760 1.1 christos slap_sl_mem_setctx(ctx, bc->op->o_tmpmemctx); 1761 1.3 christos operation_counter_init( bc->op, ctx ); 1762 1.1 christos 1763 1.1 christos if (bc->searchtime) { 1764 1.1 christos timeout_err = LDAP_TIMELIMIT_EXCEEDED; 1765 1.1 christos } else { 1766 1.1 christos timeout_err = op->o_protocol >= LDAP_VERSION3 ? 1767 1.1 christos LDAP_ADMINLIMIT_EXCEEDED : LDAP_OTHER; 1768 1.1 christos } 1769 1.1 christos 1770 1.1 christos if ( bc->bc_invalid ) { 1771 1.1 christos timeout_text = "Operation is invalid - target connection has been reset"; 1772 1.1 christos } else { 1773 1.1 christos a_metasingleconn_t *log_msc = &mc->mc_conns[0]; 1774 1.1 christos Debug( asyncmeta_debug, 1775 1.1 christos "asyncmeta_timeout_loop:Timeout op %s loop[%p], " 1776 1.1 christos "current_time:%ld, op->o_time:%ld msc: %p, " 1777 1.1 christos "msc->msc_binding_time: %x, msc->msc_flags:%x \n", 1778 1.1 christos bc->op->o_log_prefix, rtask, current_time, bc->op->o_time, 1779 1.1 christos log_msc, (unsigned int)log_msc->msc_binding_time, log_msc->msc_mscflags ); 1780 1.1 christos 1781 1.1 christos if (bc->searchtime) { 1782 1.1 christos timeout_text = NULL; 1783 1.1 christos } else { 1784 1.1 christos timeout_text = "Operation timed out"; 1785 1.1 christos } 1786 1.1 christos 1787 1.1 christos for (j=0; j<mi->mi_ntargets; j++) { 1788 1.1 christos if (bc->candidates[j].sr_msgid >= 0) { 1789 1.1 christos a_metatarget_t *mt = mi->mi_targets[j]; 1790 1.1 christos if (!META_BACK_TGT_QUARANTINE( mt ) || 1791 1.1 christos bc->candidates[j].sr_type == REP_RESULT) { 1792 1.1 christos continue; 1793 1.1 christos } 1794 1.1 christos 1795 1.1 christos if (mt->mt_isquarantined > LDAP_BACK_FQ_NO) { 1796 1.1 christos timeout_err = LDAP_UNAVAILABLE; 1797 1.1 christos } else { 1798 1.1 christos mt->mt_timeout_ops++; 1799 1.1 christos if ((mi->mi_max_timeout_ops > 0) && 1800 1.1 christos (mt->mt_timeout_ops > mi->mi_max_timeout_ops)) { 1801 1.1 christos timeout_err = LDAP_UNAVAILABLE; 1802 1.1 christos rs->sr_err = timeout_err; 1803 1.1 christos if (mt->mt_isquarantined == LDAP_BACK_FQ_NO) 1804 1.1 christos asyncmeta_quarantine(op, mi, rs, j); 1805 1.1 christos } 1806 1.1 christos } 1807 1.1 christos } 1808 1.1 christos } 1809 1.1 christos } 1810 1.1 christos rs->sr_err = timeout_err; 1811 1.1 christos rs->sr_text = timeout_text; 1812 1.1 christos if (!bc->op->o_abandon ) { 1813 1.1 christos asyncmeta_send_ldap_result( bc, bc->op, &bc->rs ); 1814 1.1 christos } 1815 1.1 christos asyncmeta_clear_bm_context(bc); 1816 1.1 christos } 1817 1.1 christos 1818 1.1 christos ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex ); 1819 1.1 christos if (mi->mi_idle_timeout) { 1820 1.1 christos for (j=0; j<mi->mi_ntargets; j++) { 1821 1.1 christos a_metasingleconn_t *msc = &mc->mc_conns[j]; 1822 1.1 christos if ( msc->msc_active > 0 ) { 1823 1.1 christos continue; 1824 1.1 christos } 1825 1.1 christos if (mc->pending_ops > 0) { 1826 1.1 christos continue; 1827 1.1 christos } 1828 1.1 christos current_time = slap_get_time(); 1829 1.1 christos if (msc->msc_ld && msc->msc_time > 0 && msc->msc_time + mi->mi_idle_timeout < current_time) { 1830 1.1 christos asyncmeta_clear_one_msc(NULL, mc, j, 1, __FUNCTION__); 1831 1.1 christos } 1832 1.1 christos } 1833 1.1 christos } 1834 1.1 christos ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex ); 1835 1.1 christos } 1836 1.1 christos 1837 1.1 christos slap_sl_mem_setctx(ctx, oldctx); 1838 1.1 christos current_time = slap_get_time(); 1839 1.1 christos Debug( asyncmeta_debug, "asyncmeta_timeout_loop[%p] stop at [%ld] \n", rtask, current_time ); 1840 1.1 christos ldap_pvt_thread_mutex_lock( &slapd_rq.rq_mutex ); 1841 1.1 christos if ( ldap_pvt_runqueue_isrunning( &slapd_rq, rtask )) { 1842 1.1 christos ldap_pvt_runqueue_stoptask( &slapd_rq, rtask ); 1843 1.1 christos } 1844 1.1 christos ldap_pvt_thread_mutex_unlock( &slapd_rq.rq_mutex ); 1845 1.1 christos return NULL; 1846 1.1 christos } 1847 1.1 christos 1848