From cfbc3f86952ce8f90669ff605c7b3ecf0a0cf0d3 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Tue, 7 Jun 2011 18:27:41 +0200 Subject: [PATCH 1/3] s3:libsmb/cli_np_tstream: use larger buffers to avoid a bug NT4 servers (bug #8195) NT4 servers return NT_STATUS_PIPE_BUSY if we try a SMBtrans and the SMBwriteX before hasn't transmited the whole DCERPC fragment. W2K and above is happy with that. As a result we try to match the behavior of Windows and older Samba clients, they use write and read buffers of 4280 bytes instead of 1024 bytes. On Windows only the SMBtrans based read uses 1024 (while we also use 4280 there). metze --- source3/libsmb/cli_np_tstream.c | 19 +++++++++++++++++-- 1 files changed, 17 insertions(+), 2 deletions(-) diff --git a/source3/libsmb/cli_np_tstream.c b/source3/libsmb/cli_np_tstream.c index ba37ea5..5e11a92 100644 --- a/source3/libsmb/cli_np_tstream.c +++ b/source3/libsmb/cli_np_tstream.c @@ -28,9 +28,24 @@ static const struct tstream_context_ops tstream_cli_np_ops; /* - * Window uses 1024 hardcoded for read size and trans max data + * Windows uses 4280 (the max xmit/recv size negotiated on DCERPC). + * This is fits into the max_xmit negotiated at the SMB layer. + * + * On the sending side they may use SMBtranss if the request does not + * fit into a single SMBtrans call. + * + * Windows uses 1024 as max data size of a SMBtrans request and then + * possibly reads the rest of the DCERPC fragment (up to 3256 bytes) + * via a SMBreadX. + * + * For now we just ask for the full 4280 bytes (max data size) in the SMBtrans + * request to get the whole fragment at once (like samba 3.5.x and below did. + * + * It is important that we use do SMBwriteX with the size of a full fragment, + * otherwise we may get NT_STATUS_PIPE_BUSY on the SMBtrans request + * from NT4 servers. (See bug #8195) */ -#define TSTREAM_CLI_NP_BUF_SIZE 1024 +#define TSTREAM_CLI_NP_BUF_SIZE 4280 struct tstream_cli_np { struct cli_state *cli; -- 1.7.4.1 From 0a6b4bb2cb99a3984a0821f327df8c3a8172cf7d Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Tue, 7 Jun 2011 18:45:54 +0200 Subject: [PATCH 2/3] s3:libsmb:cli_np_tstream: use dynamic talloc buffers Having 8192 bytes on an idle connection is a bit to much, so we better use dynamic buffers using talloc, which also avoids a memcpy in the common SMBtrans readv codepath. metze --- source3/libsmb/cli_np_tstream.c | 39 ++++++++++++++++++++++++++++++--------- 1 files changed, 30 insertions(+), 9 deletions(-) diff --git a/source3/libsmb/cli_np_tstream.c b/source3/libsmb/cli_np_tstream.c index 5e11a92..13223858 100644 --- a/source3/libsmb/cli_np_tstream.c +++ b/source3/libsmb/cli_np_tstream.c @@ -63,7 +63,7 @@ struct tstream_cli_np { struct { off_t ofs; size_t left; - uint8_t buf[TSTREAM_CLI_NP_BUF_SIZE]; + uint8_t *buf; } read, write; }; @@ -363,9 +363,26 @@ static void tstream_cli_np_writev_write_next(struct tevent_req *req) tstream_context_data(state->stream, struct tstream_cli_np); struct tevent_req *subreq; + size_t i; + size_t left = 0; + + for (i=0; i < state->count; i++) { + left += state->vector[i].iov_len; + } + + if (left == 0) { + TALLOC_FREE(cli_nps->write.buf); + tevent_req_done(req); + return; + } cli_nps->write.ofs = 0; - cli_nps->write.left = TSTREAM_CLI_NP_BUF_SIZE; + cli_nps->write.left = MIN(left, TSTREAM_CLI_NP_BUF_SIZE); + cli_nps->write.buf = talloc_realloc(cli_nps, cli_nps->write.buf, + uint8_t, cli_nps->write.left); + if (tevent_req_nomem(cli_nps->write.buf, req)) { + return; + } /* * copy the pending buffer first @@ -391,11 +408,6 @@ static void tstream_cli_np_writev_write_next(struct tevent_req *req) state->ret += len; } - if (cli_nps->write.ofs == 0) { - tevent_req_done(req); - return; - } - if (cli_nps->trans.active && state->count == 0) { cli_nps->trans.active = false; cli_nps->trans.write_req = req; @@ -634,6 +646,10 @@ static void tstream_cli_np_readv_read_next(struct tevent_req *req) state->ret += len; } + if (cli_nps->read.left == 0) { + TALLOC_FREE(cli_nps->read.buf); + } + if (state->count == 0) { tevent_req_done(req); return; @@ -740,8 +756,7 @@ static void tstream_cli_np_readv_trans_done(struct tevent_req *subreq) cli_nps->read.ofs = 0; cli_nps->read.left = received; - memcpy(cli_nps->read.buf, rcvbuf, received); - TALLOC_FREE(rcvbuf); + cli_nps->read.buf = talloc_move(cli_nps, &rcvbuf); if (cli_nps->trans.write_req == NULL) { tstream_cli_np_readv_read_next(req); @@ -817,6 +832,12 @@ static void tstream_cli_np_readv_read_done(struct tevent_req *subreq) cli_nps->read.ofs = 0; cli_nps->read.left = received; + cli_nps->read.buf = talloc_array(cli_nps, uint8_t, received); + if (cli_nps->read.buf == NULL) { + TALLOC_FREE(subreq); + tevent_req_nomem(cli_nps->read.buf, req); + return; + } memcpy(cli_nps->read.buf, rcvbuf, received); TALLOC_FREE(subreq); -- 1.7.4.1 From 9e5d7ae45368d978fbcfaf4a72bb94684cf19b62 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Tue, 7 Jun 2011 18:49:55 +0200 Subject: [PATCH 3/3] s3:libsmb/cli_np_tstream: s/TSTREAM_CLI_NP_BUF_SIZE/TSTREAM_CLI_NP_MAX_BUF_SIZE This isn't the fixed buffer size anymore, as we use dynamic beffer it's just the maximum size. metze --- source3/libsmb/cli_np_tstream.c | 12 ++++++------ 1 files changed, 6 insertions(+), 6 deletions(-) diff --git a/source3/libsmb/cli_np_tstream.c b/source3/libsmb/cli_np_tstream.c index 13223858..7521181 100644 --- a/source3/libsmb/cli_np_tstream.c +++ b/source3/libsmb/cli_np_tstream.c @@ -45,7 +45,7 @@ static const struct tstream_context_ops tstream_cli_np_ops; * otherwise we may get NT_STATUS_PIPE_BUSY on the SMBtrans request * from NT4 servers. (See bug #8195) */ -#define TSTREAM_CLI_NP_BUF_SIZE 4280 +#define TSTREAM_CLI_NP_MAX_BUF_SIZE 4280 struct tstream_cli_np { struct cli_state *cli; @@ -377,7 +377,7 @@ static void tstream_cli_np_writev_write_next(struct tevent_req *req) } cli_nps->write.ofs = 0; - cli_nps->write.left = MIN(left, TSTREAM_CLI_NP_BUF_SIZE); + cli_nps->write.left = MIN(left, TSTREAM_CLI_NP_MAX_BUF_SIZE); cli_nps->write.buf = talloc_realloc(cli_nps, cli_nps->write.buf, uint8_t, cli_nps->write.left); if (tevent_req_nomem(cli_nps->write.buf, req)) { @@ -668,7 +668,7 @@ static void tstream_cli_np_readv_read_next(struct tevent_req *req) } subreq = cli_read_andx_send(state, state->ev, cli_nps->cli, - cli_nps->fnum, 0, TSTREAM_CLI_NP_BUF_SIZE); + cli_nps->fnum, 0, TSTREAM_CLI_NP_MAX_BUF_SIZE); if (tevent_req_nomem(subreq, req)) { return; } @@ -704,7 +704,7 @@ static void tstream_cli_np_readv_trans_start(struct tevent_req *req) NULL, 0, 0, cli_nps->write.buf, cli_nps->write.ofs, - TSTREAM_CLI_NP_BUF_SIZE); + TSTREAM_CLI_NP_MAX_BUF_SIZE); if (tevent_req_nomem(subreq, req)) { return; } @@ -744,7 +744,7 @@ static void tstream_cli_np_readv_trans_done(struct tevent_req *subreq) return; } - if (received > TSTREAM_CLI_NP_BUF_SIZE) { + if (received > TSTREAM_CLI_NP_MAX_BUF_SIZE) { tstream_cli_np_readv_disconnect_now(req, EIO, __location__); return; } @@ -818,7 +818,7 @@ static void tstream_cli_np_readv_read_done(struct tevent_req *subreq) return; } - if (received > TSTREAM_CLI_NP_BUF_SIZE) { + if (received > TSTREAM_CLI_NP_MAX_BUF_SIZE) { TALLOC_FREE(subreq); tstream_cli_np_readv_disconnect_now(req, EIO, __location__); return; -- 1.7.4.1