struct ldb_module *module;
void *up_context;
int (*up_callback)(struct ldb_context *, void *, struct ldb_async_result *);
- int timeout;
const char * const *attrs;
BOOL remove_guid;
ac->module = module;
ac->up_context = req->async.context;
ac->up_callback = req->async.callback;
- ac->timeout = req->async.timeout;
ac->attrs = req->op.search.attrs;
ac->remove_guid = False;
ac->remove_sid = False;
down_req->async.context = ac;
down_req->async.callback = extended_async_callback;
- down_req->async.timeout = req->async.timeout;
+ ldb_set_timeout_from_prev_req(module->ldb, req, down_req);
/* perform the search */
ret = ldb_next_request(module, down_req);
struct ldb_module *module;
void *up_context;
int (*up_callback)(struct ldb_context *, void *, struct ldb_async_result *);
- int timeout;
enum user_is user_type;
};
ac->module = module;
ac->up_context = req->async.context;
ac->up_callback = req->async.callback;
- ac->timeout = req->async.timeout;
ac->user_type = what_is_user(module);
down_req = talloc_zero(req, struct ldb_request);
down_req->async.context = ac;
down_req->async.callback = kludge_acl_async_callback;
- down_req->async.timeout = req->async.timeout;
+ ldb_set_timeout_from_prev_req(module->ldb, req, down_req);
/* perform the search */
ret = ldb_next_request(module, down_req);
}
/* ANY change type */
-static int kludge_acl_change(struct ldb_module *module, struct ldb_request *req){
+static int kludge_acl_change(struct ldb_module *module, struct ldb_request *req)
+{
enum user_is user_type = what_is_user(module);
switch (user_type) {
case SYSTEM:
return ret;
}
+ ldb_set_timeout_from_prev_req(module->ldb, req, down_req);
+
/* go on with the call chain */
ret = ldb_next_request(module, down_req);
ac->dom_req->async.context = ac;
ac->dom_req->async.callback = get_domain_data_callback;
ac->dom_req->async.timeout = ac->orig_req->async.timeout;
+ ldb_set_timeout_from_prev_req(ac->module->ldb, ac->orig_req, ac->dom_req);
return LDB_SUCCESS;
}
if (ac->down_req->op.add.message == NULL) {
return LDB_ERR_OPERATIONS_ERROR;
}
-
+
/* Some operations below require kerberos contexts */
if (smb_krb5_init_context(ac->down_req, &smb_krb5_context) != 0) {
return LDB_ERR_OPERATIONS_ERROR;
ac->step = PH_ADD_DO_ADD;
+ ldb_set_timeout_from_prev_req(ac->module->ldb, ac->orig_req, ac->down_req);
+
/* perform the operation */
return ldb_next_request(ac->module, ac->down_req);
}
ac->step = PH_MOD_DO_REQ;
+ ldb_set_timeout_from_prev_req(module->ldb, req, ac->down_req);
+
return ldb_next_request(module, ac->down_req);
}
ac->search_req->controls = NULL;
ac->search_req->async.context = ac;
ac->search_req->async.callback = get_self_callback;
- ac->search_req->async.timeout = ac->orig_req->async.timeout;
+ ldb_set_timeout_from_prev_req(ac->module->ldb, ac->orig_req, ac->search_req);
ac->step = PH_MOD_SEARCH_SELF;
ac->step = PH_MOD_DO_MOD;
+ ldb_set_timeout_from_prev_req(ac->module->ldb, ac->orig_req, ac->mod_req);
+
/* perform the search */
return ldb_next_request(ac->module, ac->mod_req);
}
struct ldb_module *module;
void *up_context;
int (*up_callback)(struct ldb_context *, void *, struct ldb_async_result *);
- int timeout;
const char * const * attrs;
};
ac->module = module;
ac->up_context = req->async.context;
ac->up_callback = req->async.callback;
- ac->timeout = req->async.timeout;
ac->attrs = req->op.search.attrs;
down_req = talloc_zero(req, struct ldb_request);
down_req->async.context = ac;
down_req->async.callback = rootdse_async_callback;
- down_req->async.timeout = req->async.timeout;
+ ldb_set_timeout_from_prev_req(module->ldb, req, down_req);
/* perform the search */
ret = ldb_next_request(module, down_req);
*down_req = *req;
down_req->op.add.message = talloc_steal(down_req, msg2);
-
+
+ ldb_set_timeout_from_prev_req(module->ldb, req, down_req);
+
/* go on with the call chain */
ret = ldb_next_request(module, down_req);
return LDB_ERR_OTHER;
}
+ /* TODO: get timeout from options if available there */
+ ldb->default_timeout = 300; /* set default to 5 minutes */
+
return LDB_SUCCESS;
}
return handle->module->ops->async_wait(handle, type);
}
-
-/*
- check for an error return from an op
- if an op fails, but has not setup an error string, then setup one now
-*/
-static int ldb_op_finish(struct ldb_context *ldb, int status)
+/* set the specified timeout or, if timeout is 0 set the default timeout */
+/* timeout == -1 means no timeout */
+int ldb_set_timeout(struct ldb_context *ldb, struct ldb_request *req, int timeout)
{
- if (status == LDB_SUCCESS) {
- return ldb_transaction_commit(ldb);
+ if (req == NULL) return LDB_ERR_OPERATIONS_ERROR;
+
+ if (timeout != 0) {
+ req->async.timeout = timeout;
+ } else {
+ req->async.timeout = ldb->default_timeout;
}
- if (ldb->err_string == NULL) {
- /* no error string was setup by the backend */
- ldb_set_errstring(ldb,
- talloc_asprintf(ldb, "%s (%d)",
- ldb_strerror(status), status));
+ req->async.starttime = time(NULL);
+
+ return LDB_SUCCESS;
+}
+
+/* calculates the new timeout based on the previous starttime and timeout */
+int ldb_set_timeout_from_prev_req(struct ldb_context *ldb, struct ldb_request *oldreq, struct ldb_request *newreq)
+{
+ time_t now;
+
+ if (newreq == NULL) return LDB_ERR_OPERATIONS_ERROR;
+
+ now = time(NULL);
+
+ if (oldreq == NULL)
+ return ldb_set_timeout(ldb, newreq, 0);
+
+ if ((now - oldreq->async.starttime) > oldreq->async.timeout) {
+ return LDB_ERR_TIME_LIMIT_EXCEEDED;
}
- ldb_transaction_cancel(ldb);
- return status;
+ newreq->async.starttime = oldreq->async.starttime;
+ newreq->async.timeout = oldreq->async.timeout - (now - oldreq->async.starttime);
+
+ return LDB_SUCCESS;
}
/*
req->controls = NULL;
req->async.context = res;
req->async.callback = ldb_search_callback;
- req->async.timeout = 600; /* 10 minutes */
+ ldb_set_timeout(ldb, req, 0); /* use default timeout */
ret = ldb_request(ldb, req);
}
if (close_transaction) {
- return ldb_op_finish(ldb, ret);
+ if (ret == LDB_SUCCESS) {
+ return ldb_transaction_commit(ldb);
+ }
+ ldb_transaction_cancel(ldb);
}
if (ldb->err_string == NULL) {
req->controls = NULL;
req->async.context = NULL;
req->async.callback = NULL;
- req->async.timeout = 600; /* 10 minutes */
+ ldb_set_timeout(ldb, req, 0); /* use default timeout */
/* do request and autostart a transaction */
ret = ldb_autotransaction_request(ldb, req);
req->controls = NULL;
req->async.context = NULL;
req->async.callback = NULL;
- req->async.timeout = 600; /* 10 minutes */
+ ldb_set_timeout(ldb, req, 0); /* use default timeout */
/* do request and autostart a transaction */
ret = ldb_autotransaction_request(ldb, req);
req->controls = NULL;
req->async.context = NULL;
req->async.callback = NULL;
- req->async.timeout = 600; /* 10 minutes */
+ ldb_set_timeout(ldb, req, 0); /* use default timeout */
/* do request and autostart a transaction */
ret = ldb_autotransaction_request(ldb, req);
req->controls = NULL;
req->async.context = NULL;
req->async.callback = NULL;
- req->async.timeout = 600; /* 10 minutes */
+ ldb_set_timeout(ldb, req, 0); /* use default timeout */
/* do request and autostart a transaction */
ret = ldb_autotransaction_request(ldb, req);
int (*callback)(struct ldb_context *, void *, struct ldb_async_result *);
int timeout;
+ time_t starttime;
struct ldb_async_handle *handle;
} async;
};
int ldb_async_wait(struct ldb_async_handle *handle, enum ldb_async_wait_type type);
+int ldb_set_timeout(struct ldb_context *ldb, struct ldb_request *req, int timeout);
+int ldb_set_timeout_from_prev_req(struct ldb_context *ldb, struct ldb_request *oldreq, struct ldb_request *newreq);
+
/**
Initialise ldbs' global information
int transaction_active;
+ int default_timeout;
+
/* a backend supplied highestCommittedUSN function */
uint64_t (*sequence_number)(struct ldb_context *);
};
DLIST_REMOVE(ac->req->conn->pending, ac->req);
}
- handle->status = LDB_ERR_OPERATIONS_ERROR;
+ handle->status = LDB_ERR_TIME_LIMIT_EXCEEDED;
return;
}
req->controls = NULL;
req->async.context = ildb;
req->async.callback = ildb_rootdse_callback;
- req->async.timeout = 60;
+ ldb_set_timeout(module->ldb, req, 60);
ret = ildb_search(module, req);
if (ret != LDB_SUCCESS) {
struct lldb_private {
LDAP *ldap;
- int timeout;
};
struct lldb_async_context {
struct ldb_module *module;
int msgid;
int timeout;
+ time_t starttime;
void *context;
int (*callback)(struct ldb_context *, void *, struct ldb_async_result *);
};
static struct ldb_async_handle *init_handle(struct lldb_private *lldb, struct ldb_module *module,
void *context,
int (*callback)(struct ldb_context *, void *, struct ldb_async_result *),
- int timeout)
+ int timeout, time_t starttime)
{
struct lldb_async_context *ac;
struct ldb_async_handle *h;
ac->context = context;
ac->callback = callback;
ac->timeout = timeout;
+ ac->starttime = starttime;
ac->msgid = 0;
return h;
ldb_debug(module->ldb, LDB_DEBUG_WARNING, "Controls are not yet supported by ldb_ldap backend!\n");
}
- req->async.handle = init_handle(lldb, module, req->async.context, req->async.callback, req->async.timeout);
+ req->async.handle = init_handle(lldb, module, req->async.context, req->async.callback, req->async.timeout, req->async.starttime);
if (req->async.handle == NULL) {
return LDB_ERR_OPERATIONS_ERROR;
}
return LDB_ERR_INVALID_DN_SYNTAX;
}
- req->async.handle = init_handle(lldb, module, req->async.context, req->async.callback, req->async.timeout);
+ req->async.handle = init_handle(lldb, module, req->async.context, req->async.callback, req->async.timeout, req->async.starttime);
if (req->async.handle == NULL) {
return LDB_ERR_OPERATIONS_ERROR;
}
return LDB_ERR_INVALID_DN_SYNTAX;
}
- req->async.handle = init_handle(lldb, module, req->async.context, req->async.callback, req->async.timeout);
+ req->async.handle = init_handle(lldb, module, req->async.context, req->async.callback, req->async.timeout, req->async.starttime);
if (req->async.handle == NULL) {
return LDB_ERR_OPERATIONS_ERROR;
}
return LDB_ERR_INVALID_DN_SYNTAX;
}
- req->async.handle = init_handle(lldb, module, req->async.context, req->async.callback, req->async.timeout);
+ req->async.handle = init_handle(lldb, module, req->async.context, req->async.callback, req->async.timeout, req->async.starttime);
if (req->async.handle == NULL) {
return LDB_ERR_OPERATIONS_ERROR;
}
return LDB_ERR_INVALID_DN_SYNTAX;
}
- req->async.handle = init_handle(lldb, module, req->async.context, req->async.callback, req->async.timeout);
+ req->async.handle = init_handle(lldb, module, req->async.context, req->async.callback, req->async.timeout, req->async.starttime);
if (req->async.handle == NULL) {
return LDB_ERR_OPERATIONS_ERROR;
}
switch(type) {
case LDB_WAIT_NONE:
+
+ if ((ac->timeout != -1) &&
+ ((ac->starttime + timeout) > time(NULL))) {
+ return LDB_ERR_TIME_LIMIT_EXCEEDED;
+ }
+
timeout.tv_sec = 0;
timeout.tv_usec = 0;
return lldb_parse_result(handle, result);
case LDB_WAIT_ALL:
- timeout.tv_sec = ac->timeout;
timeout.tv_usec = 0;
ret = LDB_ERR_OPERATIONS_ERROR;
while (handle->status == LDB_SUCCESS && handle->state != LDB_ASYNC_DONE) {
- lret = ldap_result(lldb->ldap, ac->msgid, 0, &timeout, &result);
+ if (ac->timeout == -1) {
+ lret = ldap_result(lldb->ldap, ac->msgid, 0, NULL, &result);
+ } else {
+ timeout.tv_sec = ac->timeout - (time(NULL) - ac->starttime);
+ if (timeout.tv_sec <= 0)
+ return LDB_ERR_TIME_LIMIT_EXCEEDED;
+ lret = ldap_result(lldb->ldap, ac->msgid, 0, &timeout, &result);
+ }
if (lret == -1) {
return LDB_ERR_OPERATIONS_ERROR;
}
}
lldb->ldap = NULL;
- lldb->timeout = 120; /* TODO: get timeout from options ? */
ret = ldap_initialize(&lldb->ldap, url);
if (ret != LDAP_SUCCESS) {
struct ldb_module *module;
void *up_context;
int (*up_callback)(struct ldb_context *, void *, struct ldb_async_result *);
- int timeout;
const char * const *req_attrs;
char *req_attribute;
static struct ldb_async_handle *init_handle(void *mem_ctx, struct ldb_module *module,
void *context,
- int (*callback)(struct ldb_context *, void *, struct ldb_async_result *),
- int timeout)
+ int (*callback)(struct ldb_context *, void *, struct ldb_async_result *))
{
struct asq_async_context *ac;
struct ldb_async_handle *h;
ac->module = module;
ac->up_context = context;
ac->up_callback = callback;
- ac->timeout = timeout;
return h;
}
return LDB_ERR_PROTOCOL_ERROR;
}
- h = init_handle(req, module, req->async.context, req->async.callback, req->async.timeout);
+ h = init_handle(req, module, req->async.context, req->async.callback);
if (!h) {
return LDB_ERR_OPERATIONS_ERROR;
}
ac->base_req->async.context = ac;
ac->base_req->async.callback = asq_base_callback;
- ac->base_req->async.timeout = req->async.timeout;
+ ldb_set_timeout_from_prev_req(module->ldb, req, ac->base_req);
ac->step = ASQ_SEARCH_BASE;
ac->reqs[i]->async.context = ac;
ac->reqs[i]->async.callback = asq_reqs_callback;
- ac->reqs[i]->async.timeout = ac->base_req->async.timeout;
+ ldb_set_timeout_from_prev_req(ac->module->ldb, ac->base_req, ac->reqs[i]);
}
ac->step = ASQ_SEARCH_MULTI;
static int asq_init(struct ldb_module *module)
{
- struct ldb_request request;
+ struct ldb_request *req;
int ret;
- request.operation = LDB_REQ_REGISTER;
- request.op.reg.oid = LDB_CONTROL_ASQ_OID;
- request.controls = NULL;
+ req = talloc_zero(module, struct ldb_request);
+ if (req == NULL) {
+ ldb_debug(module->ldb, LDB_DEBUG_ERROR, "asq: Out of memory!\n");
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ req->operation = LDB_REQ_REGISTER;
+ req->op.reg.oid = LDB_CONTROL_ASQ_OID;
- ret = ldb_request(module->ldb, &request);
+ ret = ldb_request(module->ldb, req);
if (ret != LDB_SUCCESS) {
ldb_debug(module->ldb, LDB_DEBUG_ERROR, "asq: Unable to register control with rootdse!\n");
return LDB_ERR_OTHER;
ac->down_req->async.context = NULL;
ac->down_req->async.callback = NULL;
+ ldb_set_timeout_from_prev_req(module->ldb, req, ac->down_req);
ac->step = OC_DO_REQ;
ac->down_req->async.context = NULL;
ac->down_req->async.callback = NULL;
+ ldb_set_timeout_from_prev_req(module->ldb, req, ac->down_req);
ac->step = OC_DO_REQ;
ac->search_req->controls = NULL;
ac->search_req->async.context = ac;
ac->search_req->async.callback = get_self_callback;
- ac->search_req->async.timeout = ac->orig_req->async.timeout;
+ ldb_set_timeout_from_prev_req(ac->module->ldb, ac->orig_req, ac->search_req);
ac->step = OC_SEARCH_SELF;
ac->mod_req->controls = NULL;
ac->mod_req->async.context = ac;
ac->mod_req->async.callback = NULL;
- ac->mod_req->async.timeout = ac->orig_req->async.timeout;
+ ldb_set_timeout_from_prev_req(ac->module->ldb, ac->orig_req, ac->mod_req);
/* use a new message structure */
ac->mod_req->op.mod.message = msg = ldb_msg_new(ac->mod_req);
struct ldb_module *module;
void *up_context;
int (*up_callback)(struct ldb_context *, void *, struct ldb_async_result *);
- int timeout;
const char * const *attrs;
};
ac->module = module;
ac->up_context = req->async.context;
ac->up_callback = req->async.callback;
- ac->timeout = req->async.timeout;
ac->attrs = req->op.search.attrs;
down_req = talloc_zero(req, struct ldb_request);
down_req->async.context = ac;
down_req->async.callback = operational_async_callback;
- down_req->async.timeout = req->async.timeout;
+ ldb_set_timeout_from_prev_req(module->ldb, req, down_req);
/* perform the search */
ret = ldb_next_request(module, down_req);
}
}
+ ldb_set_timeout_from_prev_req(module->ldb, req, down_req);
+
/* go on with the call chain */
ret = ldb_next_request(module, down_req);
return -1;
}
+ ldb_set_timeout_from_prev_req(module->ldb, req, down_req);
+
/* go on with the call chain */
ret = ldb_next_request(module, down_req);
struct ldb_module *module;
void *up_context;
int (*up_callback)(struct ldb_context *, void *, struct ldb_async_result *);
- int timeout;
int size;
static struct ldb_async_handle *init_handle(void *mem_ctx, struct ldb_module *module,
void *context,
- int (*callback)(struct ldb_context *, void *, struct ldb_async_result *),
- int timeout)
+ int (*callback)(struct ldb_context *, void *, struct ldb_async_result *))
{
struct paged_async_context *ac;
struct ldb_async_handle *h;
ac->module = module;
ac->up_context = context;
ac->up_callback = callback;
- ac->timeout = timeout;
return h;
}
return LDB_ERR_PROTOCOL_ERROR;
}
- h = init_handle(req, module, req->async.context, req->async.callback, req->async.timeout);
+ h = init_handle(req, module, req->async.context, req->async.callback);
if (!h) {
return LDB_ERR_OPERATIONS_ERROR;
}
ac->store->req->async.context = ac;
ac->store->req->async.callback = paged_search_async_callback;
- ac->store->req->async.timeout = req->async.timeout;
+ ldb_set_timeout_from_prev_req(module->ldb, req, ac->store->req);
ret = ldb_next_request(module, ac->store->req);
return LDB_ERR_OPERATIONS_ERROR;
}
- ac->mod_req->async.timeout = ac->orig_req->async.timeout;
+ ldb_set_timeout_from_prev_req(h->module->ldb, ac->orig_req, ac->mod_req);
ac->step = RENAME_MODIFY;
struct ldb_module *module;
void *up_context;
int (*up_callback)(struct ldb_context *, void *, struct ldb_async_result *);
- int timeout;
char *attributeName;
char *orderingRule;
static struct ldb_async_handle *init_handle(void *mem_ctx, struct ldb_module *module,
void *context,
- int (*callback)(struct ldb_context *, void *, struct ldb_async_result *),
- int timeout)
+ int (*callback)(struct ldb_context *, void *, struct ldb_async_result *))
{
struct sort_async_context *ac;
struct ldb_async_handle *h;
ac->module = module;
ac->up_context = context;
ac->up_callback = callback;
- ac->timeout = timeout;
return h;
}
}
static int sort_compare(struct ldb_message **msg1, struct ldb_message **msg2, void *opaque)
-{
- struct opaque *data = (struct opaque *)opaque;
- struct ldb_message_element *el1, *el2;
-
- if (data->result != 0) {
- /* an error occurred previously,
- * let's exit the sorting by returning always 0 */
- return 0;
- }
-
- el1 = ldb_msg_find_element(*msg1, data->attribute);
- el2 = ldb_msg_find_element(*msg2, data->attribute);
-
- if (!el1 || !el2) {
- /* the attribute was not found return and
- * set an error */
- data->result = 53;
- return 0;
- }
-
- if (data->reverse)
- return data->h->comparison_fn(data->ldb, data, &el2->values[0], &el1->values[0]);
-
- return data->h->comparison_fn(data->ldb, data, &el1->values[0], &el2->values[0]);
-}
-
-static int sort_compare_async(struct ldb_message **msg1, struct ldb_message **msg2, void *opaque)
{
struct sort_async_context *ac = talloc_get_type(opaque, struct sort_async_context);
struct ldb_message_element *el1, *el2;
return LDB_ERR_OPERATIONS_ERROR;
}
- h = init_handle(req, module, req->async.context, req->async.callback, req->async.timeout);
+ h = init_handle(req, module, req->async.context, req->async.callback);
if (!h) {
return LDB_ERR_OPERATIONS_ERROR;
}
ac->req->async.context = ac;
ac->req->async.callback = server_sort_search_callback;
- ac->req->async.timeout = req->async.timeout;
+ ldb_set_timeout_from_prev_req(module->ldb, req, ac->req);
req->async.handle = h;
ldb_qsort(ac->msgs, ac->num_msgs,
sizeof(struct ldb_message *),
- ac, (ldb_qsort_cmp_fn_t)sort_compare_async);
+ ac, (ldb_qsort_cmp_fn_t)sort_compare);
for (i = 0; i < ac->num_msgs; i++) {
ares = talloc_zero(ac, struct ldb_async_result);
req->controls = actx->req_ctrls;
req->async.context = actx;
req->async.callback = &search_callback;
- req->async.timeout = 3600; /* TODO: make this settable by command line */
+ ldb_set_timeout(ldb, req, 0); /* TODO: make this settable by command line */
again:
actx->pending = 0;
req->controls = ctrl;
req->async.context = actx;
req->async.callback = test_schema_search_callback;
- req->async.timeout = 3600;
+ ldb_set_timeout(ldb, req, 0);
actx->count = 0;
actx->ctrl = control;