summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStefan Metzmacher <metze@samba.org>2012-03-14 14:57:32 +0100
committerStefan Metzmacher <metze@samba.org>2012-03-15 07:35:28 +0100
commit080549f4675484d0de16c5bfae162513f13fcab6 (patch)
treee5251fbba65f096944edcb87ba94b47776d852f5
parent553a8921a453d839b87b941719b1ad44c694904f (diff)
downloadsamba-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.c60
-rw-r--r--source4/librpc/rpc/dcerpc.h3
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;