use Paged Results when talking to targets (in response to ITS#6664)

This commit is contained in:
Pierangelo Masarati 2011-01-03 17:52:55 +00:00
parent 6460f957af
commit 342980d116
4 changed files with 254 additions and 7 deletions

View File

@ -311,6 +311,18 @@ underlying libldap, with rebinding eventually performed if the
If set before any target specification, it affects all targets, unless
overridden by any per-target directive.
.TP
.B client\-pr {accept-unsolicited|DISABLE|<size>}
This feature allows to use RFC 2696 Paged Results control when performing
search operations with a specific target.
When set to a numeric value, Paged Results control is always
used with \fIsize\fP as the page size.
When set to \fIaccept-unsolicited\fP, unsolicited Paged Results
control responses are accepted and honored.
By default, Paged Results control is not used and responses are not accepted.
If set before any target specification, it affects all targets, unless
overridden by any per-target directive.
.TP
.B default\-target [<target>]
The "default\-target" directive can also be used during target specification.

View File

@ -27,6 +27,10 @@
#ifndef SLAPD_META_H
#define SLAPD_META_H
#ifdef LDAP_DEVEL
#define SLAPD_META_CLIENT_PR 1
#endif /* LDAP_DEVEL */
#include "proto-meta.h"
/* String rewrite library */
@ -335,6 +339,19 @@ typedef struct metatarget_t {
slap_mask_t mt_rep_flags;
int mt_version;
#ifdef SLAPD_META_CLIENT_PR
/*
* client-side paged results:
* -1: accept unsolicited paged results responses
* 0: off
* >0: always request paged results with size == mt_ps
*/
#define META_CLIENT_PR_DISABLE (0)
#define META_CLIENT_PR_ACCEPT_UNSOLICITED (-1)
ber_int_t mt_ps;
#endif /* SLAPD_META_CLIENT_PR */
time_t mt_network_timeout;
struct timeval mt_bind_timeout;
#define META_BIND_TIMEOUT LDAP_BACK_RESULT_UTIMEOUT
@ -411,6 +428,12 @@ typedef struct metainfo_t {
#define META_BACK_QUARANTINE(mi) LDAP_BACK_ISSET( (mi), LDAP_BACK_F_QUARANTINE )
int mi_version;
#ifdef SLAPD_META_CLIENT_PR
ber_int_t mi_ps;
#endif /* SLAPD_META_CLIENT_PR */
time_t mi_network_timeout;
time_t mi_conn_ttl;
time_t mi_idle_timeout;

View File

@ -168,6 +168,9 @@ meta_back_db_config(
}
mt->mt_flags = mi->mi_flags;
mt->mt_version = mi->mi_version;
#ifdef SLAPD_META_CLIENT_PR
mt->mt_ps = mi->mi_ps;
#endif /* SLAPD_META_CLIENT_PR */
mt->mt_network_timeout = mi->mi_network_timeout;
mt->mt_bind_timeout = mi->mi_bind_timeout;
for ( c = 0; c < SLAP_OP_LAST; c++ ) {
@ -1532,6 +1535,33 @@ idassert-authzFrom "dn:<rootdn>"
return( 1 );
}
#ifdef SLAPD_META_CLIENT_PR
} else if ( strcasecmp( argv[ 0 ], "client-pr" ) == 0 ) {
int *ps = mi->mi_ntargets ?
&mi->mi_targets[ mi->mi_ntargets - 1 ]->mt_ps
: &mi->mi_ps;
if ( argc != 2 ) {
Debug( LDAP_DEBUG_ANY,
"%s: line %d: \"client-pr {accept-unsolicited|disable|<size>}\" needs 1 argument.\n",
fname, lineno, 0 );
return( 1 );
}
if ( strcasecmp( argv[ 1 ], "accept-unsolicited" ) == 0 ) {
*ps = META_CLIENT_PR_ACCEPT_UNSOLICITED;
} else if ( strcasecmp( argv[ 1 ], "disable" ) == 0 ) {
*ps = META_CLIENT_PR_DISABLE;
} else if ( lutil_atoi( ps, argv[ 1 ] ) || *ps < -1 ) {
Debug( LDAP_DEBUG_ANY,
"%s: line %d: \"client-pr {accept-unsolicited|disable|<size>}\" invalid arg \"%s\".\n",
fname, lineno, argv[ 1 ] );
return( 1 );
}
#endif /* SLAPD_META_CLIENT_PR */
/* anything else */
} else {
return SLAP_CONF_UNKNOWN;

View File

@ -446,7 +446,9 @@ meta_back_search_start(
dncookie *dc,
metaconn_t **mcp,
int candidate,
SlapReply *candidates )
SlapReply *candidates,
struct berval *prcookie,
ber_int_t prsize )
{
metainfo_t *mi = ( metainfo_t * )op->o_bd->be_private;
metatarget_t *mt = mi->mi_targets[ candidate ];
@ -461,6 +463,9 @@ meta_back_search_start(
struct timeval tv, *tvp = NULL;
int nretries = 1;
LDAPControl **ctrls = NULL;
#ifdef SLAPD_META_CLIENT_PR
LDAPControl **save_ctrls = NULL;
#endif /* SLAPD_META_CLIENT_PR */
/* this should not happen; just in case... */
if ( msc->msc_ld == NULL ) {
@ -614,6 +619,85 @@ meta_back_search_start(
tvp = &tv;
}
#ifdef SLAPD_META_CLIENT_PR
save_ctrls = op->o_ctrls;
{
LDAPControl *pr_c = NULL, **next_c = NULL;
int i = 0, nc = 0;
if ( save_ctrls ) {
for ( ; save_ctrls[i] != NULL; i++ );
nc = i;
pr_c = ldap_control_find( LDAP_CONTROL_PAGEDRESULTS, save_ctrls, &next_c );
}
if ( pr_c != NULL ) nc--;
if ( mt->mt_ps > 0 || prcookie != NULL ) nc++;
if ( mt->mt_ps > 0 || prcookie != NULL || pr_c != NULL ) {
int src = 0, dst = 0;
BerElementBuffer berbuf;
BerElement *ber = (BerElement *)&berbuf;
struct berval val = BER_BVNULL;
ber_len_t len;
len = sizeof( LDAPControl * )*( nc + 1 ) + sizeof( LDAPControl );
if ( mt->mt_ps > 0 || prcookie != NULL ) {
struct berval nullcookie = BER_BVNULL;
ber_tag_t tag;
if ( prsize == 0 && mt->mt_ps > 0 ) prsize = mt->mt_ps;
if ( prcookie == NULL ) prcookie = &nullcookie;
ber_init2( ber, NULL, LBER_USE_DER );
tag = ber_printf( ber, "{iO}", prsize, prcookie );
if ( tag == LBER_ERROR ) {
/* error */
(void) ber_free_buf( ber );
goto done_pr;
}
tag = ber_flatten2( ber, &val, 0 );
if ( tag == LBER_ERROR ) {
/* error */
(void) ber_free_buf( ber );
goto done_pr;
}
len += val.bv_len + 1;
}
op->o_ctrls = op->o_tmpalloc( len, op->o_tmpmemctx );
if ( save_ctrls ) {
for ( ; save_ctrls[ src ] != NULL; src++ ) {
if ( save_ctrls[ src ] != pr_c ) {
op->o_ctrls[ dst ] = save_ctrls[ src ];
dst++;
}
}
}
if ( mt->mt_ps > 0 || prcookie != NULL ) {
op->o_ctrls[ dst ] = (LDAPControl *)&op->o_ctrls[ nc + 1 ];
op->o_ctrls[ dst ]->ldctl_oid = LDAP_CONTROL_PAGEDRESULTS;
op->o_ctrls[ dst ]->ldctl_iscritical = 1;
op->o_ctrls[ dst ]->ldctl_value.bv_val = (char *)&op->o_ctrls[ dst ][ 1 ];
AC_MEMCPY( op->o_ctrls[ dst ]->ldctl_value.bv_val, val.bv_val, val.bv_len + 1 );
op->o_ctrls[ dst ]->ldctl_value.bv_len = val.bv_len;
dst++;
(void)ber_free_buf( ber );
}
op->o_ctrls[ dst ] = NULL;
}
done_pr:;
}
#endif /* SLAPD_META_CLIENT_PR */
retry:;
ctrls = op->o_ctrls;
if ( meta_back_controls_add( op, rs, *mcp, candidate, &ctrls )
@ -660,6 +744,12 @@ retry:;
done:;
(void)mi->mi_ldap_extra->controls_free( op, rs, &ctrls );
#ifdef SLAPD_META_CLIENT_PR
if ( save_ctrls != op->o_ctrls ) {
op->o_tmpfree( op->o_ctrls, op->o_tmpmemctx );
op->o_ctrls = save_ctrls;
}
#endif /* SLAPD_META_CLIENT_PR */
if ( mapped_attrs ) {
ber_memfree_x( mapped_attrs, op->o_tmpmemctx );
@ -742,6 +832,7 @@ getconn:;
candidates[ i ].sr_text = NULL;
candidates[ i ].sr_ref = NULL;
candidates[ i ].sr_ctrls = NULL;
candidates[ i ].sr_nentries = 0;
/* get largest timeout among candidates */
if ( mi->mi_targets[ i ]->mt_timeout[ SLAP_OP_SEARCH ]
@ -758,7 +849,7 @@ getconn:;
continue;
}
switch ( meta_back_search_start( op, rs, &dc, &mc, i, candidates ) )
switch ( meta_back_search_start( op, rs, &dc, &mc, i, candidates, NULL, 0 ) )
{
case META_SEARCH_NOT_CANDIDATE:
candidates[ i ].sr_msgid = META_MSGID_IGNORE;
@ -975,7 +1066,7 @@ getconn:;
case META_SEARCH_CANDIDATE:
candidates[ i ].sr_msgid = META_MSGID_IGNORE;
switch ( meta_back_search_start( op, rs, &dc, &mc, i, candidates ) )
switch ( meta_back_search_start( op, rs, &dc, &mc, i, candidates, NULL, 0 ) )
{
case META_SEARCH_CANDIDATE:
assert( candidates[ i ].sr_msgid >= 0 );
@ -1062,7 +1153,7 @@ really_bad:;
if ( meta_back_retry( op, rs, &mc, i, LDAP_BACK_DONTSEND ) ) {
candidates[ i ].sr_msgid = META_MSGID_IGNORE;
switch ( meta_back_search_start( op, rs, &dc, &mc, i, candidates ) )
switch ( meta_back_search_start( op, rs, &dc, &mc, i, candidates, NULL, 0 ) )
{
/* means that failed but onerr == continue */
case META_SEARCH_NOT_CANDIDATE:
@ -1142,6 +1233,9 @@ really_bad:;
candidates[ i ].sr_type = REP_RESULT;
}
/* count entries returned by target */
candidates[ i ].sr_nentries++;
is_ok++;
e = ldap_first_entry( msc->msc_ld, msg );
@ -1285,6 +1379,7 @@ really_bad:;
} else if ( rc == LDAP_RES_SEARCH_RESULT ) {
char buf[ SLAP_TEXT_BUFLEN ];
char **references = NULL;
LDAPControl **ctrls = NULL;
if ( candidates[ i ].sr_type == REP_INTERMEDIATE ) {
/* don't retry any more... */
@ -1308,7 +1403,7 @@ really_bad:;
(char **)&candidates[ i ].sr_matched,
(char **)&candidates[ i ].sr_text,
&references,
NULL /* &candidates[ i ].sr_ctrls (unused) */ ,
&ctrls /* &candidates[ i ].sr_ctrls (unused) */ ,
0 );
if ( rs->sr_err != LDAP_SUCCESS ) {
candidates[ i ].sr_err = rs->sr_err;
@ -1403,7 +1498,7 @@ really_bad:;
/* cleanup */
ber_memvfree( (void **)references );
sres = slap_map_api2result( rs );
if ( LogTest( LDAP_DEBUG_TRACE | LDAP_DEBUG_ANY ) ) {
@ -1436,6 +1531,93 @@ really_bad:;
break;
case LDAP_SUCCESS:
if ( ctrls != NULL && ctrls[0] != NULL ) {
#ifdef SLAPD_META_CLIENT_PR
LDAPControl *pr_c, **next_c;
pr_c = ldap_control_find( LDAP_CONTROL_PAGEDRESULTS, ctrls, &next_c );
if ( pr_c != NULL ) {
BerElementBuffer berbuf;
BerElement *ber = (BerElement *)&berbuf;
ber_tag_t tag;
ber_int_t prsize;
struct berval prcookie;
/* unsolicited, do not accept */
if ( mi->mi_targets[i]->mt_ps == 0 ) {
rs->sr_err = LDAP_OTHER;
goto err_pr;
}
ber_init2( ber, &pr_c->ldctl_value, LBER_USE_DER );
tag = ber_scanf( ber, "{im}", &prsize, &prcookie );
if ( tag == LBER_ERROR ) {
rs->sr_err = LDAP_OTHER;
goto err_pr;
}
/* more pages? new search request */
if ( !BER_BVISNULL( &prcookie ) && !BER_BVISEMPTY( &prcookie ) ) {
if ( mi->mi_targets[i]->mt_ps > 0 ) {
/* ignore size if specified */
prsize = 0;
} else if ( prsize == 0 ) {
/* guess the page size from the entries returned so far */
prsize = candidates[ i ].sr_nentries;
}
candidates[ i ].sr_nentries = 0;
candidates[ i ].sr_msgid = META_MSGID_IGNORE;
candidates[ i ].sr_type = REP_INTERMEDIATE;
assert( candidates[ i ].sr_matched == NULL );
assert( candidates[ i ].sr_text == NULL );
assert( candidates[ i ].sr_ref == NULL );
switch ( meta_back_search_start( op, rs, &dc, &mc, i, candidates, &prcookie, prsize ) )
{
case META_SEARCH_CANDIDATE:
assert( candidates[ i ].sr_msgid >= 0 );
ldap_controls_free( ctrls );
goto free_message;
case META_SEARCH_ERR:
err_pr:;
candidates[ i ].sr_err = rs->sr_err;
if ( META_BACK_ONERR_STOP( mi ) ) {
savepriv = op->o_private;
op->o_private = (void *)i;
send_ldap_result( op, rs );
op->o_private = savepriv;
ldap_controls_free( ctrls );
goto finish;
}
/* fallthru */
case META_SEARCH_NOT_CANDIDATE:
/* means that meta_back_search_start()
* failed but onerr == continue */
candidates[ i ].sr_msgid = META_MSGID_IGNORE;
assert( ncandidates > 0 );
--ncandidates;
break;
default:
/* impossible */
assert( 0 );
break;
}
break;
}
}
#endif /* SLAPD_META_CLIENT_PR */
ldap_controls_free( ctrls );
}
/* fallthru */
case LDAP_REFERRAL:
is_ok++;
break;
@ -1499,7 +1681,7 @@ really_bad:;
retcode = meta_search_dobind_result( op, rs, &mc, i, candidates, msg );
if ( retcode == META_SEARCH_CANDIDATE ) {
candidates[ i ].sr_msgid = META_MSGID_IGNORE;
retcode = meta_back_search_start( op, rs, &dc, &mc, i, candidates );
retcode = meta_back_search_start( op, rs, &dc, &mc, i, candidates, NULL, 0 );
}
switch ( retcode ) {