diff options
Diffstat (limited to 'source3/libsmb/cli_np_tstream.c')
-rw-r--r-- | source3/libsmb/cli_np_tstream.c | 75 |
1 files changed, 55 insertions, 20 deletions
diff --git a/source3/libsmb/cli_np_tstream.c b/source3/libsmb/cli_np_tstream.c index 1f9e5ffd36..7521181ec8 100644 --- a/source3/libsmb/cli_np_tstream.c +++ b/source3/libsmb/cli_np_tstream.c @@ -19,7 +19,8 @@ #include "includes.h" #include "system/network.h" -#include "../util/tevent_unix.h" +#include "libsmb/libsmb.h" +#include "../lib/util/tevent_ntstatus.h" #include "../lib/tsocket/tsocket.h" #include "../lib/tsocket/tsocket_internal.h" #include "cli_np_tstream.h" @@ -27,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_MAX_BUF_SIZE 4280 struct tstream_cli_np { struct cli_state *cli; @@ -47,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; }; @@ -347,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_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)) { + return; + } /* * copy the pending buffer first @@ -375,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; @@ -478,9 +506,8 @@ static void tstream_cli_np_writev_disconnect_done(struct tevent_req *subreq) tevent_req_data(req, struct tstream_cli_np_writev_state); struct tstream_cli_np *cli_nps = tstream_context_data(state->stream, struct tstream_cli_np); - NTSTATUS status; - status = cli_close_recv(subreq); + cli_close_recv(subreq); TALLOC_FREE(subreq); cli_nps->cli = NULL; @@ -619,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; @@ -637,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; } @@ -673,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; } @@ -713,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; } @@ -725,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); @@ -788,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; @@ -802,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); @@ -852,9 +888,8 @@ static void tstream_cli_np_readv_disconnect_done(struct tevent_req *subreq) tevent_req_data(req, struct tstream_cli_np_readv_state); struct tstream_cli_np *cli_nps = tstream_context_data(state->stream, struct tstream_cli_np); - NTSTATUS status; - status = cli_close_recv(subreq); + cli_close_recv(subreq); TALLOC_FREE(subreq); cli_nps->cli = NULL; |