Operation * slap_op_alloc( BerElement *ber, ber_int_t msgid, ber_tag_t tag, ber_int_t id ) { Operation *op; ldap_pvt_thread_mutex_lock( &slap_op_mutex ); if (op = LDAP_STAILQ_FIRST( &slap_free_ops )) { LDAP_STAILQ_REMOVE_HEAD( &slap_free_ops, o_next ); } ldap_pvt_thread_mutex_unlock( &slap_op_mutex ); if (!op) op = (Operation *) ch_calloc( 1, sizeof(Operation) ); op->o_ber = ber; op->o_msgid = msgid; op->o_tag = tag; op->o_time = slap_get_time(); op->o_opid = id; #ifdef LDAP_CONNECTIONLESS op->o_res_ber = NULL; #endif #if defined( LDAP_SLAPI ) op->o_pb = slapi_pblock_new(); #endif /* defined( LDAP_SLAPI ) */ return( op ); }
void slap_op_destroy(void) { Operation *o; while ( (o = LDAP_STAILQ_FIRST( &slap_free_ops )) != NULL) { LDAP_STAILQ_REMOVE_HEAD( &slap_free_ops, o_next ); LDAP_STAILQ_NEXT(o, o_next) = NULL; ch_free( o ); } ldap_pvt_thread_mutex_destroy( &slap_op_mutex ); }
meta_search_candidate_t asyncmeta_send_all_pending_ops(a_metaconn_t *mc, int candidate, void *ctx, int dolock) { a_metainfo_t *mi = mc->mc_info; bm_context_t *bc, *onext; a_metasingleconn_t *msc = &mc->mc_conns[candidate]; if ( dolock ) ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex ); msc->msc_active++; for (bc = LDAP_STAILQ_FIRST(&mc->mc_om_list); bc; bc = onext) { meta_search_candidate_t ret; onext = LDAP_STAILQ_NEXT(bc, bc_next); if (bc->candidates[candidate].sr_msgid != META_MSGID_NEED_BIND || bc->bc_active > 0 || bc->op->o_abandon > 0) { continue; } bc->op->o_threadctx = ctx; bc->op->o_tid = ldap_pvt_thread_pool_tid( ctx ); slap_sl_mem_setctx(ctx, bc->op->o_tmpmemctx); bc->bc_active++; ret = asyncmeta_send_pending_op(bc, candidate); if (ret != META_SEARCH_CANDIDATE) { bc->candidates[ candidate ].sr_msgid = META_MSGID_IGNORE; bc->candidates[ candidate ].sr_type = REP_RESULT; bc->candidates[ candidate ].sr_err = bc->rs.sr_err; if (bc->op->o_tag != LDAP_REQ_SEARCH || (META_BACK_ONERR_STOP( mi )) || (asyncmeta_is_last_result(mc, bc, candidate) == 0)) { LDAP_STAILQ_REMOVE(&mc->mc_om_list, bc, bm_context_t, bc_next); mc->pending_ops--; asyncmeta_send_ldap_result(bc, bc->op, &bc->rs); asyncmeta_clear_bm_context(bc); } } else { bc->bc_active--; } } msc->msc_active--; if ( dolock ) ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex ); return META_SEARCH_CANDIDATE; }
void* asyncmeta_timeout_loop(void *ctx, void *arg) { struct re_s* rtask = arg; a_metainfo_t *mi = rtask->arg; bm_context_t *bc, *onext; time_t current_time = slap_get_time(); int i, j; LDAP_STAILQ_HEAD(BCList, bm_context_t) timeout_list; LDAP_STAILQ_INIT( &timeout_list ); Debug( asyncmeta_debug, "asyncmeta_timeout_loop[%p] start at [%ld] \n", rtask, current_time ); void *oldctx = slap_sl_mem_create(SLAP_SLAB_SIZE, SLAP_SLAB_STACK, ctx, 0); for (i=0; i<mi->mi_num_conns; i++) { a_metaconn_t * mc= &mi->mi_conns[i]; ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex ); for (bc = LDAP_STAILQ_FIRST(&mc->mc_om_list); bc; bc = onext) { onext = LDAP_STAILQ_NEXT(bc, bc_next); if (bc->bc_active > 0) { continue; } if (bc->op->o_abandon ) { /* set our memctx */ bc->op->o_threadctx = ctx; bc->op->o_tid = ldap_pvt_thread_pool_tid( ctx ); slap_sl_mem_setctx(ctx, bc->op->o_tmpmemctx); Operation *op = bc->op; LDAP_STAILQ_REMOVE(&mc->mc_om_list, bc, bm_context_t, bc_next); mc->pending_ops--; for (j=0; j<mi->mi_ntargets; j++) { if (bc->candidates[j].sr_msgid >= 0) { a_metasingleconn_t *msc = &mc->mc_conns[j]; if ( op->o_tag == LDAP_REQ_SEARCH ) { msc->msc_active++; asyncmeta_back_cancel( mc, op, bc->candidates[ j ].sr_msgid, j ); msc->msc_active--; } } } asyncmeta_clear_bm_context(bc); continue; } if (bc->bc_invalid) { LDAP_STAILQ_REMOVE(&mc->mc_om_list, bc, bm_context_t, bc_next); mc->pending_ops--; LDAP_STAILQ_INSERT_TAIL( &timeout_list, bc, bc_next); continue; } if (bc->timeout && bc->stoptime < current_time) { Operation *op = bc->op; LDAP_STAILQ_REMOVE(&mc->mc_om_list, bc, bm_context_t, bc_next); mc->pending_ops--; LDAP_STAILQ_INSERT_TAIL( &timeout_list, bc, bc_next); for (j=0; j<mi->mi_ntargets; j++) { if (bc->candidates[j].sr_msgid >= 0) { a_metasingleconn_t *msc = &mc->mc_conns[j]; asyncmeta_set_msc_time(msc); if ( op->o_tag == LDAP_REQ_SEARCH ) { msc->msc_active++; asyncmeta_back_cancel( mc, op, bc->candidates[ j ].sr_msgid, j ); msc->msc_active--; } } } } } ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex ); for (bc = LDAP_STAILQ_FIRST(&timeout_list); bc; bc = onext) { Operation *op = bc->op; SlapReply *rs = &bc->rs; int timeout_err; const char *timeout_text; onext = LDAP_STAILQ_NEXT(bc, bc_next); LDAP_STAILQ_REMOVE(&timeout_list, bc, bm_context_t, bc_next); /* set our memctx */ bc->op->o_threadctx = ctx; bc->op->o_tid = ldap_pvt_thread_pool_tid( ctx ); slap_sl_mem_setctx(ctx, bc->op->o_tmpmemctx); if (bc->searchtime) { timeout_err = LDAP_TIMELIMIT_EXCEEDED; } else { timeout_err = op->o_protocol >= LDAP_VERSION3 ? LDAP_ADMINLIMIT_EXCEEDED : LDAP_OTHER; } if ( bc->bc_invalid ) { timeout_text = "Operation is invalid - target connection has been reset"; } else { a_metasingleconn_t *log_msc = &mc->mc_conns[0]; Debug( asyncmeta_debug, "asyncmeta_timeout_loop:Timeout op %s loop[%p], " "current_time:%ld, op->o_time:%ld msc: %p, " "msc->msc_binding_time: %x, msc->msc_flags:%x \n", bc->op->o_log_prefix, rtask, current_time, bc->op->o_time, log_msc, (unsigned int)log_msc->msc_binding_time, log_msc->msc_mscflags ); if (bc->searchtime) { timeout_text = NULL; } else { timeout_text = "Operation timed out"; } for (j=0; j<mi->mi_ntargets; j++) { if (bc->candidates[j].sr_msgid >= 0) { a_metatarget_t *mt = mi->mi_targets[j]; if (!META_BACK_TGT_QUARANTINE( mt ) || bc->candidates[j].sr_type == REP_RESULT) { continue; } if (mt->mt_isquarantined > LDAP_BACK_FQ_NO) { timeout_err = LDAP_UNAVAILABLE; } else { mt->mt_timeout_ops++; if ((mi->mi_max_timeout_ops > 0) && (mt->mt_timeout_ops > mi->mi_max_timeout_ops)) { timeout_err = LDAP_UNAVAILABLE; rs->sr_err = timeout_err; if (mt->mt_isquarantined == LDAP_BACK_FQ_NO) asyncmeta_quarantine(op, mi, rs, j); } } } } } rs->sr_err = timeout_err; rs->sr_text = timeout_text; if (!bc->op->o_abandon ) { asyncmeta_send_ldap_result( bc, bc->op, &bc->rs ); } asyncmeta_clear_bm_context(bc); } ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex ); if (mi->mi_idle_timeout) { for (j=0; j<mi->mi_ntargets; j++) { a_metasingleconn_t *msc = &mc->mc_conns[j]; if ( msc->msc_active > 0 ) { continue; } if (mc->pending_ops > 0) { continue; } current_time = slap_get_time(); if (msc->msc_ld && msc->msc_time > 0 && msc->msc_time + mi->mi_idle_timeout < current_time) { asyncmeta_clear_one_msc(NULL, mc, j, 1, __FUNCTION__); } } } ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex ); } slap_sl_mem_setctx(ctx, oldctx); current_time = slap_get_time(); Debug( asyncmeta_debug, "asyncmeta_timeout_loop[%p] stop at [%ld] \n", rtask, current_time ); ldap_pvt_thread_mutex_lock( &slapd_rq.rq_mutex ); if ( ldap_pvt_runqueue_isrunning( &slapd_rq, rtask )) { ldap_pvt_runqueue_stoptask( &slapd_rq, rtask ); } rtask->interval.tv_sec = 1; rtask->interval.tv_usec = 0; ldap_pvt_runqueue_resched(&slapd_rq, rtask, 0); ldap_pvt_thread_mutex_unlock( &slapd_rq.rq_mutex ); return NULL; }
/* This takes care to clean out the outbound queue in case we have a read error * sending back responses to the client */ int asyncmeta_op_read_error(a_metaconn_t *mc, int candidate, int error, void* ctx) { bm_context_t *bc, *onext; int cleanup; Operation *op; SlapReply *rs; SlapReply *candidates; /* no outstanding ops, nothing to do but log */ Debug( LDAP_DEBUG_TRACE, "asyncmeta_op_read_error: ldr=%p\n", mc->mc_conns[candidate].msc_ldr ); ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex ); /*someone may be trying to write */ if (mc->mc_conns[candidate].msc_active <= 1) { asyncmeta_clear_one_msc(NULL, mc, candidate, 0, __FUNCTION__); } else { META_BACK_CONN_INVALID_SET(&mc->mc_conns[candidate]); } if (mc->pending_ops <= 0) { ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex ); return LDAP_SUCCESS; } for (bc = LDAP_STAILQ_FIRST(&mc->mc_om_list); bc; bc = onext) { onext = LDAP_STAILQ_NEXT(bc, bc_next); cleanup = 0; candidates = bc->candidates; /* was this op affected? */ if ( !META_IS_CANDIDATE( &candidates[ candidate ] ) ) continue; if (bc->op->o_abandon) { bc->bc_invalid = 1; continue; } if (bc->bc_active > 0) { continue; } bc->op->o_threadctx = ctx; bc->op->o_tid = ldap_pvt_thread_pool_tid( ctx ); slap_sl_mem_setctx(ctx, bc->op->o_tmpmemctx); op = bc->op; rs = &bc->rs; switch (op->o_tag) { case LDAP_REQ_ADD: case LDAP_REQ_MODIFY: case LDAP_REQ_MODRDN: case LDAP_REQ_COMPARE: case LDAP_REQ_DELETE: rs->sr_err = LDAP_UNAVAILABLE; rs->sr_text = "Read error on connection to target"; asyncmeta_send_ldap_result( bc, op, rs ); cleanup = 1; break; case LDAP_REQ_SEARCH: { a_metainfo_t *mi = mc->mc_info; rs->sr_err = LDAP_UNAVAILABLE; rs->sr_text = "Read error on connection to target"; candidates[ candidate ].sr_msgid = META_MSGID_IGNORE; candidates[ candidate ].sr_type = REP_RESULT; if ( (META_BACK_ONERR_STOP( mi ) || asyncmeta_is_last_result(mc, bc, candidate)) && op->o_conn) { asyncmeta_send_ldap_result( bc, op, rs ); cleanup = 1; } } break; default: break; } if (cleanup) { int j; a_metainfo_t *mi = mc->mc_info; for (j=0; j<mi->mi_ntargets; j++) { if (j != candidate && bc->candidates[j].sr_msgid >= 0 && mc->mc_conns[j].msc_ld != NULL) { asyncmeta_back_cancel( mc, op, bc->candidates[ j ].sr_msgid, j ); } } LDAP_STAILQ_REMOVE(&mc->mc_om_list, bc, bm_context_t, bc_next); mc->pending_ops--; asyncmeta_clear_bm_context(bc); } } ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex ); return LDAP_SUCCESS; }
int starttls_extop ( Operation *op, SlapReply *rs ) { int rc; Statslog( LDAP_DEBUG_STATS, "%s STARTTLS\n", op->o_log_prefix, 0, 0, 0, 0 ); if ( op->ore_reqdata != NULL ) { /* no request data should be provided */ rs->sr_text = "no request data expected"; return LDAP_PROTOCOL_ERROR; } /* acquire connection lock */ ldap_pvt_thread_mutex_lock( &op->o_conn->c_mutex ); /* can't start TLS if it is already started */ if (op->o_conn->c_is_tls != 0) { rs->sr_text = "TLS already started"; rc = LDAP_OPERATIONS_ERROR; goto done; } /* can't start TLS if there are other op's around */ if (( !LDAP_STAILQ_EMPTY(&op->o_conn->c_ops) && (LDAP_STAILQ_FIRST(&op->o_conn->c_ops) != op || LDAP_STAILQ_NEXT(op, o_next) != NULL)) || ( !LDAP_STAILQ_EMPTY(&op->o_conn->c_pending_ops) )) { rs->sr_text = "cannot start TLS when operations are outstanding"; rc = LDAP_OPERATIONS_ERROR; goto done; } if ( !( global_disallows & SLAP_DISALLOW_TLS_2_ANON ) && ( op->o_conn->c_dn.bv_len != 0 ) ) { Statslog( LDAP_DEBUG_STATS, "%s AUTHZ anonymous mech=starttls ssf=0\n", op->o_log_prefix, 0, 0, 0, 0 ); /* force to anonymous */ connection2anonymous( op->o_conn ); } if ( ( global_disallows & SLAP_DISALLOW_TLS_AUTHC ) && ( op->o_conn->c_dn.bv_len != 0 ) ) { rs->sr_text = "cannot start TLS after authentication"; rc = LDAP_OPERATIONS_ERROR; goto done; } /* fail if TLS could not be initialized */ if ( slap_tls_ctx == NULL ) { if (default_referral != NULL) { /* caller will put the referral in the result */ rc = LDAP_REFERRAL; goto done; } rs->sr_text = "Could not initialize TLS"; rc = LDAP_UNAVAILABLE; goto done; } op->o_conn->c_is_tls = 1; op->o_conn->c_needs_tls_accept = 1; rc = LDAP_SUCCESS; done: /* give up connection lock */ ldap_pvt_thread_mutex_unlock( &op->o_conn->c_mutex ); /* FIXME: RACE CONDITION! we give up lock before sending result * Should be resolved by reworking connection state, not * by moving send here (so as to ensure proper TLS sequencing) */ return rc; }