From: Pierangelo Masarati Date: Mon, 3 Jan 2011 17:52:55 +0000 (+0000) Subject: use Paged Results when talking to targets (in response to ITS#6664) X-Git-Tag: MIGRATION_CVS2GIT~279 X-Git-Url: https://git.sur5r.net/?a=commitdiff_plain;h=342980d116247dde1a76968a5573b8fafe26ae0f;p=openldap use Paged Results when talking to targets (in response to ITS#6664) --- diff --git a/doc/man/man5/slapd-meta.5 b/doc/man/man5/slapd-meta.5 index 92a694ea72..1af67466f3 100644 --- a/doc/man/man5/slapd-meta.5 +++ b/doc/man/man5/slapd-meta.5 @@ -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|} +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 [] The "default\-target" directive can also be used during target specification. diff --git a/servers/slapd/back-meta/back-meta.h b/servers/slapd/back-meta/back-meta.h index e285ef4bf3..9a6654c759 100644 --- a/servers/slapd/back-meta/back-meta.h +++ b/servers/slapd/back-meta/back-meta.h @@ -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; diff --git a/servers/slapd/back-meta/config.c b/servers/slapd/back-meta/config.c index e6de08a8eb..ae87023b3d 100644 --- a/servers/slapd/back-meta/config.c +++ b/servers/slapd/back-meta/config.c @@ -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:" 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|}\" 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|}\" invalid arg \"%s\".\n", + fname, lineno, argv[ 1 ] ); + return( 1 ); + } +#endif /* SLAPD_META_CLIENT_PR */ + /* anything else */ } else { return SLAP_CONF_UNKNOWN; diff --git a/servers/slapd/back-meta/search.c b/servers/slapd/back-meta/search.c index 27127cf166..2c958c7190 100644 --- a/servers/slapd/back-meta/search.c +++ b/servers/slapd/back-meta/search.c @@ -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 ) {