From: Pierangelo Masarati Date: Sun, 24 Dec 2006 18:23:36 +0000 (+0000) Subject: pool privileged connections (ITS#4791) X-Git-Tag: OPENLDAP_REL_ENG_2_4_4ALPHA~8^2~309 X-Git-Url: https://git.sur5r.net/?a=commitdiff_plain;h=7e8242d50d829776caeebd04bbc06bc92e6f7da7;p=openldap pool privileged connections (ITS#4791) --- diff --git a/servers/slapd/back-ldap/back-ldap.h b/servers/slapd/back-ldap/back-ldap.h index 6fbabaec5e..12cc7fa414 100644 --- a/servers/slapd/back-ldap/back-ldap.h +++ b/servers/slapd/back-ldap/back-ldap.h @@ -44,22 +44,57 @@ typedef struct ldap_monitor_info_t { 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; @@ -93,6 +128,7 @@ typedef struct ldapconn_t { #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) @@ -120,12 +156,17 @@ typedef struct ldapconn_t { #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 { @@ -259,8 +300,11 @@ typedef struct ldapinfo_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 ) @@ -269,6 +313,10 @@ typedef struct ldapinfo_t { #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 ) @@ -285,10 +333,23 @@ typedef struct ldapinfo_t { 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) diff --git a/servers/slapd/back-ldap/bind.c b/servers/slapd/back-ldap/bind.c index 738549f6af..a3309b3477 100644 --- a/servers/slapd/back-ldap/bind.c +++ b/servers/slapd/back-ldap/bind.c @@ -41,7 +41,7 @@ #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; @@ -50,38 +50,70 @@ ravl_print( Avlnode *root, int depth ) 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 ); @@ -116,10 +148,17 @@ ldap_back_bind( Operation *op, SlapReply *rs ) 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:; @@ -159,13 +198,17 @@ 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; } } @@ -174,8 +217,8 @@ retry:; /* 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; @@ -190,13 +233,31 @@ retry_lock:; } #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 ) ) { @@ -209,6 +270,7 @@ retry_lock:; if ( tmplc->lc_refcnt != 0 ) { /* taint it */ LDAP_BACK_CONN_TAINTED_SET( tmplc ); + LDAP_BACK_CONN_CACHED_CLEAR( tmplc ); } else { /* @@ -224,19 +286,20 @@ retry_lock:; 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: @@ -350,29 +413,51 @@ ldap_back_conndn_dup( void *c1, void *c2 ) 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 ) { @@ -394,13 +479,9 @@ ldap_back_start_tls( 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 @@ -509,7 +590,7 @@ retry:; break; default: - if ( LDAP_BACK_TLS_CRITICAL( &dummy ) ) { + if ( LDAP_BACK_TLS_CRITICAL_F( flags ) ) { *text = "could not start TLS"; break; } @@ -655,19 +736,21 @@ ldap_back_getconn( 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; @@ -682,7 +765,7 @@ ldap_back_getconn( 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, @@ -723,12 +806,12 @@ ldap_back_getconn( } 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; @@ -736,19 +819,51 @@ ldap_back_getconn( 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 ) ) { @@ -758,11 +873,10 @@ retry_lock: 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 ) ); @@ -813,8 +927,10 @@ retry_lock: 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 { @@ -832,15 +948,22 @@ retry_lock: * 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; @@ -855,56 +978,83 @@ retry_lock: } #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 { @@ -918,16 +1068,37 @@ retry_lock: /* 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 ) ) { @@ -1620,8 +1791,9 @@ retry:; 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 ); @@ -1629,6 +1801,8 @@ ldap_back_retry( ldapconn_t **lcp, Operation *op, SlapReply *rs, ldap_back_send_ 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", @@ -1651,6 +1825,9 @@ ldap_back_retry( ldapconn_t **lcp, Operation *op, SlapReply *rs, ldap_back_send_ rc = 0; } else if ( ( sendok & LDAP_BACK_BINDING ) ) { + if ( binding ) { + LDAP_BACK_CONN_BINDING_SET( *lcp ); + } rc = 1; } else { @@ -1937,13 +2114,17 @@ ldap_back_proxy_authz_bind( 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:; diff --git a/servers/slapd/back-ldap/config.c b/servers/slapd/back-ldap/config.c index 4f2745d62b..8efa614bea 100644 --- a/servers/slapd/back-ldap/config.c +++ b/servers/slapd/back-ldap/config.c @@ -66,6 +66,7 @@ enum { 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, @@ -286,6 +287,14 @@ static ConfigTable ldapcfg[] = { "SYNTAX OMsBoolean " "SINGLE-VALUE )", NULL, NULL }, + { "conn-pool-max", "", 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]> 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; @@ -1190,6 +1204,10 @@ ldap_back_cf_gen( ConfigArgs *c ) 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; @@ -1744,6 +1762,24 @@ done_url:; } 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 " + "(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; diff --git a/servers/slapd/back-ldap/init.c b/servers/slapd/back-ldap/init.c index 4fa8eaea4d..c3f1ec2b15 100644 --- a/servers/slapd/back-ldap/init.c +++ b/servers/slapd/back-ldap/init.c @@ -102,6 +102,7 @@ ldap_back_db_init( Backend *be ) { ldapinfo_t *li; int rc; + unsigned i; li = (ldapinfo_t *)ch_calloc( 1, sizeof( ldapinfo_t ) ); if ( li == NULL ) { @@ -146,6 +147,12 @@ ldap_back_db_init( Backend *be ) 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; @@ -244,6 +251,8 @@ ldap_back_conn_free( void *v_lc ) 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 ); } @@ -264,6 +273,7 @@ ldap_back_db_destroy( Backend *be ) { if ( be->be_private ) { ldapinfo_t *li = ( ldapinfo_t * )be->be_private; + unsigned i; (void)ldap_back_monitor_db_destroy( be ); @@ -328,6 +338,14 @@ ldap_back_db_destroy( Backend *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 ); diff --git a/servers/slapd/back-ldap/proto-ldap.h b/servers/slapd/back-ldap/proto-ldap.h index 4cc5b14de9..e7431bb868 100644 --- a/servers/slapd/back-ldap/proto-ldap.h +++ b/servers/slapd/back-ldap/proto-ldap.h @@ -45,7 +45,6 @@ extern BI_connection_destroy ldap_back_conn_destroy; 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 ); @@ -83,7 +82,7 @@ ldap_back_quarantine( #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 ); diff --git a/servers/slapd/back-ldap/unbind.c b/servers/slapd/back-ldap/unbind.c index fc75e675c3..0980511f9e 100644 --- a/servers/slapd/back-ldap/unbind.c +++ b/servers/slapd/back-ldap/unbind.c @@ -49,7 +49,7 @@ ldap_back_conn_destroy( 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 ) { @@ -67,7 +67,7 @@ ldap_back_conn_destroy( 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 ); diff --git a/servers/slapd/back-meta/back-meta.h b/servers/slapd/back-meta/back-meta.h index 945d54623f..6a6870fe07 100644 --- a/servers/slapd/back-meta/back-meta.h +++ b/servers/slapd/back-meta/back-meta.h @@ -241,6 +241,8 @@ typedef struct metaconn_t { 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 @@ -346,7 +348,14 @@ typedef struct metainfo_t { 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; @@ -417,7 +426,7 @@ meta_back_conn_free( #if META_BACK_PRINT_CONNTREE > 0 extern void meta_back_print_conntree( - Avlnode *root, + metainfo_t *mi, char *msg ); #endif diff --git a/servers/slapd/back-meta/bind.c b/servers/slapd/back-meta/bind.c index 3880e06e54..0f450bef66 100644 --- a/servers/slapd/back-meta/bind.c +++ b/servers/slapd/back-meta/bind.c @@ -220,7 +220,7 @@ retry_lock:; 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 ); @@ -252,12 +252,12 @@ retry_lock:; 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 ) { diff --git a/servers/slapd/back-meta/config.c b/servers/slapd/back-meta/config.c index 6bdc63e90e..17e8b0fc89 100644 --- a/servers/slapd/back-meta/config.c +++ b/servers/slapd/back-meta/config.c @@ -877,6 +877,32 @@ meta_back_db_config( 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 \" 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 \": 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 ? diff --git a/servers/slapd/back-meta/conn.c b/servers/slapd/back-meta/conn.c index 9758cf1cd0..168ae855d5 100644 --- a/servers/slapd/back-meta/conn.c +++ b/servers/slapd/back-meta/conn.c @@ -140,7 +140,7 @@ meta_back_conndn_dup( */ #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; @@ -149,7 +149,7 @@ ravl_print( Avlnode *root, int depth ) 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, "-" ); @@ -163,19 +163,49 @@ ravl_print( Avlnode *root, int depth ) 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 ); @@ -708,13 +738,33 @@ meta_back_retry( } 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 */ } } @@ -970,7 +1020,7 @@ meta_back_getconn( 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; @@ -980,7 +1030,8 @@ meta_back_getconn( 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 ); } } @@ -989,8 +1040,41 @@ meta_back_getconn( /* 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 ) ); @@ -1013,17 +1097,36 @@ retry_lock:; || ( 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 ) ); @@ -1092,6 +1195,9 @@ retry_lock:; } 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 ) { @@ -1261,6 +1367,9 @@ retry_lock2:; } 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 ); } } } @@ -1319,6 +1428,9 @@ retry_lock2:; 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 ); } } @@ -1452,51 +1564,71 @@ done:; */ 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, @@ -1535,28 +1667,46 @@ meta_back_release_conn_lock( * 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; diff --git a/servers/slapd/back-meta/init.c b/servers/slapd/back-meta/init.c index 2b0c41835c..7a7c604a90 100644 --- a/servers/slapd/back-meta/init.c +++ b/servers/slapd/back-meta/init.c @@ -90,6 +90,7 @@ meta_back_db_init( Backend *be ) { metainfo_t *mi; + int i; mi = ch_calloc( 1, sizeof( metainfo_t ) ); if ( mi == NULL ) { @@ -113,6 +114,12 @@ meta_back_db_init( /* 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; @@ -298,6 +305,14 @@ meta_back_db_destroy( 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 diff --git a/servers/slapd/back-meta/unbind.c b/servers/slapd/back-meta/unbind.c index 1051b0b3b1..a71e533c9b 100644 --- a/servers/slapd/back-meta/unbind.c +++ b/servers/slapd/back-meta/unbind.c @@ -52,7 +52,7 @@ meta_back_conn_destroy( 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 ) { @@ -65,7 +65,7 @@ meta_back_conn_destroy( 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 );