STEP01: librpc/rpc/dcerpc_connection.c do_request use_trans part2
authorStefan Metzmacher <metze@samba.org>
Sat, 11 Jan 2014 08:08:07 +0000 (09:08 +0100)
committerStefan Metzmacher <metze@samba.org>
Tue, 4 Jun 2019 10:45:39 +0000 (12:45 +0200)
librpc/rpc/dcerpc_connection.c

index 50242bf648ab00499d6719416a49961bd406fc53..e3c4dd6cc5e5ff314da57414cfd7a5ed3eaf0eec 100644 (file)
@@ -1621,7 +1621,9 @@ static void dcerpc_do_request_cleanup(struct tevent_req *req,
        }
 }
 
+static void dcerpc_do_request_out_frag_trans_wait1(struct tevent_req *subreq);
 static void dcerpc_do_request_out_frag_done(struct tevent_req *subreq);
+static void dcerpc_do_request_out_frag_trans_wait2(struct tevent_req *subreq);
 
 static void dcerpc_do_request_out_frag_next(struct tevent_req *req,
                                            void *private_data)
@@ -1642,6 +1644,7 @@ static void dcerpc_do_request_out_frag_next(struct tevent_req *req,
        DATA_BLOB payload;
        bool ok;
        struct tevent_req *subreq;
+       bool use_trans = true;
 
        if (state->object) {
                flags |= DCERPC_PFC_FLAG_OBJECT_UUID;
@@ -1744,9 +1747,45 @@ static void dcerpc_do_request_out_frag_next(struct tevent_req *req,
 
        frag->is_last = ((flags & DCERPC_PFC_FLAG_LAST) != 0);
 
+       if (!frag->is_last) {
+               use_trans = false;
+       }
+
+       if (frag->conn->transport.use_trans_fn == NULL) {
+               use_trans = false;
+       }
+
+       if (frag->conn->loop.subreq != NULL) {
+               use_trans = false;
+       }
+
+       if (frag->conn->features.concurrent_multiplex) {
+               use_trans = false;
+       }
+
+       if (tevent_queue_length(frag->conn->calls.out_queue) > 1) {
+               use_trans = false;
+       }
+
+       if (use_trans) {
+               frag->subreq_wait1 = tevent_queue_wait_send(frag,
+                                               frag->ev,
+                                               frag->conn->transport.write_queue);
+               if (tevent_req_nomem(req, frag->subreq_wait1)) {
+                       return;
+               }
+               tevent_req_set_callback(frag->subreq_wait1,
+                                       dcerpc_do_request_out_frag_trans_wait1,
+                                       frag);
+               /*
+                * we need to block reads until our write is
+                * the next in the write queue.
+                */
+               frag->conn->loop.subreq = frag->subreq_wait1;
+               frag->conn->loop.ev = frag->ev;
+       }
+
        /*
-        * TODO: add smb_trans handling for ncacn_np
-        *
         * We need to add a dcerpc_write_fragment_queue_send/recv()
         */
 
@@ -1763,6 +1802,18 @@ static void dcerpc_do_request_out_frag_next(struct tevent_req *req,
                                dcerpc_do_request_out_frag_done,
                                frag);
 
+       if (use_trans) {
+               frag->subreq_wait2 = tevent_queue_wait_send(frag,
+                                               frag->ev,
+                                               frag->conn->transport.write_queue);
+               if (tevent_req_nomem(req, frag->subreq_wait2)) {
+                       return;
+               }
+               tevent_req_set_callback(frag->subreq_wait2,
+                                       dcerpc_do_request_out_frag_trans_wait2,
+                                       frag);
+       }
+
        if (!frag->is_last) {
                return;
        }
@@ -1773,6 +1824,77 @@ static void dcerpc_do_request_out_frag_next(struct tevent_req *req,
        }
 }
 
+static void dcerpc_do_request_out_frag_trans_wait1(struct tevent_req *subreq)
+{
+       struct dcerpc_do_request_out_frag *frag =
+               tevent_req_callback_data(subreq,
+               struct dcerpc_do_request_out_frag);
+       struct tevent_req *req = frag->req;
+       NTSTATUS status;
+       bool ok;
+
+       /*
+        * TODO; what if the caller has been free'ed?
+        */
+
+       frag->subreq_wait1 = NULL;
+       frag->conn->loop.subreq = NULL;
+
+       ok = tevent_queue_wait_recv(subreq);
+       if (!ok) {
+               status = NT_STATUS_INTERNAL_ERROR;
+               TALLOC_FREE(frag);
+               if (req) {
+                       tevent_req_nterror(req, status);
+               }
+               //dcerpc_transport_dead(p, NT_STATUS_NO_MEMORY);
+               return;
+       }
+
+       if (tevent_queue_length(frag->conn->transport.write_queue) > 3) {
+               /*
+                * We added 3 entries into the queue,
+                * wait1, writev and wait2.
+                *
+                * There's more to write, we should not block
+                * further writev calls for a trans call.
+                *
+                * The wait2 stage will trigger the read.
+                */
+               TALLOC_FREE(subreq);
+               return;
+       }
+
+       /*
+        * we don't need wait2 anymore, we're sure that
+        * we'll do a trans call.
+        */
+       TALLOC_FREE(frag->subreq_wait2);
+
+       status = frag->conn->transport.use_trans_fn(frag->conn->transport.stream);
+       if (!NT_STATUS_IS_OK(status)) {
+               TALLOC_FREE(frag);
+               if (req) {
+                       tevent_req_nterror(req, status);
+               }
+               //dcerpc_transport_dead(p, NT_STATUS_NO_MEMORY);
+               return;
+       }
+
+       /* we free subreq after tstream_cli_np_use_trans */
+       TALLOC_FREE(subreq);
+
+       status = dcerpc_connection_loop_restart(frag->conn, frag->ev);
+       if (!NT_STATUS_IS_OK(status)) {
+               TALLOC_FREE(frag);
+               if (req) {
+                       tevent_req_nterror(req, status);
+               }
+               //dcerpc_transport_dead(p, NT_STATUS_NO_MEMORY);
+               return;
+       }
+}
+
 static void dcerpc_do_request_out_frag_done(struct tevent_req *subreq)
 {
        struct dcerpc_do_request_out_frag *frag =
@@ -1806,6 +1928,10 @@ static void dcerpc_do_request_out_frag_done(struct tevent_req *subreq)
                return;
        }
 
+       if (frag->subreq_wait2 != NULL) {
+               return;
+       }
+
        if (frag->is_last) {
                TALLOC_FREE(frag);
                return;
@@ -1819,6 +1945,45 @@ static void dcerpc_do_request_out_frag_done(struct tevent_req *subreq)
        dcerpc_do_request_out_frag_next(req, NULL);
 }
 
+static void dcerpc_do_request_out_frag_trans_wait2(struct tevent_req *subreq)
+{
+       struct dcerpc_do_request_out_frag *frag =
+               tevent_req_callback_data(subreq,
+               struct dcerpc_do_request_out_frag);
+       struct tevent_req *req = frag->req;
+       NTSTATUS status;
+       bool ok;
+
+       frag->subreq_wait2 = NULL;
+
+       ok = tevent_queue_wait_recv(subreq);
+       if (!ok) {
+               status = NT_STATUS_INTERNAL_ERROR;
+               TALLOC_FREE(frag);
+               if (req) {
+                       tevent_req_nterror(req, status);
+               }
+               //dcerpc_transport_dead(p, NT_STATUS_NO_MEMORY);
+               return;
+       }
+
+       TALLOC_FREE(subreq);
+
+       status = dcerpc_connection_loop_restart(frag->conn, frag->ev);
+       if (!NT_STATUS_IS_OK(status)) {
+               TALLOC_FREE(frag);
+               if (req) {
+                       tevent_req_nterror(req, status);
+               }
+               //dcerpc_transport_dead(p, NT_STATUS_NO_MEMORY);
+               return;
+       }
+
+       TALLOC_FREE(frag);
+
+       /* we need to wait for incoming pdus */
+}
+
 static NTSTATUS dcerpc_do_request_handle_in_frag(void *private_data,
                                                 struct ncacn_packet *pkt,
                                                 DATA_BLOB frag)