From 8d79eb52f104d023122de3965592b4ea36adbb2b Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Sat, 13 Dec 2003 11:44:28 +0000 Subject: make the IO in the dcerpc over TCP server completely async, handling partial packets on both input and output (This used to be commit 4f46606af880f6dd86c20b8dc5799102a8e80cc9) --- source4/rpc_server/dcerpc_server.c | 56 +++++++++++++++++++++++++++++++++++++- source4/rpc_server/dcerpc_server.h | 4 +++ source4/rpc_server/dcerpc_tcp.c | 4 +-- 3 files changed, 61 insertions(+), 3 deletions(-) (limited to 'source4') diff --git a/source4/rpc_server/dcerpc_server.c b/source4/rpc_server/dcerpc_server.c index 81c9d4cb8f..bde7063dcc 100644 --- a/source4/rpc_server/dcerpc_server.c +++ b/source4/rpc_server/dcerpc_server.c @@ -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; diff --git a/source4/rpc_server/dcerpc_server.h b/source4/rpc_server/dcerpc_server.h index 38340bcf16..b7206163f4 100644 --- a/source4/rpc_server/dcerpc_server.h +++ b/source4/rpc_server/dcerpc_server.h @@ -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; }; diff --git a/source4/rpc_server/dcerpc_tcp.c b/source4/rpc_server/dcerpc_tcp.c index 110789dba6..1f8230eb1c 100644 --- a/source4/rpc_server/dcerpc_tcp.c +++ b/source4/rpc_server/dcerpc_tcp.c @@ -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"); } -- cgit