make the IO in the dcerpc over TCP server completely async, handling
authorAndrew Tridgell <tridge@samba.org>
Sat, 13 Dec 2003 11:44:28 +0000 (11:44 +0000)
committerAndrew Tridgell <tridge@samba.org>
Sat, 13 Dec 2003 11:44:28 +0000 (11:44 +0000)
partial packets on both input and output
(This used to be commit 4f46606af880f6dd86c20b8dc5799102a8e80cc9)

source4/rpc_server/dcerpc_server.c
source4/rpc_server/dcerpc_server.h
source4/rpc_server/dcerpc_tcp.c

index 81c9d4cb8f5348f1fce1616cb0af661a758d59ed..bde7063dcc596a132134c5c3faa2e4415ea58881 100644 (file)
@@ -100,6 +100,7 @@ NTSTATUS dcesrv_endpoint_connect_ops(struct dcesrv_context *dce,
        (*p)->dispatch = NULL;
        (*p)->handles = NULL;
        (*p)->next_handle = 0;
+       (*p)->partial_input = data_blob(NULL, 0);
 
        /* make sure the endpoint server likes the connection */
        status = ops->connect(*p);
@@ -479,6 +480,40 @@ static NTSTATUS dcesrv_request(struct dcesrv_call_state *call)
 }
 
 
+/*
+  work out if we have a full packet yet
+*/
+static BOOL dce_full_packet(const DATA_BLOB *data)
+{
+       if (data->length < DCERPC_FRAG_LEN_OFFSET+2) {
+               return False;
+       }
+       if (SVAL(data->data, DCERPC_FRAG_LEN_OFFSET) > data->length) {
+               return False;
+       }
+       return True;
+}
+
+/*
+  we might have consumed only part of our input - advance past that part
+*/
+static void dce_partial_advance(struct dcesrv_state *dce, uint32 offset)
+{
+       DATA_BLOB blob;
+
+       if (dce->partial_input.length == offset) {
+               talloc_free(dce->mem_ctx, dce->partial_input.data);
+               dce->partial_input = data_blob(NULL, 0);
+               return;
+       }
+
+       blob = dce->partial_input;
+       dce->partial_input = data_blob_talloc(dce->mem_ctx, 
+                                             blob.data + offset,
+                                             blob.length - offset);
+       talloc_free(dce->mem_ctx, blob.data);
+}
+
 /*
   provide some input to a dcerpc endpoint server. This passes data
   from a dcerpc client into the server
@@ -490,12 +525,27 @@ NTSTATUS dcesrv_input(struct dcesrv_state *dce, const DATA_BLOB *data)
        NTSTATUS status;
        struct dcesrv_call_state *call;
 
+       dce->partial_input.data = talloc_realloc(dce->mem_ctx,
+                                                dce->partial_input.data,
+                                                dce->partial_input.length + data->length);
+       if (!dce->partial_input.data) {
+               return NT_STATUS_NO_MEMORY;
+       }
+       memcpy(dce->partial_input.data + dce->partial_input.length,
+              data->data, data->length);
+       dce->partial_input.length += data->length;
+
+       if (!dce_full_packet(&dce->partial_input)) {
+               return NT_STATUS_OK;
+       }
+
        mem_ctx = talloc_init("dcesrv_input");
        if (!mem_ctx) {
                return NT_STATUS_NO_MEMORY;
        }
        call = talloc_p(mem_ctx, struct dcesrv_call_state);
        if (!call) {
+               talloc_free(dce->mem_ctx, dce->partial_input.data);
                talloc_destroy(mem_ctx);
                return NT_STATUS_NO_MEMORY;
        }
@@ -503,18 +553,22 @@ NTSTATUS dcesrv_input(struct dcesrv_state *dce, const DATA_BLOB *data)
        call->dce = dce;
        call->replies = NULL;
 
-       ndr = ndr_pull_init_blob(data, mem_ctx);
+       ndr = ndr_pull_init_blob(&dce->partial_input, mem_ctx);
        if (!ndr) {
+               talloc_free(dce->mem_ctx, dce->partial_input.data);
                talloc_destroy(mem_ctx);
                return NT_STATUS_NO_MEMORY;
        }
 
        status = ndr_pull_dcerpc_packet(ndr, NDR_SCALARS|NDR_BUFFERS, &call->pkt);
        if (!NT_STATUS_IS_OK(status)) {
+               talloc_free(dce->mem_ctx, dce->partial_input.data);
                talloc_destroy(mem_ctx);
                return status;
        }
 
+       dce_partial_advance(dce, ndr->offset);
+
        /* see if this is a continued packet */
        if (!(call->pkt.pfc_flags & DCERPC_PFC_FLAG_FIRST)) {
                struct dcesrv_call_state *call2 = call;
index 38340bcf16fe201654cc91fd3605113a46966b34..b7206163f43c5f246a34df5e1765a9bc13dabe4b 100644 (file)
@@ -53,6 +53,8 @@ struct dcesrv_call_state {
        TALLOC_CTX *mem_ctx;
        struct dcerpc_packet pkt;
 
+       DATA_BLOB input;
+
        struct dcesrv_call_reply {
                struct dcesrv_call_reply *next, *prev;
                DATA_BLOB data;
@@ -101,6 +103,8 @@ struct dcesrv_state {
           them, but it will do for now */
        uint32 next_handle;
        struct dcesrv_handle *handles;
+
+       DATA_BLOB partial_input;
 };
 
 
index 110789dba69d9e876bf34d6eefd8a97ec7a4dd33..1f8230eb1c5f545bb0c702af9bb726de92f0e3a2 100644 (file)
@@ -38,7 +38,7 @@ static void dcerpc_write_handler(struct event_context *ev, struct fd_event *fde,
        DATA_BLOB blob;
        NTSTATUS status;
 
-       blob = data_blob(NULL, 0x4000);
+       blob = data_blob(NULL, 3);
        if (!blob.data) {
                smb_panic("out of memory in rpc write handler");
        }
@@ -63,7 +63,7 @@ static void dcerpc_read_handler(struct event_context *ev, struct fd_event *fde,
        DATA_BLOB blob;
        ssize_t ret;
 
-       blob = data_blob(NULL, 0x4000);
+       blob = data_blob(NULL, 3);
        if (!blob.data) {
                smb_panic("out of memory in rpc read handler");
        }