#define LDAP_BACK_CONN_BINDING_CLEAR(lc) LDAP_BACK_CONN_CLEAR((lc), LDAP_BACK_FCONN_BINDING)
unsigned lc_refcnt;
+ unsigned lc_binding;
unsigned lc_flags;
time_t lc_create_time;
time_t lc_time;
}
done:;
+ assert( lc->lc_binding == 1 );
+ lc->lc_binding = 0;
+
/* must re-insert if local DN changed as result of bind */
- if ( LDAP_BACK_CONN_ISBOUND( lc )
- && !dn_match( &op->o_req_ndn, &lc->lc_local_ndn ) )
+ if ( !LDAP_BACK_CONN_ISBOUND( lc )
+ || ( LDAP_BACK_CONN_ISBOUND( lc )
+ && !dn_match( &op->o_req_ndn, &lc->lc_local_ndn ) ) )
{
- int lerr;
+ int lerr = -1;
/* wait for all other ops to release the connection */
retry_lock:;
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_conndn_cmp, ldap_back_conndn_dup );
+ if ( LDAP_BACK_CONN_ISBOUND( lc ) ) {
+ ber_bvreplace( &lc->lc_local_ndn, &op->o_req_ndn );
+ lerr = avl_insert( &li->li_conninfo.lai_tree, (caddr_t)lc,
+ 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 */
return rc;
}
+/*
+ * ldap_back_conndnlc_cmp
+ *
+ * compares two ldapconn_t based on the value of the conn pointer,
+ * the local DN and the lc pointer; used by avl stuff for insert, lookup
+ * and direct delete
+ */
+static int
+ldap_back_conndnlc_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 */
+ /* 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 );
+ if ( rc == 0 ) {
+ rc = SLAP_PTRCMP( lc1, lc2 );
+ }
+ }
+
+ return rc;
+}
+
/*
* ldap_back_conn_cmp
*
}
lc = root->avl_data;
- fprintf( stderr, "lc=%p local=\"%s\" conn=%p %s\n",
+ fprintf( stderr, "lc=%p local=\"%s\" conn=%p %s refcnt=%d\n",
(void *)lc, lc->lc_local_ndn.bv_val, (void *)lc->lc_conn,
- avl_bf2str( root->avl_bf) );
+ avl_bf2str( root->avl_bf ), lc->lc_refcnt );
ravl_print( root->avl_left, depth+1 );
}
}
ldap_set_option( ld, LDAP_OPT_PROTOCOL_VERSION, (const void *)&vers );
- /* automatically chase referrals ("[dont-]chase-referrals" statement) */
- if ( LDAP_BACK_CHASE_REFERRALS( li ) ) {
- ldap_set_option( ld, LDAP_OPT_REFERRALS, LDAP_OPT_ON );
- }
+ /* automatically chase referrals ("chase-referrals [{yes|no}]" statement) */
+ ldap_set_option( ld, LDAP_OPT_REFERRALS,
+ LDAP_BACK_CHASE_REFERRALS( li ) ? LDAP_OPT_ON : LDAP_OPT_OFF );
#ifdef HAVE_TLS
rs->sr_err = ldap_back_start_tls( ld, op->o_protocol, &is_tls,
}
(*lcp)->lc_ld = ld;
(*lcp)->lc_refcnt = 1;
+ (*lcp)->lc_binding = 1;
#ifdef HAVE_TLS
if ( is_tls ) {
LDAP_BACK_CONN_ISTLS_SET( *lcp );
ldapinfo_t *li = (ldapinfo_t *)op->o_bd->be_private;
ldapconn_t *lc = NULL,
lc_curr = { 0 };
- int refcnt = 1;
+ int refcnt = 1, binding = 1;
/* Internal searches are privileged and shared. So is root. */
if ( op->o_do_not_cache || be_isroot( op ) ) {
goto retry_lock;
}
refcnt = ++lc->lc_refcnt;
+ binding = ++lc->lc_binding;
}
ldap_pvt_thread_mutex_unlock( &li->li_conninfo.lai_mutex );
}
(caddr_t)&lc_curr, ldap_back_conndn_cmp );
if ( tmplc != NULL ) {
refcnt = ++tmplc->lc_refcnt;
+ binding = ++tmplc->lc_binding;
ldap_back_conn_free( lc );
lc = tmplc;
}
ldap_pvt_thread_mutex_lock( &li->li_conninfo.lai_mutex );
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 );
ldap_pvt_thread_mutex_unlock( &li->li_conninfo.lai_mutex );
Debug( LDAP_DEBUG_TRACE,
- "=>ldap_back_getconn: conn %p inserted (refcnt=%u)\n",
- (void *)lc, refcnt, 0 );
+ "=>ldap_back_getconn: conn %p inserted refcnt=%u binding=%u\n",
+ (void *)lc, refcnt, binding );
/* Err could be -1 in case a duplicate ldapconn is inserted */
if ( rs->sr_err != 0 ) {
}
} else {
+ char buf[ SLAP_TEXT_BUFLEN ];
+ int expiring = 0;
+
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 ) ) {
- lc = NULL;
- }
+ expiring = 1;
+
+ /* 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 );
+ (void *)avl_delete( &li->li_conninfo.lai_tree, (caddr_t)lc,
+ ldap_back_conndnlc_cmp );
+ ldap_pvt_thread_mutex_unlock( &li->li_conninfo.lai_mutex );
}
- if ( lc ) {
+ if ( LogTest( LDAP_DEBUG_TRACE ) ) {
+ snprintf( buf, sizeof( buf ),
+ "conn %p fetched refcnt=%u binding=%u%s",
+ (void *)lc, refcnt, binding, expiring ? " expiring" : "" );
Debug( LDAP_DEBUG_TRACE,
- "=>ldap_back_getconn: conn %p fetched (refcnt=%u)\n",
- (void *)lc, refcnt, 0 );
+ "=>ldap_back_getconn: %s.\n", buf, 0, 0 );
}
+
}
if ( li->li_idle_timeout && lc ) {
{
ldapinfo_t *li = (ldapinfo_t *)op->o_bd->be_private;
- int rc = LDAP_BACK_CONN_ISBOUND( lc );
+ int rc, binding = 0;
ber_int_t msgid;
assert( retries >= 0 );
- if ( rc ) {
- return rc;
+retry_lock:;
+ if ( dolock ) {
+ ldap_pvt_thread_mutex_lock( &li->li_conninfo.lai_mutex );
+ }
+
+ if ( binding == 0 ) {
+ /* check if already bound */
+ rc = LDAP_BACK_CONN_ISBOUND( lc );
+ if ( rc ) {
+ lc->lc_binding--;
+ if ( dolock ) {
+ ldap_pvt_thread_mutex_unlock( &li->li_conninfo.lai_mutex );
+ }
+ return rc;
+ }
+
+ if ( LDAP_BACK_CONN_BINDING( lc ) ) {
+ /* if someone else is about to bind it, give up and retry */
+ if ( dolock ) {
+ ldap_pvt_thread_mutex_unlock( &li->li_conninfo.lai_mutex );
+ }
+ ldap_pvt_thread_yield();
+ goto retry_lock;
+
+ } else {
+ /* otherwise this thread will bind it */
+ LDAP_BACK_CONN_BINDING_SET( lc );
+ binding = 1;
+ }
}
+ /* wait for pending operations to finish */
+ /* FIXME: may become a bottleneck! */
+ if ( lc->lc_refcnt != lc->lc_binding ) {
+ if ( dolock ) {
+ ldap_pvt_thread_mutex_unlock( &li->li_conninfo.lai_mutex );
+ }
+ ldap_pvt_thread_yield();
+ goto retry_lock;
+ }
+
+ if ( dolock ) {
+ ldap_pvt_thread_mutex_unlock( &li->li_conninfo.lai_mutex );
+ }
+
+#if 0
while ( lc->lc_refcnt > 1 ) {
ldap_pvt_thread_yield();
rc = LDAP_BACK_CONN_ISBOUND( lc );
if ( dolock ) {
ldap_pvt_thread_mutex_unlock( &li->li_conninfo.lai_mutex );
}
+#endif
/*
* FIXME: we need to let clients use proxyAuthz
}
}
+ lc->lc_binding--;
ldap_back_freeconn( op, lc, dolock );
rs->sr_err = slap_map_api2result( rs );
}
done:;
+ lc->lc_binding--;
LDAP_BACK_CONN_BINDING_CLEAR( lc );
rc = LDAP_BACK_CONN_ISBOUND( lc );
if ( !rc ) {
*lcp = NULL;
}
}
+
+ } else {
+ Debug( LDAP_DEBUG_TRACE,
+ "ldap_back_retry: conn %p refcnt=%u unable to retry.\n",
+ (void *)(*lcp), (*lcp)->lc_refcnt, 0 );
+
+ ldap_back_release_conn_lock( op, rs, *lcp, 0 );
+ *lcp = NULL;
+
+ if ( sendok ) {
+ rs->sr_err = LDAP_UNAVAILABLE;
+ rs->sr_text = "unable to retry";
+ send_ldap_result( op, rs );
+ }
}
ldap_pvt_thread_mutex_unlock( &li->li_conninfo.lai_mutex );
{
/* ndn is not authorized
* to use idassert */
- return rc;
+ rs->sr_err = rc;
}
- return rs->sr_err;
+ goto done;
}
}
return 0;
}
-static int
-ldap_chain_operational( Operation *op, SlapReply *rs )
-{
- /* Trap entries generated by back-ldap.
- *
- * FIXME: we need a better way to recognize them; a cleaner
- * solution would be to be able to intercept the response
- * of be_operational(), so that we can divert only those
- * calls that fail because operational attributes were
- * requested for entries that do not belong to the underlying
- * database. This fix is likely to intercept also entries
- * generated by back-perl and so. */
- if ( rs->sr_entry->e_private == NULL ) {
- return 0;
- }
-
- return SLAP_CB_CONTINUE;
-}
-
/*
* Search specific response that strips entryDN from entries
*/
break;
}
}
+
+ /* tell the frontend not to add generated
+ * operational attributes */
+ rs->sr_flags |= REP_NO_OPERATIONALS;
return SLAP_CB_CONTINUE;
ldap_chain_op(
Operation *op,
SlapReply *rs,
- int ( *op_f )( Operation *op, SlapReply *rs ),
+ BI_op_func *op_f,
BerVarray ref )
{
slap_overinst *on = (slap_overinst *) op->o_bd->bd_info;
}
}
- rc = ( *op_f )( op, rs );
+ rc = op_f( op, rs );
cleanup:;
ldap_memfree( li.li_uri );
/* FIXME: ldap_back_extended() by design
* doesn't send result; frontend is expected
* to send it... */
- /* FIXME: what aboit chaining? */
+ /* FIXME: what about chaining? */
if ( rc != SLAPD_ABANDON ) {
send_ldap_extended( op, rs );
rc = LDAP_SUCCESS;
case LDAP_SUCCESS:
case LDAP_REFERRAL:
/* slapd-ldap sent response */
- assert( sc2.sc_private == LDAP_CH_RES );
+ if ( !op->o_abandon && sc2.sc_private != LDAP_CH_RES ) {
+ /* FIXME: should we send response? */
+ Debug( LDAP_DEBUG_ANY,
+ "%s: ldap_chain_response: "
+ "overlay should have sent result.\n",
+ op->o_log_prefix, 0, 0 );
+ }
break;
default:
ldapchain.on_bi.bi_db_close = ldap_chain_db_close;
ldapchain.on_bi.bi_db_destroy = ldap_chain_db_destroy;
- /* ... otherwise the underlying backend's function would be called,
- * likely passing an invalid entry; on the contrary, the requested
- * operational attributes should have been returned while chasing
- * the referrals. This all in all is a bit messy, because part
- * of the operational attributes are generated by the backend;
- * part by the frontend; back-ldap should receive all the available
- * ones from the remote server, but then, on its own, it strips those
- * it assumes will be (re)generated by the frontend (e.g.
- * subschemaSubentry.) */
- ldapchain.on_bi.bi_operational = ldap_chain_operational;
-
ldapchain.on_bi.bi_connection_destroy = ldap_chain_connection_destroy;
ldapchain.on_response = ldap_chain_response;
struct berval bv = BER_BVNULL;
rc = 0;
+ if ( li == NULL ) {
+ return 1;
+ }
+
switch( c->type ) {
case LDAP_BACK_CFG_URI:
if ( li->li_uri != NULL ) {
rs->sr_attrs = op->ors_attrs;
rs->sr_operational_attrs = NULL;
rs->sr_flags = 0;
+ rs->sr_err = LDAP_SUCCESS;
rc = rs->sr_err = send_search_entry( op, rs );
if ( !BER_BVISNULL( &ent.e_name ) ) {
assert( ent.e_name.bv_val != bdn.bv_val );
attrs, op->o_ctrls, NULL, &msgid );
if ( rs->sr_err == LDAP_UNAVAILABLE && do_retry ) {
do_retry = 0;
- if ( meta_back_retry( op, rs, mc, candidate, LDAP_BACK_SENDERR ) ) {
+ if ( meta_back_retry( op, rs, &mc, candidate, LDAP_BACK_SENDERR ) ) {
goto retry;
}
+ goto cleanup;
} else if ( rs->sr_err == LDAP_SUCCESS ) {
struct timeval tv, *tvp = NULL;
}
done:;
- meta_back_release_conn( op, mc );
+ if ( mc ) {
+ meta_back_release_conn( op, mc );
+ }
return rs->sr_err;
}
/* NOTE: lc_lcflags is redefined to msc_mscflags to reuse the macros
* defined for back-ldap */
#define lc_lcflags msc_mscflags
-#if 0
- int msc_bound;
-#define META_UNBOUND 0
-#define META_BOUND 1
-#define META_ANONYMOUS 2
-#endif
-
- time_t msc_create_time;
- time_t msc_time;
struct metainfo_t *msc_info;
} metasingleconn_t;
typedef struct metaconn_t {
struct slap_conn *mc_conn;
- ldap_pvt_thread_mutex_t mc_mutex;
unsigned mc_refcnt;
- int mc_tainted;
+
+ time_t mc_create_time;
+ time_t mc_time;
struct berval mc_local_ndn;
/* NOTE: msc_mscflags is used to recycle the #define
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
time_t mt_timeout[ LDAP_BACK_OP_LAST ];
ldap_back_send_t sendok );
extern void
-meta_back_release_conn(
+meta_back_release_conn_lock(
Operation *op,
- metaconn_t *mc );
+ metaconn_t *mc,
+ int dofree,
+ int dolock );
+#define meta_back_release_conn(op, mc) meta_back_release_conn_lock( (op), (mc), 0, 1 )
extern int
-meta_back_retry_lock(
+meta_back_retry(
Operation *op,
SlapReply *rs,
- metaconn_t *mc,
+ metaconn_t **mcp,
int candidate,
- ldap_back_send_t sendok,
- int dolock );
-#define meta_back_retry(op, rs, mc, candidate, sendok) \
- meta_back_retry_lock((op), (rs), (mc), (candidate), (sendok), 1)
+ ldap_back_send_t sendok );
extern void
meta_back_conn_free(
meta_back_single_dobind(
Operation *op,
SlapReply *rs,
- metaconn_t *msc,
+ metaconn_t **mcp,
int candidate,
ldap_back_send_t sendok,
int retries,
const void *c2 );
extern int
-meta_back_dnconn_cmp(
+meta_back_conndn_cmp(
const void *c1,
const void *c2 );
extern int
-meta_back_dnconn_dup(
+meta_back_conndn_dup(
void *c1,
void *c2 );
meta_clear_one_candidate(
metasingleconn_t *mc );
+extern int
+meta_clear_candidates(
+ Operation *op,
+ metaconn_t *mc );
+
/*
* Dn cache stuff (experimental)
*/
if ( lerr != LDAP_SUCCESS ) {
rc = rs->sr_err = lerr;
+ /* FIXME: in some cases (e.g. unavailable)
+ * do not assume it's not candidate; rather
+ * mark this as an error to be eventually
+ * reported to client */
candidates[ i ].sr_tag = META_NOT_CANDIDATE;
break;
}
}
if ( !dn_match( &op->o_req_ndn, &mc->mc_local_ndn ) ) {
+ metaconn_t *tmpmc;
int lerr;
/* wait for all other ops to release the connection */
}
assert( mc->mc_refcnt == 1 );
- mc = avl_delete( &mi->mi_conninfo.lai_tree, (caddr_t)mc,
- meta_back_dnconn_cmp );
- assert( mc != NULL );
+ tmpmc = avl_delete( &mi->mi_conninfo.lai_tree, (caddr_t)mc,
+ meta_back_conndn_cmp );
+ assert( tmpmc == mc );
ber_bvreplace( &mc->mc_local_ndn, &op->o_req_ndn );
lerr = avl_insert( &mi->mi_conninfo.lai_tree, (caddr_t)mc,
- meta_back_dnconn_cmp, meta_back_dnconn_dup );
+ meta_back_conndn_cmp, meta_back_conndn_dup );
ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex );
if ( lerr == -1 ) {
- for ( i = 0; i < mi->mi_ntargets; ++i ) {
- if ( mc->mc_conns[ i ].msc_ld != NULL ) {
- meta_clear_one_candidate( &mc->mc_conns[ i ] );
- }
- }
+ meta_clear_candidates( op, mc );
/* we can do this because mc_refcnt == 1 */
mc->mc_refcnt = 0;
dc.ctx = "bindDN";
if ( ldap_back_dn_massage( &dc, &op->o_req_dn, &mdn ) ) {
- send_ldap_result( op, rs );
- return -1;
+ rs->sr_text = "DN rewrite error";
+ rs->sr_err = LDAP_OTHER;
+ return rs->sr_err;
}
} else {
}
snprintf( buf, sizeof( buf ),
- "err=%d nretries=%d",
- rs->sr_err, nretries );
+ "err=%d (%s) nretries=%d",
+ rs->sr_err, ldap_err2string( rs->sr_err ), nretries );
Debug( LDAP_DEBUG_ANY,
"### %s meta_back_single_bind[%d]: %s.\n",
op->o_log_prefix, candidate, buf );
rc = slap_map_api2result( rs );
if ( rs->sr_err == LDAP_UNAVAILABLE && nretries != META_RETRY_NEVER ) {
- rc = meta_back_retry( op, rs, mc, candidate, LDAP_BACK_DONTSEND );
+ rc = meta_back_retry( op, rs, &mc, candidate, LDAP_BACK_DONTSEND );
if ( rc ) {
if ( nretries > 0 ) {
nretries--;
ldap_pvt_thread_yield();
goto rebind;
}
+ goto return_results;
}
break;
meta_back_single_dobind(
Operation *op,
SlapReply *rs,
- metaconn_t *mc,
+ metaconn_t **mcp,
int candidate,
ldap_back_send_t sendok,
int nretries,
{
metainfo_t *mi = ( metainfo_t * )op->o_bd->be_private;
metatarget_t *mt = &mi->mi_targets[ candidate ];
+ metaconn_t *mc = *mcp;
metasingleconn_t *msc = &mc->mc_conns[ candidate ];
int rc;
static struct berval cred = BER_BVC( "" );
assert( !LDAP_BACK_CONN_ISBOUND( msc ) );
+ /*
+ * meta_back_single_dobind() calls meta_back_single_bind()
+ * if required.
+ */
+ if ( be_isroot( op ) && !BER_BVISNULL( &mi->mi_targets[ candidate ].mt_pseudorootdn ) )
+ {
+ Operation op2 = *op;
+
+ op2.o_tag = LDAP_REQ_BIND;
+ op2.o_req_dn = mi->mi_targets[ candidate ].mt_pseudorootdn;
+ op2.o_req_ndn = mi->mi_targets[ candidate ].mt_pseudorootdn;
+ op2.orb_cred = mi->mi_targets[ candidate ].mt_pseudorootpw;
+ op2.orb_method = LDAP_AUTH_SIMPLE;
+
+ rc = meta_back_single_bind( &op2, rs, *mcp, candidate, 0 );
+ goto done;
+ }
+
/*
* Otherwise an anonymous bind is performed
* (note: if the target was already bound, the anonymous
}
snprintf( buf, sizeof( buf ),
- "err=%d nretries=%d",
- rs->sr_err, nretries );
+ "err=%d (%s) nretries=%d",
+ rs->sr_err, ldap_err2string( rs->sr_err ), nretries );
Debug( LDAP_DEBUG_ANY,
"### %s meta_back_single_dobind[%d]: %s.\n",
op->o_log_prefix, candidate, buf );
rc = slap_map_api2result( rs );
if ( rc == LDAP_UNAVAILABLE && nretries != META_RETRY_NEVER ) {
- /* NOTE: we do not use meta_back_retry() here
- * to avoid circular loops; mc_mutex is set
- * by the caller */
if ( dolock ) {
ldap_pvt_thread_mutex_lock( &mi->mi_conninfo.lai_mutex );
}
mt, mc, candidate,
LDAP_BACK_CONN_ISPRIV( mc ),
LDAP_BACK_DONTSEND );
+ LDAP_BACK_CONN_BINDING_SET( msc );
} else {
/* can't do anything about it */
rc = slap_map_api2result( rs );
}
+done:;
rs->sr_err = rc;
- if ( rc != LDAP_SUCCESS && ( sendok & LDAP_BACK_SENDERR ) ) {
- send_ldap_result( op, rs );
+ if ( rc != LDAP_SUCCESS && META_BACK_ONERR_STOP( mi ) ) {
+ LDAP_BACK_CONN_BINDING_CLEAR( msc );
+ meta_back_release_conn_lock( op, mc, 1, dolock );
+ *mcp = NULL;
+
+ if ( sendok & LDAP_BACK_SENDERR ) {
+ send_ldap_result( op, rs );
+ }
}
return rc;
LDAP_BACK_PCONN_ID( mc->mc_conn ),
isroot ? " (isroot)" : "" );
- ldap_pvt_thread_mutex_lock( &mc->mc_mutex );
-
/*
* all the targets are bound as pseudoroot
*/
/*
* If the target is already bound it is skipped
*/
+
+retry_binding:;
+ ldap_pvt_thread_mutex_lock( &mi->mi_conninfo.lai_mutex );
if ( LDAP_BACK_CONN_ISBOUND( msc ) || LDAP_BACK_CONN_ISANON( msc ) ) {
+ ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex );
++bound;
continue;
- }
-retry:;
- if ( isroot && !BER_BVISNULL( &mi->mi_targets[ i ].mt_pseudorootdn ) )
- {
- Operation op2 = *op;
-
- op2.o_tag = LDAP_REQ_BIND;
- op2.o_req_dn = mi->mi_targets[ i ].mt_pseudorootdn;
- op2.o_req_ndn = mi->mi_targets[ i ].mt_pseudorootdn;
- op2.orb_cred = mi->mi_targets[ i ].mt_pseudorootpw;
- op2.orb_method = LDAP_AUTH_SIMPLE;
-
- rootdn = mi->mi_targets[ i ].mt_pseudorootdn.bv_val;
-
- rc = meta_back_single_bind( &op2, rs, mc, i, 0 );
+ } else if ( LDAP_BACK_CONN_BINDING( msc ) ) {
+ ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex );
+ ldap_pvt_thread_yield();
+ goto retry_binding;
} else {
- rc = meta_back_single_dobind( op, rs, mc, i,
- LDAP_BACK_DONTSEND, mt->mt_nretries, 1 );
- }
+ LDAP_BACK_CONN_BINDING_SET( msc );
+ ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex );
+ }
+retry:;
+ rc = meta_back_single_dobind( op, rs, &mc, i,
+ LDAP_BACK_DONTSEND, mt->mt_nretries, 1 );
+ /*
+ * NOTE: meta_back_single_dobind() already retries;
+ * in case of failure, it resets mc...
+ */
if ( rc != LDAP_SUCCESS ) {
char buf[ SLAP_TEXT_BUFLEN ];
+ if ( mc == NULL ) {
+ /* meta_back_single_dobind() already sent
+ * response and released connection */
+ goto send_err;
+ }
+
+
if ( rc == LDAP_UNAVAILABLE && do_retry ) {
do_retry = 0;
- if ( meta_back_retry_lock( op, rs, mc, i, LDAP_BACK_DONTSEND, 0 ) ) {
+ if ( meta_back_retry( op, rs, &mc, i, sendok ) ) {
goto retry;
}
+ ldap_pvt_thread_mutex_lock( &mi->mi_conninfo.lai_mutex );
+ LDAP_BACK_CONN_BINDING_CLEAR( msc );
+ ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex );
+
+ return 0;
}
+ ldap_pvt_thread_mutex_lock( &mi->mi_conninfo.lai_mutex );
+ LDAP_BACK_CONN_BINDING_CLEAR( msc );
+ ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex );
+
snprintf( buf, sizeof( buf ),
- "meta_back_dobind[%d]: (%s) err=%d.",
- i, rootdn ? rootdn : "anonymous", rc );
+ "meta_back_dobind[%d]: (%s) err=%d (%s).",
+ i, rootdn ? rootdn : "anonymous",
+ rc, ldap_err2string( rc ) );
Debug( LDAP_DEBUG_ANY,
"%s %s\n",
op->o_log_prefix, buf, 0 );
bound = 0;
goto done;
}
+
continue;
} /* else */
op->o_log_prefix, i,
rootdn ? rootdn : "anonymous" );
+ ldap_pvt_thread_mutex_lock( &mi->mi_conninfo.lai_mutex );
+ LDAP_BACK_CONN_BINDING_CLEAR( msc );
if ( rootdn ) {
LDAP_BACK_CONN_ISBOUND_SET( msc );
} else {
LDAP_BACK_CONN_ISANON_SET( msc );
}
+ ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex );
++bound;
}
done:;
- ldap_pvt_thread_mutex_unlock( &mc->mc_mutex );
-
Debug( LDAP_DEBUG_TRACE,
"%s meta_back_dobind: conn=%ld bound=%d\n",
op->o_log_prefix, LDAP_BACK_PCONN_ID( mc->mc_conn ), bound );
if ( bound == 0 ) {
meta_back_release_conn( op, mc );
+send_err:;
if ( sendok & LDAP_BACK_SENDERR ) {
if ( rs->sr_err == LDAP_SUCCESS ) {
rs->sr_err = LDAP_BUSY;
}
send_ldap_result( op, rs );
}
+
+ return 0;
}
- return( bound > 0 );
+ return ( bound > 0 );
}
/*
return 0;
}
+/*
+ * meta_clear_candidates
+ *
+ * clears all candidates
+ */
+int
+meta_clear_candidates( Operation *op, metaconn_t *mc )
+{
+ metainfo_t *mi = ( metainfo_t * )op->o_bd->be_private;
+ int c;
+
+ for ( c = 0; c < mi->mi_ntargets; c++ ) {
+ if ( mc->mc_conns[ c ].msc_ld != NULL ) {
+ meta_clear_one_candidate( &mc->mc_conns[ c ] );
+ }
+ }
+
+ return 0;
+}
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++ ) {
mi->mi_targets[ i ].mt_timeout[ c ] = mi->mi_timeout[ c ];
/* idle timeout when connecting to ldap servers */
} else if ( strcasecmp( argv[ 0 ], "idle-timeout" ) == 0 ) {
unsigned long t;
- time_t *tp = mi->mi_ntargets ?
- &mi->mi_targets[ mi->mi_ntargets - 1 ].mt_idle_timeout
- : &mi->mi_idle_timeout;
switch ( argc ) {
case 1:
}
- *tp = (time_t)t;
+ mi->mi_idle_timeout = (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:
}
- *tp = (time_t)t;
+ mi->mi_conn_ttl = (time_t)t;
/* bind timeout when connecting to ldap servers */
} else if ( strcasecmp( argv[ 0 ], "bind-timeout" ) == 0 ) {
#define PRINT_CONNTREE 0
/*
- * meta_back_dnconn_cmp
+ * meta_back_conndn_cmp
*
* compares two struct metaconn based on the value of the conn pointer
* and of the local DN; used by avl stuff
*/
int
-meta_back_dnconn_cmp(
+meta_back_conndn_cmp(
const void *c1,
const void *c2 )
{
return rc;
}
+/*
+ * meta_back_conndnmc_cmp
+ *
+ * compares two struct metaconn based on the value of the conn pointer,
+ * the local DN and the struct pointer; used by avl stuff
+ */
+static int
+meta_back_conndnmc_cmp(
+ const void *c1,
+ const void *c2 )
+{
+ metaconn_t *mc1 = ( metaconn_t * )c1;
+ metaconn_t *mc2 = ( metaconn_t * )c2;
+ int rc;
+
+ /* If local DNs don't match, it is definitely not a match */
+ /* 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 );
+ if ( rc == 0 ) {
+ rc = SLAP_PTRCMP( mc1, mc2 );
+ }
+ }
+
+ return rc;
+}
+
/*
* meta_back_conn_cmp
*
}
/*
- * meta_back_dnconn_dup
+ * meta_back_conndn_dup
*
* returns -1 in case a duplicate struct metaconn has been inserted;
* used by avl stuff
*/
int
-meta_back_dnconn_dup(
+meta_back_conndn_dup(
void *c1,
void *c2 )
{
mc->mc_conns[ i ].msc_ld = NULL;
BER_BVZERO( &mc->mc_conns[ i ].msc_bound_ndn );
BER_BVZERO( &mc->mc_conns[ i ].msc_cred );
- LDAP_BACK_CONN_ISBOUND_CLEAR( &mc->mc_conns[ i ] );
+ mc->mc_conns[ i ].msc_mscflags = 0;
mc->mc_conns[ i ].msc_info = mi;
}
BER_BVZERO( &mc->mc_local_ndn );
mc->msc_mscflags = 0;
mc->mc_authz_target = META_BOUND_NONE;
- ldap_pvt_thread_mutex_init( &mc->mc_mutex );
mc->mc_refcnt = 1;
- mc->mc_tainted = 0;
return mc;
}
* Already init'ed
*/
if ( msc->msc_ld != NULL ) {
- int doreturn = 1;
-
- 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/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;
- }
-
- if ( doreturn ) {
- return rs->sr_err = LDAP_SUCCESS;
- }
+ return rs->sr_err = LDAP_SUCCESS;
}
+
+ msc->msc_mscflags = 0;
/*
* Attempts to initialize the connection to the target ds
vers = op->o_conn->c_protocol;
ldap_set_option( msc->msc_ld, LDAP_OPT_PROTOCOL_VERSION, &vers );
- /* automatically chase referrals ("chase-referrals"/"dont-chase-referrals" statement) */
- if ( LDAP_BACK_CHASE_REFERRALS( mi ) ) {
- ldap_set_option( msc->msc_ld, LDAP_OPT_REFERRALS, LDAP_OPT_ON );
- }
+ /* automatically chase referrals ("chase-referrals [{yes|no}]" statement) */
+ ldap_set_option( msc->msc_ld, LDAP_OPT_REFERRALS,
+ LDAP_BACK_CHASE_REFERRALS( mi ) ? LDAP_OPT_ON : LDAP_OPT_OFF );
#ifdef HAVE_TLS
/* start TLS ("tls [try-]{start|propagate}" statement) */
assert( !BER_BVISNULL( &msc->msc_bound_ndn ) );
- LDAP_BACK_CONN_ISBOUND_CLEAR( msc );
-
error_return:;
if ( rs->sr_err == LDAP_SUCCESS ) {
/*
*/
( void )rewrite_session_init( mt->mt_rwmap.rwm_rw, op->o_conn );
- if ( mt->mt_idle_timeout ) {
- 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 ) {
}
/*
- * meta_back_retry_lock
+ * meta_back_retry
*
* Retries one connection
*/
int
-meta_back_retry_lock(
+meta_back_retry(
Operation *op,
SlapReply *rs,
- metaconn_t *mc,
+ metaconn_t **mcp,
int candidate,
- ldap_back_send_t sendok,
- int dolock )
+ ldap_back_send_t sendok )
{
metainfo_t *mi = ( metainfo_t * )op->o_bd->be_private;
metatarget_t *mt = &mi->mi_targets[ candidate ];
- int rc = LDAP_UNAVAILABLE;
+ metaconn_t *mc = *mcp;
metasingleconn_t *msc = &mc->mc_conns[ candidate ];
+ int rc = LDAP_UNAVAILABLE,
+ binding = LDAP_BACK_CONN_BINDING( msc );
-retry_lock:;
ldap_pvt_thread_mutex_lock( &mi->mi_conninfo.lai_mutex );
assert( mc->mc_refcnt > 0 );
-
if ( mc->mc_refcnt == 1 ) {
char buf[ SLAP_TEXT_BUFLEN ];
- while ( dolock && ldap_pvt_thread_mutex_trylock( &mc->mc_mutex ) ) {
- ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex );
- ldap_pvt_thread_yield();
- goto retry_lock;
- }
-
snprintf( buf, sizeof( buf ),
"retrying URI=\"%s\" DN=\"%s\"",
mt->mt_uri,
/* mc here must be the regular mc, reset and ready for init */
rc = meta_back_init_one_conn( op, rs, mt, mc, candidate,
LDAP_BACK_CONN_ISPRIV( mc ), sendok );
+ if ( binding ) {
+ LDAP_BACK_CONN_BINDING_SET( msc );
+ }
if ( rc == LDAP_SUCCESS ) {
- if ( be_isroot( op ) && !BER_BVISNULL( &mi->mi_targets[ candidate ].mt_pseudorootdn ) )
- {
- Operation op2 = *op;
-
- op2.o_tag = LDAP_REQ_BIND;
- op2.o_req_dn = mi->mi_targets[ candidate ].mt_pseudorootdn;
- op2.o_req_ndn = mi->mi_targets[ candidate ].mt_pseudorootdn;
- op2.orb_cred = mi->mi_targets[ candidate ].mt_pseudorootpw;
- op2.orb_method = LDAP_AUTH_SIMPLE;
-
- rc = meta_back_single_bind( &op2, rs, mc, candidate, 0 );
-
- } else {
- rc = meta_back_single_dobind( op, rs, mc, candidate,
- sendok, mt->mt_nretries, 0 );
- }
+ rc = meta_back_single_dobind( op, rs, mcp, candidate,
+ sendok, mt->mt_nretries, 0 );
}
-
- if ( dolock ) {
- ldap_pvt_thread_mutex_unlock( &mc->mc_mutex );
- }
}
if ( rc != LDAP_SUCCESS ) {
- mc->mc_tainted = 1;
+ if ( *mcp != NULL ) {
+ if ( binding ) {
+ LDAP_BACK_CONN_BINDING_CLEAR( msc );
+ }
+ meta_back_release_conn_lock( op, mc, 1, 0 );
+ *mcp = NULL;
+ }
+
+ if ( sendok ) {
+ rs->sr_err = LDAP_UNAVAILABLE;
+ rs->sr_text = NULL;
+ send_ldap_result( op, rs );
+ }
}
ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex );
meta_op_type op_type = META_OP_REQUIRE_SINGLE;
- int parent = 0,
- newparent = 0;
+ enum {
+ META_DNTYPE_ENTRY,
+ META_DNTYPE_PARENT,
+ META_DNTYPE_NEWPARENT
+ } dn_type = META_DNTYPE_ENTRY;
struct berval ndn = op->o_req_ndn,
pndn;
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_dnconn_cmp );
+ (caddr_t)&mc_curr, meta_back_conndn_cmp );
if ( mc ) {
- if ( mc->mc_tainted ) {
- rs->sr_err = LDAP_UNAVAILABLE;
- rs->sr_text = "remote server unavailable";
- ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex );
- return NULL;
+ if ( ( mi->mi_conn_ttl != 0 && op->o_time > mc->mc_create_time + mi->mi_conn_ttl )
+ || ( mi->mi_idle_timeout != 0 && op->o_time > mc->mc_time + mi->mi_idle_timeout ) )
+ {
+ /* don't let anyone else use this expired connection */
+ (void)avl_delete( &mi->mi_conninfo.lai_tree,
+ (caddr_t)mc, meta_back_conndnmc_cmp );
+
+ Debug( LDAP_DEBUG_TRACE, "%s meta_back_getconn: mc=%p conn=%ld expired.\n",
+ op->o_log_prefix, (void *)mc, LDAP_BACK_PCONN_ID( mc->mc_conn ) );
}
-
+
/* Don't reuse connections while they're still binding */
if ( LDAP_BACK_CONN_BINDING( mc ) ) {
ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex );
ldap_pvt_thread_yield();
goto retry_lock;
}
+
mc->mc_refcnt++;
}
ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex );
case LDAP_REQ_ADD:
/* if we go to selection, the entry must not exist,
* and we must be able to resolve the parent */
- parent = 1;
+ dn_type = META_DNTYPE_PARENT;
dnParent( &ndn, &pndn );
break;
/* if nnewSuperior is not NULL, it must resolve
* to the same candidate as the req_ndn */
if ( op->orr_nnewSup ) {
- newparent = 1;
+ dn_type = META_DNTYPE_NEWPARENT;
}
break;
if ( i == META_TARGET_NONE ) {
i = meta_back_get_candidate( op, rs, &ndn );
- if ( rs->sr_err == LDAP_NO_SUCH_OBJECT && parent ) {
+ if ( rs->sr_err == LDAP_NO_SUCH_OBJECT && dn_type == META_DNTYPE_PARENT ) {
i = meta_back_get_candidate( op, rs, &pndn );
}
}
}
- if ( newparent && meta_back_get_candidate( op, rs, op->orr_nnewSup ) != i )
+ if ( dn_type == META_DNTYPE_NEWPARENT && meta_back_get_candidate( op, rs, op->orr_nnewSup ) != i )
{
if ( mc != NULL ) {
meta_back_release_conn( op, mc );
* the reason is that the connection might have been
* created by meta_back_get_candidate() */
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,
- (caddr_t)&mc_curr, meta_back_dnconn_cmp );
+ (caddr_t)&mc_curr, meta_back_conndn_cmp );
if ( mc != NULL ) {
+ /* Don't reuse connections while they're still binding */
+ if ( LDAP_BACK_CONN_BINDING( mc ) ) {
+ ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex );
+ ldap_pvt_thread_yield();
+ goto retry_lock2;
+ }
+
mc->mc_refcnt++;
}
ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex );
rs->sr_err = LDAP_SUCCESS;
rs->sr_text = NULL;
+ /* touch the timestamp */
+ if ( mi->mi_idle_timeout != 0 ) {
+ mc->mc_time = op->o_time;
+ }
+
if ( new_conn ) {
+ if ( mi->mi_conn_ttl ) {
+ mc->mc_create_time = op->o_time;
+ }
+
/*
* Inserts the newly created metaconn in the avl tree
*/
ldap_pvt_thread_mutex_lock( &mi->mi_conninfo.lai_mutex );
err = avl_insert( &mi->mi_conninfo.lai_tree, ( caddr_t )mc,
- meta_back_dnconn_cmp, meta_back_dnconn_dup );
+ meta_back_conndn_cmp, meta_back_conndn_dup );
#if PRINT_CONNTREE > 0
myprint( mi->mi_conninfo.lai_tree );
}
void
-meta_back_release_conn(
+meta_back_release_conn_lock(
Operation *op,
- metaconn_t *mc )
+ metaconn_t *mc,
+ int dofree,
+ int dolock )
{
metainfo_t *mi = ( metainfo_t * )op->o_bd->be_private;
assert( mc != NULL );
- ldap_pvt_thread_mutex_lock( &mi->mi_conninfo.lai_mutex );
+ if ( dolock ) {
+ ldap_pvt_thread_mutex_lock( &mi->mi_conninfo.lai_mutex );
+ }
assert( mc->mc_refcnt > 0 );
mc->mc_refcnt--;
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_dnconn_cmp );
- meta_back_conn_free( mc );
+ if ( dofree
+ || ( mi->mi_conn_ttl != 0 && op->o_time > mc->mc_create_time + mi->mi_conn_ttl )
+ || ( mi->mi_idle_timeout != 0 && op->o_time > mc->mc_time + mi->mi_idle_timeout ) )
+ {
+ Debug( LDAP_DEBUG_TRACE, "%s meta_back_release_conn: mc=%p conn=%ld expired.\n",
+ op->o_log_prefix, (void *)mc, LDAP_BACK_PCONN_ID( mc->mc_conn ) );
+ (void)avl_delete( &mi->mi_conninfo.lai_tree,
+ ( caddr_t )mc, meta_back_conndnmc_cmp );
+ if ( mc->mc_refcnt == 0 ) {
+ meta_clear_candidates( op, mc );
+ meta_back_conn_free( mc );
+ }
+ }
+ if ( dolock ) {
+ ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex );
}
- ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex );
}
mdn.bv_val, op->o_ctrls, NULL, &msgid );
if ( rs->sr_err == LDAP_UNAVAILABLE && do_retry ) {
do_retry = 0;
- if ( meta_back_retry( op, rs, mc, candidate, LDAP_BACK_SENDERR ) ) {
+ if ( meta_back_retry( op, rs, &mc, candidate, LDAP_BACK_SENDERR ) ) {
goto retry;
}
+ goto cleanup;
} else if ( rs->sr_err == LDAP_SUCCESS ) {
struct timeval tv, *tvp = NULL;
}
done:;
- meta_back_release_conn( op, mc );
+ if ( mc ) {
+ meta_back_release_conn( op, mc );
+ }
return rs->sr_err;
}
(void)meta_clear_one_candidate( &mc->mc_conns[ i ] );
}
- ldap_pvt_thread_mutex_destroy( &mc->mc_mutex );
free( mc );
}
assert( e != NULL );
mp = ( monitor_entry_t *)e->e_private;
- ldap_pvt_thread_mutex_init( &mp->mp_mutex );
mc = ( monitor_cache_t * )ch_malloc( sizeof( monitor_cache_t ) );
mc->mc_ndn = e->e_nname;
mp->mp_flags = MONITOR_F_NONE;
mp->mp_cb = NULL;
+ ldap_pvt_thread_mutex_init( &mp->mp_mutex );
+
return mp;
}
* and the backend supports specific operational attributes,
* add them to the attribute list
*/
- if ( SLAP_OPATTRS( rs->sr_attr_flags ) || ( rs->sr_attrs &&
- ad_inlist( slap_schema.si_ad_entryDN, rs->sr_attrs ) ) )
+ if ( !( rs->sr_flags & REP_NO_ENTRYDN )
+ && ( SLAP_OPATTRS( rs->sr_attr_flags ) || ( rs->sr_attrs &&
+ ad_inlist( slap_schema.si_ad_entryDN, rs->sr_attrs ) ) ) )
{
*ap = slap_operational_entryDN( rs->sr_entry );
ap = &(*ap)->a_next;
}
- if ( SLAP_OPATTRS( rs->sr_attr_flags ) || ( rs->sr_attrs &&
- ad_inlist( slap_schema.si_ad_subschemaSubentry, rs->sr_attrs ) ) )
+ if ( !( rs->sr_flags & REP_NO_SUBSCHEMA)
+ && ( SLAP_OPATTRS( rs->sr_attr_flags ) || ( rs->sr_attrs &&
+ ad_inlist( slap_schema.si_ad_subschemaSubentry, rs->sr_attrs ) ) ) )
{
*ap = slap_operational_subschemaSubentry( op->o_bd );
ap = &(*ap)->a_next;
{ "syncrepl", NULL, 0, 0, 0, ARG_DB|ARG_MAGIC,
&syncrepl_config, "( OLcfgDbAt:0.11 NAME 'olcSyncrepl' "
"SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL },
- { "threads", "count", 2, 2, 0, ARG_INT|ARG_MAGIC|CFG_THREADS,
- &config_generic, "( OLcfgGlAt:66 NAME 'olcThreads' "
+ { "threads", "count", 2, 2, 0,
+#ifdef NO_THREADS
+ ARG_IGNORED, NULL,
+#else
+ ARG_INT|ARG_MAGIC|CFG_THREADS, &config_generic,
+#endif
+ "( OLcfgGlAt:66 NAME 'olcThreads' "
"SYNTAX OMsInteger SINGLE-VALUE )", NULL, NULL },
{ "timelimit", "limit", 2, 0, 0, ARG_MAY_DB|ARG_MAGIC,
&config_timelimit, "( OLcfgGlAt:67 NAME 'olcTimeLimit' "
break;
case CFG_THREADS:
- if ( c->value_int > 2 * SLAP_MAX_WORKER_THREADS ) {
+ if ( c->value_int < 2 ) {
+ snprintf( c->msg, sizeof( c->msg ),
+ "threads=%d smaller than minimum value 2",
+ c->value_int );
+ Debug(LDAP_DEBUG_ANY, "%s: %s.\n",
+ c->log, c->msg, 0 );
+ return 1;
+
+ } else if ( c->value_int > 2 * SLAP_MAX_WORKER_THREADS ) {
snprintf( c->msg, sizeof( c->msg ),
"warning, threads=%d larger than twice the default (2*%d=%d); YMMV",
c->value_int, SLAP_MAX_WORKER_THREADS, 2 * SLAP_MAX_WORKER_THREADS );
}
}
+static int connection_bind_cleanup_cb( Operation *op, SlapReply *rs )
+{
+ op->o_conn->c_sasl_bindop = NULL;
+
+ return SLAP_CB_CONTINUE;
+}
+
static int connection_bind_cb( Operation *op, SlapReply *rs )
{
slap_callback *cb = op->o_callback;
if (tag == LDAP_REQ_BIND) {
slap_callback *sc = ch_calloc( 1, sizeof( slap_callback ));
sc->sc_response = connection_bind_cb;
+ sc->sc_cleanup = connection_bind_cleanup_cb;
sc->sc_next = op->o_callback;
op->o_callback = sc;
op->o_conn->c_conn_state = SLAP_C_BINDING;
switch ( slapMode & SLAP_MODE ) {
case SLAP_SERVER_MODE:
+ ldap_pvt_thread_pool_init( &connection_pool,
+ connection_pool_max, 0);
/* FALLTHRU */
case SLAP_TOOL_MODE:
slap_name = name;
- ldap_pvt_thread_pool_init( &connection_pool,
- connection_pool_max, 0);
-
ldap_pvt_thread_mutex_init( &entry2str_mutex );
ldap_pvt_thread_mutex_init( &replog_mutex );
struct berval rd_pdn;
struct berval rd_npdn;
+ int rd_sleep;
+
retcode_item_t *rd_item;
unsigned rd_flags;
slap_overinst *on = (slap_overinst *)op->o_bd->bd_info;
Operation op2 = *op;
- SlapReply rs2 = { 0 };
BackendDB db = *op->o_bd;
slap_callback sc = { 0 };
retcode_cb_t rdc;
sc.sc_private = &rdc;
op2.o_callback = ≻
- rc = op2.o_bd->be_search( &op2, &rs2 );
+ rc = op2.o_bd->be_search( &op2, rs );
+ op->o_abandon = op2.o_abandon;
filter_free_x( &op2, op2.ors_filter );
ber_memfree_x( op2.ors_filterstr.bv_val, op2.o_tmpmemctx );
slap_callback *cb = NULL;
+ /* sleep as required */
+ if ( rd->rd_sleep < 0 ) {
+ sleep( rand() % ( - rd->rd_sleep ) );
+
+ } else if ( rd->rd_sleep > 0 ) {
+ sleep( rd->rd_sleep );
+ }
+
if ( !dnIsSuffix( &op->o_req_ndn, &rd->rd_npdn ) ) {
if ( RETCODE_INDIR( rd ) ) {
switch ( op->o_tag ) {
case LDAP_REQ_SEARCH:
if ( op->ors_scope == LDAP_SCOPE_BASE ) {
rs->sr_err = retcode_op_internal( op, rs );
- if ( rs->sr_err == SLAP_CB_CONTINUE ) {
+ switch ( rs->sr_err ) {
+ case SLAP_CB_CONTINUE:
+ if ( rs->sr_nentries == 0 ) {
+ break;
+ }
rs->sr_err = LDAP_SUCCESS;
+ /* fallthru */
+
+ default:
+ send_ldap_result( op, rs );
+ break;
}
- send_ldap_result( op, rs );
return rs->sr_err;
}
break;
} else if ( strcasecmp( argv0, "indir" ) == 0 ) {
rd->rd_flags |= RETCODE_FINDIR;
+ } else if ( strcasecmp( argv0, "sleep" ) == 0 ) {
+ switch ( argc ) {
+ case 1:
+ fprintf( stderr, "%s: line %d: retcode: "
+ "\"retcode-sleep <time>\": missing <time>\n",
+ fname, lineno );
+ return 1;
+
+ case 2:
+ break;
+
+ default:
+ fprintf( stderr, "%s: line %d: retcode: "
+ "\"retcode-sleep <time>\": extra cruft after <time>\n",
+ fname, lineno );
+ return 1;
+ }
+
+ if ( lutil_atoi( &rd->rd_sleep, argv[ 1 ] ) != 0 ) {
+ fprintf( stderr, "%s: line %d: retcode: "
+ "\"retcode-sleep <time>\": unable to parse <time>\n",
+ fname, lineno );
+ return 1;
+ }
+
} else {
return SLAP_CONF_UNKNOWN;
}
#define REP_ENTRY_MUSTBEFREED 0x0002U
#define REP_ENTRY_MUSTRELEASE 0x0004U
#define REP_MATCHED_MUSTBEFREED 0x0010U
-#define REP_REF_MUSTBEFREED 0x0020U
+#define REP_REF_MUSTBEFREED 0x0020U
+
+#define REP_NO_ENTRYDN 0x1000U
+#define REP_NO_SUBSCHEMA 0x2000U
+#define REP_NO_OPERATIONALS (REP_NO_ENTRYDN|REP_NO_SUBSCHEMA)
} SlapReply;
/* short hands for response members */