]> git.ipfire.org Git - thirdparty/openldap.git/commitdiff
ITS#9197 back-ldap: added task that prunes expired connections
authorTero Saarni <tero.saarni@gmail.com>
Wed, 24 Feb 2021 22:07:48 +0000 (22:07 +0000)
committerQuanah Gibson-Mount <quanah@openldap.org>
Wed, 24 Feb 2021 22:07:48 +0000 (22:07 +0000)
16 files changed:
servers/slapd/back-ldap/back-ldap.h
servers/slapd/back-ldap/bind.c
servers/slapd/back-ldap/chain.c
servers/slapd/back-ldap/config.c
servers/slapd/back-ldap/distproc.c
servers/slapd/back-ldap/init.c
servers/slapd/back-ldap/monitor.c
servers/slapd/back-ldap/unbind.c
servers/slapd/back-meta/bind.c
servers/slapd/back-meta/conn.c
servers/slapd/back-meta/init.c
servers/slapd/back-meta/unbind.c
tests/data/slapd-proxytimeout.conf [new file with mode: 0644]
tests/scripts/conf.sh
tests/scripts/defines.sh
tests/scripts/test079-proxy-timeout [new file with mode: 0755]

index 59ffe581315b633fef2e16217880058d178db3d4..67b1e7a19bf2217f1517337d5fb9011adc30628f 100644 (file)
@@ -180,7 +180,7 @@ typedef struct ldapconn_t {
 
 typedef struct ldap_avl_info_t {
        ldap_pvt_thread_mutex_t         lai_mutex;
-       Avlnode                         *lai_tree;
+       TAvlnode                        *lai_tree;
 } ldap_avl_info_t;
 
 typedef struct slap_retry_info_t {
@@ -417,6 +417,7 @@ typedef struct ldapinfo_t {
 
        ldap_pvt_thread_mutex_t li_counter_mutex;
        ldap_pvt_mp_t           li_ops_completed[SLAP_OP_LAST];
+       struct re_s*            li_conn_expire_task;
 } ldapinfo_t;
 
 #define        LDAP_ERR_OK(err) ((err) == LDAP_SUCCESS || (err) == LDAP_COMPARE_FALSE || (err) == LDAP_COMPARE_TRUE)
index 54f523d30f1d887985b17943ea990b34bd570477..68ab46224fd26dd7e5d3745199bf492cf5b92330 100644 (file)
@@ -34,6 +34,7 @@
 #include "back-ldap.h"
 #include "lutil.h"
 #include "lutil_ldap.h"
+#include "ldap_rq.h"
 
 #define LDAP_CONTROL_OBSOLETE_PROXY_AUTHZ      "2.16.840.1.113730.3.4.12"
 
@@ -60,7 +61,7 @@ static const struct {
 };
 
 static void
-ldap_back_conn_print( ldapconn_t *lc, const char *avlstr )
+ldap_back_conn_print( ldapconn_t *lc )
 {
        char buf[ SLAP_TEXT_BUFLEN ];
        char fbuf[ sizeof("BAPTIENSC") ];
@@ -77,31 +78,10 @@ ldap_back_conn_print( ldapconn_t *lc, const char *avlstr )
        }
        fbuf[i] = '\0';
        
-       fprintf( stderr, "lc=%p %s %s flags=0x%08x (%s)\n",
-               (void *)lc, buf, avlstr, lc->lc_lcflags, fbuf );
+       fprintf( stderr, "lc=%p %s flags=0x%08x (%s)\n",
+               (void *)lc, buf, lc->lc_lcflags, fbuf );
 }
 
-static void
-ldap_back_ravl_print( Avlnode *root, int depth )
-{
-       int             i;
-       ldapconn_t      *lc;
-       
-       if ( root == 0 ) {
-               return;
-       }
-       
-       ldap_back_ravl_print( root->avl_right, depth+1 );
-       
-       for ( i = 0; i < depth; i++ ) {
-               fprintf( stderr, "-" );
-       }
-
-       lc = root->avl_data;
-       ldap_back_conn_print( lc, avl_bf2str( root->avl_bf ) );
-
-       ldap_back_ravl_print( root->avl_left, depth + 1 );
-}
 
 static char* priv2str[] = {
        "privileged",
@@ -129,7 +109,7 @@ ldap_back_print_conntree( ldapinfo_t *li, char *msg )
                LDAP_TAILQ_FOREACH( lc, &li->li_conn_priv[ c ].lic_priv, lc_q )
                {
                        fprintf( stderr, "    [%d] ", i );
-                       ldap_back_conn_print( lc, "" );
+                       ldap_back_conn_print( lc );
                        i++;
                }
        }
@@ -138,7 +118,11 @@ ldap_back_print_conntree( ldapinfo_t *li, char *msg )
                fprintf( stderr, "\t(empty)\n" );
 
        } else {
-               ldap_back_ravl_print( li->li_conninfo.lai_tree, 0 );
+               TAvlnode *edge = tavl_end( li->li_conninfo.lai_tree, TAVL_DIR_LEFT );
+               while ( edge ) {
+                       ldap_back_conn_print( (ldapconn_t *)edge->avl_data );
+                       edge = tavl_next( edge, TAVL_DIR_RIGHT );
+               }
        }
        
        fprintf( stderr, "<======== %s\n", msg );
@@ -167,6 +151,12 @@ ldap_back_prepare_conn( ldapconn_t *lc, Operation *op, SlapReply *rs,
 static int
 ldap_back_conndnlc_cmp( const void *c1, const void *c2 );
 
+static void
+ldap_back_conn_prune( ldapinfo_t *li );
+
+static void
+ldap_back_schedule_conn_expiry( ldapinfo_t *li, ldapconn_t *lc );
+
 ldapconn_t *
 ldap_back_conn_delete( ldapinfo_t *li, ldapconn_t *lc )
 {
@@ -189,7 +179,7 @@ ldap_back_conn_delete( ldapinfo_t *li, ldapconn_t *lc )
 
                if ( LDAP_BACK_CONN_CACHED( lc ) ) {
                        assert( !LDAP_BACK_CONN_TAINTED( lc ) );
-                       tmplc = avl_delete( &li->li_conninfo.lai_tree, (caddr_t)lc,
+                       tmplc = tavl_delete( &li->li_conninfo.lai_tree, (caddr_t)lc,
                                ldap_back_conndnlc_cmp );
                        assert( tmplc == lc );
                        LDAP_BACK_CONN_CACHED_CLEAR( lc );
@@ -343,7 +333,7 @@ retry_lock:;
 
                /* delete all cached connections with the current connection */
                if ( LDAP_BACK_SINGLECONN( li ) ) {
-                       while ( ( tmplc = avl_delete( &li->li_conninfo.lai_tree, (caddr_t)lc, ldap_back_conn_cmp ) ) != NULL )
+                       while ( ( tmplc = tavl_delete( &li->li_conninfo.lai_tree, (caddr_t)lc, ldap_back_conn_cmp ) ) != NULL )
                        {
                                assert( !LDAP_BACK_PCONN_ISPRIV( lc ) );
                                Debug( LDAP_DEBUG_TRACE,
@@ -371,7 +361,7 @@ retry_lock:;
                        if ( be_isroot_dn( op->o_bd, &op->o_req_ndn ) ) {
                                LDAP_BACK_PCONN_ROOTDN_SET( lc, op );
                        }
-                       lerr = avl_insert( &li->li_conninfo.lai_tree, (caddr_t)lc,
+                       lerr = tavl_insert( &li->li_conninfo.lai_tree, (caddr_t)lc,
                                ldap_back_conndn_cmp, ldap_back_conndn_dup );
                }
 
@@ -934,7 +924,7 @@ retry_lock:
                } else {
 
                        /* Searches for a ldapconn in the avl tree */
-                       lc = (ldapconn_t *)avl_find( li->li_conninfo.lai_tree, 
+                       lc = (ldapconn_t *)tavl_find( li->li_conninfo.lai_tree, 
                                        (caddr_t)&lc_curr, ldap_back_conndn_cmp );
                }
 
@@ -1080,7 +1070,7 @@ retry_lock:
                        rs->sr_err = 0;
 
                } else {
-                       rs->sr_err = avl_insert( &li->li_conninfo.lai_tree, (caddr_t)lc,
+                       rs->sr_err = tavl_insert( &li->li_conninfo.lai_tree, (caddr_t)lc,
                                ldap_back_conndn_cmp, ldap_back_conndn_dup );
                        LDAP_BACK_CONN_CACHED_SET( lc );
                }
@@ -1126,6 +1116,7 @@ retry_lock:
                                return NULL;
                        }
                }
+               ldap_back_schedule_conn_expiry( li, lc );
 
        } else {
                int     expiring = 0;
@@ -3054,3 +3045,156 @@ ldap_back_connid2str( const ldapconn_base_t *lc, char *buf, ber_len_t buflen )
 
        return len;
 }
+
+void *
+ldap_back_conn_expire_fn( void *ctx, void *arg )
+{
+       struct re_s *rtask = arg;
+       ldapinfo_t *li = (ldapinfo_t *)rtask->arg;
+       ldap_back_conn_prune( li );
+
+       return NULL;
+}
+
+/* Pick which expires first: connection TTL or idle timeout */
+static time_t
+ldap_back_conn_expire_time( ldapinfo_t *li, ldapconn_t *lc) {
+       if ( li->li_conn_ttl != 0 && li->li_idle_timeout != 0 ) {
+               return ( lc->lc_create_time + li->li_conn_ttl ) < ( lc->lc_time + li->li_idle_timeout ) ?
+                       ( lc->lc_create_time + li->li_conn_ttl ) : ( lc->lc_time + li->li_idle_timeout );
+       } else if ( li->li_conn_ttl != 0 ) {
+               return lc->lc_create_time + li->li_conn_ttl;
+       } else if ( li->li_idle_timeout != 0 ) {
+               return lc->lc_time + li->li_idle_timeout;
+       }
+       return -1;
+}
+
+static void
+ldap_back_conn_prune( ldapinfo_t *li )
+{
+       time_t          now = slap_get_time();
+       time_t          next_timeout = -1; /* -1 means uninitialized */
+       TAvlnode        *edge;
+       int             c;
+
+       /*
+        * Iterate though connections and close those that are pass the expiry time.
+        * Also calculate the time for next connection to to expire.
+        */
+       ldap_pvt_thread_mutex_lock( &li->li_conninfo.lai_mutex );
+
+       for ( c = LDAP_BACK_PCONN_FIRST; c < LDAP_BACK_PCONN_LAST; c++ ) {
+               ldapconn_t *lc = LDAP_TAILQ_FIRST( &li->li_conn_priv[ c ].lic_priv );
+
+               while ( lc ) {
+                       ldapconn_t *next = LDAP_TAILQ_NEXT( lc, lc_q );
+                       time_t conn_expires = ldap_back_conn_expire_time( li, lc );
+
+                       if ( now >= conn_expires ) {
+                               if ( lc->lc_refcnt == 0 ) {
+                                       Debug( LDAP_DEBUG_TRACE,
+                                               "ldap_back_conn_prune: closing expired connection lc=%p\n",
+                                               lc );
+                                       ldap_back_freeconn( li, lc, 0 );
+                               } else {
+                                       Debug( LDAP_DEBUG_TRACE,
+                                               "ldap_back_conn_prune: tainting expired connection lc=%p\n",
+                                               lc );
+                                       LDAP_BACK_CONN_TAINTED_SET( lc );
+                               }
+                       } else if ( next_timeout == -1 || conn_expires < next_timeout ) {
+                               /* next_timeout was not yet initialized or current connection expires sooner */
+                               next_timeout = conn_expires;
+                       }
+
+                       lc = next;
+               }
+       }
+
+       edge = tavl_end( li->li_conninfo.lai_tree, TAVL_DIR_LEFT );
+       while ( edge ) {
+               TAvlnode *next = tavl_next( edge, TAVL_DIR_RIGHT );
+               ldapconn_t *lc = (ldapconn_t *)edge->avl_data;
+               time_t conn_expires = ldap_back_conn_expire_time( li, lc );
+
+               if ( now >= conn_expires ) {
+                       if ( lc->lc_refcnt == 0 ) {
+                               Debug( LDAP_DEBUG_TRACE,
+                                       "ldap_back_conn_prune: closing expired connection lc=%p\n",
+                                       lc );
+                               ldap_back_freeconn( li, lc, 0 );
+                       } else {
+                               Debug( LDAP_DEBUG_TRACE,
+                                       "ldap_back_conn_prune: tainting expired connection lc=%p\n",
+                                       lc );
+                               LDAP_BACK_CONN_TAINTED_SET( lc );
+                       }
+               } else if ( next_timeout == -1 || conn_expires < next_timeout ) {
+                       next_timeout = conn_expires;
+               }
+
+               edge = next;
+       }
+
+       ldap_pvt_thread_mutex_unlock( &li->li_conninfo.lai_mutex );
+
+       /* Reschedule for next timeout or cancel the task */
+       ldap_pvt_thread_mutex_lock( &slapd_rq.rq_mutex );
+       if ( next_timeout > 0 ) {
+               if ( ldap_pvt_runqueue_isrunning( &slapd_rq, li->li_conn_expire_task ) ) {
+                       ldap_pvt_runqueue_stoptask( &slapd_rq, li->li_conn_expire_task );
+               }
+               li->li_conn_expire_task->interval.tv_sec = next_timeout - now;
+               ldap_pvt_runqueue_resched( &slapd_rq, li->li_conn_expire_task, 0 );
+
+               /*
+                * The thread that handles runqueue might have already processed all tasks
+                * before we insertered new task or rescheduled the existing task with new
+                * timeout period. Wake it up to ensure that the task will be picked up.
+                */
+               slap_wake_listener();
+               Debug( LDAP_DEBUG_TRACE,
+                       "ldap_back_conn_prune: scheduled connection expiry timer to %ld sec\n",
+                       li->li_conn_expire_task->interval.tv_sec );
+       } else if ( next_timeout == -1 && li->li_conn_expire_task != NULL ) {
+               if ( ldap_pvt_runqueue_isrunning( &slapd_rq, li->li_conn_expire_task ) ) {
+                       ldap_pvt_runqueue_stoptask( &slapd_rq, li->li_conn_expire_task );
+               }
+               ldap_pvt_runqueue_remove( &slapd_rq, li->li_conn_expire_task );
+               li->li_conn_expire_task = NULL;
+       }
+       ldap_pvt_thread_mutex_unlock( &slapd_rq.rq_mutex );
+
+       return;
+}
+
+static void
+ldap_back_schedule_conn_expiry( ldapinfo_t *li, ldapconn_t *lc ) {
+       /* Do nothing if timeouts are not set. */
+       if ( li->li_conn_ttl == 0 && li->li_idle_timeout == 0 ) {
+               return;
+       }
+
+       /*
+        * If connection expire task is not running, create it and schedule for
+        * timeout of this connection.
+        *
+        * If the task is already running, this connection cannot be next one
+        * to expire and therefore timeout does not need to be re-calculated.
+        */
+       ldap_pvt_thread_mutex_lock( &slapd_rq.rq_mutex );
+       if ( li->li_conn_expire_task == NULL ) {
+               li->li_conn_expire_task = ldap_pvt_runqueue_insert( &slapd_rq,
+                       ldap_back_conn_expire_time( li, lc ) - slap_get_time(),
+                       ldap_back_conn_expire_fn, li, "ldap_back_conn_expire_fn",
+                       "ldap_back_conn_expire_timer" );
+               slap_wake_listener();
+               Debug( LDAP_DEBUG_TRACE,
+                       "ldap_back_conn_prune: scheduled connection expiry timer to %ld sec\n",
+                       li->li_conn_expire_task->interval.tv_sec );
+       }
+       ldap_pvt_thread_mutex_unlock( &slapd_rq.rq_mutex );
+
+       return;
+}
\ No newline at end of file
index 8901bf3e50a8b7bb6e0a1547514f7f99b2ad9e14..a771cd374b3c3cbd232e93d92499debe44a06697 100644 (file)
@@ -558,7 +558,7 @@ Document: RFC 4511
 
                /* Searches for a ldapinfo in the avl tree */
                ldap_pvt_thread_mutex_lock( &lc->lc_lai.lai_mutex );
-               lip = (ldapinfo_t *)avl_find( lc->lc_lai.lai_tree, 
+               lip = (ldapinfo_t *)tavl_find( lc->lc_lai.lai_tree,
                        (caddr_t)&li, ldap_chain_uri_cmp );
                ldap_pvt_thread_mutex_unlock( &lc->lc_lai.lai_mutex );
 
@@ -590,7 +590,7 @@ Document: RFC 4511
 
                        if ( LDAP_CHAIN_CACHE_URI( lc ) ) {
                                ldap_pvt_thread_mutex_lock( &lc->lc_lai.lai_mutex );
-                               if ( avl_insert( &lc->lc_lai.lai_tree,
+                               if ( tavl_insert( &lc->lc_lai.lai_tree,
                                        (caddr_t)lip, ldap_chain_uri_cmp, ldap_chain_uri_dup ) )
                                {
                                        /* someone just inserted another;
@@ -830,7 +830,7 @@ ldap_chain_search(
 
                /* Searches for a ldapinfo in the avl tree */
                ldap_pvt_thread_mutex_lock( &lc->lc_lai.lai_mutex );
-               lip = (ldapinfo_t *)avl_find( lc->lc_lai.lai_tree, 
+               lip = (ldapinfo_t *)tavl_find( lc->lc_lai.lai_tree,
                        (caddr_t)&li, ldap_chain_uri_cmp );
                ldap_pvt_thread_mutex_unlock( &lc->lc_lai.lai_mutex );
 
@@ -863,7 +863,7 @@ ldap_chain_search(
 
                        if ( LDAP_CHAIN_CACHE_URI( lc ) ) {
                                ldap_pvt_thread_mutex_lock( &lc->lc_lai.lai_mutex );
-                               if ( avl_insert( &lc->lc_lai.lai_tree,
+                               if ( tavl_insert( &lc->lc_lai.lai_tree,
                                        (caddr_t)lip, ldap_chain_uri_cmp, ldap_chain_uri_dup ) )
                                {
                                        /* someone just inserted another;
@@ -1387,7 +1387,7 @@ fail:
 
                li->li_uri = ch_strdup( at->a_vals[ 0 ].bv_val );
                value_add_one( &li->li_bvuri, &at->a_vals[ 0 ] );
-               if ( avl_insert( &lc->lc_lai.lai_tree, (caddr_t)li,
+               if ( tavl_insert( &lc->lc_lai.lai_tree, (caddr_t)li,
                        ldap_chain_uri_cmp, ldap_chain_uri_dup ) )
                {
                        Debug( LDAP_DEBUG_ANY, "slapd-chain: "
@@ -1410,34 +1410,27 @@ done:;
        return rc;
 }
 
-typedef struct ldap_chain_cfadd_apply_t {
-       Operation       *op;
-       SlapReply       *rs;
-       Entry           *p;
-       ConfigArgs      *ca;
-       int             count;
-} ldap_chain_cfadd_apply_t;
-
-static int
-ldap_chain_cfadd_apply( void *datum, void *arg )
+static void
+ldap_chain_cfadd_apply(
+       ldapinfo_t *li,
+       Operation *op,
+       SlapReply *rs,
+       Entry *p,
+       ConfigArgs *ca,
+       int count )
 {
-       ldapinfo_t                      *li = (ldapinfo_t *)datum;
-       ldap_chain_cfadd_apply_t        *lca = (ldap_chain_cfadd_apply_t *)arg;
-
        struct berval                   bv;
 
        /* FIXME: should not hardcode "olcDatabase" here */
-       bv.bv_len = snprintf( lca->ca->cr_msg, sizeof( lca->ca->cr_msg ),
-               "olcDatabase={%d}%s", lca->count, lback->bi_type );
-       bv.bv_val = lca->ca->cr_msg;
+       bv.bv_len = snprintf( ca->cr_msg, sizeof( ca->cr_msg ),
+               "olcDatabase={%d}%s", count, lback->bi_type );
+       bv.bv_val = ca->cr_msg;
 
-       lca->ca->be->be_private = (void *)li;
-       config_build_entry( lca->op, lca->rs, lca->p->e_private, lca->ca,
+       ca->be->be_private = (void *)li;
+       config_build_entry( op, rs, p->e_private, ca,
                &bv, lback->bi_cf_ocs, &chainocs[1] );
 
-       lca->count++;
-
-       return 0;
+       return;
 }
 
 static int
@@ -1447,20 +1440,20 @@ chain_cfadd( Operation *op, SlapReply *rs, Entry *p, ConfigArgs *ca )
        slap_overinst   *on = (slap_overinst *)pe->ce_bi;
        ldap_chain_t    *lc = (ldap_chain_t *)on->on_bi.bi_private;
        void            *priv = (void *)ca->be->be_private;
+       TAvlnode        *edge;
+       int             count = 0;
 
        if ( lback->bi_cf_ocs ) {
-               ldap_chain_cfadd_apply_t        lca = { 0 };
-
-               lca.op = op;
-               lca.rs = rs;
-               lca.p = p;
-               lca.ca = ca;
-               lca.count = 0;
 
-               (void)ldap_chain_cfadd_apply( (void *)lc->lc_common_li, (void *)&lca );
+               ldap_chain_cfadd_apply( lc->lc_common_li, op, rs, p, ca, count++ );
 
-               (void)avl_apply( lc->lc_lai.lai_tree, ldap_chain_cfadd_apply,
-                       &lca, 1, AVL_INORDER );
+               edge = tavl_end( lc->lc_lai.lai_tree, TAVL_DIR_LEFT );
+               while ( edge ) {
+                       TAvlnode *next = tavl_next( edge, TAVL_DIR_RIGHT );
+                       ldapinfo_t *li = (ldapinfo_t *)edge->avl_data;
+                       ldap_chain_cfadd_apply( li, op, rs, p, ca, count++ );
+                       edge = next;
+               }
 
                ca->be->be_private = priv;
        }
@@ -1480,7 +1473,7 @@ chain_lddel( CfEntryInfo *ce, Operation *op )
        ldapinfo_t      *li = (ldapinfo_t *) ce->ce_be->be_private;
 
        if ( li != lc->lc_common_li ) {
-               if (! avl_delete( &lc->lc_lai.lai_tree, li, ldap_chain_uri_cmp ) ) {
+               if (! tavl_delete( &lc->lc_lai.lai_tree, li, ldap_chain_uri_cmp ) ) {
                        Debug( LDAP_DEBUG_ANY, "slapd-chain: avl_delete failed. "
                                "\"%s\" not found.\n", li->li_uri );
                        return -1;
@@ -1889,7 +1882,7 @@ private_destroy:;
                                        goto private_destroy;
                                }
 
-                               if ( avl_insert( &lc->lc_lai.lai_tree,
+                               if ( tavl_insert( &lc->lc_lai.lai_tree,
                                        (caddr_t)lc->lc_cfg_li,
                                        ldap_chain_uri_cmp, ldap_chain_uri_dup ) )
                                {
@@ -1914,22 +1907,6 @@ enum db_which {
        db_last
 };
 
-typedef struct ldap_chain_db_apply_t {
-       BackendDB       *be;
-       BI_db_func      *func;
-} ldap_chain_db_apply_t;
-
-static int
-ldap_chain_db_apply( void *datum, void *arg )
-{
-       ldapinfo_t              *li = (ldapinfo_t *)datum;
-       ldap_chain_db_apply_t   *lca = (ldap_chain_db_apply_t *)arg;
-
-       lca->be->be_private = (void *)li;
-
-       return lca->func( lca->be, NULL );
-}
-
 static int
 ldap_chain_db_func(
        BackendDB *be,
@@ -1957,14 +1934,17 @@ ldap_chain_db_func(
                        }
 
                        if ( lc->lc_lai.lai_tree != NULL ) {
-                               ldap_chain_db_apply_t   lca;
-
-                               lca.be = &db;
-                               lca.func = func;
-
-                               rc = avl_apply( lc->lc_lai.lai_tree,
-                                       ldap_chain_db_apply, (void *)&lca,
-                                       1, AVL_INORDER ) != AVL_NOMORE;
+                               TAvlnode *edge = tavl_end( lc->lc_lai.lai_tree, TAVL_DIR_LEFT );
+                               while ( edge ) {
+                                       TAvlnode *next = tavl_next( edge, TAVL_DIR_RIGHT );
+                                       ldapinfo_t *li = (ldapinfo_t *)edge->avl_data;
+                                       db.be_private = (void *)li;
+                                       rc = func( &db, NULL );
+                                       if ( rc == 1 ) {
+                                               break;
+                                       }
+                                       edge = next;
+                               }
                        }
                }
        }
@@ -2031,7 +2011,7 @@ ldap_chain_db_destroy(
        rc = ldap_chain_db_func( be, db_destroy );
 
        if ( lc ) {
-               avl_free( lc->lc_lai.lai_tree, NULL );
+               tavl_free( lc->lc_lai.lai_tree, NULL );
                ldap_pvt_thread_mutex_destroy( &lc->lc_lai.lai_mutex );
                ch_free( lc );
        }
@@ -2145,22 +2125,6 @@ ldap_chain_db_open_one(
        return lback->bi_db_open( be, NULL );
 }
 
-typedef struct ldap_chain_conn_apply_t {
-       BackendDB       *be;
-       Connection      *conn;
-} ldap_chain_conn_apply_t;
-
-static int
-ldap_chain_conn_apply( void *datum, void *arg )
-{
-       ldapinfo_t              *li = (ldapinfo_t *)datum;
-       ldap_chain_conn_apply_t *lca = (ldap_chain_conn_apply_t *)arg;
-
-       lca->be->be_private = (void *)li;
-
-       return lback->bi_connection_destroy( lca->be, lca->conn );
-}
-
 static int
 ldap_chain_connection_destroy(
        BackendDB *be,
@@ -2170,15 +2134,24 @@ ldap_chain_connection_destroy(
        slap_overinst           *on = (slap_overinst *) be->bd_info;
        ldap_chain_t            *lc = (ldap_chain_t *)on->on_bi.bi_private;
        void                    *private = be->be_private;
-       ldap_chain_conn_apply_t lca;
+       TAvlnode                *edge;
        int                     rc;
 
        be->be_private = NULL;
-       lca.be = be;
-       lca.conn = conn;
        ldap_pvt_thread_mutex_lock( &lc->lc_lai.lai_mutex );
-       rc = avl_apply( lc->lc_lai.lai_tree, ldap_chain_conn_apply,
-               (void *)&lca, 1, AVL_INORDER ) != AVL_NOMORE;
+       edge = tavl_end( lc->lc_lai.lai_tree, TAVL_DIR_LEFT );
+       while ( edge ) {
+               TAvlnode *next = tavl_next( edge, TAVL_DIR_RIGHT );
+               ldapinfo_t *li = (ldapinfo_t *)edge->avl_data;
+               be->be_private = (void *)li;
+               rc = lback->bi_connection_destroy( be, conn );
+               if ( rc == 1 ) {
+                       break;
+               }
+               edge = next;
+       }
+
+
        ldap_pvt_thread_mutex_unlock( &lc->lc_lai.lai_mutex );
        be->be_private = private;
 
index 1f83635566f7265e3829d123ab699113c6e08a91..79fa3589ac9944e492f0fabab954f0e82b87043f 100644 (file)
@@ -1384,7 +1384,7 @@ ldap_back_cf_gen( ConfigArgs *c )
                        /* NOTE: don't worry about locking: if we got here,
                         * other threads are suspended. */
                        if ( li->li_conninfo.lai_tree != NULL ) {
-                               avl_free( li->li_conninfo.lai_tree, ldap_back_conn_free );
+                               tavl_free( li->li_conninfo.lai_tree, ldap_back_conn_free );
                                li->li_conninfo.lai_tree = NULL;
                        }
                        
index ed7b6dab9e623a33415157fec87dab40cdb61fe4..08d01e647bc7a1836950a687a2225cb53e688ae1 100644 (file)
@@ -432,7 +432,7 @@ distproc_ldadd( CfEntryInfo *p, Entry *e, ConfigArgs *ca )
        if ( lc->lc_common_li == NULL ) {
                lc->lc_common_li = li;
 
-       } else if ( avl_insert( &lc->lc_lai.lai_tree, (caddr_t)li,
+       } else if ( tavl_insert( &lc->lc_lai.lai_tree, (caddr_t)li,
                ldap_distproc_uri_cmp, ldap_distproc_uri_dup ) )
        {
                Debug( LDAP_DEBUG_ANY, "slapd-distproc: "
@@ -460,26 +460,27 @@ typedef struct ldap_distproc_cfadd_apply_t {
        int             count;
 } ldap_distproc_cfadd_apply_t;
 
-static int
-ldap_distproc_cfadd_apply( void *datum, void *arg )
+static void
+ldap_distproc_cfadd_apply(
+       ldapinfo_t *li,
+       Operation *op,
+       SlapReply *rs,
+       Entry *p,
+       ConfigArgs *ca,
+       int count )
 {
-       ldapinfo_t                      *li = (ldapinfo_t *)datum;
-       ldap_distproc_cfadd_apply_t     *lca = (ldap_distproc_cfadd_apply_t *)arg;
-
        struct berval                   bv;
 
        /* FIXME: should not hardcode "olcDatabase" here */
-       bv.bv_len = snprintf( lca->ca->cr_msg, sizeof( lca->ca->cr_msg ),
-               "olcDatabase={%d}%s", lca->count, lback->bi_type );
-       bv.bv_val = lca->ca->cr_msg;
+       bv.bv_len = snprintf( ca->cr_msg, sizeof( ca->cr_msg ),
+               "olcDatabase={%d}%s", count, lback->bi_type );
+       bv.bv_val = ca->cr_msg;
 
-       lca->ca->be->be_private = (void *)li;
-       config_build_entry( lca->op, lca->rs, lca->p->e_private, lca->ca,
+       ca->be->be_private = (void *)li;
+       config_build_entry( op, rs, p->e_private, ca,
                &bv, lback->bi_cf_ocs, &distproc_ocs[ 1 ] );
 
-       lca->count++;
-
-       return 0;
+       return;
 }
 
 static int
@@ -489,6 +490,8 @@ distproc_cfadd( Operation *op, SlapReply *rs, Entry *p, ConfigArgs *ca )
        slap_overinst   *on = (slap_overinst *)pe->ce_bi;
        ldap_distproc_t *lc = (ldap_distproc_t *)on->on_bi.bi_private;
        void            *priv = (void *)ca->be->be_private;
+       TAvlnode        *edge;
+       int             count = 0;
 
        if ( lback->bi_cf_ocs ) {
                ldap_distproc_cfadd_apply_t     lca = { 0 };
@@ -499,10 +502,15 @@ distproc_cfadd( Operation *op, SlapReply *rs, Entry *p, ConfigArgs *ca )
                lca.ca = ca;
                lca.count = 0;
 
-               (void)ldap_distproc_cfadd_apply( (void *)lc->lc_common_li, (void *)&lca );
+               ldap_distproc_cfadd_apply( lc->lc_common_li, op, rs, p, ca, count++ );
 
-               (void)avl_apply( lc->lc_lai.lai_tree, ldap_distproc_cfadd_apply,
-                       &lca, 1, AVL_INORDER );
+               edge = tavl_end( lc->lc_lai.lai_tree, TAVL_DIR_LEFT );
+               while ( edge ) {
+                       TAvlnode *next = tavl_next( edge, TAVL_DIR_RIGHT );
+                       ldapinfo_t *li = (ldapinfo_t *)edge->avl_data;
+                       ldap_distproc_cfadd_apply( li, op, rs, p, ca, count++ );
+                       edge = next;
+               }
 
                ca->be->be_private = priv;
        }
@@ -672,7 +680,7 @@ private_destroy:;
                                        goto private_destroy;
                                }
 
-                               if ( avl_insert( &lc->lc_lai.lai_tree,
+                               if ( tavl_insert( &lc->lc_lai.lai_tree,
                                        (caddr_t)lc->lc_cfg_li,
                                        ldap_distproc_uri_cmp, ldap_distproc_uri_dup ) )
                                {
@@ -697,22 +705,6 @@ enum db_which {
        db_last
 };
 
-typedef struct ldap_distproc_db_apply_t {
-       BackendDB       *be;
-       BI_db_func      *func;
-} ldap_distproc_db_apply_t;
-
-static int
-ldap_distproc_db_apply( void *datum, void *arg )
-{
-       ldapinfo_t              *li = (ldapinfo_t *)datum;
-       ldap_distproc_db_apply_t        *lca = (ldap_distproc_db_apply_t *)arg;
-
-       lca->be->be_private = (void *)li;
-
-       return lca->func( lca->be, NULL );
-}
-
 static int
 ldap_distproc_db_func(
        BackendDB *be,
@@ -740,14 +732,17 @@ ldap_distproc_db_func(
                        }
 
                        if ( lc->lc_lai.lai_tree != NULL ) {
-                               ldap_distproc_db_apply_t        lca;
-
-                               lca.be = &db;
-                               lca.func = func;
-
-                               rc = avl_apply( lc->lc_lai.lai_tree,
-                                       ldap_distproc_db_apply, (void *)&lca,
-                                       1, AVL_INORDER ) != AVL_NOMORE;
+                               TAvlnode *edge = tavl_end( lc->lc_lai.lai_tree, TAVL_DIR_LEFT );
+                               while ( edge ) {
+                                       TAvlnode *next = tavl_next( edge, TAVL_DIR_RIGHT );
+                                       ldapinfo_t *li = (ldapinfo_t *)edge->avl_data;
+                                       be->be_private = (void *)li;
+                                       rc = func( &db, NULL );
+                                       if ( rc == 1 ) {
+                                               break;
+                                       }
+                                       edge = next;
+                               }
                        }
                }
        }
@@ -784,7 +779,7 @@ ldap_distproc_db_destroy(
        rc = ldap_distproc_db_func( be, db_destroy );
 
        if ( lc ) {
-               avl_free( lc->lc_lai.lai_tree, NULL );
+               tavl_free( lc->lc_lai.lai_tree, NULL );
                ldap_pvt_thread_mutex_destroy( &lc->lc_lai.lai_mutex );
                ch_free( lc );
        }
@@ -854,22 +849,6 @@ ldap_distproc_db_init_one(
        return 0;
 }
 
-typedef struct ldap_distproc_conn_apply_t {
-       BackendDB       *be;
-       Connection      *conn;
-} ldap_distproc_conn_apply_t;
-
-static int
-ldap_distproc_conn_apply( void *datum, void *arg )
-{
-       ldapinfo_t              *li = (ldapinfo_t *)datum;
-       ldap_distproc_conn_apply_t      *lca = (ldap_distproc_conn_apply_t *)arg;
-
-       lca->be->be_private = (void *)li;
-
-       return lback->bi_connection_destroy( lca->be, lca->conn );
-}
-
 static int
 ldap_distproc_connection_destroy(
        BackendDB *be,
@@ -879,15 +858,22 @@ ldap_distproc_connection_destroy(
        slap_overinst           *on = (slap_overinst *) be->bd_info;
        ldap_distproc_t         *lc = (ldap_distproc_t *)on->on_bi.bi_private;
        void                    *private = be->be_private;
-       ldap_distproc_conn_apply_t      lca;
        int                     rc;
+       TAvlnode                *edge;
 
        be->be_private = NULL;
-       lca.be = be;
-       lca.conn = conn;
        ldap_pvt_thread_mutex_lock( &lc->lc_lai.lai_mutex );
-       rc = avl_apply( lc->lc_lai.lai_tree, ldap_distproc_conn_apply,
-               (void *)&lca, 1, AVL_INORDER ) != AVL_NOMORE;
+       edge = tavl_end( lc->lc_lai.lai_tree, TAVL_DIR_LEFT );
+       while ( edge ) {
+               TAvlnode *next = tavl_next( edge, TAVL_DIR_RIGHT );
+               ldapinfo_t *li = (ldapinfo_t *)edge->avl_data;
+               be->be_private = (void *)li;
+               rc = lback->bi_connection_destroy( be, conn );
+               if ( rc == 1 ) {
+                       break;
+               }
+               edge = next;
+       }
        ldap_pvt_thread_mutex_unlock( &lc->lc_lai.lai_mutex );
        be->be_private = private;
 
index 394fffb2f5c2d3ebb2c53768d6ba30f143c4fc4d..3232af660f3e46c02f23ba02003713a7846ab8d5 100644 (file)
@@ -31,6 +31,7 @@
 #include "slap.h"
 #include "slap-config.h"
 #include "back-ldap.h"
+#include "ldap_rq.h"
 
 static const ldap_extra_t ldap_extra = {
        ldap_back_proxy_authz_ctrl,
@@ -185,6 +186,8 @@ ldap_back_db_init( Backend *be, ConfigReply *cr )
                ldap_pvt_mp_init( li->li_ops_completed[ i ] );
        }
 
+       li->li_conn_expire_task = NULL;
+
        be->be_private = li;
        SLAP_DBFLAGS( be ) |= SLAP_DBFLAG_NOLASTMOD;
 
@@ -303,6 +306,16 @@ ldap_back_db_destroy( Backend *be, ConfigReply *cr )
 
                (void)ldap_back_monitor_db_destroy( be );
 
+               /* Stop and remove the task that prunes expired connections */
+               if ( li->li_conn_expire_task != NULL ) {
+                       ldap_pvt_thread_mutex_lock( &slapd_rq.rq_mutex );
+                       if ( ldap_pvt_runqueue_isrunning( &slapd_rq, li->li_conn_expire_task ) ) {
+                                       ldap_pvt_runqueue_stoptask( &slapd_rq, li->li_conn_expire_task );
+                       }
+                       ldap_pvt_runqueue_remove( &slapd_rq, li->li_conn_expire_task );
+                       ldap_pvt_thread_mutex_unlock( &slapd_rq.rq_mutex );
+               }
+
                ldap_pvt_thread_mutex_lock( &li->li_conninfo.lai_mutex );
 
                if ( li->li_uri != NULL ) {
@@ -323,7 +336,7 @@ ldap_back_db_destroy( Backend *be, ConfigReply *cr )
                        li->li_idassert_authz = NULL;
                }
                        if ( li->li_conninfo.lai_tree ) {
-                       avl_free( li->li_conninfo.lai_tree, ldap_back_conn_free );
+                       tavl_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 ) ) {
@@ -359,4 +372,3 @@ ldap_back_db_destroy( Backend *be, ConfigReply *cr )
 SLAP_BACKEND_INIT_MODULE( ldap )
 
 #endif /* SLAPD_LDAP == SLAPD_MOD_DYNAMIC */
-
index e96dbeff069d92569ca7eb70d3b269d8090f0f3b..cb3898822fa4105a9e5de02ae8ec4ad845b1ff6e 100644 (file)
@@ -540,6 +540,7 @@ ldap_back_monitor_conn_create(
 
        struct ldap_back_monitor_conn_arg *arg;
        int conn_type;
+       TAvlnode *edge;
 
        assert( e_parent->e_private != NULL );
 
@@ -564,8 +565,13 @@ ldap_back_monitor_conn_create(
                }
        }
 
-       avl_apply( li->li_conninfo.lai_tree, (AVL_APPLY)ldap_back_monitor_conn_entry,
-               arg, -1, AVL_INORDER );
+       edge = tavl_end( li->li_conninfo.lai_tree, TAVL_DIR_LEFT );
+       while ( edge ) {
+               TAvlnode *next = tavl_next( edge, TAVL_DIR_RIGHT );
+               ldapconn_t *lc = (ldapconn_t *)edge->avl_data;
+               ldap_back_monitor_conn_entry( lc, arg );
+               edge = next;
+       }
 
        ch_free( arg );
 
index 9c3007b0a891874f0695e4441f9b6133c978734f..ff9e20080c7f2f273de87c4d60313282bfd0d196 100644 (file)
@@ -51,7 +51,7 @@ ldap_back_conn_destroy(
 #if LDAP_BACK_PRINT_CONNTREE > 0
        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 )
+       while ( ( lc = tavl_delete( &li->li_conninfo.lai_tree, (caddr_t)&lc_curr, ldap_back_conn_cmp ) ) != NULL )
        {
                assert( !LDAP_BACK_PCONN_ISPRIV( lc ) );
                Debug( LDAP_DEBUG_TRACE,
index 4f8f65668ede47fabb90e2eef26d854877bbe5be..5b2ab6498a93271ae7ebb9d73c947f5d0256e531 100644 (file)
@@ -212,7 +212,7 @@ meta_back_bind( Operation *op, SlapReply *rs )
                        if ( LDAP_BACK_SINGLECONN( mi ) ) {
                                metaconn_t      *tmpmc;
 
-                               while ( ( tmpmc = avl_delete( &mi->mi_conninfo.lai_tree, (caddr_t)mc, meta_back_conn_cmp ) ) != NULL )
+                               while ( ( tmpmc = tavl_delete( &mi->mi_conninfo.lai_tree, (caddr_t)mc, meta_back_conn_cmp ) ) != NULL )
                                {
                                        assert( !LDAP_BACK_PCONN_ISPRIV( mc ) );
                                        Debug( LDAP_DEBUG_TRACE,
@@ -235,7 +235,7 @@ meta_back_bind( Operation *op, SlapReply *rs )
                        }
 
                        ber_bvreplace( &mc->mc_local_ndn, &op->o_req_ndn );
-                       lerr = avl_insert( &mi->mi_conninfo.lai_tree, (caddr_t)mc,
+                       lerr = tavl_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, "<<< meta_back_bind" );
index a1469d9bd52881dacfe1a776f2e426318cb12a12..90b674a8d75c776ba40b50d4a9cfea581a86119d 100644 (file)
@@ -160,7 +160,7 @@ meta_back_print( metaconn_t *mc, char *avlstr )
 }
 
 static void
-meta_back_ravl_print( Avlnode *root, int depth )
+meta_back_ravl_print( TAvlnode *root, int depth )
 {
        int             i;
 
@@ -830,7 +830,7 @@ meta_back_retry(
 
                                } else {
                                        /* FIXME: check if in tree, for consistency? */
-                                       (void)avl_delete( &mi->mi_conninfo.lai_tree,
+                                       (void)tavl_delete( &mi->mi_conninfo.lai_tree,
                                                ( caddr_t )mc, meta_back_conndnmc_cmp );
                                }
                                LDAP_BACK_CONN_CACHED_CLEAR( mc );
@@ -1155,7 +1155,7 @@ retry_lock:;
                        
 
                } else {
-                       mc = (metaconn_t *)avl_find( mi->mi_conninfo.lai_tree, 
+                       mc = (metaconn_t *)tavl_find( mi->mi_conninfo.lai_tree,
                                (caddr_t)&mc_curr, meta_back_conndn_cmp );
                }
 
@@ -1200,7 +1200,7 @@ retry_lock:;
                                                }
 
                                        } else {
-                                               (void)avl_delete( &mi->mi_conninfo.lai_tree,
+                                               (void)tavl_delete( &mi->mi_conninfo.lai_tree,
                                                        (caddr_t)mc, meta_back_conndnmc_cmp );
                                        }
 
@@ -1420,7 +1420,7 @@ retry_lock:;
                        if ( !( sendok & LDAP_BACK_BINDING ) ) {
 retry_lock2:;
                                ldap_pvt_thread_mutex_lock( &mi->mi_conninfo.lai_mutex );
-                               mc = (metaconn_t *)avl_find( mi->mi_conninfo.lai_tree, 
+                               mc = (metaconn_t *)tavl_find( mi->mi_conninfo.lai_tree,
                                        (caddr_t)&mc_curr, meta_back_conndn_cmp );
                                if ( mc != NULL ) {
                                        /* catch taint errors */
@@ -1669,7 +1669,7 @@ done:;
                        rs->sr_err = 0;
 
                } else if ( !( sendok & LDAP_BACK_BINDING ) ) {
-                       err = avl_insert( &mi->mi_conninfo.lai_tree, ( caddr_t )mc,
+                       err = tavl_insert( &mi->mi_conninfo.lai_tree, ( caddr_t )mc,
                                meta_back_conndn_cmp, meta_back_conndn_dup );
                        LDAP_BACK_CONN_CACHED_SET( mc );
                }
@@ -1786,7 +1786,7 @@ meta_back_release_conn_lock(
                } else if ( LDAP_BACK_CONN_CACHED( mc ) ) {
                        metaconn_t      *tmpmc;
 
-                       tmpmc = avl_delete( &mi->mi_conninfo.lai_tree,
+                       tmpmc = tavl_delete( &mi->mi_conninfo.lai_tree,
                                ( caddr_t )mc, meta_back_conndnmc_cmp );
 
                        /* Overparanoid, but useful... */
index 63481dfc724738f7a4f7b14e704a105a0bf13b62..251fa51d2be4a1a6a66bfb2f2891b374cc35794f 100644 (file)
@@ -405,7 +405,7 @@ meta_back_db_destroy(
                ldap_pvt_thread_mutex_lock( &mi->mi_conninfo.lai_mutex );
 
                if ( mi->mi_conninfo.lai_tree ) {
-                       avl_free( mi->mi_conninfo.lai_tree, meta_back_conn_free );
+                       tavl_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 ) ) {
index 15b4a9b91ef0b84fdf5e7d3fa04cd5678a30f862..04c6ed32e72702bac21861735b8183b0087fb3f6 100644 (file)
@@ -54,7 +54,7 @@ meta_back_conn_destroy(
 #if META_BACK_PRINT_CONNTREE > 0
        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 )
+       while ( ( mc = tavl_delete( &mi->mi_conninfo.lai_tree, ( caddr_t )&mc_curr, meta_back_conn_cmp ) ) != NULL )
        {
                assert( !LDAP_BACK_PCONN_ISPRIV( mc ) );
                Debug( LDAP_DEBUG_TRACE,
diff --git a/tests/data/slapd-proxytimeout.conf b/tests/data/slapd-proxytimeout.conf
new file mode 100644 (file)
index 0000000..2fb7c6d
--- /dev/null
@@ -0,0 +1,71 @@
+# provider slapd config -- for testing
+# $OpenLDAP$
+## This work is part of OpenLDAP Software <http://www.openldap.org/>.
+##
+## Copyright 1998-2021 The OpenLDAP Foundation.
+## All rights reserved.
+##
+## Redistribution and use in source and binary forms, with or without
+## modification, are permitted only as authorized by the OpenLDAP
+## Public License.
+##
+## A copy of this license is available in the file LICENSE in the
+## top-level directory of the distribution or, alternatively, at
+## <http://www.OpenLDAP.org/license.html>.
+
+include                @SCHEMADIR@/core.schema
+include                @SCHEMADIR@/cosine.schema
+include                @SCHEMADIR@/inetorgperson.schema
+include                @SCHEMADIR@/openldap.schema
+include                @SCHEMADIR@/nis.schema
+pidfile                @TESTDIR@/slapd.m.pid
+argsfile       @TESTDIR@/slapd.m.args
+
+#######################################################################
+# database definitions
+#######################################################################
+
+#mod#modulepath ../servers/slapd/back-@BACKEND@/:../servers/slapd/overlays
+#mod#moduleload back_@BACKEND@.la
+#ldapmod#modulepath ../servers/slapd/back-ldap/
+#ldapmod#moduleload back_ldap.la
+#rwmmod#modulepath ../servers/slapd/overlays/
+#rwmmod#moduleload rwm.la
+#monitormod#modulepath ../servers/slapd/back-monitor/
+#monitormod#moduleload back_monitor.la
+
+# here the proxy is not only acting as a proxy, but it also has a local database dc=local,dc=com"
+database       @BACKEND@
+suffix         "dc=local,dc=com"
+rootdn         "cn=Manager,dc=local,dc=com"
+rootpw         "secret"
+#~null~#directory      @TESTDIR@/db.2.a
+
+
+# Configure proxy
+# - normal user binds to "*,dc=example,dc=com" are proxied through to the remote slapd
+# - admin bind to local "cn=Manager,dc=local,dc=com" is overwritten by using idassert-bind
+database       ldap
+uri                    "@URI1@"
+suffix         "dc=idle-timeout,dc=example,dc=com"
+idassert-bind bindmethod=simple binddn="cn=Manager,dc=example,dc=com" credentials="secret"
+idassert-authzFrom "dn.exact:cn=Manager,dc=local,dc=com"
+rebind-as-user yes
+monitoring             on
+idle-timeout   @TIMEOUT@
+overlay                rwm
+rwm-suffixmassage   "dc=idle-timeout,dc=example,dc=com" "ou=People,dc=example,dc=com"
+
+database       ldap
+uri                    "@URI1@"
+suffix         "dc=conn-ttl,dc=example,dc=com"
+idassert-bind bindmethod=simple binddn="cn=Manager,dc=example,dc=com" credentials="secret"
+idassert-authzFrom "dn.exact:cn=Manager,dc=local,dc=com"
+rebind-as-user yes
+monitoring             on
+conn-ttl               @TIMEOUT@
+overlay                rwm
+rwm-suffixmassage   "dc=conn-ttl,dc=example,dc=com" "ou=People,dc=example,dc=com"
+
+database       monitor
+
index 0364573483f29efdb0b24cafe9facf885193c540..7b1ddac68c4cb64c3e68cb76ea8e506893774447 100755 (executable)
@@ -89,4 +89,5 @@ sed -e "s/@BACKEND@/${BACKEND}/"                      \
        -e "s;@KRB5REALM@;${KRB5REALM};"                \
        -e "s;@KDCHOST@;${KDCHOST};"                    \
        -e "s;@KDCPORT@;${KDCPORT};"                    \
+       -e "s;@TIMEOUT@;${TIMEOUT};"                    \
        -e "/^#/d"
index ed8426fbf84cab910688f87bbbdbe83456f1ef8e..0afa1f8c356672ba19f4573e6ee2e62303116e69 100755 (executable)
@@ -54,6 +54,7 @@ ACI=${AC_ACI_ENABLED-acino}
 SLEEP0=${SLEEP0-1}
 SLEEP1=${SLEEP1-7}
 SLEEP2=${SLEEP2-15}
+TIMEOUT=${TIMEOUT-4}
 
 # dirs
 PROGDIR=./progs
diff --git a/tests/scripts/test079-proxy-timeout b/tests/scripts/test079-proxy-timeout
new file mode 100755 (executable)
index 0000000..e097c07
--- /dev/null
@@ -0,0 +1,324 @@
+#! /bin/sh
+# $OpenLDAP$
+## This work is part of OpenLDAP Software <http://www.openldap.org/>.
+##
+## Copyright 1998-2021 The OpenLDAP Foundation.
+## All rights reserved.
+##
+## Redistribution and use in source and binary forms, with or without
+## modification, are permitted only as authorized by the OpenLDAP
+## Public License.
+##
+## A copy of this license is available in the file LICENSE in the
+## top-level directory of the distribution or, alternatively, at
+## <http://www.OpenLDAP.org/license.html>.
+
+echo "running defines.sh"
+. $SRCDIR/scripts/defines.sh
+
+if test $BACKLDAP = "ldapno" ; then
+       echo "LDAP backend not available, test skipped"
+       exit 0
+fi
+if test $RWM = "rwmno" ; then
+        echo "rwm (rewrite/remap) overlay not available, test skipped"
+        exit 0
+fi
+
+mkdir -p $TESTDIR $DBDIR1 $DBDIR2
+$SLAPPASSWD -g -n >$CONFIGPWF
+
+#
+# Start slapd that acts as a remote LDAP server that will be proxied
+#
+echo "Running slapadd to build database for the remote slapd server..."
+. $CONFFILTER $BACKEND < $CONF > $CONF1
+$SLAPADD -f $CONF1 -l $LDIFORDERED
+RC=$?
+if test $RC != 0 ; then
+        echo "slapadd failed ($RC)!"
+        exit $RC
+fi
+
+echo "Starting remote slapd server on TCP/IP port $PORT1..."
+$SLAPD -f $CONF1 -h $URI1 -d $LVL > $LOG1 2>&1 &
+SERVERPID=$!
+if test $WAIT != 0 ; then
+    echo SERVERPID $SERVERPID
+    read foo
+fi
+
+#
+# Start ldapd that will proxy for the remote server
+#
+# Proxy is configured with two slapd-ldap backends:
+# - one with idle timeout set: dc=idle-timeout,$BASED
+# - one with connection TTL set: dc=conn-ttl,$BASEDN
+#
+echo "Starting slapd proxy on TCP/IP port $PORT2..."
+. $CONFFILTER $BACKEND < $DATADIR/slapd-proxytimeout.conf > $CONF2
+$SLAPD -f $CONF2 -h $URI2 -d $LVL > $LOG2 2>&1 &
+PROXYPID=$!
+if test $WAIT != 0 ; then
+    echo PROXYPID $PROXYPID
+    read foo
+fi
+
+KILLPIDS="$SERVERPID $PROXYPID"
+
+sleep $SLEEP0
+
+##############################################################################
+#
+# Test 1: Test that shared connections are timed out
+#
+
+NOW=`date +%s`
+echo "Create shared connection towards remote LDAP (time_t now=$NOW timeout=`expr $NOW + $TIMEOUT`)"
+
+$LDAPSEARCH -b "dc=idle-timeout,$BASEDN" \
+        -D "cn=Manager,dc=local,dc=com" \
+        -H $URI2 \
+        -w $PASSWD \
+        'objectclass=*' > $TESTOUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+        echo "ldapsearch failed for base: dc=idle-timeout,$BASEDN ($RC)!"
+        test $KILLSERVERS != no && kill -HUP $KILLPIDS
+        exit $RC
+fi
+
+$LDAPSEARCH -b "dc=conn-ttl,$BASEDN" \
+        -D "cn=Manager,dc=local,dc=com" \
+        -H $URI2 \
+        -w $PASSWD \
+        'objectclass=*' >> $TESTOUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+        echo "ldapsearch failed for base: dc=conn-ttl,$BASEDN ($RC)!"
+        test $KILLSERVERS != no && kill -HUP $KILLPIDS
+        exit $RC
+fi
+
+# Check that connections are established by searching for olmDbConnURI from Monitor
+
+echo "Checking that proxy has created connections towards backend"
+
+$LDAPSEARCH -b "cn=Connections,cn=database 2,cn=databases,cn=monitor" -s one -LLL olmDbConnURI \
+        -D "cn=Manager,dc=local,dc=com" \
+        -H $URI2 \
+        -w $PASSWD 2>&1 | tee -a $TESTOUT | grep ldap://${LOCALHOST}:$PORT1 >/dev/null
+RC=$?
+if test $RC != 0 ; then
+    echo "Error: LDAP connection to remote LDAP server is not found ($RC)"
+    test $KILLSERVERS != no && kill -HUP $KILLPIDS
+    exit $RC
+fi
+
+$LDAPSEARCH -b "cn=Connections,cn=database 3,cn=databases,cn=monitor" -s one -LLL olmDbConnURI \
+        -D "cn=Manager,dc=local,dc=com" \
+        -H $URI2 \
+        -w $PASSWD 2>&1 | tee -a $TESTOUT | grep ldap://${LOCALHOST}:$PORT1 >/dev/null
+RC=$?
+if test $RC != 0 ; then
+    echo "Error: LDAP connection to remote LDAP server is not found ($RC)"
+    test $KILLSERVERS != no && kill -HUP $KILLPIDS
+    exit $RC
+fi
+
+# Wait for connections to be closed, either due to
+# - idle-timeout and
+# - conn-ttl
+
+echo "Sleeping until idle-timeout and conn-ttl have passed"
+sleep `expr $TIMEOUT + 1`
+
+echo "Checking that proxy has closed expired connections towards the remote LDAP server (time_t now=`date +%s`)"
+
+$LDAPSEARCH -b "cn=Connections,cn=database 2,cn=databases,cn=monitor" -s one -LLL olmDbConnURI \
+        -D "cn=Manager,dc=local,dc=com" \
+        -H $URI2 \
+        -w $PASSWD 2>&1 | tee -a $TESTOUT | grep ldap://${LOCALHOST}:$PORT1 >/dev/null
+RC=$?
+if test $RC != 1 ; then
+    echo "Error: LDAP connection to remote LDAP server was not closed"
+    test $KILLSERVERS != no && kill -HUP $KILLPIDS
+    exit $RC
+fi
+
+$LDAPSEARCH -b "cn=Connections,cn=database 3,cn=databases,cn=monitor" -s one -LLL olmDbConnURI \
+        -D "cn=Manager,dc=local,dc=com" \
+        -H $URI2 \
+        -w $PASSWD 2>&1 | tee -a $TESTOUT | grep ldap://${LOCALHOST}:$PORT1 >/dev/null
+RC=$?
+if test $RC != 1 ; then
+    echo "Error: LDAP connection to remote LDAP server was not closed"
+    test $KILLSERVERS != no && kill -HUP $KILLPIDS
+    exit $RC
+fi
+
+
+##############################################################################
+#
+# Test 2: Test that private connections are timed out
+#
+
+NOW=`date +%s`
+echo "Create private connection towards remote LDAP (time_t now=$NOW timeout=`expr $NOW + $TIMEOUT`)"
+
+# Create fifos that are used to pass searches from the test case to ldapsearch
+rm -f $TESTDIR/ldapsearch1.fifo $TESTDIR/ldapsearch2.fifo
+mkfifo $TESTDIR/ldapsearch1.fifo $TESTDIR/ldapsearch2.fifo
+
+# Execute ldapsearch on background and have it read searches from the fifo
+$LDAPSEARCH -b "dc=idle-timeout,$BASEDN" \
+        -D "cn=Barbara Jensen,ou=Information Technology Division,dc=idle-timeout,$BASEDN" \
+        -H $URI2 \
+        -w "bjensen" \
+        -f $TESTDIR/ldapsearch1.fifo >> $TESTOUT 2>&1 &
+LDAPSEARCHPIDS=$!
+
+$LDAPSEARCH -b "dc=conn-ttl,$BASEDN" \
+        -D "cn=Barbara Jensen,ou=Information Technology Division,dc=conn-ttl,$BASEDN" \
+        -H $URI2 \
+        -w "bjensen" \
+        -f $TESTDIR/ldapsearch2.fifo >> $TESTOUT 2>&1 &
+LDAPSEARCHPIDS="$LDAPSEARCHPIDS $!"
+
+# Open fifos as file descriptor
+exec 3>$TESTDIR/ldapsearch1.fifo
+exec 4>$TESTDIR/ldapsearch2.fifo
+
+# Trigger LDAP connections towards the proxy by executing a search
+echo 'objectclass=*' >&3
+echo 'objectclass=*' >&4
+sleep 1
+
+echo "Checking that proxy has created connections towards backend"
+
+$LDAPSEARCH -b "cn=Connections,cn=database 2,cn=databases,cn=monitor" -s one -LLL olmDbConnURI \
+        -D "cn=Manager,dc=local,dc=com" \
+        -H $URI2 \
+        -w $PASSWD 2>&1 | tee -a $TESTOUT | grep ldap://${LOCALHOST}:$PORT1 >/dev/null
+RC=$?
+if test $RC != 0 ; then
+    echo "Error: LDAP connection to remote LDAP server is not found ($RC)"
+    test $KILLSERVERS != no && kill -HUP $KILLPIDS $LDAPSEARCHPIDS
+    exit $RC
+fi
+
+$LDAPSEARCH -b "cn=Connections,cn=database 3,cn=databases,cn=monitor" -s one -LLL olmDbConnURI \
+        -D "cn=Manager,dc=local,dc=com" \
+        -H $URI2 \
+        -w $PASSWD 2>&1 | tee -a $TESTOUT | grep ldap://${LOCALHOST}:$PORT1 >/dev/null
+RC=$?
+if test $RC != 0 ; then
+    echo "Error: LDAP connection to remote LDAP server is not found ($RC)"
+    test $KILLSERVERS != no && kill -HUP $KILLPIDS $LDAPSEARCHPIDS
+    exit $RC
+fi
+
+
+echo "Sleeping until idle-timeout and conn-ttl have passed"
+sleep `expr $TIMEOUT + 1`
+
+echo "Checking that proxy has closed expired connections towards the remote LDAP server (time_t now=`date +%s`)"
+
+$LDAPSEARCH -b "cn=Connections,cn=database 2,cn=databases,cn=monitor" -s one -LLL olmDbConnURI \
+        -D "cn=Manager,dc=local,dc=com" \
+        -H $URI2 \
+        -w $PASSWD 2>&1 | tee -a $TESTOUT | grep ldap://${LOCALHOST}:$PORT1 >/dev/null
+RC=$?
+if test $RC != 1 ; then
+    echo "Error: LDAP connection to remote LDAP server was not closed"
+    test $KILLSERVERS != no && kill -HUP $KILLPIDS $LDAPSEARCHPIDS
+    exit $RC
+fi
+
+$LDAPSEARCH -b "cn=Connections,cn=database 3,cn=databases,cn=monitor" -s one -LLL olmDbConnURI \
+        -D "cn=Manager,dc=local,dc=com" \
+        -H $URI2 \
+        -w $PASSWD 2>&1 | tee -a $TESTOUT | grep ldap://${LOCALHOST}:$PORT1 >/dev/null
+RC=$?
+if test $RC != 1 ; then
+    echo "Error: LDAP connection to remote LDAP server was not closed"
+    test $KILLSERVERS != no && kill -HUP $KILLPIDS $LDAPSEARCHPIDS
+    exit $RC
+fi
+
+# Close the file descriptors associated with the fifos.
+# This will trigger EOF to ldapsearch which will cause it to exit.
+exec 3>&-
+exec 4>&-
+
+
+##############################################################################
+#
+# Test 3: Check that idle-timeout is reset on activity
+#
+
+echo "Checking that idle-timeout is reset on activity"
+NOW=`date +%s`
+echo "Create cached connection: idle-timeout timeout starts (time_t now=$NOW, original_timeout=`expr $NOW + $TIMEOUT`)"
+$LDAPSEARCH -b "dc=idle-timeout,$BASEDN" \
+        -D "cn=Manager,dc=local,dc=com" \
+        -H $URI2 \
+        -w $PASSWD \
+        'objectclass=*' >> $TESTOUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+        echo "ldapsearch failed for base: dc=idle-timeout,$BASEDN ($RC)!"
+        test $KILLSERVERS != no && kill -HUP $KILLPIDS
+        exit $RC
+fi
+
+# sleep second less than idle-timeout to extend the timeout
+sleep `expr $TIMEOUT - 1`
+NOW=`date +%s`
+echo "Do another search to reset the timeout (time_t now=$NOW, new_timeout=`expr $NOW + $TIMEOUT`)"
+$LDAPSEARCH -b "dc=idle-timeout,$BASEDN" \
+        -D "cn=Manager,dc=local,dc=com" \
+        -H $URI2 \
+        -w $PASSWD \
+        'objectclass=*' >> $TESTOUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+        echo "ldapsearch failed for base: dc=idle-timeout,$BASEDN ($RC)!"
+        test $KILLSERVERS != no && kill -HUP $KILLPIDS
+        exit $RC
+fi
+
+sleep `expr $TIMEOUT - 1`
+echo "Check that connection is still alive due to idle-timeout reset (time_t now=`date +%s`)"
+$LDAPSEARCH -b "cn=Connections,cn=database 2,cn=databases,cn=monitor" -s one -LLL olmDbConnURI \
+        -D "cn=Manager,dc=local,dc=com" \
+        -H $URI2 \
+        -w $PASSWD 2>&1 | tee -a $TESTOUT | grep ldap://${LOCALHOST}:$PORT1 >/dev/null
+RC=$?
+if test $RC != 0 ; then
+    echo "Error: LDAP connection to remote LDAP server is not found ($RC)"
+    test $KILLSERVERS != no && kill -HUP $KILLPIDS
+    exit $RC
+fi
+
+sleep 2
+echo "Check that connection is closed after extended idle-timeout has passed (time_t now=`date +%s`)"
+$LDAPSEARCH -b "cn=Connections,cn=database 2,cn=databases,cn=monitor" -s one -LLL olmDbConnURI \
+        -D "cn=Manager,dc=local,dc=com" \
+        -H $URI2 \
+        -w $PASSWD  2>&1 | tee -a $TESTOUT | grep ldap://${LOCALHOST}:$PORT1 >/dev/null
+RC=$?
+if test $RC != 1 ; then
+    echo "Error: LDAP connection to remote LDAP server was not closed"
+    test $KILLSERVERS != no && kill -HUP $KILLPIDS
+    exit $RC
+fi
+
+
+test $KILLSERVERS != no && kill -HUP $KILLPIDS
+
+echo ">>>>> Test succeeded"
+
+test $KILLSERVERS != no && wait
+
+exit 0