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