s4:librpc/rpc: ship requests via an immediate event
authorStefan Metzmacher <metze@samba.org>
Wed, 14 Mar 2012 13:57:32 +0000 (14:57 +0100)
committerStefan Metzmacher <metze@samba.org>
Thu, 15 Mar 2012 06:35:28 +0000 (07:35 +0100)
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
source4/librpc/rpc/dcerpc.h

index 47e98e844800cd7a0a031341f58a454a52442dfc..ed527b8055a8ae18fd4b30f7b551da5f970960c0 100644 (file)
@@ -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
index 22afdf880fa15b5620d90c753cb5cd13cb1dc19c..359efdabc0fb15a309075b7ddf388613ed382b6c 100644 (file)
@@ -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;