Commit 4cab386d authored by Pierangelo Masarati's avatar Pierangelo Masarati
Browse files

backport write operation timeouts from back-meta to back-ldap; minor cleanup & silence warnings

parent fc2912ba
......@@ -319,6 +319,21 @@ If set to
.BR discover ,
support is detected by reading the remote server's root DSE.
.TP
.B timeout [{add|delete|modify|modrdn}=]<val> [...]
This directive allows to set per-operation timeouts.
If no operation is specified, it affects all.
Currently, only write operations are addressed, because searches
can already be limited by means of the
.B limits
directive (see
.BR slapd.conf (5)
for details), and other operations are not supposed to incur into the
need for timeouts.
Note: if the timelimit is exceeded, the operation is abandoned;
the protocol does not provide any means to rollback the operation,
so the client will not know if the operation eventually succeeded 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
......
......@@ -36,6 +36,8 @@ ldap_back_add(
Operation *op,
SlapReply *rs )
{
struct ldapinfo *li = (struct ldapinfo *)op->o_bd->be_private;
struct ldapconn *lc;
int i = 0,
j = 0;
......@@ -100,7 +102,8 @@ ldap_back_add(
retry:
rs->sr_err = ldap_add_ext( lc->lc_ld, op->o_req_dn.bv_val, attrs,
ctrls, NULL, &msgid );
rs->sr_err = ldap_back_op_result( lc, op, rs, msgid, LDAP_BACK_SENDRESULT );
rs->sr_err = ldap_back_op_result( lc, op, rs, msgid,
li->timeout[ LDAP_BACK_OP_ADD ], LDAP_BACK_SENDRESULT );
if ( rs->sr_err == LDAP_UNAVAILABLE && do_retry ) {
do_retry = 0;
if ( ldap_back_retry( lc, op, rs, LDAP_BACK_SENDERR ) ) {
......
......@@ -93,6 +93,17 @@ enum {
LDAP_BACK_IDASSERT_OTHERID
};
/*
* operation enumeration for timeouts
*/
enum {
LDAP_BACK_OP_ADD = 0,
LDAP_BACK_OP_DELETE,
LDAP_BACK_OP_MODIFY,
LDAP_BACK_OP_MODRDN,
LDAP_BACK_OP_LAST
};
struct ldapinfo {
char *url;
LDAPURLDesc *lud;
......@@ -166,6 +177,8 @@ struct ldapinfo {
/* FIXME: automatic rwm instantiation removed */
int rwm_started;
#endif
time_t timeout[ LDAP_BACK_OP_LAST ];
};
typedef enum ldap_back_send_t {
......
......@@ -71,7 +71,7 @@ ldap_back_bind( Operation *op, SlapReply *rs )
rs->sr_err = ldap_sasl_bind( lc->lc_ld, op->o_req_dn.bv_val,
LDAP_SASL_SIMPLE,
&op->orb_cred, op->o_ctrls, NULL, &msgid );
rc = ldap_back_op_result( lc, op, rs, msgid, LDAP_BACK_SENDERR );
rc = ldap_back_op_result( lc, op, rs, msgid, 0, LDAP_BACK_SENDERR );
if ( rc == LDAP_SUCCESS ) {
/* If defined, proxyAuthz will be used also when
......@@ -737,7 +737,7 @@ retry:;
return 0;
}
rc = ldap_back_op_result( lc, op, rs, msgid, sendok );
rc = ldap_back_op_result( lc, op, rs, msgid, 0, sendok );
if ( rc == LDAP_SUCCESS ) {
LDAP_BACK_CONN_ISBOUND_SET( lc );
......@@ -800,6 +800,7 @@ ldap_back_op_result(
Operation *op,
SlapReply *rs,
ber_int_t msgid,
time_t timeout,
ldap_back_send_t sendok )
{
char *match = NULL;
......@@ -818,12 +819,26 @@ ldap_back_op_result(
int rc;
struct timeval tv;
LDAP_BACK_TV_SET( &tv );
if ( timeout ) {
tv.tv_sec = timeout;
tv.tv_usec = 0;
} else {
LDAP_BACK_TV_SET( &tv );
}
retry:;
/* if result parsing fails, note the failure reason */
switch ( ldap_result( lc->lc_ld, msgid, 1, &tv, &res ) ) {
rc = ldap_result( lc->lc_ld, msgid, 1, &tv, &res );
switch ( rc ) {
case 0:
if ( timeout ) {
(void)ldap_abandon_ext( lc->lc_ld, msgid, NULL, NULL );
rs->sr_err = LDAP_ADMINLIMIT_EXCEEDED;
rs->sr_text = "Operation timed out";
break;
}
LDAP_BACK_TV_SET( &tv );
ldap_pvt_thread_yield();
goto retry;
......@@ -893,6 +908,12 @@ ldap_back_retry( struct ldapconn *lc, Operation *op, SlapReply *rs, ldap_back_se
ldap_pvt_thread_mutex_lock( &li->conn_mutex );
if ( lc->lc_refcnt == 1 ) {
Debug( LDAP_DEBUG_ANY,
"%s ldap_back_retry: retrying URI=\"%s\" DN=\"%s\"\n",
op->o_log_prefix, li->url,
BER_BVISNULL( &lc->lc_bound_ndn ) ?
"" : lc->lc_bound_ndn.bv_val );
ldap_unbind_ext( lc->lc_ld, NULL, NULL );
lc->lc_ld = NULL;
LDAP_BACK_CONN_ISBOUND_CLEAR( lc );
......@@ -1089,7 +1110,7 @@ ldap_back_proxy_authz_bind( struct ldapconn *lc, Operation *op, SlapReply *rs )
goto done;
}
rc = ldap_back_op_result( lc, op, rs, msgid, LDAP_BACK_SENDERR );
rc = ldap_back_op_result( lc, op, rs, msgid, 0, LDAP_BACK_SENDERR );
if ( rc == LDAP_SUCCESS ) {
LDAP_BACK_CONN_ISBOUND_SET( lc );
}
......
......@@ -60,7 +60,7 @@ retry:
op->orc_ava->aa_desc->ad_cname.bv_val,
&op->orc_ava->aa_value,
ctrls, NULL, &msgid );
rc = ldap_back_op_result( lc, op, rs, msgid, LDAP_BACK_SENDRESULT );
rc = ldap_back_op_result( lc, op, rs, msgid, 0, LDAP_BACK_SENDRESULT );
if ( rc == LDAP_UNAVAILABLE && do_retry ) {
do_retry = 0;
if ( ldap_back_retry( lc, op, rs, LDAP_BACK_SENDERR ) ) {
......
......@@ -59,6 +59,7 @@ enum {
LDAP_BACK_CFG_CHASE,
LDAP_BACK_CFG_T_F,
LDAP_BACK_CFG_WHOAMI,
LDAP_BACK_CFG_TIMEOUT,
LDAP_BACK_CFG_REWRITE
};
......@@ -203,6 +204,14 @@ static ConfigTable ldapcfg[] = {
"SYNTAX OMsDirectoryString "
"SINGLE-VALUE )",
NULL, NULL },
{ "timeout", "timeout", 0, 2, 0,
ARG_MAGIC|LDAP_BACK_CFG_TIMEOUT,
ldap_back_cf_gen, "( OLcfgDbAt:3.14 "
"NAME 'olcDbTimeout' "
"DESC 'Per-operation timeouts' "
"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 },
......@@ -235,6 +244,7 @@ static ConfigOCs ldapocs[] = {
"$ olcDbChaseReferrals "
"$ olcDbTFSupport "
"$ olcDbProxyWhoAmI "
"$ olcDbTimeout "
") )",
Cft_Database, ldapcfg},
{ NULL, 0, NULL }
......@@ -272,6 +282,14 @@ static slap_verbmasks t_f_mode[] = {
{ BER_BVNULL, 0 }
};
static slap_cf_aux_table timeout_table[] = {
{ BER_BVC("add="), 0 * sizeof( time_t ), 'u', 0, NULL },
{ BER_BVC("delete="), 1 * sizeof( time_t ), 'u', 0, NULL },
{ BER_BVC("modify="), 2 * sizeof( time_t ), 'u', 0, NULL },
{ BER_BVC("modrdn="), 3 * sizeof( time_t ), 'u', 0, NULL },
{ BER_BVNULL, 0, 0, 0, NULL }
};
static int
ldap_back_cf_gen( ConfigArgs *c )
{
......@@ -512,6 +530,25 @@ ldap_back_cf_gen( ConfigArgs *c )
}
break;
case LDAP_BACK_CFG_TIMEOUT:
BER_BVZERO( &bv );
slap_cf_aux_table_unparse( li->timeout, &bv, timeout_table );
if ( !BER_BVISNULL( &bv ) ) {
for ( i = 0; isspace( bv.bv_val[ i ] ); i++ )
/* count spaces */ ;
if ( i ) {
bv.bv_len -= i;
AC_MEMCPY( bv.bv_val, &bv.bv_val[ i ],
bv.bv_len + 1 );
}
ber_bvarray_add( &c->rvalue_vals, &bv );
}
break;
default:
/* FIXME: we need to handle all... */
assert( 0 );
......@@ -582,6 +619,12 @@ ldap_back_cf_gen( ConfigArgs *c )
rc = 1;
break;
case LDAP_BACK_CFG_TIMEOUT:
for ( i = 0; i < LDAP_BACK_OP_LAST; i++ ) {
li->timeout[ i ] = 0;
}
break;
default:
/* FIXME: we need to handle all... */
assert( 0 );
......@@ -1040,8 +1083,7 @@ ldap_back_cf_gen( ConfigArgs *c )
} else {
li->flags &= ~LDAP_BACK_F_SAVECRED;
}
break;
}
} break;
case LDAP_BACK_CFG_CHASE: {
int dochase = 0;
......@@ -1066,8 +1108,7 @@ ldap_back_cf_gen( ConfigArgs *c )
} else {
li->flags &= ~LDAP_BACK_F_CHASE_REFERRALS;
}
break;
}
} break;
case LDAP_BACK_CFG_T_F:
i = verb_to_mask( c->argv[1], t_f_mode );
......@@ -1104,8 +1145,36 @@ ldap_back_cf_gen( ConfigArgs *c )
} else {
li->flags &= ~LDAP_BACK_F_PROXY_WHOAMI;
}
} break;
case LDAP_BACK_CFG_TIMEOUT:
if ( c->argc < 2 ) {
return 1;
}
for ( i = 1; i < c->argc; i++ ) {
if ( isdigit( c->argv[ i ][ 0 ] ) ) {
char *next;
int j;
unsigned u;
u = strtoul( c->argv[ i ], &next, 0 );
if ( next == c->argv[ i ] || next[ 0 ] != '\0' ) {
return 1;
}
for ( j = 0; j < LDAP_BACK_OP_LAST; j++ ) {
li->timeout[ j ] = u;
}
continue;
}
if ( slap_cf_aux_table_parse( c->argv[ i ], li->timeout, timeout_table, "slapd-ldap timeout" ) ) {
return 1;
}
}
break;
}
case LDAP_BACK_CFG_REWRITE:
fprintf( stderr, "%s: line %d: "
......
......@@ -36,6 +36,8 @@ ldap_back_delete(
Operation *op,
SlapReply *rs )
{
struct ldapinfo *li = (struct ldapinfo *)op->o_bd->be_private;
struct ldapconn *lc;
ber_int_t msgid;
LDAPControl **ctrls = NULL;
......@@ -59,7 +61,8 @@ ldap_back_delete(
retry:
rs->sr_err = ldap_delete_ext( lc->lc_ld, op->o_req_ndn.bv_val,
ctrls, NULL, &msgid );
rc = ldap_back_op_result( lc, op, rs, msgid, LDAP_BACK_SENDRESULT );
rc = ldap_back_op_result( lc, op, rs, msgid,
li->timeout[ LDAP_BACK_OP_DELETE], LDAP_BACK_SENDRESULT );
if ( rs->sr_err == LDAP_SERVER_DOWN && do_retry ) {
do_retry = 0;
if ( ldap_back_retry( lc, op, rs, LDAP_BACK_SENDERR ) ) {
......
......@@ -36,6 +36,8 @@ ldap_back_modify(
Operation *op,
SlapReply *rs )
{
struct ldapinfo *li = (struct ldapinfo *)op->o_bd->be_private;
struct ldapconn *lc;
LDAPMod **modv = NULL,
*mods = NULL;
......@@ -107,7 +109,8 @@ ldap_back_modify(
retry:
rs->sr_err = ldap_modify_ext( lc->lc_ld, op->o_req_ndn.bv_val, modv,
ctrls, NULL, &msgid );
rc = ldap_back_op_result( lc, op, rs, msgid, LDAP_BACK_SENDRESULT );
rc = ldap_back_op_result( lc, op, rs, msgid,
li->timeout[ LDAP_BACK_OP_MODIFY], LDAP_BACK_SENDRESULT );
if ( rs->sr_err == LDAP_UNAVAILABLE && do_retry ) {
do_retry = 0;
if ( ldap_back_retry( lc, op, rs, LDAP_BACK_SENDERR ) ) {
......
......@@ -36,6 +36,8 @@ ldap_back_modrdn(
Operation *op,
SlapReply *rs )
{
struct ldapinfo *li = (struct ldapinfo *)op->o_bd->be_private;
struct ldapconn *lc;
ber_int_t msgid;
LDAPControl **ctrls = NULL;
......@@ -67,7 +69,8 @@ retry:
rs->sr_err = ldap_rename( lc->lc_ld, op->o_req_ndn.bv_val,
op->orr_newrdn.bv_val, newSup,
op->orr_deleteoldrdn, ctrls, NULL, &msgid );
rc = ldap_back_op_result( lc, op, rs, msgid, LDAP_BACK_SENDRESULT );
rc = ldap_back_op_result( lc, op, rs, msgid,
li->timeout[ LDAP_BACK_OP_MODRDN ], LDAP_BACK_SENDRESULT );
if ( rs->sr_err == LDAP_SERVER_DOWN && do_retry ) {
do_retry = 0;
if ( ldap_back_retry( lc, op, rs, LDAP_BACK_SENDERR ) ) {
......
......@@ -55,7 +55,7 @@ int ldap_back_dobind(struct ldapconn *lc, Operation *op, SlapReply *rs, ldap_bac
int ldap_back_retry(struct ldapconn *lc, Operation *op, SlapReply *rs, ldap_back_send_t sendok);
int ldap_back_map_result(SlapReply *rs);
int ldap_back_op_result(struct ldapconn *lc, Operation *op, SlapReply *rs,
ber_int_t msgid, ldap_back_send_t sendok);
ber_int_t msgid, time_t timeout, ldap_back_send_t sendok);
int back_ldap_LTX_init_module(int argc, char *argv[]);
int ldap_back_init_cf( BackendInfo *bi );
......
......@@ -143,7 +143,7 @@ ldap_back_search(
{
struct ldapconn *lc;
struct timeval tv;
time_t stoptime;
time_t stoptime = (time_t)-1;
LDAPMessage *res,
*e;
int rc = 0,
......@@ -223,7 +223,7 @@ fail:;
goto retry;
}
}
rc = ldap_back_op_result( lc, op, rs, msgid, LDAP_BACK_DONTSEND );
rc = ldap_back_op_result( lc, op, rs, msgid, 0, LDAP_BACK_DONTSEND );
ldap_back_freeconn( op, lc );
lc = NULL;
goto finish;
......@@ -346,7 +346,7 @@ fail:;
/* cleanup */
if ( references ) {
ldap_value_free( references );
ber_memvfree( (void **)references );
ch_free( rs->sr_ref );
rs->sr_ref = NULL;
}
......@@ -404,7 +404,7 @@ fail:;
/* cleanup */
if ( references ) {
ldap_value_free( references );
ber_memvfree( (void **)references );
}
rc = 0;
......
......@@ -178,8 +178,8 @@ retry:;
LDAPMessage *res = NULL;
int rc;
if ( mi->mi_targets[ candidate ].mt_timeout[ META_OP_ADD ] != 0 ) {
tv.tv_sec = mi->mi_targets[ candidate ].mt_timeout[ META_OP_ADD ];
if ( mi->mi_targets[ candidate ].mt_timeout[ LDAP_BACK_OP_ADD ] != 0 ) {
tv.tv_sec = mi->mi_targets[ candidate ].mt_timeout[ LDAP_BACK_OP_ADD ];
tv.tv_usec = 0;
tvp = &tv;
}
......
......@@ -205,14 +205,6 @@ typedef struct metaconn_t {
* in one block with the metaconn_t structure */
} metaconn_t;
enum {
META_OP_ADD = 0,
META_OP_DELETE,
META_OP_MODIFY,
META_OP_MODRDN,
META_OP_LAST
};
typedef struct metatarget_t {
char *mt_uri;
int mt_scope;
......@@ -236,7 +228,7 @@ typedef struct metatarget_t {
unsigned mt_flags;
int mt_version;
time_t mt_timeout[ META_OP_LAST ];
time_t mt_timeout[ LDAP_BACK_OP_LAST ];
} metatarget_t;
typedef struct metadncache_t {
......@@ -279,7 +271,7 @@ typedef struct metainfo_t {
#define META_BACK_DEFER_ROOTDN_BIND(mi) ( (mi)->flags & META_BACK_F_DEFER_ROOTDN_BIND )
int mi_version;
time_t mi_timeout[ META_OP_LAST ];
time_t mi_timeout[ LDAP_BACK_OP_LAST ];
} metainfo_t;
typedef enum meta_op_type {
......
......@@ -163,7 +163,7 @@ meta_back_db_config(
mi->mi_targets[ i ].mt_flags = mi->flags;
mi->mi_targets[ i ].mt_version = mi->mi_version;
for ( c = 0; c < META_OP_LAST; c++ ) {
for ( c = 0; c < LDAP_BACK_OP_LAST; c++ ) {
mi->mi_targets[ i ].mt_timeout[ c ] = mi->mi_timeout[ c ];
}
......@@ -619,13 +619,13 @@ meta_back_db_config(
size_t len = sep - argv[ c ];
if ( strncasecmp( argv[ c ], "add", len ) == 0 ) {
t = &tv[ META_OP_ADD ];
t = &tv[ LDAP_BACK_OP_ADD ];
} else if ( strncasecmp( argv[ c ], "delete", len ) == 0 ) {
t = &tv[ META_OP_DELETE ];
t = &tv[ LDAP_BACK_OP_DELETE ];
} else if ( strncasecmp( argv[ c ], "modify", len ) == 0 ) {
t = &tv[ META_OP_MODIFY ];
t = &tv[ LDAP_BACK_OP_MODIFY ];
} else if ( strncasecmp( argv[ c ], "modrdn", len ) == 0 ) {
t = &tv[ META_OP_MODRDN ];
t = &tv[ LDAP_BACK_OP_MODRDN ];
} else {
fprintf( stderr,
"%s: line %d: unknown operation \"%s\" for timeout #%d.\n",
......@@ -652,7 +652,7 @@ meta_back_db_config(
} else {
int i;
for ( i = 0; i < META_OP_LAST; i++ ) {
for ( i = 0; i < LDAP_BACK_OP_LAST; i++ ) {
tv[ i ] = val;
}
}
......
......@@ -448,9 +448,11 @@ retry_lock:;
goto retry_lock;
}
Debug( LDAP_DEBUG_ANY, "%s meta_back_retry: retrying uri=\"%s\" DN=\"%s\"\n",
Debug( LDAP_DEBUG_ANY,
"%s meta_back_retry: retrying URI=\"%s\" DN=\"%s\"\n",
op->o_log_prefix, mt->mt_uri,
BER_BVISNULL( &msc->msc_bound_ndn ) ? "" : msc->msc_bound_ndn.bv_val );
BER_BVISNULL( &msc->msc_bound_ndn ) ?
"" : msc->msc_bound_ndn.bv_val );
meta_clear_one_candidate( msc );
LDAP_BACK_CONN_ISBOUND_CLEAR( msc );
......
......@@ -76,8 +76,8 @@ retry:;
LDAPMessage *res = NULL;
int rc;
if ( mi->mi_targets[ candidate ].mt_timeout[ META_OP_DELETE ] != 0 ) {
tv.tv_sec = mi->mi_targets[ candidate ].mt_timeout[ META_OP_DELETE ];
if ( mi->mi_targets[ candidate ].mt_timeout[ LDAP_BACK_OP_DELETE ] != 0 ) {
tv.tv_sec = mi->mi_targets[ candidate ].mt_timeout[ LDAP_BACK_OP_DELETE ];
tv.tv_usec = 0;
tvp = &tv;
}
......
......@@ -186,8 +186,8 @@ retry:;
struct timeval tv, *tvp = NULL;
LDAPMessage *res = NULL;
if ( mi->mi_targets[ candidate ].mt_timeout[ META_OP_MODIFY ] != 0 ) {
tv.tv_sec = mi->mi_targets[ candidate ].mt_timeout[ META_OP_MODIFY ];
if ( mi->mi_targets[ candidate ].mt_timeout[ LDAP_BACK_OP_MODIFY ] != 0 ) {
tv.tv_sec = mi->mi_targets[ candidate ].mt_timeout[ LDAP_BACK_OP_MODIFY ];
tv.tv_usec = 0;
tvp = &tv;
}
......
......@@ -117,8 +117,8 @@ retry:;
LDAPMessage *res = NULL;
int rc;
if ( mi->mi_targets[ candidate ].mt_timeout[ META_OP_MODRDN ] != 0 ) {
tv.tv_sec = mi->mi_targets[ candidate ].mt_timeout[ META_OP_MODRDN ];
if ( mi->mi_targets[ candidate ].mt_timeout[ LDAP_BACK_OP_MODRDN ] != 0 ) {
tv.tv_sec = mi->mi_targets[ candidate ].mt_timeout[ LDAP_BACK_OP_MODRDN ];
tv.tv_usec = 0;
tvp = &tv;
}
......
......@@ -245,7 +245,7 @@ meta_back_search( Operation *op, SlapReply *rs )
metainfo_t *mi = ( metainfo_t * )op->o_bd->be_private;
metaconn_t *mc;
struct timeval tv = { 0, 0 };
time_t stoptime;
time_t stoptime = (time_t)-1;
LDAPMessage *res = NULL, *e;
int rc = 0, sres = LDAP_SUCCESS;
char *matched = NULL;
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment