summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStefan Metzmacher <metze@samba.org>2011-06-08 10:31:23 +0200
committerJeremy Allison <jra@samba.org>2011-06-10 19:27:05 +0200
commit1dd24ac06a7472f53b06bc0aaa54cb22c8da0f78 (patch)
tree4dc38068ca62df77982326c09244152ee8f54211
parent10bb088cf1e005fd047c09afcf6b5b8999d416fe (diff)
downloadsamba-1dd24ac06a7472f53b06bc0aaa54cb22c8da0f78.tar.gz
samba-1dd24ac06a7472f53b06bc0aaa54cb22c8da0f78.tar.bz2
samba-1dd24ac06a7472f53b06bc0aaa54cb22c8da0f78.zip
s3:libsmb/clitrans: fix handling of multi pdu [nt]trans[s][2] calls
We now keep the primary request open for the whole logical request. The primary request is the one that gets all incoming replies. While secondary requests are handled as separate one-way requests. metze
-rw-r--r--source3/libsmb/clitrans.c88
1 files changed, 80 insertions, 8 deletions
diff --git a/source3/libsmb/clitrans.c b/source3/libsmb/clitrans.c
index cf1f725186..e23598ccbb 100644
--- a/source3/libsmb/clitrans.c
+++ b/source3/libsmb/clitrans.c
@@ -56,8 +56,26 @@ struct cli_trans_state {
uint8_t pad[4];
uint8_t zero_pad[4];
uint16_t vwv[32];
+
+ struct tevent_req *primary_subreq;
};
+static void cli_trans_cleanup_primary(struct cli_trans_state *state)
+{
+ if (state->primary_subreq) {
+ cli_smb_req_set_mid(state->primary_subreq, 0);
+ cli_smb_req_unset_pending(state->primary_subreq);
+ cli_state_seqnum_remove(state->cli, state->mid);
+ TALLOC_FREE(state->primary_subreq);
+ }
+}
+
+static int cli_trans_state_destructor(struct cli_trans_state *state)
+{
+ cli_trans_cleanup_primary(state);
+ return 0;
+}
+
static NTSTATUS cli_pull_trans(uint8_t *inbuf,
uint8_t wct, uint16_t *vwv,
uint16_t num_bytes, uint8_t *bytes,
@@ -456,11 +474,16 @@ struct tevent_req *cli_trans_send(
* (including correct SMB signing).
*/
state->mid = cli_smb_req_mid(subreq);
+ cli_smb_req_set_mid(subreq, state->mid);
cli_state_seqnum_persistent(cli, state->mid);
+ state->primary_subreq = subreq;
+ talloc_set_destructor(state, cli_trans_state_destructor);
return req;
}
+static void cli_trans_done2(struct tevent_req *subreq);
+
static void cli_trans_done(struct tevent_req *subreq)
{
struct tevent_req *req = tevent_req_callback_data(
@@ -518,8 +541,6 @@ static void cli_trans_done(struct tevent_req *subreq)
int iov_count;
struct tevent_req *subreq2;
- TALLOC_FREE(subreq);
-
cli_trans_format(state, &wct, &iov_count);
subreq2 = cli_smb_req_create(state, state->ev, state->cli,
@@ -561,23 +582,72 @@ static void cli_trans_done(struct tevent_req *subreq)
if ((state->rparam.total == state->rparam.received)
&& (state->rdata.total == state->rdata.received)) {
state->recv_flags2 = SVAL(inbuf, smb_flg2);
- TALLOC_FREE(subreq);
- cli_state_seqnum_remove(state->cli, state->mid);
+ cli_trans_cleanup_primary(state);
tevent_req_done(req);
return;
}
TALLOC_FREE(inbuf);
- if (!cli_smb_req_set_pending(subreq)) {
- status = NT_STATUS_NO_MEMORY;
+ return;
+
+ fail:
+ cli_trans_cleanup_primary(state);
+ tevent_req_nterror(req, status);
+}
+
+static void cli_trans_done2(struct tevent_req *subreq2)
+{
+ struct tevent_req *req = tevent_req_callback_data(
+ subreq2, struct tevent_req);
+ struct cli_trans_state *state = tevent_req_data(
+ req, struct cli_trans_state);
+ NTSTATUS status;
+ bool sent_all;
+ uint8_t wct;
+
+ status = cli_smb_recv(subreq2, state, NULL, 0, &wct, NULL,
+ NULL, NULL);
+ TALLOC_FREE(subreq2);
+
+ if (!NT_STATUS_IS_OK(status)) {
goto fail;
}
+
+ if (wct != 0) {
+ status = NT_STATUS_INVALID_NETWORK_RESPONSE;
+ goto fail;
+ }
+
+ sent_all = ((state->param_sent == state->num_param)
+ && (state->data_sent == state->num_data));
+
+ if (!sent_all) {
+ int iov_count;
+
+ cli_trans_format(state, &wct, &iov_count);
+
+ subreq2 = cli_smb_req_create(state, state->ev, state->cli,
+ state->cmd + 1, 0, wct, state->vwv,
+ iov_count, state->iov);
+ if (tevent_req_nomem(subreq2, req)) {
+ return;
+ }
+ cli_smb_req_set_mid(subreq2, state->mid);
+
+ status = cli_smb_req_send(subreq2);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ goto fail;
+ }
+ tevent_req_set_callback(subreq2, cli_trans_done2, req);
+ return;
+ }
+
return;
fail:
- cli_state_seqnum_remove(state->cli, state->mid);
- TALLOC_FREE(subreq);
+ cli_trans_cleanup_primary(state);
tevent_req_nterror(req, status);
}
@@ -594,6 +664,8 @@ NTSTATUS cli_trans_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
req, struct cli_trans_state);
NTSTATUS status;
+ cli_trans_cleanup_primary(state);
+
if (tevent_req_is_nterror(req, &status)) {
return status;
}