#define AP_LDAP_CHASEREFERRALS_OFF 0
#define AP_LDAP_CHASEREFERRALS_ON 1
+#define AP_LDAP_CONNPOOL_DEFAULT -1
+#define AP_LDAP_CONNPOOL_INFINITE -2
+
module AP_MODULE_DECLARE_DATA ldap_module;
static const char *ldap_cache_mutex_type = "ldap-cache";
static apr_status_t uldap_connection_unbind(void *param);
}
else {
/* mark our connection as available for reuse */
+ ldc->freed = apr_time_now();
#if APR_HAS_THREADS
apr_thread_mutex_unlock(ldc->lock);
#endif
{
struct util_ldap_connection_t *l, *p; /* To traverse the linked list */
int secureflag = secure;
+ apr_time_t now = apr_time_now();
util_ldap_state_t *st =
(util_ldap_state_t *)ap_get_module_config(r->server->module_config,
&& (l->deref == deref) && (l->secure == secureflag)
&& !compare_client_certs(dc->client_certs, l->client_certs))
{
- break;
+ if (st->connectionPoolTTL > 0) {
+ if (l->bound && (now - l->freed) > st->connectionPoolTTL) {
+ ap_log_rerror(APLOG_MARK, APLOG_TRACE1, 0, r,
+ "Removing LDAP connection last used %" APR_TIME_T_FMT " seconds ago",
+ (now - l->freed) / APR_USEC_PER_SEC);
+ uldap_connection_unbind(l);
+ /* Go ahead and use it, so we don't create more just to unbind some other old ones */
+ break;
+ }
+ }
+ else {
+ break;
+ }
}
#if APR_HAS_THREADS
/* If this connection didn't match the criteria, then we
!compare_client_certs(dc->client_certs, l->client_certs))
{
/* the bind credentials have changed */
+ /* no check for connectionPoolTTL, since we are unbinding any way */
uldap_connection_unbind(l);
- /* forget the rebind info for this conn */
- if (l->ChaseReferrals == AP_LDAP_CHASEREFERRALS_ON) {
- apr_ldap_rebind_remove(l->ldap);
- }
-
util_ldap_strdup((char**)&(l->binddn), binddn);
util_ldap_strdup((char**)&(l->bindpw), bindpw);
break;
/* save away a copy of the client cert list that is presently valid */
l->client_certs = apr_array_copy_hdr(l->pool, dc->client_certs);
- l->keep = 1;
+ /* whether or not to keep this connection in the pool when it's returned */
+ l->keep = (st->connectionPoolTTL == 0) ? 0 : 1;
if (l->ChaseReferrals == AP_LDAP_CHASEREFERRALS_ON) {
if (apr_pool_create(&(l->rebind_pool), l->pool) != APR_SUCCESS) {
return NULL;
}
+static const char *util_ldap_set_conn_ttl(cmd_parms *cmd,
+ void *dummy,
+ const char *val)
+{
+ apr_interval_time_t timeout;
+ util_ldap_state_t *st =
+ (util_ldap_state_t *)ap_get_module_config(cmd->server->module_config,
+ &ldap_module);
+
+ if (ap_timeout_parameter_parse(val, &timeout, "s") != APR_SUCCESS) {
+ return "LDAPConnPoolTTL has wrong format";
+ }
+ st->connectionPoolTTL = timeout;
+ return NULL;
+}
+
+
static void *util_ldap_create_config(apr_pool_t *p, server_rec *s)
{
st->opTimeout = apr_pcalloc(p, sizeof(struct timeval));
st->opTimeout->tv_sec = 60;
st->verify_svr_cert = 1;
+ st->connectionPoolTTL = AP_LDAP_CONNPOOL_DEFAULT; /* no limit */
return st;
}
st->verify_svr_cert = base->verify_svr_cert;
st->debug_level = base->debug_level;
+ st->connectionPoolTTL = (overrides->connectionPoolTTL == AP_LDAP_CONNPOOL_DEFAULT) ?
+ base->connectionPoolTTL : overrides->connectionPoolTTL;
+
return st;
}
NULL, RSRC_CONF,
"Specify the LDAP bind/search timeout in seconds "
"(0 = no limit). Default: 60"),
+ AP_INIT_TAKE1("LDAPConnectionPoolTTL", util_ldap_set_conn_ttl,
+ NULL, RSRC_CONF,
+ "Specify the maximum amount of time a bound connection can sit "
+ "idle and still be considered valid for reuse"
+ "(0 = no pool, -1 = no limit, n = time in seconds). Default: -1"),
{NULL}
};