summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAndrew Tridgell <tridge@samba.org>2003-12-13 11:44:28 +0000
committerAndrew Tridgell <tridge@samba.org>2003-12-13 11:44:28 +0000
commit8d79eb52f104d023122de3965592b4ea36adbb2b (patch)
tree5c6803935c841c52174a0c4401b2834b606a7dc7
parentd4705378ce88d1bb2f787338c531998d37d078ef (diff)
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)
-rw-r--r--source4/rpc_server/dcerpc_server.c56
-rw-r--r--source4/rpc_server/dcerpc_server.h4
-rw-r--r--source4/rpc_server/dcerpc_tcp.c4
3 files changed, 61 insertions, 3 deletions
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);
@@ -480,6 +481,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");
}