conn.c
来自「ldap服务器源码」· C语言 代码 · 共 1,810 行 · 第 1/3 页
C
1,810 行
* require all connections ... */ if ( op_type == META_OP_REQUIRE_ALL ) { /* Looks like we didn't get a bind. Open a new session... */ if ( mc == NULL ) { assert( new_conn == 0 ); mc = metaconn_alloc( op ); mc->mc_conn = mc_curr.mc_conn; ber_dupbv( &mc->mc_local_ndn, &mc_curr.mc_local_ndn ); new_conn = 1; if ( sendok & LDAP_BACK_BINDING ) { LDAP_BACK_CONN_BINDING_SET( mc ); } if ( LDAP_BACK_CONN_ISPRIV( &mc_curr ) ) { LDAP_BACK_CONN_ISPRIV_SET( mc ); } else if ( LDAP_BACK_CONN_ISANON( &mc_curr ) ) { LDAP_BACK_CONN_ISANON_SET( mc ); } } else if ( 0 ) { /* TODO: if any of the connections is binding, * release mc and create a new one */ } for ( i = 0; i < mi->mi_ntargets; i++ ) { /* * The target is activated; if needed, it is * also init'd */ candidates[ i ].sr_err = meta_back_init_one_conn( op, rs, mc, i, LDAP_BACK_CONN_ISPRIV( &mc_curr ), LDAP_BACK_DONTSEND, !new_conn ); if ( candidates[ i ].sr_err == LDAP_SUCCESS ) { META_CANDIDATE_SET( &candidates[ i ] ); ncandidates++; } else { /* * FIXME: in case one target cannot * be init'd, should the other ones * be tried? */ META_CANDIDATE_RESET( &candidates[ i ] ); err = candidates[ i ].sr_err; continue; } } if ( ncandidates == 0 ) { if ( new_conn ) { mc->mc_refcnt = 0; meta_back_conn_free( mc ); } else { meta_back_release_conn( mi, mc ); } rs->sr_err = LDAP_NO_SUCH_OBJECT; rs->sr_text = "Unable to select valid candidates"; if ( sendok & LDAP_BACK_SENDERR ) { if ( rs->sr_err == LDAP_NO_SUCH_OBJECT ) { rs->sr_matched = op->o_bd->be_suffix[ 0 ].bv_val; } send_ldap_result( op, rs ); rs->sr_matched = NULL; } return NULL; } goto done; } /* * looks in cache, if any */ if ( mi->mi_cache.ttl != META_DNCACHE_DISABLED ) { cached = i = meta_dncache_get_target( &mi->mi_cache, &op->o_req_ndn ); } if ( op_type == META_OP_REQUIRE_SINGLE ) { metatarget_t *mt = NULL; metasingleconn_t *msc = NULL; int j; for ( j = 0; j < mi->mi_ntargets; j++ ) { META_CANDIDATE_RESET( &candidates[ j ] ); } /* * tries to get a unique candidate * (takes care of default target) */ if ( i == META_TARGET_NONE ) { i = meta_back_get_candidate( op, rs, &ndn ); if ( rs->sr_err == LDAP_NO_SUCH_OBJECT && dn_type == META_DNTYPE_PARENT ) { i = meta_back_get_candidate( op, rs, &pndn ); } if ( i < 0 || rs->sr_err != LDAP_SUCCESS ) { if ( mc != NULL ) { meta_back_release_conn( mi, mc ); } if ( sendok & LDAP_BACK_SENDERR ) { if ( rs->sr_err == LDAP_NO_SUCH_OBJECT ) { rs->sr_matched = op->o_bd->be_suffix[ 0 ].bv_val; } send_ldap_result( op, rs ); rs->sr_matched = NULL; } return NULL; } } if ( dn_type == META_DNTYPE_NEWPARENT && meta_back_get_candidate( op, rs, op->orr_nnewSup ) != i ) { if ( mc != NULL ) { meta_back_release_conn( mi, mc ); } rs->sr_err = LDAP_UNWILLING_TO_PERFORM; rs->sr_text = "Cross-target rename not supported"; if ( sendok & LDAP_BACK_SENDERR ) { send_ldap_result( op, rs ); } return NULL; } Debug( LDAP_DEBUG_TRACE, "==>meta_back_getconn: got target=%d for ndn=\"%s\" from cache\n", i, op->o_req_ndn.bv_val, 0 ); if ( mc == NULL ) { /* Retries searching for a metaconn in the avl tree * the reason is that the connection might have been * created by meta_back_get_candidate() */ if ( !( sendok & LDAP_BACK_BINDING ) ) {retry_lock2:; ldap_pvt_thread_mutex_lock( &mi->mi_conninfo.lai_mutex ); mc = (metaconn_t *)avl_find( mi->mi_conninfo.lai_tree, (caddr_t)&mc_curr, meta_back_conndn_cmp ); if ( mc != NULL ) { /* catch taint errors */ assert( !LDAP_BACK_CONN_TAINTED( mc ) ); /* Don't reuse connections while they're still binding */ if ( META_BACK_CONN_CREATING( &mc->mc_conns[ i ] ) || LDAP_BACK_CONN_BINDING( &mc->mc_conns[ i ] ) ) { if ( !LDAP_BACK_USE_TEMPORARIES( mi ) ) { ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex ); ldap_pvt_thread_yield(); goto retry_lock2; } mc = NULL; } else { mc->mc_refcnt++; } } ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex ); } /* Looks like we didn't get a bind. Open a new session... */ if ( mc == NULL ) { assert( new_conn == 0 ); mc = metaconn_alloc( op ); mc->mc_conn = mc_curr.mc_conn; ber_dupbv( &mc->mc_local_ndn, &mc_curr.mc_local_ndn ); new_conn = 1; if ( sendok & LDAP_BACK_BINDING ) { LDAP_BACK_CONN_BINDING_SET( mc ); } if ( LDAP_BACK_CONN_ISPRIV( &mc_curr ) ) { LDAP_BACK_CONN_ISPRIV_SET( mc ); } else if ( LDAP_BACK_CONN_ISANON( &mc_curr ) ) { LDAP_BACK_CONN_ISANON_SET( mc ); } } } /* * Clear all other candidates */ ( void )meta_clear_unused_candidates( op, i ); mt = mi->mi_targets[ i ]; msc = &mc->mc_conns[ i ]; /* * The target is activated; if needed, it is * also init'd. In case of error, meta_back_init_one_conn * sends the appropriate result. */ err = meta_back_init_one_conn( op, rs, mc, i, LDAP_BACK_CONN_ISPRIV( &mc_curr ), sendok, !new_conn ); if ( err != LDAP_SUCCESS ) { /* * FIXME: in case one target cannot * be init'd, should the other ones * be tried? */ META_CANDIDATE_RESET( &candidates[ i ] ); if ( new_conn ) { mc->mc_refcnt = 0; meta_back_conn_free( mc ); } else { meta_back_release_conn( mi, mc ); } return NULL; } candidates[ i ].sr_err = LDAP_SUCCESS; META_CANDIDATE_SET( &candidates[ i ] ); ncandidates++; if ( candidate ) { *candidate = i; } /* * if no unique candidate ... */ } else { /* Looks like we didn't get a bind. Open a new session... */ if ( mc == NULL ) { assert( new_conn == 0 ); mc = metaconn_alloc( op ); mc->mc_conn = mc_curr.mc_conn; ber_dupbv( &mc->mc_local_ndn, &mc_curr.mc_local_ndn ); new_conn = 1; if ( LDAP_BACK_CONN_ISPRIV( &mc_curr ) ) { LDAP_BACK_CONN_ISPRIV_SET( mc ); } else if ( LDAP_BACK_CONN_ISANON( &mc_curr ) ) { LDAP_BACK_CONN_ISANON_SET( mc ); } } for ( i = 0; i < mi->mi_ntargets; i++ ) { metatarget_t *mt = mi->mi_targets[ i ]; META_CANDIDATE_RESET( &candidates[ i ] ); if ( i == cached || meta_back_is_candidate( mt, &op->o_req_ndn, LDAP_SCOPE_SUBTREE ) ) { /* * The target is activated; if needed, it is * also init'd */ int lerr = meta_back_init_one_conn( op, rs, mc, i, LDAP_BACK_CONN_ISPRIV( &mc_curr ), LDAP_BACK_DONTSEND, !new_conn ); candidates[ i ].sr_err = lerr; if ( lerr == LDAP_SUCCESS ) { META_CANDIDATE_SET( &candidates[ i ] ); ncandidates++; Debug( LDAP_DEBUG_TRACE, "%s: meta_back_getconn[%d]\n", op->o_log_prefix, i, 0 ); } else if ( lerr == LDAP_UNAVAILABLE && !META_BACK_ONERR_STOP( mi ) ) { META_CANDIDATE_SET( &candidates[ i ] ); Debug( LDAP_DEBUG_TRACE, "%s: meta_back_getconn[%d] %s\n", op->o_log_prefix, i, mt->mt_isquarantined != LDAP_BACK_FQ_NO ? "quarantined" : "unavailable" ); } else { /* * FIXME: in case one target cannot * be init'd, should the other ones * be tried? */ if ( new_conn ) { ( void )meta_clear_one_candidate( op, mc, i ); } /* leave the target candidate, but record the error for later use */ err = lerr; if ( lerr == LDAP_UNAVAILABLE && mt->mt_isquarantined != LDAP_BACK_FQ_NO ) { Debug( LDAP_DEBUG_TRACE, "%s: meta_back_getconn[%d] quarantined err=%d\n", op->o_log_prefix, i, lerr ); } else { Debug( LDAP_DEBUG_ANY, "%s: meta_back_getconn[%d] failed err=%d\n", op->o_log_prefix, i, lerr ); } if ( META_BACK_ONERR_STOP( mi ) ) { if ( sendok & LDAP_BACK_SENDERR ) { send_ldap_result( op, rs ); } if ( new_conn ) { mc->mc_refcnt = 0; meta_back_conn_free( mc ); } else { meta_back_release_conn( mi, mc ); } return NULL; } continue; } } else { if ( new_conn ) { ( void )meta_clear_one_candidate( op, mc, i ); } } } if ( ncandidates == 0 ) { if ( new_conn ) { mc->mc_refcnt = 0; meta_back_conn_free( mc ); } else { meta_back_release_conn( mi, mc ); } if ( rs->sr_err == LDAP_SUCCESS ) { rs->sr_err = LDAP_NO_SUCH_OBJECT; rs->sr_text = "Unable to select valid candidates"; } if ( sendok & LDAP_BACK_SENDERR ) { if ( rs->sr_err == LDAP_NO_SUCH_OBJECT ) { rs->sr_matched = op->o_bd->be_suffix[ 0 ].bv_val; } send_ldap_result( op, rs ); rs->sr_matched = NULL; } return NULL; } }done:; /* clear out meta_back_init_one_conn non-fatal errors */ rs->sr_err = LDAP_SUCCESS; rs->sr_text = NULL; /* touch the timestamp */ if ( mi->mi_idle_timeout != 0 ) { mc->mc_time = op->o_time; } if ( new_conn ) { if ( mi->mi_conn_ttl ) { mc->mc_create_time = op->o_time; } /* * Inserts the newly created metaconn in the avl tree */ ldap_pvt_thread_mutex_lock( &mi->mi_conninfo.lai_mutex );#if META_BACK_PRINT_CONNTREE > 0 meta_back_print_conntree( mi, ">>> meta_back_getconn" );#endif /* META_BACK_PRINT_CONNTREE */ if ( LDAP_BACK_PCONN_ISPRIV( mc ) ) { if ( mi->mi_conn_priv[ LDAP_BACK_CONN2PRIV( mc ) ].mic_num < mi->mi_conn_priv_max ) { LDAP_TAILQ_INSERT_TAIL( &mi->mi_conn_priv[ LDAP_BACK_CONN2PRIV( mc ) ].mic_priv, mc, mc_q ); mi->mi_conn_priv[ LDAP_BACK_CONN2PRIV( mc ) ].mic_num++; LDAP_BACK_CONN_CACHED_SET( mc ); } else { LDAP_BACK_CONN_TAINTED_SET( mc ); } rs->sr_err = 0; } else { err = avl_insert( &mi->mi_conninfo.lai_tree, ( caddr_t )mc, meta_back_conndn_cmp, meta_back_conndn_dup ); LDAP_BACK_CONN_CACHED_SET( mc ); }#if META_BACK_PRINT_CONNTREE > 0 meta_back_print_conntree( mi, ">>> meta_back_getconn" );#endif /* META_BACK_PRINT_CONNTREE */ ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex ); if ( !LDAP_BACK_PCONN_ISPRIV( mc ) ) { /* * Err could be -1 in case a duplicate metaconn is inserted */ switch ( err ) { case 0: break; case -1: LDAP_BACK_CONN_CACHED_CLEAR( mc ); /* duplicate: free and try to get the newly created one */ if ( !( sendok & LDAP_BACK_BINDING ) && !LDAP_BACK_USE_TEMPORARIES( mi ) ) { mc->mc_refcnt = 0; meta_back_conn_free( mc ); new_conn = 0; goto retry_lock; } LDAP_BACK_CONN_TAINTED_SET( mc ); break; default: LDAP_BACK_CONN_CACHED_CLEAR( mc ); Debug( LDAP_DEBUG_ANY, "%s meta_back_getconn: candidates=%d conn=%ld insert failed\n", op->o_log_prefix, ncandidates, LDAP_BACK_PCONN_ID( mc ) ); mc->mc_refcnt = 0; meta_back_conn_free( mc ); rs->sr_err = LDAP_OTHER; rs->sr_text = "Proxy bind collision"; if ( sendok & LDAP_BACK_SENDERR ) { send_ldap_result( op, rs ); } return NULL; } } Debug( LDAP_DEBUG_TRACE, "%s meta_back_getconn: candidates=%d conn=%ld inserted\n", op->o_log_prefix, ncandidates, LDAP_BACK_PCONN_ID( mc ) ); } else { Debug( LDAP_DEBUG_TRACE, "%s meta_back_getconn: candidates=%d conn=%ld fetched\n", op->o_log_prefix, ncandidates, LDAP_BACK_PCONN_ID( mc ) ); } return mc;}voidmeta_back_release_conn_lock( metainfo_t *mi, metaconn_t *mc, int dolock ){ assert( mc != NULL ); if ( dolock ) { ldap_pvt_thread_mutex_lock( &mi->mi_conninfo.lai_mutex ); } assert( mc->mc_refcnt > 0 ); mc->mc_refcnt--; /* NOTE: the connection is removed if either it is tainted * or if it is shared and no one else is using it. This needs * to occur because for intrinsic reasons cached connections * that are not privileged would live forever and pollute * the connection space (and eat up resources). Maybe this * should be configurable... */ if ( LDAP_BACK_CONN_TAINTED( mc ) ) {#if META_BACK_PRINT_CONNTREE > 0 meta_back_print_conntree( mi, ">>> meta_back_release_conn" );#endif /* META_BACK_PRINT_CONNTREE */ if ( LDAP_BACK_PCONN_ISPRIV( mc ) ) { if ( mc->mc_q.tqe_prev != NULL ) { assert( LDAP_BACK_CONN_CACHED( mc ) ); assert( mi->mi_conn_priv[ LDAP_BACK_CONN2PRIV( mc ) ].mic_num > 0 ); LDAP_TAILQ_REMOVE( &mi->mi_conn_priv[ LDAP_BACK_CONN2PRIV( mc ) ].mic_priv, mc, mc_q ); mi->mi_conn_priv[ LDAP_BACK_CONN2PRIV( mc ) ].mic_num--; LDAP_TAILQ_ENTRY_INIT( mc, mc_q ); } else { assert( !LDAP_BACK_CONN_CACHED( mc ) ); } } else { metaconn_t *tmpmc; tmpmc = avl_delete( &mi->mi_conninfo.lai_tree, ( caddr_t )mc, meta_back_conndnmc_cmp ); /* Overparanoid, but useful... */ assert( tmpmc == NULL || tmpmc == mc ); } LDAP_BACK_CONN_CACHED_CLEAR( mc );#if META_BACK_PRINT_CONNTREE > 0 meta_back_print_conntree( mi, "<<< meta_back_release_conn" );#endif /* META_BACK_PRINT_CONNTREE */ if ( mc->mc_refcnt == 0 ) { meta_back_conn_free( mc ); mc = NULL; } } if ( mc != NULL && LDAP_BACK_CONN_BINDING( mc ) ) { LDAP_BACK_CONN_BINDING_CLEAR( mc ); } if ( dolock ) { ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex ); }}voidmeta_back_quarantine( Operation *op, SlapReply *rs, int candidate ){ metainfo_t *mi = (metainfo_t *)op->o_bd->be_private; metatarget_t *mt = mi->mi_targets[ candidate ]; slap_retry_info_t *ri = &mt->mt_quarantine; ldap_pvt_thread_mutex_lock( &mt->mt_quarantine_mutex ); if ( rs->sr_err == LDAP_UNAVAILABLE ) { time_t new_last = slap_get_time(); switch ( mt->mt_isquarantined ) { case LDAP_BACK_FQ_NO: if ( ri->ri_last == new_last ) { goto done; } Debug( LDAP_DEBUG_ANY, "%s meta_back_quarantine[%d]: enter.\n", op->o_log_prefix, candidate, 0 ); ri->ri_idx = 0; ri->ri_count = 0; break; case LDAP_BACK_FQ_RETRYING: if ( StatslogTest( LDAP_DEBUG_ANY ) ) { char buf[ SLAP_TEXT_BUFLEN ]; snprintf( buf, sizeof( buf ), "meta_back_quarantine[%d]: block #%d try #%d failed", candidate, ri->ri_idx, ri->ri_count ); Debug( LDAP_DEBUG_ANY, "%s %s.\n", op->o_log_prefix, buf, 0 ); } ++ri->ri_count; if ( ri->ri_num[ ri->ri_idx ] != SLAP_RETRYNUM_FOREVER && ri->ri_count == ri->ri_num[ ri->ri_idx ] ) { ri->ri_count = 0; ++ri->ri_idx; } break; default: break; } mt->mt_isquarantined = LDAP_BACK_FQ_YES; ri->ri_last = new_last; } else if ( mt->mt_isquarantined == LDAP_BACK_FQ_RETRYING ) { Debug( LDAP_DEBUG_ANY, "%s meta_back_quarantine[%d]: exit.\n", op->o_log_prefix, candidate, 0 ); if ( mi->mi_quarantine_f ) { (void)mi->mi_quarantine_f( mi, candidate, mi->mi_quarantine_p ); } ri->ri_count = 0; ri->ri_idx = 0; mt->mt_isquarantined = LDAP_BACK_FQ_NO; }done:; ldap_pvt_thread_mutex_unlock( &mt->mt_quarantine_mutex );}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?