summaryrefslogtreecommitdiff
path: root/source4/libcli
diff options
context:
space:
mode:
authorAndrew Tridgell <tridge@samba.org>2003-11-04 03:38:46 +0000
committerAndrew Tridgell <tridge@samba.org>2003-11-04 03:38:46 +0000
commitd8cbe76b868eb6f2b3876fa540e0847bd2d4f9d7 (patch)
tree916a6642bb57c169aca82ac14bd31154fdc82366 /source4/libcli
parent994301bfec372f0b929a61425fc1eb180d16cbb1 (diff)
downloadsamba-d8cbe76b868eb6f2b3876fa540e0847bd2d4f9d7.tar.gz
samba-d8cbe76b868eb6f2b3876fa540e0847bd2d4f9d7.tar.bz2
samba-d8cbe76b868eb6f2b3876fa540e0847bd2d4f9d7.zip
added support for fragmented sends
(This used to be commit f51a216136b7cc7d4d07d4acb80e0a710d82841a)
Diffstat (limited to 'source4/libcli')
-rw-r--r--source4/libcli/raw/rawdcerpc.c32
-rw-r--r--source4/libcli/rpc/dcerpc.c57
-rw-r--r--source4/libcli/rpc/dcerpc.h2
3 files changed, 83 insertions, 8 deletions
diff --git a/source4/libcli/raw/rawdcerpc.c b/source4/libcli/raw/rawdcerpc.c
index d548129ab1..a6cd75eeaa 100644
--- a/source4/libcli/raw/rawdcerpc.c
+++ b/source4/libcli/raw/rawdcerpc.c
@@ -218,3 +218,35 @@ NTSTATUS dcerpc_raw_packet_secondary(struct dcerpc_pipe *p,
return status;
}
+
+
+/*
+ send an initial pdu in a multi-pdu sequence
+*/
+NTSTATUS dcerpc_raw_packet_initial(struct dcerpc_pipe *p,
+ TALLOC_CTX *mem_ctx,
+ DATA_BLOB *blob)
+{
+ union smb_write io;
+ NTSTATUS status;
+
+ io.generic.level = RAW_WRITE_WRITEX;
+ io.writex.in.fnum = p->fnum;
+ io.writex.in.offset = 0;
+ io.writex.in.wmode = PIPE_START_MESSAGE;
+ io.writex.in.remaining = blob->length;
+ io.writex.in.count = blob->length;
+ io.writex.in.data = blob->data;
+
+ status = smb_raw_write(p->tree, &io);
+ if (NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ /* make sure it accepted it all */
+ if (io.writex.out.nwritten != blob->length) {
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ return status;
+}
diff --git a/source4/libcli/rpc/dcerpc.c b/source4/libcli/rpc/dcerpc.c
index d4f21f969a..7d6888dde7 100644
--- a/source4/libcli/rpc/dcerpc.c
+++ b/source4/libcli/rpc/dcerpc.c
@@ -186,11 +186,11 @@ static NTSTATUS dcerpc_pull_response(DATA_BLOB *blob, TALLOC_CTX *mem_ctx,
struct dcerpc_hdr *hdr,
struct dcerpc_response *pkt)
{
- uint32 alloc_hint, stub_len;
+ uint32 stub_len;
BLOB_CHECK_BOUNDS(blob, *offset, 8);
- alloc_hint = IVAL(blob->data, (*offset) + 0);
+ pkt->alloc_hint = IVAL(blob->data, (*offset) + 0);
pkt->context_id = SVAL(blob->data, (*offset) + 4);
pkt->cancel_count = CVAL(blob->data, (*offset) + 6);
@@ -382,9 +382,7 @@ static NTSTATUS dcerpc_push_request(DATA_BLOB *blob, uint32 *offset,
struct dcerpc_hdr *hdr,
struct dcerpc_request *pkt)
{
- uint32 alloc_hint = 8 + pkt->stub_data.length + pkt->auth_verifier.length;
-
- SIVAL(blob->data, (*offset) + 0, alloc_hint);
+ SIVAL(blob->data, (*offset) + 0, pkt->alloc_hint);
SSVAL(blob->data, (*offset) + 4, pkt->context_id);
SSVAL(blob->data, (*offset) + 6, pkt->opnum);
@@ -621,24 +619,67 @@ NTSTATUS cli_dcerpc_request(struct dcerpc_pipe *p,
struct dcerpc_packet pkt;
NTSTATUS status;
DATA_BLOB blob_in, blob_out, payload;
+ uint32 remaining, chunk_size;
init_dcerpc_hdr(&pkt.hdr);
+ remaining = stub_data_in->length;
+
+ /* we can write a full max_recv_frag size, minus the dcerpc
+ request header size */
+ chunk_size = p->srv_max_recv_frag - 24;
+
pkt.hdr.ptype = DCERPC_PKT_REQUEST;
- pkt.hdr.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
pkt.hdr.call_id = p->call_id++;
pkt.hdr.auth_length = 0;
-
+ pkt.in.request.alloc_hint = remaining;
pkt.in.request.context_id = 0;
pkt.in.request.opnum = opnum;
- pkt.in.request.stub_data = *stub_data_in;
pkt.in.request.auth_verifier = data_blob(NULL, 0);
+ /* we send a series of pdus without waiting for a reply until
+ the last pdu */
+ while (remaining > chunk_size) {
+ if (remaining == stub_data_in->length) {
+ pkt.hdr.pfc_flags = DCERPC_PFC_FLAG_FIRST;
+ } else {
+ pkt.hdr.pfc_flags = 0;
+ }
+
+ pkt.in.request.stub_data.data = stub_data_in->data +
+ (stub_data_in->length - remaining);
+ pkt.in.request.stub_data.length = chunk_size;
+
+ status = dcerpc_push(&blob_in, mem_ctx, &pkt);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ status = dcerpc_raw_packet_initial(p, mem_ctx, &blob_in);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ remaining -= chunk_size;
+ }
+
+ /* now we send a pdu with LAST_FRAG sent and get the first
+ part of the reply */
+ if (remaining == stub_data_in->length) {
+ pkt.hdr.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
+ } else {
+ pkt.hdr.pfc_flags = DCERPC_PFC_FLAG_LAST;
+ }
+ pkt.in.request.stub_data.data = stub_data_in->data +
+ (stub_data_in->length - remaining);
+ pkt.in.request.stub_data.length = remaining;
+
status = dcerpc_push(&blob_in, mem_ctx, &pkt);
if (!NT_STATUS_IS_OK(status)) {
return status;
}
+ /* send the pdu and get the initial response pdu */
status = dcerpc_raw_packet(p, mem_ctx, &blob_in, &blob_out);
status = dcerpc_pull(&blob_out, mem_ctx, &pkt);
diff --git a/source4/libcli/rpc/dcerpc.h b/source4/libcli/rpc/dcerpc.h
index 7f24f46b91..09ddc3625c 100644
--- a/source4/libcli/rpc/dcerpc.h
+++ b/source4/libcli/rpc/dcerpc.h
@@ -86,6 +86,7 @@ struct dcerpc_packet {
} bind;
struct dcerpc_request {
+ uint32 alloc_hint;
uint16 context_id;
uint16 opnum;
DATA_BLOB stub_data;
@@ -114,6 +115,7 @@ struct dcerpc_packet {
} bind_nak;
struct dcerpc_response {
+ uint32 alloc_hint;
uint16 context_id;
uint8 cancel_count;
DATA_BLOB stub_data;