struct berval lmi_more_filter;
} ldap_monitor_info_t;
+enum {
+ /* even numbers are connection types */
+ LDAP_BACK_PCONN_FIRST = 0,
+ LDAP_BACK_PCONN_ROOTDN = LDAP_BACK_PCONN_FIRST,
+ LDAP_BACK_PCONN_ANON = 2,
+ LDAP_BACK_PCONN_BIND = 4,
+
+ /* add the TLS bit */
+ LDAP_BACK_PCONN_TLS = 0x1U,
+
+ LDAP_BACK_PCONN_ROOTDN_TLS = (LDAP_BACK_PCONN_ROOTDN|LDAP_BACK_PCONN_TLS),
+ LDAP_BACK_PCONN_ANON_TLS = (LDAP_BACK_PCONN_ANON|LDAP_BACK_PCONN_TLS),
+ LDAP_BACK_PCONN_BIND_TLS = (LDAP_BACK_PCONN_BIND|LDAP_BACK_PCONN_TLS),
+
+ LDAP_BACK_PCONN_LAST
+};
+
typedef struct ldapconn_t {
Connection *lc_conn;
-#define LDAP_BACK_PCONN ((void *)0x0)
-#define LDAP_BACK_PCONN_TLS ((void *)0x1)
-#define LDAP_BACK_PCONN_BIND ((void *)0x2)
-#define LDAP_BACK_PCONN_BIND_TLS ((void *)0x3)
-#define LDAP_BACK_PCONN_LAST ((void *)0x4)
-#define LDAP_BACK_PCONN_ISPRIV(lc) ((void *)(lc)->lc_conn < LDAP_BACK_PCONN_LAST)
-#define LDAP_BACK_PCONN_ID(lc) (LDAP_BACK_PCONN_ISPRIV((lc)) ? ( -1 - (long)(lc)->lc_conn ): (lc)->lc_conn->c_connid )
+#define LDAP_BACK_CONN2PRIV(lc) ((unsigned long)(lc)->lc_conn)
+#define LDAP_BACK_PCONN_ISPRIV(lc) ((void *)(lc)->lc_conn >= (void *)LDAP_BACK_PCONN_FIRST \
+ && (void *)(lc)->lc_conn < (void *)LDAP_BACK_PCONN_LAST)
+#define LDAP_BACK_PCONN_ISROOTDN(lc) (LDAP_BACK_PCONN_ISPRIV((lc)) \
+ && (LDAP_BACK_CONN2PRIV((lc)) < LDAP_BACK_PCONN_ANON))
+#define LDAP_BACK_PCONN_ISANON(lc) (LDAP_BACK_PCONN_ISPRIV((lc)) \
+ && (LDAP_BACK_CONN2PRIV((lc)) < LDAP_BACK_PCONN_BIND) \
+ && (LDAP_BACK_CONN2PRIV((lc)) >= LDAP_BACK_PCONN_ANON))
+#define LDAP_BACK_PCONN_ISBIND(lc) (LDAP_BACK_PCONN_ISPRIV((lc)) \
+ && (LDAP_BACK_CONN2PRIV((lc)) >= LDAP_BACK_PCONN_BIND))
+#define LDAP_BACK_PCONN_ISTLS(lc) (LDAP_BACK_PCONN_ISPRIV((lc)) \
+ && (LDAP_BACK_CONN2PRIV((lc)) & LDAP_BACK_PCONN_TLS))
+#define LDAP_BACK_PCONN_ID(lc) (LDAP_BACK_PCONN_ISPRIV((lc)) ? \
+ ( -1 - (long)(lc)->lc_conn ) : (lc)->lc_conn->c_connid )
#ifdef HAVE_TLS
-#define LDAP_BACK_PCONN_SET(op) ((op)->o_conn->c_is_tls ? LDAP_BACK_PCONN_TLS : LDAP_BACK_PCONN)
-#define LDAP_BACK_PCONN_BIND_SET(op) ((op)->o_conn->c_is_tls ? LDAP_BACK_PCONN_BIND_TLS : LDAP_BACK_PCONN_BIND)
+#define LDAP_BACK_PCONN_ROOTDN_SET(lc, op) \
+ ((lc)->lc_conn = (void *)((op)->o_conn->c_is_tls ? LDAP_BACK_PCONN_ROOTDN_TLS : LDAP_BACK_PCONN_ROOTDN))
+#define LDAP_BACK_PCONN_ANON_SET(lc, op) \
+ ((lc)->lc_conn = (void *)((op)->o_conn->c_is_tls ? LDAP_BACK_PCONN_ANON_TLS : LDAP_BACK_PCONN_ANON))
+#define LDAP_BACK_PCONN_BIND_SET(lc, op) \
+ ((lc)->lc_conn = (void *)((op)->o_conn->c_is_tls ? LDAP_BACK_PCONN_BIND_TLS : LDAP_BACK_PCONN_BIND))
#else /* ! HAVE_TLS */
-#define LDAP_BACK_PCONN_SET(op) (LDAP_BACK_PCONN)
-#define LDAP_BACK_PCONN_BIND_SET(op) (LDAP_BACK_PCONN_BIND)
+#define LDAP_BACK_PCONN_ROOTDN_SET(lc, op) \
+ ((lc)->lc_conn = (void *)LDAP_BACK_PCONN_ROOTDN)
+#define LDAP_BACK_PCONN_ANON_SET(lc, op) \
+ ((lc)->lc_conn = (void *)LDAP_BACK_PCONN_ANON)
+#define LDAP_BACK_PCONN_BIND_SET(lc, op) \
+ ((lc)->lc_conn = (void *)LDAP_BACK_PCONN_BIND)
#endif /* ! HAVE_TLS */
+#define LDAP_BACK_PCONN_SET(lc, op) \
+ (BER_BVISEMPTY(&(op)->o_ndn) ? \
+ LDAP_BACK_PCONN_ANON_SET((lc), (op)) : LDAP_BACK_PCONN_ROOTDN_SET((lc), (op)))
LDAP *lc_ld;
struct berval lc_cred;
#define LDAP_BACK_FCONN_BINDING (0x00000010U)
#define LDAP_BACK_FCONN_TAINTED (0x00000020U)
#define LDAP_BACK_FCONN_ISIDASR (0x00000040U)
+#define LDAP_BACK_FCONN_CACHED (0x00000080U)
#define LDAP_BACK_CONN_ISBOUND(lc) LDAP_BACK_CONN_ISSET((lc), LDAP_BACK_FCONN_ISBOUND)
#define LDAP_BACK_CONN_ISBOUND_SET(lc) LDAP_BACK_CONN_SET((lc), LDAP_BACK_FCONN_ISBOUND)
#define LDAP_BACK_CONN_ISIDASSERT_SET(lc) LDAP_BACK_CONN_SET((lc), LDAP_BACK_FCONN_ISIDASR)
#define LDAP_BACK_CONN_ISIDASSERT_CLEAR(lc) LDAP_BACK_CONN_CLEAR((lc), LDAP_BACK_FCONN_ISIDASR)
#define LDAP_BACK_CONN_ISIDASSERT_CPY(lc, mlc) LDAP_BACK_CONN_CPY((lc), LDAP_BACK_FCONN_ISIDASR, (mlc))
+#define LDAP_BACK_CONN_CACHED(lc) LDAP_BACK_CONN_ISSET((lc), LDAP_BACK_FCONN_CACHED)
+#define LDAP_BACK_CONN_CACHED_SET(lc) LDAP_BACK_CONN_SET((lc), LDAP_BACK_FCONN_CACHED)
+#define LDAP_BACK_CONN_CACHED_CLEAR(lc) LDAP_BACK_CONN_CLEAR((lc), LDAP_BACK_FCONN_CACHED)
unsigned lc_refcnt;
unsigned lc_binding;
unsigned lc_flags;
time_t lc_create_time;
time_t lc_time;
+
+ LDAP_TAILQ_ENTRY(ldapconn_t) lc_q;
} ldapconn_t;
typedef struct ldap_avl_info_t {
#define LDAP_BACK_F_CANCEL_MASK (LDAP_BACK_F_CANCEL_IGNORE|LDAP_BACK_F_CANCEL_EXOP)
#define LDAP_BACK_F_CANCEL_MASK2 (LDAP_BACK_F_CANCEL_MASK|LDAP_BACK_F_CANCEL_EXOP_DISCOVER)
-#define LDAP_BACK_ISSET(li,f) ( ( (li)->li_flags & (f) ) == (f) )
-#define LDAP_BACK_ISMASK(li,m,f) ( ( (li)->li_flags & (m) ) == (f) )
+#define LDAP_BACK_ISSET_F(ff,f) ( ( (ff) & (f) ) == (f) )
+#define LDAP_BACK_ISMASK_F(ff,m,f) ( ( (ff) & (m) ) == (f) )
+
+#define LDAP_BACK_ISSET(li,f) LDAP_BACK_ISSET_F( (li)->li_flags, (f) )
+#define LDAP_BACK_ISMASK(li,m,f) LDAP_BACK_ISMASK_F( (li)->li_flags, (m), (f) )
#define LDAP_BACK_SAVECRED(li) LDAP_BACK_ISSET( (li), LDAP_BACK_F_SAVECRED )
#define LDAP_BACK_USE_TLS(li) LDAP_BACK_ISSET( (li), LDAP_BACK_F_USE_TLS )
#define LDAP_BACK_CHASE_REFERRALS(li) LDAP_BACK_ISSET( (li), LDAP_BACK_F_CHASE_REFERRALS )
#define LDAP_BACK_PROXY_WHOAMI(li) LDAP_BACK_ISSET( (li), LDAP_BACK_F_PROXY_WHOAMI )
+#define LDAP_BACK_USE_TLS_F(ff) LDAP_BACK_ISSET_F( (ff), LDAP_BACK_F_USE_TLS )
+#define LDAP_BACK_PROPAGATE_TLS_F(ff) LDAP_BACK_ISSET_F( (ff), LDAP_BACK_F_PROPAGATE_TLS )
+#define LDAP_BACK_TLS_CRITICAL_F(ff) LDAP_BACK_ISSET_F( (ff), LDAP_BACK_F_TLS_CRITICAL )
+
#define LDAP_BACK_T_F(li) LDAP_BACK_ISMASK( (li), LDAP_BACK_F_T_F_MASK, LDAP_BACK_F_T_F )
#define LDAP_BACK_T_F_DISCOVER(li) LDAP_BACK_ISMASK( (li), LDAP_BACK_F_T_F_MASK2, LDAP_BACK_F_T_F_DISCOVER )
int li_version;
+ /* cached connections;
+ * special conns are in tailq rather than in tree */
ldap_avl_info_t li_conninfo;
ldap_monitor_info_t li_monitor_info;
+ struct {
+ int lic_num;
+ LDAP_TAILQ_HEAD(lc_conn_priv_q, ldapconn_t) lic_priv;
+ } li_conn_priv[ LDAP_BACK_PCONN_LAST ];
+ int li_conn_priv_max;
+#define LDAP_BACK_CONN_PRIV_MIN (1)
+#define LDAP_BACK_CONN_PRIV_MAX (256)
+ /* must be between LDAP_BACK_CONN_PRIV_MIN
+ * and LDAP_BACK_CONN_PRIV_MAX ! */
+#define LDAP_BACK_CONN_PRIV_DEFAULT (16)
+
sig_atomic_t li_isquarantined;
#define LDAP_BACK_FQ_NO (0)
#define LDAP_BACK_FQ_YES (1)
#if LDAP_BACK_PRINT_CONNTREE > 0
static void
-ravl_print( Avlnode *root, int depth )
+ldap_back_ravl_print( Avlnode *root, int depth )
{
int i;
ldapconn_t *lc;
return;
}
- ravl_print( root->avl_right, depth+1 );
+ ldap_back_ravl_print( root->avl_right, depth+1 );
for ( i = 0; i < depth; i++ ) {
fprintf( stderr, "-" );
}
lc = root->avl_data;
- fprintf( stderr, "lc=%p local=\"%s\" conn=%p %s refcnt=%d\n",
+ fprintf( stderr, "lc=%p local=\"%s\" conn=%p %s refcnt=%d flags=0x%08x\n",
(void *)lc,
lc->lc_local_ndn.bv_val ? lc->lc_local_ndn.bv_val : "",
(void *)lc->lc_conn,
- avl_bf2str( root->avl_bf ), lc->lc_refcnt );
+ avl_bf2str( root->avl_bf ), lc->lc_refcnt, lc->lc_lcflags );
- ravl_print( root->avl_left, depth+1 );
+ ldap_back_ravl_print( root->avl_left, depth+1 );
}
+static char* priv2str[] = {
+ "privileged",
+ "privileged/TLS",
+ "anonymous",
+ "anonymous/TLS",
+ "bind",
+ "bind/TLS",
+ NULL
+};
+
void
-ldap_back_print_conntree( Avlnode *root, char *msg )
+ldap_back_print_conntree( ldapinfo_t *li, char *msg )
{
+ int c;
+
fprintf( stderr, "========> %s\n", msg );
+
+ for ( c = LDAP_BACK_PCONN_FIRST; c < LDAP_BACK_PCONN_LAST; c++ ) {
+ int i = 0;
+ ldapconn_t *lc;
+
+ fprintf( stderr, " %s[%d]\n", priv2str[ c ], li->li_conn_priv[ c ].lic_num );
+
+ LDAP_TAILQ_FOREACH( lc, &li->li_conn_priv[ c ].lic_priv, lc_q )
+ {
+ fprintf( stderr, " [%d] lc=%p local=\"%s\" conn=%p refcnt=%d flags=0x%08x\n",
+ i,
+ (void *)lc,
+ lc->lc_local_ndn.bv_val ? lc->lc_local_ndn.bv_val : "",
+ (void *)lc->lc_conn, lc->lc_refcnt, lc->lc_lcflags );
+ i++;
+ }
+ }
- if ( root == 0 ) {
+ if ( li->li_conninfo.lai_tree == 0 ) {
fprintf( stderr, "\t(empty)\n" );
} else {
- ravl_print( root, 0 );
+ ldap_back_ravl_print( li->li_conninfo.lai_tree, 0 );
}
fprintf( stderr, "<======== %s\n", msg );
}
#endif /* LDAP_BACK_PRINT_CONNTREE */
+static int
+ldap_back_freeconn( Operation *op, ldapconn_t *lc, int dolock );
+
static ldapconn_t *
ldap_back_getconn( Operation *op, SlapReply *rs, ldap_back_send_t sendok,
struct berval *binddn, struct berval *bindcred );
return rs->sr_err;
}
+ /* we can do (almost) whatever we want with this conn,
+ * because either it's temporary, or it's marked as binding */
if ( !BER_BVISNULL( &lc->lc_bound_ndn ) ) {
ch_free( lc->lc_bound_ndn.bv_val );
BER_BVZERO( &lc->lc_bound_ndn );
}
+ if ( !BER_BVISNULL( &lc->lc_cred ) ) {
+ memset( lc->lc_cred.bv_val, 0, lc->lc_cred.bv_len );
+ ch_free( lc->lc_cred.bv_val );
+ BER_BVZERO( &lc->lc_cred );
+ }
LDAP_BACK_CONN_ISBOUND_CLEAR( lc );
retry:;
LDAP_BACK_CONN_ISBOUND_SET( lc );
ber_dupbv( &lc->lc_bound_ndn, &op->o_req_ndn );
+ if ( !BER_BVISNULL( &lc->lc_cred ) ) {
+ memset( lc->lc_cred.bv_val, 0,
+ lc->lc_cred.bv_len );
+ }
+
if ( LDAP_BACK_SAVECRED( li ) ) {
- if ( !BER_BVISNULL( &lc->lc_cred ) ) {
- memset( lc->lc_cred.bv_val, 0,
- lc->lc_cred.bv_len );
- }
ber_bvreplace( &lc->lc_cred, &op->orb_cred );
ldap_set_rebind_proc( lc->lc_ld, li->li_rebind_f, lc );
+
+ } else {
+ lc->lc_cred.bv_len = 0;
}
}
/* must re-insert if local DN changed as result of bind */
if ( !LDAP_BACK_CONN_ISBOUND( lc )
- || ( LDAP_BACK_CONN_ISBOUND( lc )
- && !dn_match( &op->o_req_ndn, &lc->lc_local_ndn ) ) )
+ || ( !dn_match( &op->o_req_ndn, &lc->lc_local_ndn )
+ && !LDAP_BACK_PCONN_ISPRIV( lc ) ) )
{
int lerr = -1;
ldapconn_t *tmplc;
}
#if LDAP_BACK_PRINT_CONNTREE > 0
- ldap_back_print_conntree( li->li_conninfo.lai_tree, ">>> ldap_back_bind" );
+ ldap_back_print_conntree( li, ">>> ldap_back_bind" );
#endif /* LDAP_BACK_PRINT_CONNTREE */
-
+
assert( lc->lc_refcnt == 1 );
- tmplc = avl_delete( &li->li_conninfo.lai_tree, (caddr_t)lc,
- ldap_back_conndnlc_cmp );
- assert( tmplc == NULL || lc == tmplc );
+ if ( LDAP_BACK_PCONN_ISPRIV( lc ) ) {
+ /* this can happen, for example, if the bind fails
+ * for some reason... */
+ if ( lc->lc_q.tqe_prev != NULL ) {
+ assert( LDAP_BACK_CONN_CACHED( lc ) );
+ assert( li->li_conn_priv[ LDAP_BACK_CONN2PRIV( lc ) ].lic_num > 0 );
+ LDAP_TAILQ_REMOVE( &li->li_conn_priv[ LDAP_BACK_CONN2PRIV( lc ) ].lic_priv, lc, lc_q );
+ li->li_conn_priv[ LDAP_BACK_CONN2PRIV( lc ) ].lic_num--;
+ lc->lc_q.tqe_prev = NULL;
+ lc->lc_q.tqe_next = NULL;
+
+ } else {
+ assert( !LDAP_BACK_CONN_CACHED( lc ) );
+ }
+
+ } else {
+ tmplc = avl_delete( &li->li_conninfo.lai_tree, (caddr_t)lc,
+ ldap_back_conndnlc_cmp );
+ assert( ( LDAP_BACK_CONN_TAINTED( lc ) && tmplc == NULL ) || lc == tmplc );
+ }
+ LDAP_BACK_CONN_CACHED_CLEAR( lc );
/* delete all cached connections with the current connection */
if ( LDAP_BACK_SINGLECONN( li ) ) {
if ( tmplc->lc_refcnt != 0 ) {
/* taint it */
LDAP_BACK_CONN_TAINTED_SET( tmplc );
+ LDAP_BACK_CONN_CACHED_CLEAR( tmplc );
} else {
/*
if ( LDAP_BACK_CONN_ISBOUND( lc ) ) {
ber_bvreplace( &lc->lc_local_ndn, &op->o_req_ndn );
if ( be_isroot_dn( op->o_bd, &op->o_req_ndn ) ) {
- lc->lc_conn = LDAP_BACK_PCONN_SET( op );
+ LDAP_BACK_PCONN_ROOTDN_SET( lc, op );
}
lerr = avl_insert( &li->li_conninfo.lai_tree, (caddr_t)lc,
ldap_back_conndn_cmp, ldap_back_conndn_dup );
}
#if LDAP_BACK_PRINT_CONNTREE > 0
- ldap_back_print_conntree( li->li_conninfo.lai_tree, "<<< ldap_back_bind" );
+ ldap_back_print_conntree( li, "<<< ldap_back_bind" );
#endif /* LDAP_BACK_PRINT_CONNTREE */
ldap_pvt_thread_mutex_unlock( &li->li_conninfo.lai_mutex );
switch ( lerr ) {
case 0:
+ LDAP_BACK_CONN_CACHED_SET( lc );
break;
case -1:
return 0;
}
-int
+static int
ldap_back_freeconn( Operation *op, ldapconn_t *lc, int dolock )
{
ldapinfo_t *li = (ldapinfo_t *) op->o_bd->be_private;
- ldapconn_t *tmplc;
if ( dolock ) {
ldap_pvt_thread_mutex_lock( &li->li_conninfo.lai_mutex );
}
#if LDAP_BACK_PRINT_CONNTREE > 0
- ldap_back_print_conntree( li->li_conninfo.lai_tree, ">>> ldap_back_freeconn" );
+ ldap_back_print_conntree( li, ">>> ldap_back_freeconn" );
#endif /* LDAP_BACK_PRINT_CONNTREE */
- tmplc = avl_delete( &li->li_conninfo.lai_tree, (caddr_t)lc,
- ldap_back_conndnlc_cmp );
- assert( LDAP_BACK_CONN_TAINTED( lc ) || tmplc == lc );
+ if ( LDAP_BACK_PCONN_ISPRIV( lc ) ) {
+ if ( lc->lc_q.tqe_prev != NULL ) {
+ assert( LDAP_BACK_CONN_CACHED( lc ) );
+ assert( li->li_conn_priv[ LDAP_BACK_CONN2PRIV( lc ) ].lic_num > 0 );
+ li->li_conn_priv[ LDAP_BACK_CONN2PRIV( lc ) ].lic_num--;
+ LDAP_TAILQ_REMOVE( &li->li_conn_priv[ LDAP_BACK_CONN2PRIV( lc ) ].lic_priv, lc, lc_q );
+ LDAP_BACK_CONN_CACHED_CLEAR( lc );
+
+ } else {
+ assert( !LDAP_BACK_CONN_CACHED( lc ) );
+ }
+ lc->lc_q.tqe_prev = NULL;
+ lc->lc_q.tqe_next = NULL;
+
+ } else {
+ ldapconn_t *tmplc = NULL;
+
+ if ( LDAP_BACK_CONN_CACHED( lc ) ) {
+ tmplc = avl_delete( &li->li_conninfo.lai_tree, (caddr_t)lc,
+ ldap_back_conndnlc_cmp );
+ assert( tmplc == lc );
+ LDAP_BACK_CONN_CACHED_CLEAR( lc );
+ }
+ assert( LDAP_BACK_CONN_TAINTED( lc ) || tmplc == lc );
+ }
+
if ( lc->lc_refcnt == 0 ) {
ldap_back_conn_free( (void *)lc );
}
#if LDAP_BACK_PRINT_CONNTREE > 0
- ldap_back_print_conntree( li->li_conninfo.lai_tree, "<<< ldap_back_freeconn" );
+ ldap_back_print_conntree( li, "<<< ldap_back_freeconn" );
#endif /* LDAP_BACK_PRINT_CONNTREE */
if ( dolock ) {
const char **text )
{
int rc = LDAP_SUCCESS;
- ldapinfo_t dummy;
-
- /* this is ridiculous... */
- dummy.li_flags = flags;
/* start TLS ("tls-[try-]{start,propagate}" statements) */
- if ( ( LDAP_BACK_USE_TLS( &dummy ) || ( *is_tls && LDAP_BACK_PROPAGATE_TLS( &dummy ) ) )
+ if ( ( LDAP_BACK_USE_TLS_F( flags ) || ( *is_tls && LDAP_BACK_PROPAGATE_TLS_F( flags ) ) )
&& !ldap_is_ldaps_url( url ) )
{
#ifdef SLAP_STARTTLS_ASYNCHRONOUS
break;
default:
- if ( LDAP_BACK_TLS_CRITICAL( &dummy ) ) {
+ if ( LDAP_BACK_TLS_CRITICAL_F( flags ) ) {
*text = "could not start TLS";
break;
}
slap_retry_info_t *ri = &li->li_quarantine;
int dont_retry = 1;
- ldap_pvt_thread_mutex_lock( &li->li_quarantine_mutex );
- if ( li->li_isquarantined == LDAP_BACK_FQ_YES ) {
- dont_retry = ( ri->ri_num[ ri->ri_idx ] == SLAP_RETRYNUM_TAIL
- || slap_get_time() < ri->ri_last + ri->ri_interval[ ri->ri_idx ] );
- if ( !dont_retry ) {
- Debug( LDAP_DEBUG_ANY,
- "%s: ldap_back_getconn quarantine "
- "retry block #%d try #%d.\n",
- op->o_log_prefix, ri->ri_idx, ri->ri_count );
- li->li_isquarantined = LDAP_BACK_FQ_RETRYING;
+ if ( li->li_quarantine.ri_interval ) {
+ ldap_pvt_thread_mutex_lock( &li->li_quarantine_mutex );
+ if ( li->li_isquarantined == LDAP_BACK_FQ_YES ) {
+ dont_retry = ( ri->ri_num[ ri->ri_idx ] == SLAP_RETRYNUM_TAIL
+ || slap_get_time() < ri->ri_last + ri->ri_interval[ ri->ri_idx ] );
+ if ( !dont_retry ) {
+ Debug( LDAP_DEBUG_ANY,
+ "%s: ldap_back_getconn quarantine "
+ "retry block #%d try #%d.\n",
+ op->o_log_prefix, ri->ri_idx, ri->ri_count );
+ li->li_isquarantined = LDAP_BACK_FQ_RETRYING;
+ }
}
+ ldap_pvt_thread_mutex_unlock( &li->li_quarantine_mutex );
}
- ldap_pvt_thread_mutex_unlock( &li->li_quarantine_mutex );
if ( dont_retry ) {
rs->sr_err = LDAP_UNAVAILABLE;
if ( op->o_do_not_cache || be_isroot( op ) ) {
LDAP_BACK_CONN_ISPRIV_SET( &lc_curr );
lc_curr.lc_local_ndn = op->o_bd->be_rootndn;
- lc_curr.lc_conn = LDAP_BACK_PCONN_SET( op );
+ LDAP_BACK_PCONN_ROOTDN_SET( &lc_curr, op );
} else {
struct berval tmpbinddn,
} else {
if ( isproxyauthz && !( sendok & LDAP_BACK_BINDING ) ) {
lc_curr.lc_local_ndn = *binddn;
- lc_curr.lc_conn = LDAP_BACK_PCONN_SET( op );
+ LDAP_BACK_PCONN_ROOTDN_SET( &lc_curr, op );
LDAP_BACK_CONN_ISIDASSERT_SET( &lc_curr );
} else if ( isproxyauthz && ( li->li_idassert_flags & LDAP_BACK_AUTH_OVERRIDE ) ) {
lc_curr.lc_local_ndn = slap_empty_bv;
- lc_curr.lc_conn = LDAP_BACK_PCONN_BIND_SET( op );
+ LDAP_BACK_PCONN_BIND_SET( &lc_curr, op );
LDAP_BACK_CONN_ISIDASSERT_SET( &lc_curr );
lookupconn = 1;
lc_curr.lc_conn = op->o_conn;
} else {
- lc_curr.lc_conn = LDAP_BACK_PCONN_SET( op );
+ LDAP_BACK_PCONN_ANON_SET( &lc_curr, op );
}
}
}
/* Explicit Bind requests always get their own conn */
if ( lookupconn ) {
- /* Searches for a ldapconn in the avl tree */
retry_lock:
ldap_pvt_thread_mutex_lock( &li->li_conninfo.lai_mutex );
+ if ( LDAP_BACK_PCONN_ISPRIV( &lc_curr ) ) {
+ /* lookup a conn that's not binding */
+ LDAP_TAILQ_FOREACH( lc,
+ &li->li_conn_priv[ LDAP_BACK_CONN2PRIV( &lc_curr ) ].lic_priv,
+ lc_q )
+ {
+ if ( !LDAP_BACK_CONN_BINDING( lc ) && lc->lc_refcnt == 0 ) {
+ break;
+ }
+ }
+
+ if ( lc != NULL ) {
+ if ( lc != LDAP_TAILQ_LAST( &li->li_conn_priv[ LDAP_BACK_CONN2PRIV( lc ) ].lic_priv,
+ ldapconn_t, lc_q ) )
+ {
+ LDAP_TAILQ_REMOVE( &li->li_conn_priv[ LDAP_BACK_CONN2PRIV( lc ) ].lic_priv,
+ lc, lc_q );
+ lc->lc_q.tqe_prev = NULL;
+ lc->lc_q.tqe_next = NULL;
+ LDAP_TAILQ_INSERT_TAIL( &li->li_conn_priv[ LDAP_BACK_CONN2PRIV( lc ) ].lic_priv,
+ lc, lc_q );
+ }
+
+ } else if ( !LDAP_BACK_USE_TEMPORARIES( li )
+ && li->li_conn_priv[ LDAP_BACK_CONN2PRIV( &lc_curr ) ].lic_num == li->li_conn_priv_max )
+ {
+ lc = LDAP_TAILQ_FIRST( &li->li_conn_priv[ LDAP_BACK_CONN2PRIV( &lc_curr ) ].lic_priv );
+ }
+
+ } else {
+
+ /* Searches for a ldapconn in the avl tree */
+ lc = (ldapconn_t *)avl_find( li->li_conninfo.lai_tree,
+ (caddr_t)&lc_curr, ldap_back_conndn_cmp );
+ }
- lc = (ldapconn_t *)avl_find( li->li_conninfo.lai_tree,
- (caddr_t)&lc_curr, ldap_back_conndn_cmp );
if ( lc != NULL ) {
/* Don't reuse connections while they're still binding */
if ( LDAP_BACK_CONN_BINDING( lc ) ) {
ldap_pvt_thread_yield();
goto retry_lock;
}
-
lc = NULL;
+ }
- } else {
-
+ if ( lc != NULL ) {
if ( op->o_tag == LDAP_REQ_BIND ) {
/* right now, this is the only possible case */
assert( ( li->li_idassert_flags & LDAP_BACK_AUTH_OVERRIDE ) );
LDAP_BACK_CONN_ISPRIV_SET( lc );
} else if ( LDAP_BACK_CONN_ISIDASSERT( &lc_curr ) ) {
- ber_dupbv( &lc->lc_bound_ndn, &li->li_idassert_authcDN );
- ber_dupbv( &lc->lc_cred, &li->li_idassert_passwd );
+ if ( !LDAP_BACK_PCONN_ISBIND( &lc_curr ) ) {
+ ber_dupbv( &lc->lc_bound_ndn, &li->li_idassert_authcDN );
+ ber_dupbv( &lc->lc_cred, &li->li_idassert_passwd );
+ }
LDAP_BACK_CONN_ISIDASSERT_SET( lc );
} else {
* check if the non-TLS connection was already
* in cache; in case, destroy the newly created
* connection and use the existing one */
- if ( lc->lc_conn == LDAP_BACK_PCONN_TLS
+ if ( LDAP_BACK_PCONN_ISTLS( lc )
&& !ldap_tls_inplace( lc->lc_ld ) )
{
- ldapconn_t *tmplc;
+ ldapconn_t *tmplc = NULL;
+ int idx = LDAP_BACK_CONN2PRIV( &lc_curr ) - 1;
- lc_curr.lc_conn = LDAP_BACK_PCONN;
ldap_pvt_thread_mutex_lock( &li->li_conninfo.lai_mutex );
- tmplc = (ldapconn_t *)avl_find( li->li_conninfo.lai_tree,
- (caddr_t)&lc_curr, ldap_back_conndn_cmp );
+ LDAP_TAILQ_FOREACH( tmplc,
+ &li->li_conn_priv[ idx ].lic_priv,
+ lc_q )
+ {
+ if ( !LDAP_BACK_CONN_BINDING( tmplc ) ) {
+ break;
+ }
+ }
+
if ( tmplc != NULL ) {
refcnt = ++tmplc->lc_refcnt;
binding = ++tmplc->lc_binding;
}
#endif /* HAVE_TLS */
- LDAP_BACK_CONN_ISBOUND_CLEAR( lc );
-
/* Inserts the newly created ldapconn in the avl tree */
ldap_pvt_thread_mutex_lock( &li->li_conninfo.lai_mutex );
+ LDAP_BACK_CONN_ISBOUND_CLEAR( lc );
+
+ assert( lc->lc_refcnt == 1 );
+ assert( lc->lc_binding == 1 );
+
#if LDAP_BACK_PRINT_CONNTREE > 0
- ldap_back_print_conntree( li->li_conninfo.lai_tree, ">>> ldap_back_getconn(insert)" );
+ ldap_back_print_conntree( li, ">>> ldap_back_getconn(insert)" );
#endif /* LDAP_BACK_PRINT_CONNTREE */
- assert( lc->lc_refcnt == 1 );
- assert( lc->lc_binding == 1 );
- rs->sr_err = avl_insert( &li->li_conninfo.lai_tree, (caddr_t)lc,
- ldap_back_conndn_cmp, ldap_back_conndn_dup );
+ if ( LDAP_BACK_PCONN_ISPRIV( lc ) ) {
+ if ( li->li_conn_priv[ LDAP_BACK_CONN2PRIV( lc ) ].lic_num < li->li_conn_priv_max ) {
+ LDAP_TAILQ_INSERT_TAIL( &li->li_conn_priv[ LDAP_BACK_CONN2PRIV( lc ) ].lic_priv, lc, lc_q );
+ li->li_conn_priv[ LDAP_BACK_CONN2PRIV( lc ) ].lic_num++;
+ LDAP_BACK_CONN_CACHED_SET( lc );
+
+ } else {
+ LDAP_BACK_CONN_TAINTED_SET( lc );
+ }
+ rs->sr_err = 0;
+
+ } else {
+ rs->sr_err = avl_insert( &li->li_conninfo.lai_tree, (caddr_t)lc,
+ ldap_back_conndn_cmp, ldap_back_conndn_dup );
+ LDAP_BACK_CONN_CACHED_SET( lc );
+ }
#if LDAP_BACK_PRINT_CONNTREE > 0
- ldap_back_print_conntree( li->li_conninfo.lai_tree, "<<< ldap_back_getconn(insert)" );
+ ldap_back_print_conntree( li, "<<< ldap_back_getconn(insert)" );
#endif /* LDAP_BACK_PRINT_CONNTREE */
ldap_pvt_thread_mutex_unlock( &li->li_conninfo.lai_mutex );
- Debug( LDAP_DEBUG_TRACE,
- "=>ldap_back_getconn: conn %p inserted refcnt=%u binding=%u\n",
- (void *)lc, refcnt, binding );
+ if ( LogTest( LDAP_DEBUG_TRACE ) ) {
+ char buf[ SLAP_TEXT_BUFLEN ];
+
+ snprintf( buf, sizeof( buf ),
+ "lc=%p inserted refcnt=%u binding=%u rc=%d",
+ (void *)lc, refcnt, binding, rs->sr_err );
+
+ Debug( LDAP_DEBUG_TRACE,
+ "=>ldap_back_getconn: %s: %s\n",
+ op->o_log_prefix, buf, 0 );
+ }
- /* Err could be -1 in case a duplicate ldapconn is inserted */
- switch ( rs->sr_err ) {
- case 0:
- break;
+ if ( !LDAP_BACK_PCONN_ISPRIV( lc ) ) {
+ /* Err could be -1 in case a duplicate ldapconn is inserted */
+ switch ( rs->sr_err ) {
+ case 0:
+ break;
- case -1:
- if ( !( sendok & LDAP_BACK_BINDING ) && !LDAP_BACK_USE_TEMPORARIES( li ) ) {
- /* duplicate: free and try to get the newly created one */
- ldap_back_conn_free( lc );
- lc = NULL;
- goto retry_lock;
- }
+ case -1:
+ LDAP_BACK_CONN_CACHED_CLEAR( lc );
+ if ( !( sendok & LDAP_BACK_BINDING ) && !LDAP_BACK_USE_TEMPORARIES( li ) ) {
+ /* duplicate: free and try to get the newly created one */
+ ldap_back_conn_free( lc );
+ lc = NULL;
+ goto retry_lock;
+ }
- /* taint connection, so that it'll be freed when released */
- LDAP_BACK_CONN_TAINTED_SET( lc );
- break;
+ /* taint connection, so that it'll be freed when released */
+ LDAP_BACK_CONN_TAINTED_SET( lc );
+ break;
- default:
- ldap_back_conn_free( lc );
- rs->sr_err = LDAP_OTHER;
- rs->sr_text = "proxy bind collision";
- if ( op->o_conn && ( sendok & LDAP_BACK_SENDERR ) ) {
- send_ldap_result( op, rs );
- rs->sr_text = NULL;
+ default:
+ LDAP_BACK_CONN_CACHED_CLEAR( lc );
+ ldap_back_conn_free( lc );
+ rs->sr_err = LDAP_OTHER;
+ rs->sr_text = "proxy bind collision";
+ if ( op->o_conn && ( sendok & LDAP_BACK_SENDERR ) ) {
+ send_ldap_result( op, rs );
+ rs->sr_text = NULL;
+ }
+ return NULL;
}
- return NULL;
}
} else {
/* let it be used, but taint/delete it so that
* no-one else can look it up any further */
ldap_pvt_thread_mutex_lock( &li->li_conninfo.lai_mutex );
+
#if LDAP_BACK_PRINT_CONNTREE > 0
- ldap_back_print_conntree( li->li_conninfo.lai_tree, ">>> ldap_back_getconn(timeout)" );
+ ldap_back_print_conntree( li, ">>> ldap_back_getconn(timeout)" );
#endif /* LDAP_BACK_PRINT_CONNTREE */
- (void *)avl_delete( &li->li_conninfo.lai_tree, (caddr_t)lc,
+
+ if ( LDAP_BACK_PCONN_ISPRIV( lc ) ) {
+ if ( lc->lc_q.tqe_prev != NULL ) {
+ assert( LDAP_BACK_CONN_CACHED( lc ) );
+ assert( li->li_conn_priv[ LDAP_BACK_CONN2PRIV( lc ) ].lic_num > 0 );
+ LDAP_TAILQ_REMOVE( &li->li_conn_priv[ LDAP_BACK_CONN2PRIV( lc ) ].lic_priv,
+ lc, lc_q );
+ li->li_conn_priv[ LDAP_BACK_CONN2PRIV( lc ) ].lic_num--;
+ lc->lc_q.tqe_prev = NULL;
+ lc->lc_q.tqe_next = NULL;
+
+ } else {
+ assert( !LDAP_BACK_CONN_CACHED( lc ) );
+ }
+
+ } else {
+ (void)avl_delete( &li->li_conninfo.lai_tree, (caddr_t)lc,
ldap_back_conndnlc_cmp );
+ }
+ LDAP_BACK_CONN_TAINTED_SET( lc );
+ LDAP_BACK_CONN_CACHED_CLEAR( lc );
+
#if LDAP_BACK_PRINT_CONNTREE > 0
- ldap_back_print_conntree( li->li_conninfo.lai_tree, "<<< ldap_back_getconn(timeout)" );
+ ldap_back_print_conntree( li, "<<< ldap_back_getconn(timeout)" );
#endif /* LDAP_BACK_PRINT_CONNTREE */
+
ldap_pvt_thread_mutex_unlock( &li->li_conninfo.lai_mutex );
- LDAP_BACK_CONN_TAINTED_SET( lc );
}
if ( LogTest( LDAP_DEBUG_TRACE ) ) {
int
ldap_back_retry( ldapconn_t **lcp, Operation *op, SlapReply *rs, ldap_back_send_t sendok )
{
- int rc = 0;
ldapinfo_t *li = (ldapinfo_t *)op->o_bd->be_private;
+ int rc = 0,
+ binding;
assert( lcp != NULL );
assert( *lcp != NULL );
ldap_pvt_thread_mutex_lock( &li->li_conninfo.lai_mutex );
if ( (*lcp)->lc_refcnt == 1 ) {
+ binding = LDAP_BACK_CONN_BINDING( *lcp );
+
ldap_pvt_thread_mutex_lock( &li->li_uri_mutex );
Debug( LDAP_DEBUG_ANY,
"%s ldap_back_retry: retrying URI=\"%s\" DN=\"%s\"\n",
rc = 0;
} else if ( ( sendok & LDAP_BACK_BINDING ) ) {
+ if ( binding ) {
+ LDAP_BACK_CONN_BINDING_SET( *lcp );
+ }
rc = 1;
} else {
LDAP_BACK_CONN_ISBOUND_SET( lc );
ber_bvreplace( &lc->lc_bound_ndn, binddn );
+ if ( !BER_BVISNULL( &lc->lc_cred ) ) {
+ memset( lc->lc_cred.bv_val, 0,
+ lc->lc_cred.bv_len );
+ }
+
if ( LDAP_BACK_SAVECRED( li ) ) {
- if ( !BER_BVISNULL( &lc->lc_cred ) ) {
- memset( lc->lc_cred.bv_val, 0,
- lc->lc_cred.bv_len );
- }
ber_bvreplace( &lc->lc_cred, bindcred );
ldap_set_rebind_proc( lc->lc_ld, li->li_rebind_f, lc );
+
+ } else {
+ lc->lc_cred.bv_len = 0;
}
}
done:;
LDAP_BACK_CFG_VERSION,
LDAP_BACK_CFG_SINGLECONN,
LDAP_BACK_CFG_USETEMP,
+ LDAP_BACK_CFG_CONNPOOLMAX,
LDAP_BACK_CFG_CANCEL,
LDAP_BACK_CFG_QUARANTINE,
LDAP_BACK_CFG_REWRITE,
"SYNTAX OMsBoolean "
"SINGLE-VALUE )",
NULL, NULL },
+ { "conn-pool-max", "<n>", 2, 0, 0,
+ ARG_MAGIC|ARG_INT|LDAP_BACK_CFG_CONNPOOLMAX,
+ ldap_back_cf_gen, "( OLcfgDbAt:3.23 "
+ "NAME 'olcDbConnectionPoolMax' "
+ "DESC 'Max size of privileged connections pool' "
+ "SYNTAX OMsInteger "
+ "SINGLE-VALUE )",
+ NULL, NULL },
{ "suffixmassage", "[virtual]> <real", 2, 3, 0,
ARG_STRING|ARG_MAGIC|LDAP_BACK_CFG_REWRITE,
ldap_back_cf_gen, NULL, NULL, NULL },
"$ olcDbCancel "
"$ olcDbQuarantine "
"$ olcDbUseTemporaryConn "
+ "$ olcDbConnectionPoolMax "
") )",
Cft_Database, ldapcfg},
{ NULL, 0, NULL }
c->value_int = LDAP_BACK_USE_TEMPORARIES( li );
break;
+ case LDAP_BACK_CFG_CONNPOOLMAX:
+ c->value_int = li->li_conn_priv_max;
+ break;
+
case LDAP_BACK_CFG_CANCEL: {
slap_mask_t mask = LDAP_BACK_F_CANCEL_MASK2;
li->li_flags &= ~LDAP_BACK_F_USE_TEMPORARIES;
break;
+ case LDAP_BACK_CFG_CONNPOOLMAX:
+ li->li_conn_priv_max = LDAP_BACK_CONN_PRIV_MIN;
+ break;
+
case LDAP_BACK_CFG_QUARANTINE:
if ( !LDAP_BACK_QUARANTINE( li ) ) {
break;
}
break;
+ case LDAP_BACK_CFG_CONNPOOLMAX:
+ if ( c->value_int < LDAP_BACK_CONN_PRIV_MIN
+ || c->value_int > LDAP_BACK_CONN_PRIV_MAX )
+ {
+ snprintf( c->msg, sizeof( c->msg ),
+ "invalid max size " "of privileged "
+ "connections pool \"%s\" "
+ "in \"conn-pool-max <n> "
+ "(must be between %d and %d)\"",
+ c->argv[ 1 ],
+ LDAP_BACK_CONN_PRIV_MIN,
+ LDAP_BACK_CONN_PRIV_MAX );
+ Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->msg, 0 );
+ return 1;
+ }
+ li->li_conn_priv_max = c->value_int;
+ break;
+
case LDAP_BACK_CFG_CANCEL: {
slap_mask_t mask;
{
ldapinfo_t *li;
int rc;
+ unsigned i;
li = (ldapinfo_t *)ch_calloc( 1, sizeof( ldapinfo_t ) );
if ( li == NULL ) {
ldap_pvt_thread_mutex_init( &li->li_conninfo.lai_mutex );
+ for ( i = LDAP_BACK_PCONN_FIRST; i < LDAP_BACK_PCONN_LAST; i++ ) {
+ li->li_conn_priv[ i ].lic_num = 0;
+ LDAP_TAILQ_INIT( &li->li_conn_priv[ i ].lic_priv );
+ }
+ li->li_conn_priv_max = LDAP_BACK_CONN_PRIV_DEFAULT;
+
be->be_private = li;
SLAP_DBFLAGS( be ) |= SLAP_DBFLAG_NOLASTMOD;
if ( !BER_BVISNULL( &lc->lc_local_ndn ) ) {
ch_free( lc->lc_local_ndn.bv_val );
}
+ lc->lc_q.tqe_prev = NULL;
+ lc->lc_q.tqe_next = NULL;
ch_free( lc );
}
{
if ( be->be_private ) {
ldapinfo_t *li = ( ldapinfo_t * )be->be_private;
+ unsigned i;
(void)ldap_back_monitor_db_destroy( be );
if ( li->li_conninfo.lai_tree ) {
avl_free( li->li_conninfo.lai_tree, ldap_back_conn_free );
}
+ for ( i = LDAP_BACK_PCONN_FIRST; i < LDAP_BACK_PCONN_LAST; i++ ) {
+ while ( !LDAP_TAILQ_EMPTY( &li->li_conn_priv[ i ].lic_priv ) ) {
+ ldapconn_t *lc = LDAP_TAILQ_FIRST( &li->li_conn_priv[ i ].lic_priv );
+
+ LDAP_TAILQ_REMOVE( &li->li_conn_priv[ i ].lic_priv, lc, lc_q );
+ ldap_back_conn_free( lc );
+ }
+ }
if ( LDAP_BACK_QUARANTINE( li ) ) {
slap_retry_info_destroy( &li->li_quarantine );
ldap_pvt_thread_mutex_destroy( &li->li_quarantine_mutex );
extern BI_entry_get_rw ldap_back_entry_get;
-int ldap_back_freeconn( Operation *op, ldapconn_t *lc, int dolock );
void ldap_back_release_conn_lock( Operation *op, SlapReply *rs, ldapconn_t **lcp, int dolock );
#define ldap_back_release_conn(op, rs, lc) ldap_back_release_conn_lock((op), (rs), &(lc), 1)
int ldap_back_dobind( ldapconn_t **lcp, Operation *op, SlapReply *rs, ldap_back_send_t sendok );
#ifdef LDAP_BACK_PRINT_CONNTREE
extern void
-ldap_back_print_conntree( Avlnode *root, char *msg );
+ldap_back_print_conntree( ldapinfo_t *li, char *msg );
#endif /* LDAP_BACK_PRINT_CONNTREE */
extern void slap_retry_info_destroy( slap_retry_info_t *ri );
ldap_pvt_thread_mutex_lock( &li->li_conninfo.lai_mutex );
#if LDAP_BACK_PRINT_CONNTREE > 0
- ldap_back_print_conntree( li->li_conninfo.lai_tree, ">>> ldap_back_conn_destroy" );
+ ldap_back_print_conntree( li, ">>> ldap_back_conn_destroy" );
#endif /* LDAP_BACK_PRINT_CONNTREE */
while ( ( lc = avl_delete( &li->li_conninfo.lai_tree, (caddr_t)&lc_curr, ldap_back_conn_cmp ) ) != NULL )
{
ldap_back_conn_free( lc );
}
#if LDAP_BACK_PRINT_CONNTREE > 0
- ldap_back_print_conntree( li->li_conninfo.lai_tree, "<<< ldap_back_conn_destroy" );
+ ldap_back_print_conntree( li, "<<< ldap_back_conn_destroy" );
#endif /* LDAP_BACK_PRINT_CONNTREE */
ldap_pvt_thread_mutex_unlock( &li->li_conninfo.lai_mutex );
struct metainfo_t *mc_info;
+ LDAP_TAILQ_ENTRY(metaconn_t) mc_q;
+
/* supersedes the connection stuff */
metasingleconn_t mc_conns[ 1 ];
/* NOTE: mc_conns must be last, because
metadncache_t mi_cache;
+ /* cached connections;
+ * special conns are in tailq rather than in tree */
ldap_avl_info_t mi_conninfo;
+ struct {
+ int mic_num;
+ LDAP_TAILQ_HEAD(mc_conn_priv_q, metaconn_t) mic_priv;
+ } mi_conn_priv[ LDAP_BACK_PCONN_LAST ];
+ int mi_conn_priv_max;
/* NOTE: quarantine uses the connection mutex */
slap_retry_info_t mi_quarantine;
#if META_BACK_PRINT_CONNTREE > 0
extern void
meta_back_print_conntree(
- Avlnode *root,
+ metainfo_t *mi,
char *msg );
#endif
assert( mc->mc_refcnt == 1 );
#if META_BACK_PRINT_CONNTREE > 0
- meta_back_print_conntree( mi->mi_conninfo.lai_tree, ">>> meta_back_bind" );
+ meta_back_print_conntree( mi, ">>> meta_back_bind" );
#endif /* META_BACK_PRINT_CONNTREE */
tmpmc = avl_delete( &mi->mi_conninfo.lai_tree, (caddr_t)mc,
meta_back_conndn_cmp );
ber_bvreplace( &mc->mc_local_ndn, &op->o_req_ndn );
if ( isroot ) {
LDAP_BACK_CONN_ISPRIV_SET( mc );
- mc->mc_conn = LDAP_BACK_PCONN_SET( op );
+ LDAP_BACK_PCONN_SET( mc, op );
}
lerr = avl_insert( &mi->mi_conninfo.lai_tree, (caddr_t)mc,
meta_back_conndn_cmp, meta_back_conndn_dup );
#if META_BACK_PRINT_CONNTREE > 0
- meta_back_print_conntree( mi->mi_conninfo.lai_tree, "<<< meta_back_bind" );
+ meta_back_print_conntree( mi, "<<< meta_back_bind" );
#endif /* META_BACK_PRINT_CONNTREE */
ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex );
if ( lerr == -1 ) {
return 1;
}
+ /* privileged connections pool max size ? */
+ } else if ( strcasecmp( argv[ 0 ], "conn-pool-max" ) == 0 ) {
+ if ( argc != 2 ) {
+ Debug( LDAP_DEBUG_ANY,
+ "%s: line %d: \"conn-pool-max <n>\" takes 1 argument\n",
+ fname, lineno, 0 );
+ return( 1 );
+ }
+
+ if ( mi->mi_ntargets > 0 ) {
+ Debug( LDAP_DEBUG_ANY,
+ "%s: line %d: \"conn-pool-max\" must appear before target definitions\n",
+ fname, lineno, 0 );
+ return( 1 );
+ }
+
+ if ( lutil_atoi( &mi->mi_conn_priv_max, argv[1] )
+ || mi->mi_conn_priv_max < LDAP_BACK_CONN_PRIV_MIN
+ || mi->mi_conn_priv_max > LDAP_BACK_CONN_PRIV_MAX )
+ {
+ Debug( LDAP_DEBUG_ANY,
+ "%s: line %d: \"conn-pool-max <n>\": invalid arg \"%s\".\n",
+ fname, lineno, argv[ 1 ] );
+ return 1;
+ }
+
} else if ( strcasecmp( argv[ 0 ], "cancel" ) == 0 ) {
unsigned flag = 0;
unsigned *flagsp = mi->mi_ntargets ?
*/
#if META_BACK_PRINT_CONNTREE > 0
static void
-ravl_print( Avlnode *root, int depth )
+meta_back_ravl_print( Avlnode *root, int depth )
{
int i;
metaconn_t *mc;
return;
}
- ravl_print( root->avl_right, depth + 1 );
+ meta_back_ravl_print( root->avl_right, depth + 1 );
for ( i = 0; i < depth; i++ ) {
fprintf( stderr, "-" );
avl_bf2str( root->avl_bf ), mc->mc_refcnt,
LDAP_BACK_CONN_TAINTED( mc ) ? " tainted" : "" );
- ravl_print( root->avl_left, depth + 1 );
+ meta_back_ravl_print( root->avl_left, depth + 1 );
}
+/* NOTE: duplicate from back-ldap/bind.c */
+static char* priv2str[] = {
+ "privileged",
+ "privileged/TLS",
+ "anonymous",
+ "anonymous/TLS",
+ "bind",
+ "bind/TLS",
+ NULL
+};
+
void
-meta_back_print_conntree( Avlnode *root, char *msg )
+meta_back_print_conntree( metainfo_t *mi, char *msg )
{
+ int c;
+
fprintf( stderr, "========> %s\n", msg );
- if ( root == 0 ) {
+ for ( c = LDAP_BACK_PCONN_FIRST; c < LDAP_BACK_PCONN_LAST; c++ ) {
+ int i = 0;
+ metaconn_t *mc;
+
+ fprintf( stderr, " %s[%d]\n", priv2str[ c ], mi->mi_conn_priv[ c ].mic_num );
+
+ LDAP_TAILQ_FOREACH( mc, &mi->mi_conn_priv[ c ].mic_priv, mc_q )
+ {
+ fprintf( stderr, " [%d] mc=%p local=\"%s\" conn=%p refcnt=%d flags=0x%08x\n",
+ i,
+ (void *)mc,
+ mc->mc_local_ndn.bv_val ? mc->mc_local_ndn.bv_val : "",
+ (void *)mc->mc_conn, mc->mc_refcnt, mc->msc_mscflags );
+ i++;
+ }
+ }
+
+ if ( mi->mi_conninfo.lai_tree == NULL ) {
fprintf( stderr, "\t(empty)\n" );
} else {
- ravl_print( root, 0 );
+ meta_back_ravl_print( mi->mi_conninfo.lai_tree, 0 );
}
fprintf( stderr, "<======== %s\n", msg );
} else {
#if META_BACK_PRINT_CONNTREE > 0
- meta_back_print_conntree( mi->mi_conninfo.lai_tree, ">>> meta_back_retry" );
+ meta_back_print_conntree( mi, ">>> meta_back_retry" );
#endif /* META_BACK_PRINT_CONNTREE */
+
/* FIXME: could be done better, reworking meta_back_release_conn_lock() */
- (void)avl_delete( &mi->mi_conninfo.lai_tree,
- ( caddr_t )mc, meta_back_conndnmc_cmp );
+ 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--;
+ mc->mc_q.tqe_prev = NULL;
+ mc->mc_q.tqe_next = NULL;
+
+ } 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->mi_conninfo.lai_tree, "<<< meta_back_retry" );
+ meta_back_print_conntree( mi, "<<< meta_back_retry" );
#endif /* META_BACK_PRINT_CONNTREE */
}
}
if ( META_BACK_PROXYAUTHZ_ALWAYS( mi ) || op->o_do_not_cache || be_isroot( op ) ) {
mc_curr.mc_local_ndn = op->o_bd->be_rootndn;
LDAP_BACK_CONN_ISPRIV_SET( &mc_curr );
- mc_curr.mc_conn = LDAP_BACK_PCONN_SET( op );
+ LDAP_BACK_PCONN_ROOTDN_SET( &mc_curr, op );
} else {
mc_curr.mc_local_ndn = op->o_ndn;
mc_curr.mc_conn = op->o_conn;
} else {
- mc_curr.mc_conn = LDAP_BACK_PCONN_SET( op );
+ LDAP_BACK_CONN_ISANON_SET( &mc_curr );
+ LDAP_BACK_PCONN_ANON_SET( &mc_curr, op );
}
}
/* Searches for a metaconn in the avl tree */
retry_lock:;
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 ( 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 );
+ mc->mc_q.tqe_prev = NULL;
+ mc->mc_q.tqe_next = NULL;
+ 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 ) );
|| ( 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->mi_conninfo.lai_tree,
+ meta_back_print_conntree( mi,
">>> meta_back_getconn(expired)" );
#endif /* META_BACK_PRINT_CONNTREE */
+
/* don't let anyone else use this expired connection */
- (void)avl_delete( &mi->mi_conninfo.lai_tree,
- (caddr_t)mc, meta_back_conndnmc_cmp );
+ 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--;
+ mc->mc_q.tqe_prev = NULL;
+ mc->mc_q.tqe_next = NULL;
+
+ } 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->mi_conninfo.lai_tree,
+ 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 ) );
}
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 ) {
}
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 );
}
}
}
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 );
}
}
*/
ldap_pvt_thread_mutex_lock( &mi->mi_conninfo.lai_mutex );
#if META_BACK_PRINT_CONNTREE > 0
- meta_back_print_conntree( mi->mi_conninfo.lai_tree, ">>> meta_back_getconn" );
+ meta_back_print_conntree( mi, ">>> meta_back_getconn" );
#endif /* META_BACK_PRINT_CONNTREE */
- err = avl_insert( &mi->mi_conninfo.lai_tree, ( caddr_t )mc,
+
+ 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->mi_conninfo.lai_tree, ">>> meta_back_getconn" );
+ meta_back_print_conntree( mi, ">>> meta_back_getconn" );
#endif /* META_BACK_PRINT_CONNTREE */
ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex );
- /*
- * Err could be -1 in case a duplicate metaconn is inserted
- */
- switch ( err ) {
- case 0:
- break;
-
- case -1:
- /* 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 );
+ if ( !LDAP_BACK_PCONN_ISPRIV( mc ) ) {
+ /*
+ * Err could be -1 in case a duplicate metaconn is inserted
+ */
+ switch ( err ) {
+ case 0:
+ break;
- new_conn = 0;
- goto retry_lock;
- }
+ 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;
+ LDAP_BACK_CONN_TAINTED_SET( mc );
+ break;
- default:
- 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 ) );
+ 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 );
+ 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 );
- rs->sr_text = NULL;
+ rs->sr_err = LDAP_OTHER;
+ rs->sr_text = "proxy bind collision";
+ if ( sendok & LDAP_BACK_SENDERR ) {
+ send_ldap_result( op, rs );
+ rs->sr_text = NULL;
+ }
+ return NULL;
}
- return NULL;
}
Debug( LDAP_DEBUG_TRACE,
* 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 ) ||
- ( !LDAP_BACK_CONN_ISPRIV( mc ) && LDAP_BACK_PCONN_ISPRIV( mc ) && mc->mc_refcnt == 0 ) )
- {
- metaconn_t *tmpmc;
-
+ if ( LDAP_BACK_CONN_TAINTED( mc ) ) {
Debug( LDAP_DEBUG_TRACE, "%s meta_back_release_conn: mc=%p conn=%ld tainted.\n",
op->o_log_prefix, (void *)mc, LDAP_BACK_PCONN_ID( mc ) );
#if META_BACK_PRINT_CONNTREE > 0
- meta_back_print_conntree( mi->mi_conninfo.lai_tree, ">>> meta_back_release_conn" );
-#endif /* META_BACK_PRINT_CONNTREE */
- tmpmc = 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->mi_conninfo.lai_tree, "<<< meta_back_release_conn" );
+ meta_back_print_conntree( mi, ">>> meta_back_release_conn" );
#endif /* META_BACK_PRINT_CONNTREE */
- if ( tmpmc == NULL ) {
- Debug( LDAP_DEBUG_TRACE, "%s: meta_back_release_conn: unable to find mc=%p\n",
- op->o_log_prefix, (void *)mc, 0 );
+
+ 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 );
+ mi->mi_conn_priv[ LDAP_BACK_CONN2PRIV( mc ) ].mic_num--;
+ LDAP_TAILQ_REMOVE( &mi->mi_conn_priv[ LDAP_BACK_CONN2PRIV( mc ) ].mic_priv, mc, mc_q );
+
+ } else {
+ assert( !LDAP_BACK_CONN_CACHED( mc ) );
+ }
+ mc->mc_q.tqe_prev = NULL;
+ mc->mc_q.tqe_next = NULL;
+
} else {
- assert( tmpmc == mc );
+ metaconn_t *tmpmc;
+
+ tmpmc = avl_delete( &mi->mi_conninfo.lai_tree,
+ ( caddr_t )mc, meta_back_conndnmc_cmp );
+
+ if ( tmpmc == NULL ) {
+ Debug( LDAP_DEBUG_TRACE, "%s: meta_back_release_conn: unable to find mc=%p\n",
+ op->o_log_prefix, (void *)mc, 0 );
+ } else {
+ assert( 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;
Backend *be )
{
metainfo_t *mi;
+ int i;
mi = ch_calloc( 1, sizeof( metainfo_t ) );
if ( mi == NULL ) {
/* safe default */
mi->mi_nretries = META_RETRY_DEFAULT;
mi->mi_version = LDAP_VERSION3;
+
+ for ( i = LDAP_BACK_PCONN_FIRST; i < LDAP_BACK_PCONN_LAST; i++ ) {
+ mi->mi_conn_priv[ i ].mic_num = 0;
+ LDAP_TAILQ_INIT( &mi->mi_conn_priv[ i ].mic_priv );
+ }
+ mi->mi_conn_priv_max = LDAP_BACK_CONN_PRIV_DEFAULT;
be->be_private = mi;
if ( mi->mi_conninfo.lai_tree ) {
avl_free( mi->mi_conninfo.lai_tree, meta_back_conn_free );
}
+ for ( i = LDAP_BACK_PCONN_FIRST; i < LDAP_BACK_PCONN_LAST; i++ ) {
+ while ( !LDAP_TAILQ_EMPTY( &mi->mi_conn_priv[ i ].mic_priv ) ) {
+ metaconn_t *mc = LDAP_TAILQ_FIRST( &mi->mi_conn_priv[ i ].mic_priv );
+
+ LDAP_TAILQ_REMOVE( &mi->mi_conn_priv[ i ].mic_priv, mc, mc_q );
+ meta_back_conn_free( mc );
+ }
+ }
/*
* Destroy the per-target stuff (assuming there's at
ldap_pvt_thread_mutex_lock( &mi->mi_conninfo.lai_mutex );
#if META_BACK_PRINT_CONNTREE > 0
- meta_back_print_conntree( mi->mi_conninfo.lai_tree, ">>> meta_back_conn_destroy" );
+ meta_back_print_conntree( mi, ">>> meta_back_conn_destroy" );
#endif /* META_BACK_PRINT_CONNTREE */
while ( ( mc = avl_delete( &mi->mi_conninfo.lai_tree, ( caddr_t )&mc_curr, meta_back_conn_cmp ) ) != NULL )
{
meta_back_conn_free( mc );
}
#if META_BACK_PRINT_CONNTREE > 0
- meta_back_print_conntree( mi->mi_conninfo.lai_tree, "<<< meta_back_conn_destroy" );
+ meta_back_print_conntree( mi, "<<< meta_back_conn_destroy" );
#endif /* META_BACK_PRINT_CONNTREE */
ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex );