diff options
author | Stefan Metzmacher <metze@samba.org> | 2012-03-14 14:57:32 +0100 |
---|---|---|
committer | Stefan Metzmacher <metze@samba.org> | 2012-03-15 07:35:28 +0100 |
commit | 080549f4675484d0de16c5bfae162513f13fcab6 (patch) | |
tree | e5251fbba65f096944edcb87ba94b47776d852f5 | |
parent | 553a8921a453d839b87b941719b1ad44c694904f (diff) | |
download | samba-080549f4675484d0de16c5bfae162513f13fcab6.tar.gz |
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
-rw-r--r-- | source4/librpc/rpc/dcerpc.c | 60 | ||||
-rw-r--r-- | source4/librpc/rpc/dcerpc.h | 3 |
2 files changed, 56 insertions, 7 deletions
diff --git a/source4/librpc/rpc/dcerpc.c b/source4/librpc/rpc/dcerpc.c index 47e98e84480..ed527b8055a 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 22afdf880fa..359efdabc0f 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; |