TODO s4:librpc/rpc: prepare LIBNDR_FLAG_INCOMPLETE_BUFFER support...
authorStefan Metzmacher <metze@samba.org>
Sat, 31 Aug 2013 09:59:10 +0000 (11:59 +0200)
committerStefan Metzmacher <metze@samba.org>
Tue, 4 Jun 2019 11:14:55 +0000 (13:14 +0200)
source4/librpc/rpc/dcerpc.c

index a0b00aff817d4b3215410f5e473158124d10e52b..013531a5a722fde5b8433fec25b27ccea10fb2ae 100644 (file)
@@ -67,6 +67,8 @@ struct rpc_request {
        bool wait_for_sync;
        bool verify_bitmask1;
        bool verify_pcontext;
+       bool first_pdu_done;
+       bool incomplete_request_data;
 
        struct {
                void (*callback)(struct rpc_request *);
@@ -1649,7 +1651,6 @@ static void dcerpc_ship_next_request(struct dcecli_connection *c)
        struct ncacn_packet pkt;
        DATA_BLOB blob;
        uint32_t remaining, chunk_size;
-       bool first_packet = true;
        size_t sig_size = 0;
        bool need_async = false;
        bool can_async = true;
@@ -1676,10 +1677,6 @@ static void dcerpc_ship_next_request(struct dcecli_connection *c)
                return;
        }
 
-       DLIST_REMOVE(c->request_queue, req);
-       DLIST_ADD(c->pending, req);
-       req->state = RPC_REQUEST_PENDING;
-
        init_ncacn_hdr(p->conn, &pkt);
 
        remaining = stub_data->length;
@@ -1717,20 +1714,23 @@ static void dcerpc_ship_next_request(struct dcecli_connection *c)
        }
 
        /* we send a series of pdus without waiting for a reply */
-       while (remaining > 0 || first_packet) {
+       while (remaining > 0 || !req->first_pdu_done) {
                uint32_t chunk = MIN(chunk_size, remaining);
                bool last_frag = false;
                bool do_trans = false;
 
-               first_packet = false;
+               if ((chunk == remaining) && !req->incomplete_request_data) {
+                       last_frag = true;
+               }
+
                pkt.pfc_flags &= ~(DCERPC_PFC_FLAG_FIRST |DCERPC_PFC_FLAG_LAST);
 
-               if (remaining == stub_data->length) {
+               if (!req->first_pdu_done) {
+                       req->first_pdu_done = true;
                        pkt.pfc_flags |= DCERPC_PFC_FLAG_FIRST;
                }
-               if (chunk == remaining) {
+               if (last_frag) {
                        pkt.pfc_flags |= DCERPC_PFC_FLAG_LAST;
-                       last_frag = true;
                }
 
                pkt.u.request.alloc_hint = remaining;
@@ -1741,7 +1741,7 @@ static void dcerpc_ship_next_request(struct dcecli_connection *c)
                req->status = ncacn_push_request_sign(p->conn, &blob, req, sig_size, &pkt);
                if (!NT_STATUS_IS_OK(req->status)) {
                        req->state = RPC_REQUEST_DONE;
-                       DLIST_REMOVE(p->conn->pending, req);
+                       DLIST_REMOVE(c->request_queue, req);
                        return;
                }
 
@@ -1752,7 +1752,7 @@ static void dcerpc_ship_next_request(struct dcecli_connection *c)
                req->status = dcerpc_send_request(p->conn, &blob, do_trans);
                if (!NT_STATUS_IS_OK(req->status)) {
                        req->state = RPC_REQUEST_DONE;
-                       DLIST_REMOVE(p->conn->pending, req);
+                       DLIST_REMOVE(c->request_queue, req);
                        return;
                }               
 
@@ -1760,13 +1760,22 @@ static void dcerpc_ship_next_request(struct dcecli_connection *c)
                        req->status = dcerpc_send_read(p->conn);
                        if (!NT_STATUS_IS_OK(req->status)) {
                                req->state = RPC_REQUEST_DONE;
-                               DLIST_REMOVE(p->conn->pending, req);
+                               DLIST_REMOVE(c->request_queue, req);
                                return;
                        }
                }
 
                remaining -= chunk;
+
+               if ((remaining == 0) && req->incomplete_request_data) {
+                       req->request_data = data_blob_null;
+                       return;
+               }
        }
+
+       DLIST_REMOVE(c->request_queue, req);
+       DLIST_ADD(c->pending, req);
+       req->state = RPC_REQUEST_PENDING;
 }
 
 static void dcerpc_io_trigger(struct tevent_context *ctx,