[SCM] Samba Shared Repository - branch master updated

Stefan Metzmacher metze at samba.org
Sat Jul 9 05:56:01 MDT 2011


The branch, master has been updated
       via  244c856 s3:smb2cli_base: ask for the next response if there're still pending requests
       via  8b4a368 s3:smb2cli_base: make use of tevent_req_defer_callback()
       via  facc110 s3:smb2cli_base: fix memory hierachy in smb2cli_req_recv()
       via  504d092 s3:smb2cli_base: call smb2cli_req_unset_pending() before tevent_req_done()
       via  242ca5d s3:smb2cli_base: unset the destructor in smb2cli_req_unset_pending()
       via  c55bfc0 s3:smb2cli_base: keep the order of pending requests
       via  a9f03f1 s3:smb2cli_base: rename 'result' => 'req' in smb2cli_req_create()
      from  4768fc6 tevent: change version to 0.9.13 after adding tevent_req_defer_callback()

http://gitweb.samba.org/?p=samba.git;a=shortlog;h=master


- Log -----------------------------------------------------------------
commit 244c856cbfee2d08c0d47241daa7adb6a32f5f24
Author: Stefan Metzmacher <metze at samba.org>
Date:   Sat Jul 9 10:13:15 2011 +0200

    s3:smb2cli_base: ask for the next response if there're still pending requests
    
    metze
    
    Autobuild-User: Stefan Metzmacher <metze at samba.org>
    Autobuild-Date: Sat Jul  9 13:55:04 CEST 2011 on sn-devel-104

commit 8b4a3681e511adafe0efea3d64bad5135867477c
Author: Stefan Metzmacher <metze at samba.org>
Date:   Sat Jul 9 10:12:11 2011 +0200

    s3:smb2cli_base: make use of tevent_req_defer_callback()
    
    In order to notify requests of transport layer errors,
    we need to defer the triggering of the callbacks,
    otherwise we may crash, if one of the callbacks
    destroys the cli_state.
    
    metze

commit facc110c79b9ec4e3b0509ad6b00e1fd464d3a33
Author: Stefan Metzmacher <metze at samba.org>
Date:   Fri Jul 8 17:57:56 2011 +0200

    s3:smb2cli_base: fix memory hierachy in smb2cli_req_recv()
    
    We need to use talloc_reference() if there're more than one
    response, but we use it in a way that the caller can't
    call talloc_free() or talloc_unlink() on it.
    
    metze

commit 504d092aa7d83304373b001cbe68c65a62a824bb
Author: Stefan Metzmacher <metze at samba.org>
Date:   Sat Jul 9 10:42:21 2011 +0200

    s3:smb2cli_base: call smb2cli_req_unset_pending() before tevent_req_done()
    
    metze

commit 242ca5dba35ba282ddfe96751120810eadb4de8e
Author: Stefan Metzmacher <metze at samba.org>
Date:   Sat Jul 9 10:40:30 2011 +0200

    s3:smb2cli_base: unset the destructor in smb2cli_req_unset_pending()
    
    metze

commit c55bfc0733dd4be99c17ff8ee60c8e669c12bc3f
Author: Stefan Metzmacher <metze at samba.org>
Date:   Sat Jul 9 09:51:33 2011 +0200

    s3:smb2cli_base: keep the order of pending requests
    
    metze

commit a9f03f198292f9e88647c3e2c3491e68bab3e9cf
Author: Stefan Metzmacher <metze at samba.org>
Date:   Fri Jul 8 17:59:51 2011 +0200

    s3:smb2cli_base: rename 'result' => 'req' in smb2cli_req_create()
    
    metze

-----------------------------------------------------------------------

Summary of changes:
 source3/libsmb/smb2cli_base.c            |  190 +++++++++++++++++++++---------
 source3/libsmb/smb2cli_base.h            |    1 -
 source3/libsmb/smb2cli_query_directory.c |    9 +-
 source3/libsmb/smb2cli_read.c            |    9 +-
 4 files changed, 142 insertions(+), 67 deletions(-)


Changeset truncated at 500 lines:

diff --git a/source3/libsmb/smb2cli_base.c b/source3/libsmb/smb2cli_base.c
index 318f1a2..8760c30 100644
--- a/source3/libsmb/smb2cli_base.c
+++ b/source3/libsmb/smb2cli_base.c
@@ -37,7 +37,7 @@ struct smb2cli_req_state {
 	uint8_t hdr[64];
 	uint8_t pad[7];	/* padding space for compounding */
 
-	uint8_t *inbuf;
+	/* always an array of 3 talloc elements */
 	struct iovec *recv_iov;
 };
 
@@ -50,6 +50,8 @@ static void smb2cli_req_unset_pending(struct tevent_req *req)
 	int num_pending = talloc_array_length(cli->pending);
 	int i;
 
+	talloc_set_destructor(req, NULL);
+
 	if (num_pending == 1) {
 		/*
 		 * The pending read_smb tevent_req is a child of
@@ -77,8 +79,8 @@ static void smb2cli_req_unset_pending(struct tevent_req *req)
 	/*
 	 * Remove ourselves from the cli->pending array
 	 */
-	if (num_pending > 1) {
-		cli->pending[i] = cli->pending[num_pending-1];
+	for (; i < (num_pending - 1); i++) {
+		cli->pending[i] = cli->pending[i+1];
 	}
 
 	/*
@@ -137,27 +139,63 @@ 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,
-				       uint16_t cmd,
-				       uint32_t flags,
-				       const uint8_t *fixed,
-				       uint16_t fixed_len,
-				       const uint8_t *dyn,
-				       uint16_t dyn_len)
+				      struct tevent_context *ev,
+				      struct cli_state *cli,
+				      uint16_t cmd,
+				      uint32_t flags,
+				      const uint8_t *fixed,
+				      uint16_t fixed_len,
+				      const uint8_t *dyn,
+				      uint16_t dyn_len)
 {
-	struct tevent_req *result;
+	struct tevent_req *req;
 	struct smb2cli_req_state *state;
 
-	result = tevent_req_create(mem_ctx, &state,
-				   struct smb2cli_req_state);
-	if (result == NULL) {
+	req = tevent_req_create(mem_ctx, &state,
+				struct smb2cli_req_state);
+	if (req == NULL) {
 		return NULL;
 	}
 	state->ev = ev;
 	state->cli = cli;
 
+	state->recv_iov = talloc_zero_array(state, struct iovec, 3);
+	if (state->recv_iov == NULL) {
+		TALLOC_FREE(req);
+		return NULL;
+	}
+
 	state->fixed = fixed;
 	state->fixed_len = fixed_len;
 	state->dyn = dyn;
@@ -174,7 +212,7 @@ struct tevent_req *smb2cli_req_create(TALLOC_CTX *mem_ctx,
 	SIVAL(state->hdr, SMB2_HDR_TID,		cli->smb2.tid);
 	SBVAL(state->hdr, SMB2_HDR_SESSION_ID,	cli->smb2.uid);
 
-	return result;
+	return req;
 }
 
 static void smb2cli_writev_done(struct tevent_req *subreq);
@@ -304,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;
 	}
 }
@@ -437,65 +472,110 @@ static void smb2cli_inbuf_received(struct tevent_req *subreq)
 	struct cli_state *cli =
 		tevent_req_callback_data(subreq,
 		struct cli_state);
+	TALLOC_CTX *frame = talloc_stackframe();
 	struct tevent_req *req;
+	struct smb2cli_req_state *state;
 	struct iovec *iov;
 	int i, num_iov;
 	NTSTATUS status;
 	uint8_t *inbuf;
 	ssize_t received;
 	int err;
+	size_t num_pending;
 
-	received = read_smb_recv(subreq, talloc_tos(), &inbuf, &err);
+	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, talloc_tos(),
+	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) {
+		uint8_t *inbuf_ref = NULL;
 		struct iovec *cur = &iov[i];
 		uint8_t *inhdr = (uint8_t *)cur[0].iov_base;
-		struct smb2cli_req_state *state;
 
 		req = cli_smb2_find_pending(
 			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);
-		if (i+3 >= num_iov) {
-			/* last in chain */
-			state->inbuf = inbuf;
+
+		/*
+		 * 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.
+		 */
+		inbuf_ref = talloc_reference(state->recv_iov, inbuf);
+		if (tevent_req_nomem(inbuf_ref, req)) {
+			continue;
 		}
-		state->recv_iov = cur;
+
+		/* copy the related buffers */
+		state->recv_iov[0] = cur[0];
+		state->recv_iov[1] = cur[1];
+		state->recv_iov[2] = cur[2];
+
 		tevent_req_done(req);
 	}
-	return;
- fail:
+
+	TALLOC_FREE(frame);
+
+	num_pending = talloc_array_length(cli->pending);
+	if (num_pending == 0) {
+		/* no more pending requests, so we are done for now */
+		return;
+	}
+	req = cli->pending[0];
+	state = tevent_req_data(req, struct smb2cli_req_state);
+
 	/*
-	 * Cancel all pending requests. We don't do a for-loop walking
-	 * cli->pending because that array changes in
-	 * cli_smb_req_destructor().
+	 * add the read_smb request that waits for the
+	 * next answer from the server
 	 */
-	while (talloc_array_length(cli->pending) > 0) {
-		req = cli->pending[0];
-		talloc_set_destructor(req, NULL);
-		smb2cli_req_destructor(req);
-		tevent_req_nterror(req, status);
+	subreq = read_smb_send(cli->pending, state->ev, cli->fd);
+	if (subreq == NULL) {
+		smb2cli_notify_pending(cli, NT_STATUS_NO_MEMORY);
+		return;
 	}
+	tevent_req_set_callback(subreq, smb2cli_inbuf_received, cli);
 }
 
 NTSTATUS smb2cli_req_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
@@ -509,23 +589,17 @@ NTSTATUS smb2cli_req_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
 	if (tevent_req_is_nterror(req, &status)) {
 		return status;
 	}
+
+	status = NT_STATUS(IVAL(state->recv_iov[0].iov_base, SMB2_HDR_STATUS));
+
 	if (body_size != 0) {
 		if (body_size != SVAL(state->recv_iov[1].iov_base, 0)) {
 			return NT_STATUS_INVALID_NETWORK_RESPONSE;
 		}
 	}
-	talloc_steal(req, state->inbuf);
 	if (piov != NULL) {
-		*piov = state->recv_iov;
+		*piov = talloc_move(mem_ctx, &state->recv_iov);
 	}
 
-	return NT_STATUS(IVAL(state->recv_iov[0].iov_base, SMB2_HDR_STATUS));
-}
-
-uint8_t *smb2cli_req_inbuf(struct tevent_req *req)
-{
-	struct smb2cli_req_state *state = tevent_req_data(
-		req, struct smb2cli_req_state);
-
-	return state->inbuf;
+	return status;
 }
diff --git a/source3/libsmb/smb2cli_base.h b/source3/libsmb/smb2cli_base.h
index 09a6b7f..9c49a8c 100644
--- a/source3/libsmb/smb2cli_base.h
+++ b/source3/libsmb/smb2cli_base.h
@@ -42,6 +42,5 @@ struct tevent_req *smb2cli_req_send(TALLOC_CTX *mem_ctx,
 				    uint16_t dyn_len);
 NTSTATUS smb2cli_req_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
 			  struct iovec **piov, int body_size);
-uint8_t *smb2cli_req_inbuf(struct tevent_req *req);
 
 #endif
diff --git a/source3/libsmb/smb2cli_query_directory.c b/source3/libsmb/smb2cli_query_directory.c
index fc6c0b7..554b267 100644
--- a/source3/libsmb/smb2cli_query_directory.c
+++ b/source3/libsmb/smb2cli_query_directory.c
@@ -27,7 +27,7 @@
 
 struct smb2cli_query_directory_state {
 	uint8_t fixed[32];
-	uint8_t *inbuf;
+	struct iovec *recv_iov;
 	uint8_t *data;
 	uint32_t data_length;
 };
@@ -97,7 +97,7 @@ static void smb2cli_query_directory_done(struct tevent_req *subreq)
 	struct iovec *iov;
 	uint16_t data_offset;
 
-	status = smb2cli_req_recv(subreq, talloc_tos(), &iov, 9);
+	status = smb2cli_req_recv(subreq, state, &iov, 9);
 	if (tevent_req_nterror(req, status)) {
 		return;
 	}
@@ -110,7 +110,8 @@ static void smb2cli_query_directory_done(struct tevent_req *subreq)
 		tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
 		return;
 	}
-	state->inbuf = smb2cli_req_inbuf(subreq);
+
+	state->recv_iov = iov;
 	state->data = (uint8_t *)iov[2].iov_base;
 	tevent_req_done(req);
 }
@@ -128,7 +129,7 @@ NTSTATUS smb2cli_query_directory_recv(struct tevent_req *req,
 	if (tevent_req_is_nterror(req, &status)) {
 		return status;
 	}
-	talloc_steal(mem_ctx, state->inbuf);
+	talloc_steal(mem_ctx, state->recv_iov);
 	*data_length = state->data_length;
 	*data = state->data;
 	return NT_STATUS_OK;
diff --git a/source3/libsmb/smb2cli_read.c b/source3/libsmb/smb2cli_read.c
index 79224e5..c348c99 100644
--- a/source3/libsmb/smb2cli_read.c
+++ b/source3/libsmb/smb2cli_read.c
@@ -27,7 +27,7 @@
 
 struct smb2cli_read_state {
 	uint8_t fixed[48];
-	uint8_t *inbuf;
+	struct iovec *recv_iov;
 	uint8_t *data;
 	uint32_t data_length;
 };
@@ -85,7 +85,7 @@ static void smb2cli_read_done(struct tevent_req *subreq)
 	struct iovec *iov;
 	uint8_t data_offset;
 
-	status = smb2cli_req_recv(subreq, talloc_tos(), &iov, 17);
+	status = smb2cli_req_recv(subreq, state, &iov, 17);
 	if (tevent_req_nterror(req, status)) {
 		return;
 	}
@@ -98,7 +98,8 @@ static void smb2cli_read_done(struct tevent_req *subreq)
 		tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
 		return;
 	}
-	state->inbuf = smb2cli_req_inbuf(subreq);
+
+	state->recv_iov = iov;
 	state->data = (uint8_t *)iov[2].iov_base;
 	tevent_req_done(req);
 }
@@ -114,7 +115,7 @@ NTSTATUS smb2cli_read_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
 	if (tevent_req_is_nterror(req, &status)) {
 		return status;
 	}
-	talloc_steal(mem_ctx, state->inbuf);
+	talloc_steal(mem_ctx, state->recv_iov);
 	*data_length = state->data_length;
 	*data = state->data;
 	return NT_STATUS_OK;


-- 
Samba Shared Repository


More information about the samba-cvs mailing list