This directive causes a cached connection to be dropped an recreated
after it has been idle for the specified time.
+.TP
+.B conn-ttl <time>
+This directive causes a cached connection to be dropped an recreated
+after a given ttl, regardless of being idle or not.
+
.SH BACKWARD COMPATIBILITY
The LDAP backend has been heavily reworked between releases 2.2 and 2.3;
as a side-effect, some of the traditional directives have been
.B idle-timeout
directive.
+.TP
+.B conn-ttl <time>
+This directive causes a cached connection to be dropped an recreated
+after a given ttl, regardless of being idle or not.
+
.TP
.B onerr {CONTINUE|stop}
This directive allows to select the behavior in case an error is returned
does not respond.
.RE
+.TP
+.B subtree-exclude "<DN>"
+This directive instructs back-meta to ignore the current target
+for operations whose requestDN is subordinate to
+.BR DN .
+There may be multiple occurrences of the
+.B subtree-exclude
+directive for each of the targets.
+
.TP
.B acl-authcDN "<administrative DN for access control purposes>"
DN which is used to query the target server for acl checking,
unsigned lc_refcnt;
unsigned lc_flags;
+ time_t lc_create_time;
time_t lc_time;
} ldapconn_t;
ldap_avl_info_t li_conninfo;
time_t li_network_timeout;
+ time_t li_conn_ttl;
time_t li_idle_timeout;
time_t li_timeout[ LDAP_BACK_OP_LAST ];
} ldapinfo_t;
#include <lutil_ldap.h>
+#ifndef PRINT_CONNTREE
#define PRINT_CONNTREE 0
+#endif /* !PRINT_CONNTREE */
+
+#define LDAP_CONTROL_OBSOLETE_PROXY_AUTHZ "2.16.840.1.113730.3.4.12"
static LDAP_REBIND_PROC ldap_back_default_rebind;
assert( lc->lc_refcnt == 1 );
lc = avl_delete( &li->li_conninfo.lai_tree, (caddr_t)lc,
- ldap_back_conn_cmp );
+ ldap_back_conndn_cmp );
assert( lc != NULL );
ber_bvreplace( &lc->lc_local_ndn, &op->o_req_ndn );
lerr = avl_insert( &li->li_conninfo.lai_tree, (caddr_t)lc,
- ldap_back_conn_cmp, ldap_back_conn_dup );
+ ldap_back_conndn_cmp, ldap_back_conndn_dup );
ldap_pvt_thread_mutex_unlock( &li->li_conninfo.lai_mutex );
if ( lerr == -1 ) {
/* we can do this because lc_refcnt == 1 */
}
/*
- * ldap_back_conn_cmp
+ * ldap_back_conndn_cmp
*
- * compares two ldapconn_t based on the value of the conn pointer;
- * used by avl stuff
+ * compares two ldapconn_t based on the value of the conn pointer
+ * and of the local DN; used by avl stuff for insert, lookup
+ * and direct delete
*/
int
-ldap_back_conn_cmp( const void *c1, const void *c2 )
+ldap_back_conndn_cmp( const void *c1, const void *c2 )
{
const ldapconn_t *lc1 = (const ldapconn_t *)c1;
const ldapconn_t *lc2 = (const ldapconn_t *)c2;
int rc;
/* If local DNs don't match, it is definitely not a match */
- rc = ber_bvcmp( &lc1->lc_local_ndn, &lc2->lc_local_ndn );
- if ( rc ) {
- return rc;
+ /* For shared sessions, conn is NULL. Only explicitly
+ * bound sessions will have non-NULL conn.
+ */
+ rc = SLAP_PTRCMP( lc1->lc_conn, lc2->lc_conn );
+ if ( rc == 0 ) {
+ rc = ber_bvcmp( &lc1->lc_local_ndn, &lc2->lc_local_ndn );
}
+ return rc;
+}
+
+/*
+ * ldap_back_conn_cmp
+ *
+ * compares two ldapconn_t based on the value of the conn pointer;
+ * used by avl stuff for delete of all conns with the same connid
+ */
+int
+ldap_back_conn_cmp( const void *c1, const void *c2 )
+{
+ const ldapconn_t *lc1 = (const ldapconn_t *)c1;
+ const ldapconn_t *lc2 = (const ldapconn_t *)c2;
+
/* For shared sessions, conn is NULL. Only explicitly
* bound sessions will have non-NULL conn.
*/
}
/*
- * ldap_back_conn_dup
+ * ldap_back_conndn_dup
*
* returns -1 in case a duplicate ldapconn_t has been inserted;
* used by avl stuff
*/
int
-ldap_back_conn_dup( void *c1, void *c2 )
+ldap_back_conndn_dup( void *c1, void *c2 )
{
ldapconn_t *lc1 = (ldapconn_t *)c1;
ldapconn_t *lc2 = (ldapconn_t *)c2;
/* Cannot have more than one shared session with same DN */
- if ( dn_match( &lc1->lc_local_ndn, &lc2->lc_local_ndn ) &&
- lc1->lc_conn == lc2->lc_conn )
+ if ( lc1->lc_conn == lc2->lc_conn &&
+ dn_match( &lc1->lc_local_ndn, &lc2->lc_local_ndn ) )
{
return -1;
}
ravl_print( root->avl_right, depth+1 );
for ( i = 0; i < depth; i++ ) {
- printf( " " );
+ fprintf( stderr, "-" );
}
lc = root->avl_data;
- printf( "lc(%lx) local(%s) conn(%lx) %d\n",
- lc, lc->lc_local_ndn.bv_val, lc->lc_conn, root->avl_bf );
+ fprintf( stderr, "lc=%p local=\"%s\" conn=%p %s\n",
+ (void *)lc, lc->lc_local_ndn.bv_val, (void *)lc->lc_conn,
+ avl_bf2str( root->avl_bf) );
ravl_print( root->avl_left, depth+1 );
}
static void
myprint( Avlnode *root )
{
- printf( "********\n" );
+ fprintf( stderr, "========>\n" );
if ( root == 0 ) {
- printf( "\tNULL\n" );
+ fprintf( stderr, "\tNULL\n" );
} else {
ravl_print( root, 0 );
}
- printf( "********\n" );
+ fprintf( stderr, "<========\n" );
}
#endif /* PRINT_CONNTREE */
assert( lc->lc_refcnt > 0 );
if ( --lc->lc_refcnt == 0 ) {
lc = avl_delete( &li->li_conninfo.lai_tree, (caddr_t)lc,
- ldap_back_conn_cmp );
+ ldap_back_conndn_cmp );
assert( lc != NULL );
ldap_back_conn_free( (void *)lc );
send_ldap_result( op, rs );
rs->sr_text = NULL;
}
+
+ } else {
+ if ( li->li_conn_ttl > 0 ) {
+ (*lcp)->lc_create_time = op->o_time;
+ }
}
return rs->sr_err;
ldap_pvt_thread_mutex_lock( &li->li_conninfo.lai_mutex );
lc = (ldapconn_t *)avl_find( li->li_conninfo.lai_tree,
- (caddr_t)&lc_curr, ldap_back_conn_cmp );
+ (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 ) ) {
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_conn_cmp );
+ (caddr_t)&lc_curr, ldap_back_conndn_cmp );
if ( tmplc != NULL ) {
refcnt = ++tmplc->lc_refcnt;
ldap_back_conn_free( lc );
assert( lc->lc_refcnt == 1 );
rs->sr_err = avl_insert( &li->li_conninfo.lai_tree, (caddr_t)lc,
- ldap_back_conn_cmp, ldap_back_conn_dup );
+ ldap_back_conndn_cmp, ldap_back_conndn_dup );
#if PRINT_CONNTREE > 0
myprint( li->li_conninfo.lai_tree );
}
} else {
- if ( li->li_idle_timeout != 0 && op->o_time > lc->lc_time + li->li_idle_timeout ) {
+ if ( ( li->li_idle_timeout != 0 && op->o_time > lc->lc_time + li->li_idle_timeout )
+ || ( li->li_conn_ttl != 0 && op->o_time > lc->lc_create_time + li->li_conn_ttl ) )
+ {
/* in case of failure, it frees/taints lc and sets it to NULL */
- if ( ldap_back_retry( &lc, op, rs, sendok ) ) {
+ if ( !ldap_back_retry( &lc, op, rs, sendok ) ) {
lc = NULL;
}
}
LDAP_BACK_CFG_WHOAMI,
LDAP_BACK_CFG_TIMEOUT,
LDAP_BACK_CFG_IDLE_TIMEOUT,
+ LDAP_BACK_CFG_CONN_TTL,
LDAP_BACK_CFG_REWRITE,
LDAP_BACK_CFG_LAST
"SYNTAX OMsDirectoryString "
"SINGLE-VALUE )",
NULL, NULL },
+ { "conn-ttl", "ttl", 2, 0, 0,
+ ARG_MAGIC|LDAP_BACK_CFG_CONN_TTL,
+ ldap_back_cf_gen, "( OLcfgDbAt:3.16 "
+ "NAME 'olcDbConnTtl' "
+ "DESC 'connection ttl' "
+ "SYNTAX OMsDirectoryString "
+ "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 },
value_add_one( &c->rvalue_vals, &bv );
} break;
+ case LDAP_BACK_CFG_CONN_TTL: {
+ char buf[ SLAP_TEXT_BUFLEN ];
+
+ if ( li->li_conn_ttl == 0 ) {
+ return 1;
+ }
+
+ lutil_unparse_time( buf, sizeof( buf ), li->li_conn_ttl );
+ ber_str2bv( buf, 0, 0, &bv );
+ value_add_one( &c->rvalue_vals, &bv );
+ } break;
+
default:
/* FIXME: we need to handle all... */
assert( 0 );
li->li_idle_timeout = 0;
break;
+ case LDAP_BACK_CFG_CONN_TTL:
+ li->li_conn_ttl = 0;
+ break;
+
default:
/* FIXME: we need to handle all... */
assert( 0 );
snprintf( c->msg, sizeof( c->msg ),
"\"idassert-bind <args>\": "
"unknown flag \"%s\"",
- c->fname, c->lineno, flags[ j ] );
+ flags[ j ] );
Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->msg, 0 );
return 1;
}
li->li_idle_timeout = (time_t)t;
} break;
+ case LDAP_BACK_CFG_CONN_TTL: {
+ unsigned long t;
+
+ if ( lutil_parse_time( c->argv[ 1 ], &t ) != 0 ) {
+ snprintf( c->msg, sizeof( c->msg),
+ "unable to parse conn ttl\"%s\"",
+ c->argv[ 1 ] );
+ Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->msg, 0 );
+ return 1;
+ }
+ li->li_conn_ttl = (time_t)t;
+ } break;
+
case LDAP_BACK_CFG_REWRITE:
snprintf( c->msg, sizeof( c->msg ),
"rewrite/remap capabilities have been moved "
int ldap_back_init_cf( BackendInfo *bi );
+extern int ldap_back_conndn_cmp( const void *c1, const void *c2);
extern int ldap_back_conn_cmp( const void *c1, const void *c2);
-extern int ldap_back_conn_dup( void *c1, void *c2 );
+extern int ldap_back_conndn_dup( void *c1, void *c2 );
extern void ldap_back_conn_free( void *c );
extern int
struct berval bdn;
LDAPMessage *result = NULL,
*e = NULL;
- char *gattr[3];
+ char *attr[3], **attrp = NULL;
char *filter = NULL;
SlapReply rs;
int do_retry = 1;
LDAPControl **ctrls = NULL;
+ *ent = NULL;
+
/* Tell getconn this is a privileged op */
do_not_cache = op->o_do_not_cache;
op->o_do_not_cache = 1;
op->o_do_not_cache = do_not_cache;
if ( at ) {
+ attrp = attr;
if ( oc && at != slap_schema.si_ad_objectClass ) {
- gattr[0] = slap_schema.si_ad_objectClass->ad_cname.bv_val;
- gattr[1] = at->ad_cname.bv_val;
- gattr[2] = NULL;
+ attr[0] = slap_schema.si_ad_objectClass->ad_cname.bv_val;
+ attr[1] = at->ad_cname.bv_val;
+ attr[2] = NULL;
} else {
- gattr[0] = at->ad_cname.bv_val;
- gattr[1] = NULL;
+ attr[0] = at->ad_cname.bv_val;
+ attr[1] = NULL;
}
}
retry:
rc = ldap_search_ext_s( lc->lc_ld, ndn->bv_val, LDAP_SCOPE_BASE, filter,
- at ? gattr : NULL, 0, ctrls, NULL,
- LDAP_NO_LIMIT, LDAP_NO_LIMIT, &result );
+ attrp, 0, ctrls, NULL,
+ NULL, LDAP_NO_LIMIT, &result );
if ( rc != LDAP_SUCCESS ) {
if ( rc == LDAP_SERVER_DOWN && do_retry ) {
do_retry = 0;
e = ldap_first_entry( lc->lc_ld, result );
if ( e == NULL ) {
+ /* the entry exists, but it doesn't match the filter? */
goto cleanup;
}
*ent = ch_calloc( 1, sizeof( Entry ) );
+ if ( *ent == NULL ) {
+ rc = LDAP_NO_MEMORY;
+ goto cleanup;
+ }
rc = ldap_build_entry( op, e, *ent, &bdn );
conn->c_connid, 0, 0 );
lc_curr.lc_conn = conn;
- lc_curr.lc_local_ndn = conn->c_ndn;
ldap_pvt_thread_mutex_lock( &li->li_conninfo.lai_mutex );
- lc = avl_delete( &li->li_conninfo.lai_tree, (caddr_t)&lc_curr, ldap_back_conn_cmp );
- ldap_pvt_thread_mutex_unlock( &li->li_conninfo.lai_mutex );
-
- if ( lc ) {
+ while ( ( lc = avl_delete( &li->li_conninfo.lai_tree, (caddr_t)&lc_curr, ldap_back_conn_cmp ) ) != NULL )
+ {
Debug( LDAP_DEBUG_TRACE,
"=>ldap_back_conn_destroy: destroying conn %ld (refcnt=%u)\n",
LDAP_BACK_PCONN_ID( lc->lc_conn ), lc->lc_refcnt, 0 );
*/
ldap_back_conn_free( lc );
}
-
- /* no response to unbind */
+ ldap_pvt_thread_mutex_unlock( &li->li_conninfo.lai_mutex );
return 0;
}
#define META_ANONYMOUS 2
#endif
+ time_t msc_create_time;
time_t msc_time;
struct metainfo_t *msc_info;
typedef struct metatarget_t {
char *mt_uri;
+ BerVarray mt_subtree_exclude;
int mt_scope;
struct berval mt_psuffix; /* pretty suffix */
unsigned mt_flags;
int mt_version;
time_t mt_network_timeout;
+ time_t mt_conn_ttl;
time_t mt_idle_timeout;
struct timeval mt_bind_timeout;
#define META_BIND_TIMEOUT LDAP_BACK_RESULT_UTIMEOUT
int mi_version;
time_t mi_network_timeout;
+ time_t mi_conn_ttl;
time_t mi_idle_timeout;
struct timeval mi_bind_timeout;
time_t mi_timeout[ LDAP_BACK_OP_LAST ];
const void *c2 );
extern int
-meta_back_conn_dup(
+meta_back_dnconn_cmp(
+ const void *c1,
+ const void *c2 );
+
+extern int
+meta_back_dnconn_dup(
void *c1,
void *c2 );
meta_back_is_candidate(
struct berval *nsuffix,
int suffixscope,
+ BerVarray subtree_exclude,
struct berval *ndn,
int scope );
assert( mc->mc_refcnt == 1 );
mc = avl_delete( &mi->mi_conninfo.lai_tree, (caddr_t)mc,
- meta_back_conn_cmp );
+ meta_back_dnconn_cmp );
assert( mc != NULL );
ber_bvreplace( &mc->mc_local_ndn, &op->o_req_ndn );
lerr = avl_insert( &mi->mi_conninfo.lai_tree, (caddr_t)mc,
- meta_back_conn_cmp, meta_back_conn_dup );
+ meta_back_dnconn_cmp, meta_back_dnconn_dup );
ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex );
if ( lerr == -1 ) {
for ( i = 0; i < mi->mi_ntargets; ++i ) {
meta_back_is_candidate(
struct berval *nsuffix,
int suffixscope,
+ BerVarray subtree_exclude,
struct berval *ndn,
int scope )
{
if ( dnIsSuffix( ndn, nsuffix ) ) {
+ if ( subtree_exclude ) {
+ int i;
+
+ for ( i = 0; !BER_BVISNULL( &subtree_exclude[ i ] ); i++ ) {
+ if ( dnIsSuffix( ndn, &subtree_exclude[ i ] ) ) {
+ return META_NOT_CANDIDATE;
+ }
+ }
+ }
+
switch ( suffixscope ) {
case LDAP_SCOPE_SUBTREE:
default:
for ( i = 0; i < mi->mi_ntargets; ++i ) {
if ( meta_back_is_candidate( &mi->mi_targets[ i ].mt_nsuffix,
mi->mi_targets[ i ].mt_scope,
+ mi->mi_targets[ i ].mt_subtree_exclude,
ndn, LDAP_SCOPE_BASE ) )
{
if ( candidate == META_TARGET_NONE ) {
mi->mi_targets[ i ].mt_flags = mi->mi_flags;
mi->mi_targets[ i ].mt_version = mi->mi_version;
mi->mi_targets[ i ].mt_network_timeout = mi->mi_network_timeout;
+ mi->mi_targets[ i ].mt_conn_ttl = mi->mi_conn_ttl;
mi->mi_targets[ i ].mt_idle_timeout = mi->mi_idle_timeout;
mi->mi_targets[ i ].mt_bind_timeout = mi->mi_bind_timeout;
for ( c = 0; c < LDAP_BACK_OP_LAST; c++ ) {
}
#endif
+ /* subtree-exclude */
+ } else if ( strcasecmp( argv[ 0 ], "subtree-exclude" ) == 0 ) {
+ int i = mi->mi_ntargets - 1;
+ struct berval dn, ndn;
+
+ if ( i < 0 ) {
+ Debug( LDAP_DEBUG_ANY,
+ "%s: line %d: need \"uri\" directive first\n",
+ fname, lineno, 0 );
+ return 1;
+ }
+
+ switch ( argc ) {
+ case 1:
+ Debug( LDAP_DEBUG_ANY,
+ "%s: line %d: missing DN in \"subtree-exclude <DN>\" line\n",
+ fname, lineno, 0 );
+ return 1;
+
+ case 2:
+ break;
+
+ default:
+ Debug( LDAP_DEBUG_ANY,
+ "%s: line %d: too many args in \"subtree-exclude <DN>\" line\n",
+ fname, lineno, 0 );
+ return 1;
+ }
+
+ ber_str2bv( argv[ 1 ], 0, 0, &dn );
+ if ( dnNormalize( 0, NULL, NULL, &dn, &ndn, NULL )
+ != LDAP_SUCCESS )
+ {
+ Debug( LDAP_DEBUG_ANY, "%s: line %d: "
+ "subtree-exclude DN=\"%s\" is invalid\n",
+ fname, lineno, argv[ 1 ] );
+ return( 1 );
+ }
+
+ if ( !dnIsSuffix( &ndn, &mi->mi_targets[ i ].mt_nsuffix ) ) {
+ Debug( LDAP_DEBUG_ANY, "%s: line %d: "
+ "subtree-exclude DN=\"%s\" "
+ "must be subtree of target\n",
+ fname, lineno, argv[ 1 ] );
+ ber_memfree( ndn.bv_val );
+ return( 1 );
+ }
+
+ if ( mi->mi_targets[ i ].mt_subtree_exclude != NULL ) {
+ int j;
+
+ for ( j = 0; !BER_BVISNULL( &mi->mi_targets[ i ].mt_subtree_exclude[ j ] ); j++ )
+ {
+ if ( dnIsSuffix( &mi->mi_targets[ i ].mt_subtree_exclude[ j ], &ndn ) ) {
+ Debug( LDAP_DEBUG_ANY, "%s: line %d: "
+ "subtree-exclude DN=\"%s\" "
+ "is suffix of another subtree-exclude\n",
+ fname, lineno, argv[ 1 ] );
+ /* reject, because it might be superior
+ * to more than one subtree-exclude */
+ ber_memfree( ndn.bv_val );
+ return( 1 );
+
+ } else if ( dnIsSuffix( &ndn, &mi->mi_targets[ i ].mt_subtree_exclude[ j ] ) ) {
+ Debug( LDAP_DEBUG_ANY, "%s: line %d: "
+ "another subtree-exclude is suffix of "
+ "subtree-exclude DN=\"%s\"\n",
+ fname, lineno, argv[ 1 ] );
+ ber_memfree( ndn.bv_val );
+ return( 0 );
+ }
+ }
+ }
+
+ ber_bvarray_add( &mi->mi_targets[ i ].mt_subtree_exclude, &ndn );
+
/* default target directive */
} else if ( strcasecmp( argv[ 0 ], "default-target" ) == 0 ) {
int i = mi->mi_ntargets - 1;
/* network timeout when connecting to ldap servers */
} else if ( strcasecmp( argv[ 0 ], "network-timeout" ) == 0 ) {
- int i = mi->mi_ntargets - 1;
unsigned long t;
time_t *tp = mi->mi_ntargets ?
&mi->mi_targets[ mi->mi_ntargets - 1 ].mt_network_timeout
/* idle timeout when connecting to ldap servers */
} else if ( strcasecmp( argv[ 0 ], "idle-timeout" ) == 0 ) {
- int i = mi->mi_ntargets - 1;
unsigned long t;
time_t *tp = mi->mi_ntargets ?
&mi->mi_targets[ mi->mi_ntargets - 1 ].mt_idle_timeout
*tp = (time_t)t;
+ /* conn ttl */
+ } else if ( strcasecmp( argv[ 0 ], "conn-ttl" ) == 0 ) {
+ unsigned long t;
+ time_t *tp = mi->mi_ntargets ?
+ &mi->mi_targets[ mi->mi_ntargets - 1 ].mt_conn_ttl
+ : &mi->mi_conn_ttl;
+
+ switch ( argc ) {
+ case 1:
+ Debug( LDAP_DEBUG_ANY,
+ "%s: line %d: missing ttl value in \"conn-ttl <seconds>\" line\n",
+ fname, lineno, 0 );
+ return 1;
+ case 2:
+ break;
+ default:
+ Debug( LDAP_DEBUG_ANY,
+ "%s: line %d: extra cruft after ttl value in \"conn-ttl <seconds>\" line\n",
+ fname, lineno, 0 );
+ return 1;
+ }
+
+ if ( lutil_parse_time( argv[ 1 ], &t ) ) {
+ Debug( LDAP_DEBUG_ANY,
+ "%s: line %d: unable to parse ttl \"%s\" in \"conn-ttl <seconds>\" line\n",
+ fname, lineno, argv[ 1 ] );
+ return 1;
+
+ }
+
+ *tp = (time_t)t;
+
/* bind timeout when connecting to ldap servers */
} else if ( strcasecmp( argv[ 0 ], "bind-timeout" ) == 0 ) {
- int i = mi->mi_ntargets - 1;
unsigned long t;
struct timeval *tp = mi->mi_ntargets ?
&mi->mi_targets[ mi->mi_ntargets - 1 ].mt_bind_timeout
/* FIXME: some day we'll need to throw an error */
}
- dn.bv_val = argv[ 1 ];
- dn.bv_len = strlen( argv[ 1 ] );
+ ber_str2bv( argv[ 1 ], 0, 0, &dn );
if ( dnNormalize( 0, NULL, NULL, &dn, &mi->mi_targets[ i ].mt_binddn,
NULL ) != LDAP_SUCCESS )
{
|| avl_find( map->remap, (caddr_t)&mapping[ 1 ], mapping_cmp ) != NULL)
{
Debug( LDAP_DEBUG_ANY,
- "%s: line %d: duplicate mapping found" SLAPD_CONF_UNKNOWN_IGNORED ".\n",
+ "%s: line %d: duplicate mapping found.\n",
fname, lineno, 0 );
goto error_return;
}
#define PRINT_CONNTREE 0
/*
- * meta_back_conn_cmp
+ * meta_back_dnconn_cmp
*
- * compares two struct metaconn based on the value of the conn pointer;
- * used by avl stuff
+ * compares two struct metaconn based on the value of the conn pointer
+ * and of the local DN; used by avl stuff
*/
int
-meta_back_conn_cmp(
+meta_back_dnconn_cmp(
const void *c1,
const void *c2 )
{
int rc;
/* If local DNs don't match, it is definitely not a match */
- rc = ber_bvcmp( &mc1->mc_local_ndn, &mc2->mc_local_ndn );
- if ( rc ) {
- return rc;
+ /* For shared sessions, conn is NULL. Only explicitly
+ * bound sessions will have non-NULL conn.
+ */
+ rc = SLAP_PTRCMP( mc1->mc_conn, mc2->mc_conn );
+ if ( rc == 0 ) {
+ rc = ber_bvcmp( &mc1->mc_local_ndn, &mc2->mc_local_ndn );
}
+ return rc;
+}
+
+/*
+ * meta_back_conn_cmp
+ *
+ * compares two struct metaconn based on the value of the conn pointer;
+ * used by avl stuff
+ */
+int
+meta_back_conn_cmp(
+ const void *c1,
+ const void *c2 )
+{
+ metaconn_t *mc1 = ( metaconn_t * )c1;
+ metaconn_t *mc2 = ( metaconn_t * )c2;
+
/* For shared sessions, conn is NULL. Only explicitly
* bound sessions will have non-NULL conn.
*/
}
/*
- * meta_back_conn_dup
+ * meta_back_dnconn_dup
*
* returns -1 in case a duplicate struct metaconn has been inserted;
* used by avl stuff
*/
int
-meta_back_conn_dup(
+meta_back_dnconn_dup(
void *c1,
void *c2 )
{
metaconn_t *mc2 = ( metaconn_t * )c2;
/* Cannot have more than one shared session with same DN */
- if ( dn_match( &mc1->mc_local_ndn, &mc2->mc_local_ndn ) &&
- mc1->mc_conn == mc2->mc_conn )
+ if ( mc1->mc_conn == mc2->mc_conn &&
+ dn_match( &mc1->mc_local_ndn, &mc2->mc_local_ndn ) )
{
return -1;
}
* Already init'ed
*/
if ( msc->msc_ld != NULL ) {
- if ( mt->mt_idle_timeout == 0 ) {
- return rs->sr_err = LDAP_SUCCESS;
- }
+ int doreturn = 1;
- if ( op->o_time > msc->msc_time + mt->mt_idle_timeout ) {
+ if ( ( mt->mt_idle_timeout != 0 && op->o_time > msc->msc_time + mt->mt_idle_timeout )
+ || ( mt->mt_conn_ttl != 0 && op->o_time > msc->msc_create_time + mt->mt_conn_ttl ) )
+ {
Debug( LDAP_DEBUG_TRACE,
- "%s meta_back_init_one_conn[%d]: idle timeout.\n",
+ "%s meta_back_init_one_conn[%d]: idle timeout/ttl.\n",
op->o_log_prefix, candidate, 0 );
if ( meta_back_retry( op, rs, mc, candidate, sendok ) ) {
return rs->sr_err;
}
+
+ doreturn = 0;
+ }
+
+ if ( mt->mt_idle_timeout != 0 ) {
+ msc->msc_time = op->o_time;
}
- msc->msc_time = op->o_time;
+ if ( doreturn ) {
+ return rs->sr_err = LDAP_SUCCESS;
+ }
}
/*
msc->msc_time = op->o_time;
}
+ if ( mt->mt_conn_ttl ) {
+ msc->msc_create_time = op->o_time;
+ }
+
} else {
rs->sr_err = slap_map_api2result( rs );
if ( sendok & LDAP_BACK_SENDERR ) {
if ( mi->mi_defaulttarget != META_DEFAULT_TARGET_NONE
&& meta_back_is_candidate( &mi->mi_targets[ mi->mi_defaulttarget ].mt_nsuffix,
mi->mi_targets[ mi->mi_defaulttarget ].mt_scope,
+ mi->mi_targets[ mi->mi_defaulttarget ].mt_subtree_exclude,
ndn, op->o_tag == LDAP_REQ_SEARCH ? op->ors_scope : LDAP_SCOPE_BASE ) )
{
candidate = mi->mi_defaulttarget;
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_conn_cmp );
+ (caddr_t)&mc_curr, meta_back_dnconn_cmp );
if ( mc ) {
if ( mc->mc_tainted ) {
rs->sr_err = LDAP_UNAVAILABLE;
i = meta_back_get_candidate( op, rs, &pndn );
}
- if ( rs->sr_err != LDAP_SUCCESS ) {
+ if ( i < 0 || rs->sr_err != LDAP_SUCCESS ) {
if ( mc != NULL ) {
meta_back_release_conn( op, mc );
}
if ( !( sendok & LDAP_BACK_BINDING ) ) {
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_conn_cmp );
+ (caddr_t)&mc_curr, meta_back_dnconn_cmp );
if ( mc != NULL ) {
mc->mc_refcnt++;
}
if ( i == cached
|| meta_back_is_candidate( &mt->mt_nsuffix,
mt->mt_scope,
+ mt->mt_subtree_exclude,
&op->o_req_ndn,
LDAP_SCOPE_SUBTREE ) )
{
*/
ldap_pvt_thread_mutex_lock( &mi->mi_conninfo.lai_mutex );
err = avl_insert( &mi->mi_conninfo.lai_tree, ( caddr_t )mc,
- meta_back_conn_cmp, meta_back_conn_dup );
+ meta_back_dnconn_cmp, meta_back_dnconn_dup );
#if PRINT_CONNTREE > 0
myprint( mi->mi_conninfo.lai_tree );
LDAP_BACK_CONN_BINDING_CLEAR( mc );
if ( mc->mc_refcnt == 0 && mc->mc_tainted ) {
(void)avl_delete( &mi->mi_conninfo.lai_tree, ( caddr_t )mc,
- meta_back_conn_cmp );
+ meta_back_dnconn_cmp );
meta_back_conn_free( mc );
}
ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex );
BER_BVISNULL( &conn->c_ndn ) ? "" : conn->c_ndn.bv_val, 0 );
mc_curr.mc_conn = conn;
- mc_curr.mc_local_ndn = conn->c_ndn;
ldap_pvt_thread_mutex_lock( &mi->mi_conninfo.lai_mutex );
- mc = avl_delete( &mi->mi_conninfo.lai_tree, ( caddr_t )&mc_curr,
- meta_back_conn_cmp );
- ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex );
-
- if ( mc ) {
+ while ( ( mc = avl_delete( &mi->mi_conninfo.lai_tree, ( caddr_t )&mc_curr, meta_back_conn_cmp ) ) != NULL )
+ {
Debug( LDAP_DEBUG_TRACE,
"=>meta_back_conn_destroy: destroying conn %ld\n",
LDAP_BACK_PCONN_ID( mc->mc_conn ), 0, 0 );
meta_back_conn_free( mc );
}
+ ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex );
/*
* Cleanup rewrite session