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 + -
显示快捷键?