conn.c

来自「ldap服务器源码」· C语言 代码 · 共 1,810 行 · 第 1/3 页

C
1,810
字号
				ber_dupbv( &msc->msc_bound_ndn, &op->o_conn->c_dn );			}			assert( !BER_BVISNULL( &msc->msc_bound_ndn ) );		} else {			ber_dupbv( &msc->msc_bound_ndn, (struct berval *)&slap_empty_bv );		}	}	assert( !BER_BVISNULL( &msc->msc_bound_ndn ) );error_return:;	if ( dolock ) {		ldap_pvt_thread_mutex_lock( &mi->mi_conninfo.lai_mutex );	}	META_BACK_CONN_CREATING_CLEAR( msc );	if ( rs->sr_err == LDAP_SUCCESS ) {		/*		 * Sets a cookie for the rewrite session		 */		( void )rewrite_session_init( mt->mt_rwmap.rwm_rw, op->o_conn );		META_BACK_CONN_INITED_SET( msc );	}	if ( dolock ) {		ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex );	}	if ( rs->sr_err != LDAP_SUCCESS ) {		rs->sr_err = slap_map_api2result( rs );		if ( sendok & LDAP_BACK_SENDERR ) {			send_ldap_result( op, rs );		}	}	return rs->sr_err;}/* * meta_back_retry *  * Retries one connection */intmeta_back_retry(	Operation		*op,	SlapReply		*rs,	metaconn_t		**mcp,	int			candidate,	ldap_back_send_t	sendok ){	metainfo_t		*mi = ( metainfo_t * )op->o_bd->be_private;	metatarget_t		*mt = mi->mi_targets[ candidate ];	metaconn_t		*mc = *mcp;	metasingleconn_t	*msc = &mc->mc_conns[ candidate ];	int			rc = LDAP_UNAVAILABLE,				binding,				quarantine = 1;	ldap_pvt_thread_mutex_lock( &mi->mi_conninfo.lai_mutex );	assert( !META_BACK_CONN_CREATING( msc ) );	binding = LDAP_BACK_CONN_BINDING( msc );	LDAP_BACK_CONN_BINDING_CLEAR( msc );	assert( mc->mc_refcnt > 0 );	if ( mc->mc_refcnt == 1 ) {		if ( StatslogTest( LDAP_DEBUG_ANY ) ) {			char	buf[ SLAP_TEXT_BUFLEN ];			/* this lock is required; however,			 * it's invoked only when logging is on */			ldap_pvt_thread_mutex_lock( &mt->mt_uri_mutex );			snprintf( buf, sizeof( buf ),				"retrying URI=\"%s\" DN=\"%s\"",				mt->mt_uri,				BER_BVISNULL( &msc->msc_bound_ndn ) ?					"" : msc->msc_bound_ndn.bv_val );			ldap_pvt_thread_mutex_unlock( &mt->mt_uri_mutex );			Debug( LDAP_DEBUG_ANY,				"%s meta_back_retry[%d]: %s.\n",				op->o_log_prefix, candidate, buf );		}		meta_clear_one_candidate( op, mc, candidate );		LDAP_BACK_CONN_ISBOUND_CLEAR( msc );		( void )rewrite_session_delete( mt->mt_rwmap.rwm_rw, op->o_conn );		/* mc here must be the regular mc, reset and ready for init */		rc = meta_back_init_one_conn( op, rs, mc, candidate,			LDAP_BACK_CONN_ISPRIV( mc ), sendok, 0 );		/* restore the "binding" flag, in case */		if ( binding ) {			LDAP_BACK_CONN_BINDING_SET( msc );		}		if ( rc == LDAP_SUCCESS ) {			quarantine = 0;			rc = meta_back_single_dobind( op, rs, mcp, candidate,				sendok, mt->mt_nretries, 0 );			Debug( LDAP_DEBUG_ANY,				"%s meta_back_retry[%d]: "				"meta_back_single_dobind=%d\n",				op->o_log_prefix, candidate, rc );			if ( rc == LDAP_SUCCESS ) {				if ( !BER_BVISNULL( &msc->msc_bound_ndn ) &&					!BER_BVISEMPTY( &msc->msc_bound_ndn ) )				{					LDAP_BACK_CONN_ISBOUND_SET( msc );				} else {					LDAP_BACK_CONN_ISANON_SET( msc );				}				/* when bound, dispose of the "binding" flag */				if ( binding ) {					LDAP_BACK_CONN_BINDING_CLEAR( msc );				}			}        	}		/* don't send twice */		sendok &= ~LDAP_BACK_SENDERR;	}	if ( rc != LDAP_SUCCESS ) {		SlapReply		*candidates = meta_back_candidates_get( op );		candidates[ candidate ].sr_err = rc;		if ( *mcp != NULL ) {			if ( mc->mc_refcnt == 1 ) {				if ( binding ) {					LDAP_BACK_CONN_BINDING_CLEAR( msc );				}				(void)meta_clear_one_candidate( op, mc, candidate );			}			LDAP_BACK_CONN_TAINTED_SET( mc );			/* only release if mandatory; otherwise			 * let the caller do what's best before			 * releasing */			if ( META_BACK_ONERR_STOP( mi ) ) {				meta_back_release_conn_lock( mi, mc, 0 );				*mcp = NULL;			} else {#if META_BACK_PRINT_CONNTREE > 0				meta_back_print_conntree( mi, ">>> meta_back_retry" );#endif /* META_BACK_PRINT_CONNTREE */				/* FIXME: could be done better, reworking meta_back_release_conn_lock() */				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 {					/* FIXME: check if in tree, for consistency? */					(void)avl_delete( &mi->mi_conninfo.lai_tree,						( caddr_t )mc, meta_back_conndnmc_cmp );				}				LDAP_BACK_CONN_CACHED_CLEAR( mc );#if META_BACK_PRINT_CONNTREE > 0				meta_back_print_conntree( mi, "<<< meta_back_retry" );#endif /* META_BACK_PRINT_CONNTREE */			}		}		if ( sendok & LDAP_BACK_SENDERR ) {			rs->sr_err = rc;			rs->sr_text = "Unable to retry";			send_ldap_result( op, rs );		}	}	if ( quarantine && META_BACK_TGT_QUARANTINE( mt ) ) {		meta_back_quarantine( op, rs, candidate );	}	ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex );	return rc == LDAP_SUCCESS ? 1 : 0;}/* * callback for unique candidate selection */static intmeta_back_conn_cb( Operation *op, SlapReply *rs ){	assert( op->o_tag == LDAP_REQ_SEARCH );	switch ( rs->sr_type ) {	case REP_SEARCH:		((long *)op->o_callback->sc_private)[0] = (long)op->o_private;		break;	case REP_SEARCHREF:	case REP_RESULT:		break;	default:		return rs->sr_err;	}	return 0;}static intmeta_back_get_candidate(	Operation	*op,	SlapReply	*rs,	struct berval	*ndn ){	metainfo_t	*mi = ( metainfo_t * )op->o_bd->be_private;	long		candidate;	/*	 * tries to get a unique candidate	 * (takes care of default target)	 */	candidate = meta_back_select_unique_candidate( mi, ndn );	/*	 * if any is found, inits the connection	 */	if ( candidate == META_TARGET_NONE ) {		rs->sr_err = LDAP_NO_SUCH_OBJECT;		rs->sr_text = "No suitable candidate target found";	} else if ( candidate == META_TARGET_MULTIPLE ) {		Filter		f = { 0 };		Operation	op2 = *op;		SlapReply	rs2 = { 0 };		slap_callback	cb2 = { 0 };		int		rc;		/* try to get a unique match for the request ndn		 * among the multiple candidates available */		op2.o_tag = LDAP_REQ_SEARCH;		op2.o_req_dn = *ndn;		op2.o_req_ndn = *ndn;		op2.ors_scope = LDAP_SCOPE_BASE;		op2.ors_deref = LDAP_DEREF_NEVER;		op2.ors_attrs = slap_anlist_no_attrs;		op2.ors_attrsonly = 0;		op2.ors_limit = NULL;		op2.ors_slimit = 1;		op2.ors_tlimit = SLAP_NO_LIMIT;		f.f_choice = LDAP_FILTER_PRESENT;		f.f_desc = slap_schema.si_ad_objectClass;		op2.ors_filter = &f;		BER_BVSTR( &op2.ors_filterstr, "(objectClass=*)" );		op2.o_callback = &cb2;		cb2.sc_response = meta_back_conn_cb;		cb2.sc_private = (void *)&candidate;		rc = op->o_bd->be_search( &op2, &rs2 );		switch ( rs2.sr_err ) {		case LDAP_SUCCESS:		default:			rs->sr_err = rs2.sr_err;			break;		case LDAP_SIZELIMIT_EXCEEDED:			/* if multiple candidates can serve the operation,			 * and a default target is defined, and it is			 * a candidate, try using it (FIXME: YMMV) */			if ( mi->mi_defaulttarget != META_DEFAULT_TARGET_NONE				&& meta_back_is_candidate( mi->mi_targets[ mi->mi_defaulttarget ],						ndn, op->o_tag == LDAP_REQ_SEARCH ? op->ors_scope : LDAP_SCOPE_BASE ) )			{				candidate = mi->mi_defaulttarget;				rs->sr_err = LDAP_SUCCESS;				rs->sr_text = NULL;			} else {				rs->sr_err = LDAP_UNWILLING_TO_PERFORM;				rs->sr_text = "Unable to select unique candidate target";			}			break;		}	} else {		rs->sr_err = LDAP_SUCCESS;	}	return candidate;}static void	*meta_back_candidates_dummy;static voidmeta_back_candidates_keyfree(	void		*key,	void		*data ){	metacandidates_t	*mc = (metacandidates_t *)data;	ber_memfree_x( mc->mc_candidates, NULL );	ber_memfree_x( data, NULL );}SlapReply *meta_back_candidates_get( Operation *op ){	metainfo_t		*mi = ( metainfo_t * )op->o_bd->be_private;	metacandidates_t	*mc;	if ( op->o_threadctx ) {		void		*data = NULL;		ldap_pvt_thread_pool_getkey( op->o_threadctx,				&meta_back_candidates_dummy, &data, NULL );		mc = (metacandidates_t *)data;	} else {		mc = mi->mi_candidates;	}	if ( mc == NULL ) {		mc = ch_calloc( sizeof( metacandidates_t ), 1 );		mc->mc_ntargets = mi->mi_ntargets;		mc->mc_candidates = ch_calloc( sizeof( SlapReply ), mc->mc_ntargets );		if ( op->o_threadctx ) {			void		*data = NULL;			data = (void *)mc;			ldap_pvt_thread_pool_setkey( op->o_threadctx,					&meta_back_candidates_dummy, data,					meta_back_candidates_keyfree );		} else {			mi->mi_candidates = mc;		}	} else if ( mc->mc_ntargets < mi->mi_ntargets ) {		/* NOTE: in the future, may want to allow back-config		 * to add/remove targets from back-meta... */		mc->mc_candidates = ch_realloc( mc->mc_candidates,				sizeof( SlapReply ) * mi->mi_ntargets );		memset( &mc->mc_candidates[ mc->mc_ntargets ], 0,			sizeof( SlapReply ) * ( mi->mi_ntargets - mc->mc_ntargets ) );		mc->mc_ntargets = mi->mi_ntargets;	}	return mc->mc_candidates;}/* * meta_back_getconn *  * Prepares the connection structure *  * RATIONALE: * * - determine what DN is being requested: * *	op	requires candidate	checks * *	add	unique			parent of o_req_ndn *	bind	unique^*[/all]		o_req_ndn [no check] *	compare	unique^+		o_req_ndn *	delete	unique			o_req_ndn *	modify	unique			o_req_ndn *	search	any			o_req_ndn *	modrdn	unique[, unique]	o_req_ndn[, orr_nnewSup] * * - for ops that require the candidate to be unique, in case of multiple *   occurrences an internal search with sizeLimit=1 is performed *   if a unique candidate can actually be determined.  If none is found, *   the operation aborts; if multiple are found, the default target *   is used if defined and candidate; otherwise the operation aborts. * * *^note: actually, the bind operation is handled much like a search; *   i.e. the bind is broadcast to all candidate targets. * * +^note: actually, the compare operation is handled much like a search; *   i.e. the compare is broadcast to all candidate targets, while checking *   that exactly none (noSuchObject) or one (TRUE/FALSE/UNDEFINED) is *   returned. */metaconn_t *meta_back_getconn(       	Operation 		*op,	SlapReply		*rs,	int 			*candidate,	ldap_back_send_t	sendok ){	metainfo_t	*mi = ( metainfo_t * )op->o_bd->be_private;	metaconn_t	*mc = NULL,			mc_curr = { 0 };	int		cached = META_TARGET_NONE,			i = META_TARGET_NONE,			err = LDAP_SUCCESS,			new_conn = 0,			ncandidates = 0;	meta_op_type	op_type = META_OP_REQUIRE_SINGLE;	enum		{		META_DNTYPE_ENTRY,		META_DNTYPE_PARENT,		META_DNTYPE_NEWPARENT	}		dn_type = META_DNTYPE_ENTRY;	struct berval	ndn = op->o_req_ndn,			pndn;	SlapReply	*candidates = meta_back_candidates_get( op );	/* Internal searches are privileged and shared. So is root. */	if ( ( !BER_BVISEMPTY( &op->o_ndn ) && META_BACK_PROXYAUTHZ_ALWAYS( mi ) )		|| ( BER_BVISEMPTY( &op->o_ndn ) && META_BACK_PROXYAUTHZ_ANON( mi ) )		|| op->o_do_not_cache || be_isroot( op ) )	{		LDAP_BACK_CONN_ISPRIV_SET( &mc_curr );		mc_curr.mc_local_ndn = op->o_bd->be_rootndn;		LDAP_BACK_PCONN_ROOTDN_SET( &mc_curr, op );	} else if ( BER_BVISEMPTY( &op->o_ndn ) && META_BACK_PROXYAUTHZ_NOANON( mi ) )	{		LDAP_BACK_CONN_ISANON_SET( &mc_curr );		BER_BVSTR( &mc_curr.mc_local_ndn, "" );		LDAP_BACK_PCONN_ANON_SET( &mc_curr, op );	} else {		mc_curr.mc_local_ndn = op->o_ndn;		/* Explicit binds must not be shared */		if ( !BER_BVISEMPTY( &op->o_ndn )			|| op->o_tag == LDAP_REQ_BIND			|| SLAP_IS_AUTHZ_BACKEND( op ) )		{			mc_curr.mc_conn = op->o_conn;			} else {			LDAP_BACK_CONN_ISANON_SET( &mc_curr );			LDAP_BACK_PCONN_ANON_SET( &mc_curr, op );		}	}	/* Explicit Bind requests always get their own conn */	if ( sendok & LDAP_BACK_BINDING ) {		mc_curr.mc_conn = op->o_conn;	} else {		/* Searches for a metaconn in the avl tree */retry_lock:;		ldap_pvt_thread_mutex_lock( &mi->mi_conninfo.lai_mutex );		if ( LDAP_BACK_PCONN_ISPRIV( &mc_curr ) ) {			/* lookup a conn that's not binding */			LDAP_TAILQ_FOREACH( mc,				&mi->mi_conn_priv[ LDAP_BACK_CONN2PRIV( &mc_curr ) ].mic_priv,				mc_q )			{				if ( !LDAP_BACK_CONN_BINDING( mc ) && mc->mc_refcnt == 0 ) {					break;				}			}			if ( mc != NULL ) {				if ( mc != LDAP_TAILQ_LAST( &mi->mi_conn_priv[ LDAP_BACK_CONN2PRIV( mc ) ].mic_priv,					metaconn_t, mc_q ) )				{					LDAP_TAILQ_REMOVE( &mi->mi_conn_priv[ LDAP_BACK_CONN2PRIV( mc ) ].mic_priv,						mc, mc_q );					LDAP_TAILQ_ENTRY_INIT( mc, mc_q );					LDAP_TAILQ_INSERT_TAIL( &mi->mi_conn_priv[ LDAP_BACK_CONN2PRIV( mc ) ].mic_priv,						mc, mc_q );				}			} else if ( !LDAP_BACK_USE_TEMPORARIES( mi )				&& mi->mi_conn_priv[ LDAP_BACK_CONN2PRIV( &mc_curr ) ].mic_num == mi->mi_conn_priv_max )			{				mc = LDAP_TAILQ_FIRST( &mi->mi_conn_priv[ LDAP_BACK_CONN2PRIV( &mc_curr ) ].mic_priv );			}					} else {			mc = (metaconn_t *)avl_find( mi->mi_conninfo.lai_tree, 				(caddr_t)&mc_curr, meta_back_conndn_cmp );		}		if ( mc ) {			/* catch taint errors */			assert( !LDAP_BACK_CONN_TAINTED( mc ) );			/* Don't reuse connections while they're still binding			 * NOTE: only makes sense for binds */			if ( LDAP_BACK_CONN_BINDING( mc ) ) {				if ( !LDAP_BACK_USE_TEMPORARIES( mi ) ) {					ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex );					ldap_pvt_thread_yield();					goto retry_lock;				}				/* release conn, and create a temporary */				mc = NULL;			} else {				if ( ( mi->mi_conn_ttl != 0 && op->o_time > mc->mc_create_time + mi->mi_conn_ttl )					|| ( mi->mi_idle_timeout != 0 && op->o_time > mc->mc_time + mi->mi_idle_timeout ) )				{#if META_BACK_PRINT_CONNTREE > 0					meta_back_print_conntree( mi,						">>> meta_back_getconn(expired)" );#endif /* META_BACK_PRINT_CONNTREE */					/* don't let anyone else use this expired connection */					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 {						(void)avl_delete( &mi->mi_conninfo.lai_tree,							(caddr_t)mc, meta_back_conndnmc_cmp );					}#if META_BACK_PRINT_CONNTREE > 0					meta_back_print_conntree( mi,						"<<< meta_back_getconn(expired)" );#endif /* META_BACK_PRINT_CONNTREE */					LDAP_BACK_CONN_TAINTED_SET( mc );					LDAP_BACK_CONN_CACHED_CLEAR( mc );					Debug( LDAP_DEBUG_TRACE, "%s meta_back_getconn: mc=%p conn=%ld expired (tainted).\n",						op->o_log_prefix, (void *)mc, LDAP_BACK_PCONN_ID( mc ) );				}				mc->mc_refcnt++;			}		}		ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex );	}	switch ( op->o_tag ) {	case LDAP_REQ_ADD:		/* if we go to selection, the entry must not exist,		 * and we must be able to resolve the parent */		dn_type = META_DNTYPE_PARENT;		dnParent( &ndn, &pndn );		break;	case LDAP_REQ_MODRDN:		/* if nnewSuperior is not NULL, it must resolve		 * to the same candidate as the req_ndn */		if ( op->orr_nnewSup ) {			dn_type = META_DNTYPE_NEWPARENT;		}		break;	case LDAP_REQ_BIND:		/* if bound as rootdn, the backend must bind to all targets		 * with the administrative identity */		if ( op->orb_method == LDAP_AUTH_SIMPLE && be_isroot_pw( op ) ) {			op_type = META_OP_REQUIRE_ALL;		}		break;	case LDAP_REQ_COMPARE:	case LDAP_REQ_DELETE:	case LDAP_REQ_MODIFY:		/* just a unique candidate */		break;	case LDAP_REQ_SEARCH:		/* allow multiple candidates for the searchBase */		op_type = META_OP_ALLOW_MULTIPLE;		break;	default:		/* right now, just break (exop?) */		break;	}	/*

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?