]> git.sur5r.net Git - openldap/commitdiff
pool privileged connections (ITS#4791)
authorPierangelo Masarati <ando@openldap.org>
Sun, 24 Dec 2006 18:23:36 +0000 (18:23 +0000)
committerPierangelo Masarati <ando@openldap.org>
Sun, 24 Dec 2006 18:23:36 +0000 (18:23 +0000)
12 files changed:
servers/slapd/back-ldap/back-ldap.h
servers/slapd/back-ldap/bind.c
servers/slapd/back-ldap/config.c
servers/slapd/back-ldap/init.c
servers/slapd/back-ldap/proto-ldap.h
servers/slapd/back-ldap/unbind.c
servers/slapd/back-meta/back-meta.h
servers/slapd/back-meta/bind.c
servers/slapd/back-meta/config.c
servers/slapd/back-meta/conn.c
servers/slapd/back-meta/init.c
servers/slapd/back-meta/unbind.c

index 6fbabaec5e2ace1ee58ea104a61f4a194893b1a1..12cc7fa41430d894be4aa1ac46041b6c1569c853 100644 (file)
@@ -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)
index 738549f6af1d427dab4212b7dee86e3cab8e081c..a3309b3477bb7da3f5b37cfeb34b6cee81f9be43 100644 (file)
@@ -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:;
index 4f2745d62b0c097aa7d52d5b01fca69c08f8e9a2..8efa614bea99b5b6c42095eefd4348018883c236 100644 (file)
@@ -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", "<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 },
@@ -324,6 +333,7 @@ static ConfigOCs ldapocs[] = {
                        "$ olcDbCancel "
                        "$ olcDbQuarantine "
                        "$ olcDbUseTemporaryConn "
+                       "$ olcDbConnectionPoolMax "
                ") )",
                        Cft_Database, ldapcfg},
        { NULL, 0, NULL }
@@ -1060,6 +1070,10 @@ ldap_back_cf_gen( ConfigArgs *c )
                        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;
 
@@ -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 <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;
 
index 4fa8eaea4d03414f1f0b93e3bdf325f892ed0879..c3f1ec2b154ab8a4a304cdd8294e9e8281ba28a0 100644 (file)
@@ -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 );
index 4cc5b14de96a6e61e3749bd5279885617929d49f..e7431bb868a9c262591fbcb2c5e8af3354896829 100644 (file)
@@ -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 );
index fc75e675c3699010047c9a5460cbc200686694fc..0980511f9e56b8e468e5621e6efecc2837cb216d 100644 (file)
@@ -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 );
 
index 945d54623f0bd22bcda21401f55d0d54ec661b88..6a6870fe07ecd9d5898631e6838f21a5b8069013 100644 (file)
@@ -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
 
index 3880e06e548f0864c8da87d5015c3f8e4705eef3..0f450bef669f91bfcba697769825ada9b2aae134 100644 (file)
@@ -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 ) {
index 6bdc63e90e0372eebde753f16d164bd1a91c5edc..17e8b0fc89db0b8b39dfdfc58b87f01814b442b0 100644 (file)
@@ -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 <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 ?
index 9758cf1cd07ad8185e4aa837f7d650a169089f98..168ae855d575c681ad897b019c450cbf138cb122 100644 (file)
@@ -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;
index 2b0c41835c47bef2263494be3d133cdf8c2e7203..7a7c604a90746b167af4a6d6aa081931329ad5da 100644 (file)
@@ -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
index 1051b0b3b1114361c49f89e0634e385cd5429e2b..a71e533c9b279ff58f4ec93f3b960f89f5beab84 100644 (file)
@@ -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 );