static int
parse_paged_cookie( Operation *op, SlapReply *rs )
{
- LDAPControl **c;
int rc = LDAP_SUCCESS;
- ber_tag_t tag;
- ber_int_t size;
- BerElement *ber;
- struct berval cookie = BER_BVNULL;
PagedResultsState *ps = op->o_pagedresults_state;
/* this function must be invoked only if the pagedResults
* by the frontend */
assert( get_pagedresults( op ) > SLAP_CONTROL_IGNORED );
- /* look for the appropriate ctrl structure */
- for ( c = op->o_ctrls; c[0] != NULL; c++ ) {
- if ( strcmp( c[0]->ldctl_oid, LDAP_CONTROL_PAGEDRESULTS ) == 0 )
- {
- break;
- }
- }
-
- if ( c[0] == NULL ) {
- rs->sr_text = "missing pagedResults control";
- return LDAP_PROTOCOL_ERROR;
- }
-
- /* Tested by frontend */
- assert( c[0]->ldctl_value.bv_len > 0 );
-
- /* Parse the control value
- * realSearchControlValue ::= SEQUENCE {
- * size INTEGER (0..maxInt),
- * -- requested page size from client
- * -- result set size estimate from server
- * cookie OCTET STRING
- * }
- */
- ber = ber_init( &c[0]->ldctl_value );
- if ( ber == NULL ) {
- rs->sr_text = "internal error";
- return LDAP_OTHER;
- }
-
- tag = ber_scanf( ber, "{im}", &size, &cookie );
-
- /* Tested by frontend */
- assert( tag != LBER_ERROR );
- assert( size >= 0 );
-
/* cookie decoding/checks deferred to backend... */
- if ( cookie.bv_len ) {
+ if ( ps->ps_cookieval.bv_len ) {
PagedResultsCookie reqcookie;
- if( cookie.bv_len != sizeof( reqcookie ) ) {
+ if( ps->ps_cookieval.bv_len != sizeof( reqcookie ) ) {
/* bad cookie */
rs->sr_text = "paged results cookie is invalid";
rc = LDAP_PROTOCOL_ERROR;
goto done;
}
- AC_MEMCPY( &reqcookie, cookie.bv_val, sizeof( reqcookie ));
+ AC_MEMCPY( &reqcookie, ps->ps_cookieval.bv_val, sizeof( reqcookie ));
if ( reqcookie > ps->ps_cookie ) {
/* bad cookie */
} else {
/* Initial request. Initialize state. */
-#if 0
- if ( op->o_conn->c_pagedresults_state.ps_cookie != 0 ) {
- /* There's another pagedResults control on the
- * same connection; reject new pagedResults controls
- * (allowed by RFC2696) */
- rs->sr_text = "paged results cookie unavailable; try later";
- rc = LDAP_UNWILLING_TO_PERFORM;
- goto done;
- }
-#endif
ps->ps_cookie = 0;
ps->ps_count = 0;
}
done:;
- (void)ber_free( ber, 1 );
return rc;
}
static int
parse_paged_cookie( Operation *op, SlapReply *rs )
{
- LDAPControl **c;
int rc = LDAP_SUCCESS;
- ber_tag_t tag;
- ber_int_t size;
- BerElement *ber;
- struct berval cookie = BER_BVNULL;
PagedResultsState *ps = op->o_pagedresults_state;
/* this function must be invoked only if the pagedResults
* by the frontend */
assert( get_pagedresults( op ) > SLAP_CONTROL_IGNORED );
- /* look for the appropriate ctrl structure */
- for ( c = op->o_ctrls; c[0] != NULL; c++ ) {
- if ( strcmp( c[0]->ldctl_oid, LDAP_CONTROL_PAGEDRESULTS ) == 0 )
- {
- break;
- }
- }
-
- if ( c[0] == NULL ) {
- rs->sr_text = "missing pagedResults control";
- return LDAP_PROTOCOL_ERROR;
- }
-
- /* Tested by frontend */
- assert( c[0]->ldctl_value.bv_len > 0 );
-
- /* Parse the control value
- * realSearchControlValue ::= SEQUENCE {
- * size INTEGER (0..maxInt),
- * -- requested page size from client
- * -- result set size estimate from server
- * cookie OCTET STRING
- * }
- */
- ber = ber_init( &c[0]->ldctl_value );
- if ( ber == NULL ) {
- rs->sr_text = "internal error";
- return LDAP_OTHER;
- }
-
- tag = ber_scanf( ber, "{im}", &size, &cookie );
-
- /* Tested by frontend */
- assert( tag != LBER_ERROR );
- assert( size >= 0 );
-
/* cookie decoding/checks deferred to backend... */
- if ( cookie.bv_len ) {
+ if ( ps->ps_cookieval.bv_len ) {
PagedResultsCookie reqcookie;
- if( cookie.bv_len != sizeof( reqcookie ) ) {
+ if( ps->ps_cookieval.bv_len != sizeof( reqcookie ) ) {
/* bad cookie */
rs->sr_text = "paged results cookie is invalid";
rc = LDAP_PROTOCOL_ERROR;
goto done;
}
- AC_MEMCPY( &reqcookie, cookie.bv_val, sizeof( reqcookie ));
+ AC_MEMCPY( &reqcookie, ps->ps_cookieval.bv_val, sizeof( reqcookie ));
if ( reqcookie > ps->ps_cookie ) {
/* bad cookie */
} else {
/* Initial request. Initialize state. */
-#if 0
- if ( op->o_conn->c_pagedresults_state.ps_cookie != 0 ) {
- /* There's another pagedResults control on the
- * same connection; reject new pagedResults controls
- * (allowed by RFC2696) */
- rs->sr_text = "paged results cookie unavailable; try later";
- rc = LDAP_UNWILLING_TO_PERFORM;
- goto done;
- }
-#endif
ps->ps_cookie = 0;
ps->ps_count = 0;
}
done:;
- (void)ber_free( ber, 1 );
return rc;
}
if (!j) {
newctrls = ch_malloc((i+1)*sizeof(LDAPControl *));
} else {
+ /* Forget old pagedResults response if we're sending
+ * a new one now
+ */
+ if ( get_pagedresults( op ) > SLAP_CONTROL_IGNORED ) {
+ int newpage = 0;
+ for ( k=0; k<i; k++ ) {
+ if ( !strcmp(rs->sr_ctrls[k]->ldctl_oid,
+ LDAP_CONTROL_PAGEDRESULTS )) {
+ newpage = 1;
+ break;
+ }
+ }
+ if ( newpage ) {
+ for ( k=0; k<j; k++ ) {
+ if ( !strcmp(gs->ctrls[k]->ldctl_oid,
+ LDAP_CONTROL_PAGEDRESULTS )) {
+ gs->ctrls[k]->ldctl_oid = NULL;
+ ldap_control_free( gs->ctrls[k] );
+ gs->ctrls[k] = gs->ctrls[--j];
+ gs->ctrls[j] = NULL;
+ break;
+ }
+ }
+ }
+ }
newctrls = ch_realloc(gs->ctrls,
(j+i+1)*sizeof(LDAPControl *));
}
slap_overinst *on = (slap_overinst *)op->o_bd->bd_info;
glueinfo *gi = (glueinfo *)on->on_bi.bi_private;
BackendDB *b0 = op->o_bd;
- BackendDB *b1 = NULL, *btmp;
+ BackendDB *btmp;
BackendInfo *bi0 = op->o_bd->bd_info;
int i;
long stoptime = 0, starttime;
tlimit0 = op->ors_tlimit;
dn = op->o_req_dn;
ndn = op->o_req_ndn;
- b1 = op->o_bd;
/*
* Execute in reverse order, most specific first
}
if (!btmp || !btmp->be_search)
continue;
- if (!dnIsSuffix(&btmp->be_nsuffix[0], &b1->be_nsuffix[0]))
+ if (!dnIsSuffix(&btmp->be_nsuffix[0], &b0->be_nsuffix[0]))
+ continue;
+ if (get_no_subordinate_glue(op) && btmp != b0)
continue;
- if (get_no_subordinate_glue(op) && btmp != b1)
+ /* If we remembered which backend we were on before,
+ * skip down to it now
+ */
+ if ( get_pagedresults( op ) > SLAP_CONTROL_IGNORED &&
+ op->o_conn->c_pagedresults_state.ps_be &&
+ op->o_conn->c_pagedresults_state.ps_be != btmp )
continue;
if (tlimit0 != SLAP_NO_LIMIT) {
case LDAP_X_CANNOT_CHAIN:
#endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
goto end_of_loop;
-
+
+ case LDAP_SUCCESS:
+ if ( get_pagedresults( op ) > SLAP_CONTROL_IGNORED ) {
+ PagedResultsState *ps = op->o_pagedresults_state;
+
+ /* Assume this backend can be forgotten now */
+ op->o_conn->c_pagedresults_state.ps_be = NULL;
+
+ /* If we have a full page, exit the loop. We may
+ * need to remember this backend so we can continue
+ * from here on a subsequent request.
+ */
+ if ( rs->sr_nentries >= ps->ps_size ) {
+ /* Don't bother to remember the first backend.
+ * Only remember the last one if there's more state left.
+ */
+ if ( op->o_bd != b0 &&
+ ( op->o_conn->c_pagedresults_state.ps_cookie ||
+ op->o_bd != gi->gi_n[0].gn_be ))
+ op->o_conn->c_pagedresults_state.ps_be = op->o_bd;
+ goto end_of_loop;
+ }
+
+ /* This backend has run out of entries, but more responses
+ * can fit in the page. Fake a reset of the state so the
+ * next backend will start up properly. Only back-[bh]db
+ * and back-sql look at this state info.
+ */
+ if ( ps->ps_cookieval.bv_len == sizeof( PagedResultsCookie )) {
+ ps->ps_cookie = 0;
+ memset( ps->ps_cookieval.bv_val, 0,
+ sizeof( PagedResultsCookie ));
+ }
+ }
+
default:
break;
}
SlapReply *rs,
LDAPControl *ctrl )
{
+ BerElementBuffer berbuf;
+ BerElement *ber = (BerElement *)&berbuf;
+ struct berval cookie;
+ PagedResultsState *ps;
int rc = LDAP_SUCCESS;
ber_tag_t tag;
ber_int_t size;
- BerElement *ber;
- struct berval cookie = BER_BVNULL;
- PagedResultsState *ps;
if ( op->o_pagedresults != SLAP_CONTROL_NONE ) {
rs->sr_text = "paged results control specified multiple times";
* cookie OCTET STRING
* }
*/
- ber = ber_init( &ctrl->ldctl_value );
- if ( ber == NULL ) {
- rs->sr_text = "internal error";
- return LDAP_OTHER;
- }
+ ber_init2( ber, &ctrl->ldctl_value, LBER_USE_DER );
tag = ber_scanf( ber, "{im}", &size, &cookie );
ps = op->o_tmpalloc( sizeof(PagedResultsState), op->o_tmpmemctx );
*ps = op->o_conn->c_pagedresults_state;
ps->ps_size = size;
+ ps->ps_cookieval = cookie;
op->o_pagedresults_state = ps;
/* NOTE: according to RFC 2696 3.:
}
done:;
- (void)ber_free( ber, 1 );
return rc;
}
typedef struct PagedResultsState {
Backend *ps_be;
ber_int_t ps_size;
- PagedResultsCookie ps_cookie;
int ps_count;
+ PagedResultsCookie ps_cookie;
+ struct berval ps_cookieval;
} PagedResultsState;
struct slap_csn_entry {