+ /* 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 );
+
+ if ( LogTest( LDAP_DEBUG_TRACE ) ) {
+ char buf[STRLENOF("4294967295U") + 1] = { 0 };
+ mi->mi_ldap_extra->connid2str( &mc->mc_base, buf, sizeof(buf) );
+
+ Debug( LDAP_DEBUG_TRACE,
+ "%s meta_back_getconn: mc=%p conn=%s expired (tainted).\n",
+ op->o_log_prefix, (void *)mc, buf );
+ }
+ }
+
+ mc->mc_refcnt++;
+ }
+ }
+ ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex );
+ }