summaryrefslogtreecommitdiff
path: root/source3
diff options
context:
space:
mode:
Diffstat (limited to 'source3')
-rw-r--r--source3/libsmb/smb2cli_base.c92
1 files changed, 64 insertions, 28 deletions
diff --git a/source3/libsmb/smb2cli_base.c b/source3/libsmb/smb2cli_base.c
index 1b5a8a6798..ac7d423b57 100644
--- a/source3/libsmb/smb2cli_base.c
+++ b/source3/libsmb/smb2cli_base.c
@@ -139,6 +139,36 @@ static bool smb2cli_req_set_pending(struct tevent_req *req)
return true;
}
+static void smb2cli_notify_pending(struct cli_state *cli, NTSTATUS status)
+{
+ if (cli->fd != -1) {
+ close(cli->fd);
+ cli->fd = -1;
+ }
+
+ /*
+ * Cancel all pending requests. We don't do a for-loop walking
+ * cli->pending because that array changes in
+ * cli_smb_req_destructor().
+ */
+ while (talloc_array_length(cli->pending) > 0) {
+ struct tevent_req *req;
+ struct smb2cli_req_state *state;
+
+ req = cli->pending[0];
+ state = tevent_req_data(req, struct smb2cli_req_state);
+
+ smb2cli_req_unset_pending(req);
+
+ /*
+ * we need to defer the callback, because we may notify more
+ * then one caller.
+ */
+ tevent_req_defer_callback(req, state->ev);
+ tevent_req_nterror(req, status);
+ }
+}
+
struct tevent_req *smb2cli_req_create(TALLOC_CTX *mem_ctx,
struct tevent_context *ev,
struct cli_state *cli,
@@ -312,11 +342,8 @@ static void smb2cli_writev_done(struct tevent_req *subreq)
nwritten = writev_recv(subreq, &err);
TALLOC_FREE(subreq);
if (nwritten == -1) {
- if (state->cli->fd != -1) {
- close(state->cli->fd);
- state->cli->fd = -1;
- }
- tevent_req_nterror(req, map_nt_error_from_unix(err));
+ /* here, we need to notify all pending requests */
+ smb2cli_notify_pending(state->cli, map_nt_error_from_unix(err));
return;
}
}
@@ -457,18 +484,28 @@ static void smb2cli_inbuf_received(struct tevent_req *subreq)
received = read_smb_recv(subreq, frame, &inbuf, &err);
TALLOC_FREE(subreq);
if (received == -1) {
- if (cli->fd != -1) {
- close(cli->fd);
- cli->fd = -1;
- }
- status = map_nt_error_from_unix(err);
- goto fail;
+ /*
+ * We need to close the connection and notify
+ * all pending requests.
+ */
+ smb2cli_notify_pending(cli, map_nt_error_from_unix(err));
+ TALLOC_FREE(frame);
+ return;
}
status = smb2cli_inbuf_parse_compound(inbuf, frame,
&iov, &num_iov);
if (!NT_STATUS_IS_OK(status)) {
- goto fail;
+ /*
+ * if we cannot parse the incoming pdu,
+ * the connection becomes unusable.
+ *
+ * We need to close the connection and notify
+ * all pending requests.
+ */
+ smb2cli_notify_pending(cli, status);
+ TALLOC_FREE(frame);
+ return;
}
for (i=1; i<num_iov; i+=3) {
@@ -481,14 +518,27 @@ static void smb2cli_inbuf_received(struct tevent_req *subreq)
cli, BVAL(inhdr, SMB2_HDR_MESSAGE_ID));
if (req == NULL) {
/*
- * oplock breaks ??
+ * TODO: handle oplock breaks and async responses
+ */
+
+ /*
+ * We need to close the connection and notify
+ * all pending requests.
*/
- goto fail;
+ smb2cli_notify_pending(cli, status);
+ TALLOC_FREE(frame);
+ return;
}
smb2cli_req_unset_pending(req);
state = tevent_req_data(req, struct smb2cli_req_state);
/*
+ * There might be more than one response
+ * we need to defer the notifications
+ */
+ tevent_req_defer_callback(req, state->ev);
+
+ /*
* Note: here we use talloc_reference() in a way
* that does not expose it to the caller.
*/
@@ -506,20 +556,6 @@ static void smb2cli_inbuf_received(struct tevent_req *subreq)
}
TALLOC_FREE(frame);
- return;
- fail:
- /*
- * Cancel all pending requests. We don't do a for-loop walking
- * cli->pending because that array changes in
- * cli_smb_req_destructor().
- */
- while (talloc_array_length(cli->pending) > 0) {
- req = cli->pending[0];
- smb2cli_req_unset_pending(req);
- tevent_req_nterror(req, status);
- }
-
- TALLOC_FREE(frame);
}
NTSTATUS smb2cli_req_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,