From 080549f4675484d0de16c5bfae162513f13fcab6 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Wed, 14 Mar 2012 14:57:32 +0100 Subject: s4:librpc/rpc: ship requests via an immediate event Deep inside dcerpc_ship_next_request() some code path could trigger dcerpc_connection_dead(), which means it's not safe to do any processing after calling dcerpc_ship_next_request(). metze --- source4/librpc/rpc/dcerpc.c | 60 +++++++++++++++++++++++++++++++++++++++------ source4/librpc/rpc/dcerpc.h | 3 +++ 2 files changed, 56 insertions(+), 7 deletions(-) (limited to 'source4/librpc/rpc') diff --git a/source4/librpc/rpc/dcerpc.c b/source4/librpc/rpc/dcerpc.c index 47e98e8448..ed527b8055 100644 --- a/source4/librpc/rpc/dcerpc.c +++ b/source4/librpc/rpc/dcerpc.c @@ -82,7 +82,7 @@ _PUBLIC_ NTSTATUS dcerpc_init(void) } static void dcerpc_connection_dead(struct dcecli_connection *conn, NTSTATUS status); -static void dcerpc_ship_next_request(struct dcecli_connection *c); +static void dcerpc_schedule_io_trigger(struct dcecli_connection *c); static struct rpc_request *dcerpc_request_send(struct dcerpc_pipe *p, const struct GUID *object, @@ -147,6 +147,12 @@ static struct dcecli_connection *dcerpc_connection_init(TALLOC_CTX *mem_ctx, c->srv_max_recv_frag = 0; c->pending = NULL; + c->io_trigger = tevent_create_immediate(c); + if (c->io_trigger == NULL) { + talloc_free(c); + return NULL; + } + talloc_set_destructor(c, dcerpc_connection_destructor); return c; @@ -989,6 +995,9 @@ static void dcerpc_connection_dead(struct dcecli_connection *conn, NTSTATUS stat conn->dead = true; + TALLOC_FREE(conn->io_trigger); + conn->io_trigger_pending = false; + conn->transport.recv_data = NULL; if (conn->transport.shutdown_pipe) { @@ -1376,11 +1385,11 @@ req_done: req->state = RPC_REQUEST_DONE; DLIST_REMOVE(c->pending, req); - if (c->request_queue != NULL) { - /* We have to look at shipping further requests before calling - * the async function, that one might close the pipe */ - dcerpc_ship_next_request(c); - } + /* + * We have to look at shipping further requests before calling + * the async function, that one might close the pipe + */ + dcerpc_schedule_io_trigger(c); if (req->async.callback) { req->async.callback(req); @@ -1436,7 +1445,7 @@ static struct rpc_request *dcerpc_request_send(struct dcerpc_pipe *p, DLIST_ADD_END(p->conn->request_queue, req, struct rpc_request *); talloc_set_destructor(req, dcerpc_req_dequeue); - dcerpc_ship_next_request(p->conn); + dcerpc_schedule_io_trigger(p->conn); if (p->request_timeout) { tevent_add_timer(dcerpc_event_context(p), req, @@ -1564,6 +1573,43 @@ static void dcerpc_ship_next_request(struct dcecli_connection *c) } } +static void dcerpc_io_trigger(struct tevent_context *ctx, + struct tevent_immediate *im, + void *private_data) +{ + struct dcecli_connection *c = + talloc_get_type_abort(private_data, + struct dcecli_connection); + + c->io_trigger_pending = false; + + dcerpc_schedule_io_trigger(c); + + dcerpc_ship_next_request(c); +} + +static void dcerpc_schedule_io_trigger(struct dcecli_connection *c) +{ + if (c->dead) { + return; + } + + if (c->request_queue == NULL) { + return; + } + + if (c->io_trigger_pending) { + return; + } + + c->io_trigger_pending = true; + + tevent_schedule_immediate(c->io_trigger, + c->event_ctx, + dcerpc_io_trigger, + c); +} + /* return the event context for a dcerpc pipe used by callers who wish to operate asynchronously diff --git a/source4/librpc/rpc/dcerpc.h b/source4/librpc/rpc/dcerpc.h index 22afdf880f..359efdabc0 100644 --- a/source4/librpc/rpc/dcerpc.h +++ b/source4/librpc/rpc/dcerpc.h @@ -63,6 +63,9 @@ struct dcecli_connection { const char *binding_string; struct tevent_context *event_ctx; + struct tevent_immediate *io_trigger; + bool io_trigger_pending; + /** Directory in which to save ndrdump-parseable files */ const char *packet_log_dir; -- cgit