diff options
-rw-r--r-- | source4/rpc_server/dcerpc_server.c | 33 |
1 files changed, 29 insertions, 4 deletions
diff --git a/source4/rpc_server/dcerpc_server.c b/source4/rpc_server/dcerpc_server.c index 46341e6db1..a4f5fb9768 100644 --- a/source4/rpc_server/dcerpc_server.c +++ b/source4/rpc_server/dcerpc_server.c @@ -689,15 +689,14 @@ static void dce_partial_advance(struct dcesrv_connection *dce_conn, uint32 offse DATA_BLOB blob; if (dce_conn->partial_input.length == offset) { - free(dce_conn->partial_input.data); - dce_conn->partial_input = data_blob(NULL, 0); + data_blob_free(&dce_conn->partial_input); return; } blob = dce_conn->partial_input; dce_conn->partial_input = data_blob(blob.data + offset, - blob.length - offset); - free(blob.data); + blob.length - offset); + data_blob_free(&blob); } /* @@ -840,6 +839,32 @@ NTSTATUS dcesrv_input(struct dcesrv_connection *dce_conn, const DATA_BLOB *data) { NTSTATUS status; + /* handle the very common case that the input contains a full packet and there + is no partial packet pending. In this case we can avoid a copy of the + data */ + if (dce_conn->partial_input.length == 0) { + dce_conn->partial_input = *data; + /* make sure that dce_partial_advance doesn't free this data */ + dce_conn->partial_input.free = NULL; + while (dce_full_packet(&dce_conn->partial_input)) { + status = dcesrv_input_process(dce_conn); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + } + if (dce_conn->partial_input.length) { + /* there was some data left over. We have to copy this + as the caller may free the data */ + dce_conn->partial_input = + data_blob(dce_conn->partial_input.data, + dce_conn->partial_input.length); + if (!dce_conn->partial_input.data) { + return NT_STATUS_NO_MEMORY; + } + } + return NT_STATUS_OK; + } + dce_conn->partial_input.data = Realloc(dce_conn->partial_input.data, dce_conn->partial_input.length + data->length); if (!dce_conn->partial_input.data) { |