[SCM] Samba Shared Repository - branch v3-devel updated - release-3-2-0pre2-3854-gce3dc9f

Volker Lendecke vlendec at samba.org
Thu Aug 28 16:30:57 GMT 2008


The branch, v3-devel has been updated
       via  ce3dc9f616cafc1289a94ac7cae0beca967d836e (commit)
       via  c1d645fbe39433541d8bfe6b818c855cee318dc5 (commit)
       via  cb2e338eb33dfb4627f9b43456af0c86d7d268c6 (commit)
       via  82992d74a99b056bbfe90e1b79190e0b7c0bf2bd (commit)
       via  b4c539ba041bab8856c83816f08a35b5f5b21740 (commit)
       via  2ecc311f785317caf5b60051147dcd085c80d64f (commit)
       via  253134d3aaa359fdfb665709dd5686f69af7f8fd (commit)
       via  debb37f703075008e5ea7d34d214cfa4d0f8f916 (commit)
       via  faf353edd60967efac4d5c222db14fa730866273 (commit)
       via  f84a2b5dbf8a072a9e356fa39523f65d042a2643 (commit)
       via  7e73dd4e7622db64d30d48ba106892e0895fc188 (commit)
      from  5eee7423351ffd05486e33ff8eb905babcbc9422 (commit)

http://gitweb.samba.org/?p=samba.git;a=shortlog;h=v3-devel


- Log -----------------------------------------------------------------
commit ce3dc9f616cafc1289a94ac7cae0beca967d836e
Author: Volker Lendecke <vl at samba.org>
Date:   Thu Aug 28 15:44:14 2008 +0200

    Remove cli_request_get()
    
    req->private_data==NULL at this point is definitely a bug.

commit c1d645fbe39433541d8bfe6b818c855cee318dc5
Author: Volker Lendecke <vl at samba.org>
Date:   Wed Aug 27 19:30:57 2008 +0200

    Add async smbecho client support

commit cb2e338eb33dfb4627f9b43456af0c86d7d268c6
Author: Volker Lendecke <vl at samba.org>
Date:   Wed Aug 27 19:26:40 2008 +0200

    Add cli_request->recv_helper
    
    Necessary for requests with multiple replies

commit 82992d74a99b056bbfe90e1b79190e0b7c0bf2bd
Author: Volker Lendecke <vl at samba.org>
Date:   Mon Aug 25 15:59:36 2008 +0200

    Activate code to enable chained requests
    
    Add the CHAIN1 torture test

commit b4c539ba041bab8856c83816f08a35b5f5b21740
Author: Volker Lendecke <vl at samba.org>
Date:   Mon Aug 25 15:56:26 2008 +0200

    This adds the code to allow chained requests in libsmb/
    
    This is not compiled yet, but it makes the patches much easier to read if it is
    add in bulk.

commit 2ecc311f785317caf5b60051147dcd085c80d64f
Author: Volker Lendecke <vl at samba.org>
Date:   Mon Aug 25 14:40:15 2008 +0200

    Move "struct cli_request" from client.h to async_smb.h
    
    Also add some comments

commit 253134d3aaa359fdfb665709dd5686f69af7f8fd
Author: Volker Lendecke <vl at samba.org>
Date:   Mon Aug 25 13:33:41 2008 +0200

    Add cli_pull_reply
    
    Along the lines of cli_request_send this abstracts away the smb-level buffer
    handling when parsing replies we got from the server.

commit debb37f703075008e5ea7d34d214cfa4d0f8f916
Author: Volker Lendecke <vl at samba.org>
Date:   Sun Aug 24 14:17:43 2008 +0200

    Remove cli->event_ctx, pass it explicitly
    
    Storing the event_context as permanent state in struct cli_state creates more
    complex code than necessary IMO.

commit faf353edd60967efac4d5c222db14fa730866273
Author: Volker Lendecke <vl at samba.org>
Date:   Sat Aug 2 18:44:39 2008 +0200

    Add async open&x

commit f84a2b5dbf8a072a9e356fa39523f65d042a2643
Author: Volker Lendecke <vl at samba.org>
Date:   Fri Aug 1 23:18:15 2008 +0200

    Add async cli_close

commit 7e73dd4e7622db64d30d48ba106892e0895fc188
Author: Volker Lendecke <vl at samba.org>
Date:   Fri Aug 1 23:14:51 2008 +0200

    Refactoring: Add the routine cli_request_send()
    
    cli_request_send() is supposed to bundle all generic SMB-header handling. This
    makes cli_request_new static to async_smb.c.

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

Summary of changes:
 source/client/client.c       |   10 +-
 source/include/async_smb.h   |  126 +++++++--
 source/include/client.h      |   41 +--
 source/include/proto.h       |   34 +--
 source/libsmb/async_smb.c    |  697 +++++++++++++++++++++++++++++++++++-------
 source/libsmb/clientgen.c    |  166 +++++++++--
 source/libsmb/clifile.c      |  233 +++++++++++---
 source/libsmb/clireadwrite.c |  129 ++++----
 source/torture/torture.c     |  113 +++++++
 9 files changed, 1230 insertions(+), 319 deletions(-)


Changeset truncated at 500 lines:

diff --git a/source/client/client.c b/source/client/client.c
index 18b2863..1c0dff9 100644
--- a/source/client/client.c
+++ b/source/client/client.c
@@ -943,6 +943,7 @@ static int cmd_echo(void)
 	TALLOC_CTX *ctx = talloc_tos();
 	char *num;
 	char *data;
+	NTSTATUS status;
 
 	if (!next_token_talloc(ctx, &cmd_ptr, &num, NULL)
 	    || !next_token_talloc(ctx, &cmd_ptr, &data, NULL)) {
@@ -950,9 +951,10 @@ static int cmd_echo(void)
 		return 1;
 	}
 
-	if (!cli_echo(cli, atoi(num), (uint8 *)data, strlen(data))) {
-		d_printf("echo failed: %s\n",
-			 nt_errstr(cli_get_nt_error(cli)));
+	status = cli_echo(cli, atoi(num), data_blob_const(data, strlen(data)));
+
+	if (!NT_STATUS_IS_OK(status)) {
+		d_printf("echo failed: %s\n", nt_errstr(status));
 		return 1;
 	}
 
@@ -4417,7 +4419,7 @@ static void readline_callback(void)
 	{
 		unsigned char garbage[16];
 		memset(garbage, 0xf0, sizeof(garbage));
-		cli_echo(cli, 1, garbage, sizeof(garbage));
+		cli_echo(cli, 1, data_blob_const(garbage, sizeof(garbage)));
 	}
 }
 
diff --git a/source/include/async_smb.h b/source/include/async_smb.h
index 19408be..e9e1002 100644
--- a/source/include/async_smb.h
+++ b/source/include/async_smb.h
@@ -17,23 +17,117 @@
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
 
+#ifndef __ASYNC_SMB_H__
+#define __ASYNC_SMB_H__
+
 #include "includes.h"
 
-/*
- * Create a fresh async smb request
+/**
+ * struct cli_request is the state holder for an async client request we sent
+ * to the server. It can consist of more than one struct async_req that we
+ * have to server if the application did a cli_chain_cork() and
+ * cli_chain_uncork()
  */
 
-struct async_req *cli_request_new(TALLOC_CTX *mem_ctx,
-				  struct event_context *ev,
-				  struct cli_state *cli,
-				  uint8_t num_words, size_t num_bytes,
-				  struct cli_request **preq);
+struct cli_request {
+	/**
+	 * "prev" and "next" form the doubly linked list in
+	 * cli_state->outstanding_requests
+	 */
+	struct cli_request *prev, *next;
+
+	/**
+	 * num_async: How many chained requests do we serve?
+	 */
+	int num_async;
+
+	/**
+	 * async: This is the list of chained requests that were queued up by
+	 * cli_request_chain before we sent out this request
+	 */
+	struct async_req **async;
+
+	/**
+	 * The client connection for this request
+	 */
+	struct cli_state *cli;
+
+	/**
+	 * The enc_state to decrypt the reply
+	 */
+	struct smb_trans_enc_state *enc_state;
+
+	/**
+	 * The mid we used for this request. Mainly used to demultiplex on
+	 * receiving replies.
+	 */
+	uint16_t mid;
+
+	/**
+	 * The bytes we have to ship to the server
+	 */
+	char *outbuf;
+
+	/**
+	 * How much from "outbuf" did we already send
+	 */
+	size_t sent;
+
+	/**
+	 * The reply comes in here. Its intended size is implicit by
+	 * smb_len(), its current size can be read via talloc_get_size()
+	 */
+	char *inbuf;
+
+	/**
+	 * Specific requests might add stuff here. Maybe convert this to a
+	 * private_pointer at some point.
+	 */
+	union {
+		struct {
+			off_t ofs;
+			size_t size;
+			ssize_t received;
+			uint8_t *rcvbuf;
+		} read;
+		struct {
+			DATA_BLOB data;
+			uint16_t num_echos;
+		} echo;
+	} data;
+
+	/**
+	 * For requests that don't follow the strict request/reply pattern
+	 * such as the transaction request family and echo requests it is
+	 * necessary to break the standard procedure in
+	 * handle_incoming_pdu(). For a simple example look at
+	 * cli_echo_recv_helper().
+	 */
+	struct {
+		void (*fn)(struct async_req *req);
+		void *priv;
+	} recv_helper;
+};
 
 /*
- * Convenience function to get the SMB part out of an async_req
+ * Ship a new smb request to the server
  */
 
-struct cli_request *cli_request_get(struct async_req *req);
+struct async_req *cli_request_send(TALLOC_CTX *mem_ctx,
+				   struct event_context *ev,
+				   struct cli_state *cli,
+				   uint8_t smb_command,
+				   uint8_t additional_flags,
+				   uint8_t wct, const uint16_t *vwv,
+				   uint16_t num_bytes, const uint8_t *bytes);
+
+bool cli_chain_cork(struct cli_state *cli, struct event_context *ev,
+		    size_t size_hint);
+void cli_chain_uncork(struct cli_state *cli);
+
+NTSTATUS cli_pull_reply(struct async_req *req,
+			uint8_t *pwct, uint16_t **pvwv,
+			uint16_t *pnum_bytes, uint8_t **pbytes);
 
 /*
  * Fetch an error out of a NBT packet
@@ -47,16 +141,4 @@ NTSTATUS cli_pull_error(char *buf);
 
 void cli_set_error(struct cli_state *cli, NTSTATUS status);
 
-/*
- * Create a temporary event context for use in the sync helper functions
- */
-
-struct cli_tmp_event *cli_tmp_event_ctx(TALLOC_CTX *mem_ctx,
-					struct cli_state *cli);
-
-/*
- * Attach an event context permanently to a cli_struct
- */
-
-NTSTATUS cli_add_event_ctx(struct cli_state *cli,
-			   struct event_context *event_ctx);
+#endif
diff --git a/source/include/client.h b/source/include/client.h
index 51ced99..9b564fc 100644
--- a/source/include/client.h
+++ b/source/include/client.h
@@ -204,35 +204,28 @@ struct cli_state {
 	bool force_dos_errors;
 	bool case_sensitive; /* False by default. */
 
-	struct event_context *event_ctx;
+	/**
+	 * fd_event is around while we have async requests outstanding or are
+	 * building a chained request.
+	 *
+	 * (fd_event!=NULL) &&
+	 *  ((outstanding_request!=NULL)||(chain_accumulator!=NULL))
+	 *
+	 * should always be true, as well as the reverse: If both cli_request
+	 * pointers are NULL, no fd_event is around.
+	 */
 	struct fd_event *fd_event;
 	char *evt_inbuf;
 
+	/**
+	 * A linked list of requests that are waiting for a reply
+	 */
 	struct cli_request *outstanding_requests;
-};
-
-struct cli_request {
-	struct cli_request *prev, *next;
-	struct async_req *async;
-
-	struct cli_state *cli;
-
-	struct smb_trans_enc_state *enc_state;
 
-	uint16_t mid;
-
-	char *outbuf;
-	size_t sent;
-	char *inbuf;
-
-	union {
-		struct {
-			off_t ofs;
-			size_t size;
-			ssize_t received;
-			uint8_t *rcvbuf;
-		} read;
-	} data;
+	/**
+	 * The place to build up the list of chained requests.
+	 */
+	struct cli_request *chain_accumulator;
 };
 
 typedef struct file_info {
diff --git a/source/include/proto.h b/source/include/proto.h
index d5e942a..abfc790 100644
--- a/source/include/proto.h
+++ b/source/include/proto.h
@@ -4201,21 +4201,6 @@ bool asn1_write_enumerated(ASN1_DATA *data, uint8 v);
 bool ber_write_OID_String(DATA_BLOB *blob, const char *OID);
 bool ber_read_OID_String(TALLOC_CTX *mem_ctx, DATA_BLOB blob, const char **OID);
 
-/* The following definitions come from libsmb/async_smb.c  */
-
-NTSTATUS cli_pull_error(char *buf);
-void cli_set_error(struct cli_state *cli, NTSTATUS status);
-struct async_req *cli_request_new(TALLOC_CTX *mem_ctx,
-				  struct event_context *ev,
-				  struct cli_state *cli,
-				  uint8_t num_words, size_t num_bytes,
-				  struct cli_request **preq);
-struct cli_request *cli_request_get(struct async_req *req);
-struct cli_tmp_event *cli_tmp_event_ctx(TALLOC_CTX *mem_ctx,
-					struct cli_state *cli);
-NTSTATUS cli_add_event_ctx(struct cli_state *cli,
-			   struct event_context *event_ctx);
-
 /* The following definitions come from libsmb/cliconnect.c  */
 
 ADS_STATUS cli_session_setup_spnego(struct cli_state *cli, const char *user, 
@@ -4353,8 +4338,11 @@ void cli_sockopt(struct cli_state *cli, const char *options);
 uint16 cli_setpid(struct cli_state *cli, uint16 pid);
 bool cli_set_case_sensitive(struct cli_state *cli, bool case_sensitive);
 bool cli_send_keepalive(struct cli_state *cli);
-bool cli_echo(struct cli_state *cli, uint16 num_echos,
-	      unsigned char *data, size_t length);
+struct async_req *cli_echo_send(TALLOC_CTX *mem_ctx, struct event_context *ev,
+				struct cli_state *cli, uint16_t num_echos,
+				DATA_BLOB data);
+NTSTATUS cli_echo_recv(struct async_req *req);
+NTSTATUS cli_echo(struct cli_state *cli, uint16_t num_echos, DATA_BLOB data);
 
 /* The following definitions come from libsmb/clierror.c  */
 
@@ -4393,7 +4381,14 @@ int cli_nt_create_full(struct cli_state *cli, const char *fname,
 		 uint32 CreateDisposition, uint32 CreateOptions,
 		 uint8 SecuityFlags);
 int cli_nt_create(struct cli_state *cli, const char *fname, uint32 DesiredAccess);
+struct async_req *cli_open_send(TALLOC_CTX *mem_ctx, struct event_context *ev,
+				struct cli_state *cli,
+				const char *fname, int flags, int share_mode);
+NTSTATUS cli_open_recv(struct async_req *req, int *fnum);
 int cli_open(struct cli_state *cli, const char *fname, int flags, int share_mode);
+struct async_req *cli_close_send(TALLOC_CTX *mem_ctx, struct event_context *ev,
+				 struct cli_state *cli, int fnum);
+NTSTATUS cli_close_recv(struct async_req *req);
 bool cli_close(struct cli_state *cli, int fnum);
 bool cli_ftruncate(struct cli_state *cli, int fnum, uint64_t size);
 NTSTATUS cli_locktype(struct cli_state *cli, int fnum,
@@ -4627,11 +4622,14 @@ int cli_NetConnectionEnum(struct cli_state *cli, const char *qualifier,
 /* The following definitions come from libsmb/clireadwrite.c  */
 
 struct async_req *cli_read_andx_send(TALLOC_CTX *mem_ctx,
+				     struct event_context *ev,
 				     struct cli_state *cli, int fnum,
 				     off_t offset, size_t size);
 NTSTATUS cli_read_andx_recv(struct async_req *req, ssize_t *received,
 			    uint8_t **rcvbuf);
-struct async_req *cli_pull_send(TALLOC_CTX *mem_ctx, struct cli_state *cli,
+struct async_req *cli_pull_send(TALLOC_CTX *mem_ctx,
+				struct event_context *ev,
+				struct cli_state *cli,
 				uint16_t fnum, off_t start_offset,
 				SMB_OFF_T size, size_t window_size,
 				NTSTATUS (*sink)(char *buf, size_t n,
diff --git a/source/libsmb/async_smb.c b/source/libsmb/async_smb.c
index 58bba2b..79a924b 100644
--- a/source/libsmb/async_smb.c
+++ b/source/libsmb/async_smb.c
@@ -19,8 +19,13 @@
 
 #include "includes.h"
 
-/*
+static void cli_state_handler(struct event_context *event_ctx,
+			      struct fd_event *event, uint16 flags, void *p);
+
+/**
  * Fetch an error out of a NBT packet
+ * @param[in] buf	The SMB packet
+ * @retval		The error, converted to NTSTATUS
  */
 
 NTSTATUS cli_pull_error(char *buf)
@@ -40,8 +45,10 @@ NTSTATUS cli_pull_error(char *buf)
 	return NT_STATUS_DOS(CVAL(buf, smb_rcls), SVAL(buf,smb_err));
 }
 
-/*
+/**
  * Compatibility helper for the sync APIs: Fake NTSTATUS in cli->inbuf
+ * @param[in] cli	The client connection that just received an error
+ * @param[in] status	The error to set on "cli"
  */
 
 void cli_set_error(struct cli_state *cli, NTSTATUS status)
@@ -61,8 +68,10 @@ void cli_set_error(struct cli_state *cli, NTSTATUS status)
 	return;
 }
 
-/*
+/**
  * Allocate a new mid
+ * @param[in] cli	The client connection
+ * @retval		The new, unused mid
  */
 
 static uint16_t cli_new_mid(struct cli_state *cli)
@@ -88,10 +97,18 @@ static uint16_t cli_new_mid(struct cli_state *cli)
 	}
 }
 
+/**
+ * Print an async req that happens to be a cli_request
+ * @param[in] mem_ctx	The TALLOC_CTX to put the result on
+ * @param[in] req	The request to print
+ * @retval		The string representation of "req"
+ */
+
 static char *cli_request_print(TALLOC_CTX *mem_ctx, struct async_req *req)
 {
 	char *result = async_req_print(mem_ctx, req);
-	struct cli_request *cli_req = cli_request_get(req);
+	struct cli_request *cli_req = talloc_get_type_abort(
+		req->private_data, struct cli_request);
 
 	if (result == NULL) {
 		return NULL;
@@ -101,79 +118,560 @@ static char *cli_request_print(TALLOC_CTX *mem_ctx, struct async_req *req)
 		result, "mid=%d\n", cli_req->mid);
 }
 
+/**
+ * Destroy a cli_request
+ * @param[in] req	The cli_request to kill
+ * @retval Can't fail
+ */
+
 static int cli_request_destructor(struct cli_request *req)
 {
 	if (req->enc_state != NULL) {
 		common_free_enc_buffer(req->enc_state, req->outbuf);
 	}
 	DLIST_REMOVE(req->cli->outstanding_requests, req);
+	if (req->cli->outstanding_requests == NULL) {
+		TALLOC_FREE(req->cli->fd_event);
+	}
 	return 0;
 }
 
-/*
- * Create a fresh async smb request
+/**
+ * Is the SMB command able to hold an AND_X successor
+ * @param[in] cmd	The SMB command in question
+ * @retval Can we add a chained request after "cmd"?
  */
 
-struct async_req *cli_request_new(TALLOC_CTX *mem_ctx,
-				  struct event_context *ev,
-				  struct cli_state *cli,
-				  uint8_t num_words, size_t num_bytes,
-				  struct cli_request **preq)
+static bool is_andx_req(uint8_t cmd)
 {
-	struct async_req *result;
-	struct cli_request *cli_req;
-	size_t bufsize = smb_size + num_words * 2 + num_bytes;
+	switch (cmd) {
+	case SMBtconX:
+	case SMBlockingX:
+	case SMBopenX:
+	case SMBreadX:
+	case SMBwriteX:
+	case SMBsesssetupX:
+	case SMBulogoffX:
+	case SMBntcreateX:
+		return true;
+		break;
+	default:
+		break;
+	}
 
-	result = async_req_new(mem_ctx, ev);
-	if (result == NULL) {
+	return false;
+}
+
+/**
+ * @brief Find the smb_cmd offset of the last command pushed
+ * @param[in] buf	The buffer we're building up
+ * @retval		Where can we put our next andx cmd?
+ *
+ * While chaining requests, the "next" request we're looking at needs to put
+ * its SMB_Command before the data the previous request already built up added
+ * to the chain. Find the offset to the place where we have to put our cmd.
+ */
+
+static bool find_andx_cmd_ofs(char *buf, size_t *pofs)
+{
+	uint8_t cmd;
+	size_t ofs;
+
+	cmd = CVAL(buf, smb_com);
+
+	SMB_ASSERT(is_andx_req(cmd));
+
+	ofs = smb_vwv0;
+
+	while (CVAL(buf, ofs) != 0xff) {
+
+		if (!is_andx_req(CVAL(buf, ofs))) {
+			return false;
+		}
+
+		/*
+		 * ofs is from start of smb header, so add the 4 length
+		 * bytes. The next cmd is right after the wct field.
+		 */
+		ofs = SVAL(buf, ofs+2) + 4 + 1;
+
+		SMB_ASSERT(ofs+4 < talloc_get_size(buf));
+	}
+
+	*pofs = ofs;
+	return true;
+}
+
+/**
+ * @brief Destroy an async_req that is the visible part of a cli_request
+ * @param[in] req	The request to kill
+ * @retval Return 0 to make talloc happy
+ *
+ * This destructor is a bit tricky: Because a cli_request can host more than
+ * one async_req for chained requests, we need to make sure that the
+ * "cli_request" that we were part of is correctly destroyed at the right
+ * time. This is done by NULLing out ourself from the "async" member of our
+ * "cli_request". If there is none left, then also TALLOC_FREE() the
+ * cli_request, which was a talloc child of the client connection cli_state.
+ */
+
+static int cli_async_req_destructor(struct async_req *req)
+{
+	struct cli_request *cli_req = talloc_get_type_abort(
+		req->private_data, struct cli_request);
+	int i, pending;
+	bool found = false;
+
+	pending = 0;
+
+	for (i=0; i<cli_req->num_async; i++) {
+		if (cli_req->async[i] == req) {
+			cli_req->async[i] = NULL;


-- 
Samba Shared Repository


More information about the samba-cvs mailing list