[SCM] Samba Shared Repository - branch master updated

Volker Lendecke vlendec at samba.org
Thu Jul 28 10:54:01 MDT 2011


The branch, master has been updated
       via  5812645 s3: Priorize the async echo responder over the client
       via  8374055 tevent: Slightly simplify poll_event_loop_poll
       via  4dd0a3b s3: Remove unused smbd_echo_reader()
       via  710e5d9 s3: Use smbd_echo_read_send in the async echo handler
       via  27afb89 s3: Add smbd_echo_read_send/recv
       via  4281967 Add wait_for_read_send/recv
      from  e84c7a2 s3-rpc_server: Use talloc for pipe_rpc_fns

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


- Log -----------------------------------------------------------------
commit 5812645f496e85d2178e7f0b9812c95ed651ded5
Author: Volker Lendecke <vl at samba.org>
Date:   Thu Jul 28 14:24:40 2011 +0200

    s3: Priorize the async echo responder over the client
    
    Without this, an active client connection can starve the echo responder. This
    leads to apparently "lost" SMBs.
    
    Autobuild-User: Volker Lendecke <vlendec at samba.org>
    Autobuild-Date: Thu Jul 28 18:53:38 CEST 2011 on sn-devel-104

commit 83740555ea8664da0830f88a1dd5afa69880bb40
Author: Volker Lendecke <vl at samba.org>
Date:   Thu Jul 28 14:09:13 2011 +0200

    tevent: Slightly simplify poll_event_loop_poll
    
    No real code change. Do an early return instead of an if-statement, avoiding
    one level of indentation.

commit 4dd0a3b5e29e3a39e90a425a827d6a17b9868ced
Author: Volker Lendecke <vl at samba.org>
Date:   Tue Jul 26 15:39:58 2011 +0200

    s3: Remove unused smbd_echo_reader()

commit 710e5d92562b2f43a20a33575ea0ec44e9b49a0a
Author: Volker Lendecke <vl at samba.org>
Date:   Tue Jul 26 15:39:29 2011 +0200

    s3: Use smbd_echo_read_send in the async echo handler

commit 27afb8910fabd51641d3e0129c16c7c1156f8541
Author: Volker Lendecke <vl at samba.org>
Date:   Tue Jul 26 15:07:22 2011 +0200

    s3: Add smbd_echo_read_send/recv
    
    Read a SMB packet in the echo responder, giving the parent one second to step
    in

commit 428196799028d80a5fe3b09392cb7015049c5397
Author: Volker Lendecke <vl at samba.org>
Date:   Tue Jul 26 15:06:44 2011 +0200

    Add wait_for_read_send/recv
    
    Wait for readability of a socket as a tevent_req

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

Summary of changes:
 lib/async_req/async_sock.c |   55 +++++++
 lib/async_req/async_sock.h |    5 +
 lib/tevent/tevent_poll.c   |   71 +++++-----
 source3/smbd/process.c     |  343 ++++++++++++++++++++++++++++++--------------
 4 files changed, 335 insertions(+), 139 deletions(-)


Changeset truncated at 500 lines:

diff --git a/lib/async_req/async_sock.c b/lib/async_req/async_sock.c
index dfb1a1c..811cf8d 100644
--- a/lib/async_req/async_sock.c
+++ b/lib/async_req/async_sock.c
@@ -667,3 +667,58 @@ ssize_t read_packet_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
 	*pbuf = talloc_move(mem_ctx, &state->buf);
 	return talloc_get_size(*pbuf);
 }
+
+struct wait_for_read_state {
+	struct tevent_req *req;
+	struct tevent_fd *fde;
+};
+
+static void wait_for_read_done(struct tevent_context *ev,
+			       struct tevent_fd *fde,
+			       uint16_t flags,
+			       void *private_data);
+
+struct tevent_req *wait_for_read_send(TALLOC_CTX *mem_ctx,
+				      struct tevent_context *ev,
+				      int fd)
+{
+	struct tevent_req *req;
+	struct wait_for_read_state *state;
+
+	req = tevent_req_create(mem_ctx, &state, struct wait_for_read_state);
+	if (req == NULL) {
+		return NULL;
+	}
+	state->req = req;
+	state->fde = tevent_add_fd(ev, state, fd, TEVENT_FD_READ,
+				   wait_for_read_done, state);
+	if (tevent_req_nomem(state->fde, req)) {
+		return tevent_req_post(req, ev);
+	}
+	return req;
+}
+
+static void wait_for_read_done(struct tevent_context *ev,
+			       struct tevent_fd *fde,
+			       uint16_t flags,
+			       void *private_data)
+{
+	struct wait_for_read_state *state = talloc_get_type_abort(
+		private_data, struct wait_for_read_state);
+
+	if (flags & TEVENT_FD_READ) {
+		TALLOC_FREE(state->fde);
+		tevent_req_done(state->req);
+	}
+}
+
+bool wait_for_read_recv(struct tevent_req *req, int *perr)
+{
+	int err;
+
+	if (tevent_req_is_unix_error(req, &err)) {
+		*perr = err;
+		return false;
+	}
+	return true;
+}
diff --git a/lib/async_req/async_sock.h b/lib/async_req/async_sock.h
index 8d98886..1910643 100644
--- a/lib/async_req/async_sock.h
+++ b/lib/async_req/async_sock.h
@@ -61,4 +61,9 @@ struct tevent_req *read_packet_send(TALLOC_CTX *mem_ctx,
 ssize_t read_packet_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
 			 uint8_t **pbuf, int *perrno);
 
+struct tevent_req *wait_for_read_send(TALLOC_CTX *mem_ctx,
+				      struct tevent_context *ev,
+				      int fd);
+bool wait_for_read_recv(struct tevent_req *req, int *perr);
+
 #endif
diff --git a/lib/tevent/tevent_poll.c b/lib/tevent/tevent_poll.c
index 0b782e9..0a9c0f0 100644
--- a/lib/tevent/tevent_poll.c
+++ b/lib/tevent/tevent_poll.c
@@ -222,40 +222,45 @@ static int poll_event_loop_poll(struct tevent_context *ev,
 		return 0;
 	}
 
-	if (pollrtn > 0) {
-		/* at least one file descriptor is ready - check
-		   which ones and call the handler, being careful to allow
-		   the handler to remove itself when called */
-		for (fde = ev->fd_events; fde; fde = fde->next) {
-			struct pollfd *pfd;
-			uint64_t pfd_idx = fde->additional_flags;
-			uint16_t flags = 0;
-
-			pfd = &poll_ev->fds[pfd_idx];
-
-			if (pfd->revents & (POLLHUP|POLLERR)) {
-				/* If we only wait for TEVENT_FD_WRITE, we
-				   should not tell the event handler about it,
-				   and remove the writable flag, as we only
-				   report errors when waiting for read events
-				   to match the select behavior. */
-				if (!(fde->flags & TEVENT_FD_READ)) {
-					TEVENT_FD_NOT_WRITEABLE(fde);
-					continue;
-				}
-				flags |= TEVENT_FD_READ;
-			}
-			if (pfd->revents & POLLIN) {
-				flags |= TEVENT_FD_READ;
-			}
-			if (pfd->revents & POLLOUT) {
-				flags |= TEVENT_FD_WRITE;
-			}
-			if (flags != 0) {
-				fde->handler(ev, fde, flags,
-					     fde->private_data);
-				break;
+	if (pollrtn <= 0) {
+		/*
+		 * No fd's ready
+		 */
+		return 0;
+	}
+
+	/* at least one file descriptor is ready - check
+	   which ones and call the handler, being careful to allow
+	   the handler to remove itself when called */
+
+	for (fde = ev->fd_events; fde; fde = fde->next) {
+		struct pollfd *pfd;
+		uint64_t pfd_idx = fde->additional_flags;
+		uint16_t flags = 0;
+
+		pfd = &poll_ev->fds[pfd_idx];
+
+		if (pfd->revents & (POLLHUP|POLLERR)) {
+			/* If we only wait for TEVENT_FD_WRITE, we
+			   should not tell the event handler about it,
+			   and remove the writable flag, as we only
+			   report errors when waiting for read events
+			   to match the select behavior. */
+			if (!(fde->flags & TEVENT_FD_READ)) {
+				TEVENT_FD_NOT_WRITEABLE(fde);
+				continue;
 			}
+			flags |= TEVENT_FD_READ;
+		}
+		if (pfd->revents & POLLIN) {
+			flags |= TEVENT_FD_READ;
+		}
+		if (pfd->revents & POLLOUT) {
+			flags |= TEVENT_FD_WRITE;
+		}
+		if (flags != 0) {
+			fde->handler(ev, fde, flags, fde->private_data);
+			break;
 		}
 	}
 
diff --git a/source3/smbd/process.c b/source3/smbd/process.c
index 0e198ee..9df95a8 100644
--- a/source3/smbd/process.c
+++ b/source3/smbd/process.c
@@ -35,6 +35,7 @@
 #include "smbprofile.h"
 #include "rpc_server/spoolss/srv_spoolss_nt.h"
 #include "libsmb/libsmb.h"
+#include "../lib/util/tevent_ntstatus.h"
 
 extern bool global_machine_password_needs_changing;
 
@@ -2200,10 +2201,21 @@ static void smbd_server_connection_read_handler(
 	if (from_client) {
 		smbd_lock_socket(sconn);
 
-		if (lp_async_smb_echo_handler() && !fd_is_readable(fd)) {
-			DEBUG(10,("the echo listener was faster\n"));
-			smbd_unlock_socket(sconn);
-			return;
+		if (lp_async_smb_echo_handler()) {
+
+			if (fd_is_readable(sconn->smb1.echo_handler.trusted_fd)) {
+				/*
+				 * This is the super-ugly hack to
+				 * prefer the packets forwarded by the
+				 * echo handler over the ones by the
+				 * client directly
+				 */
+				fd = sconn->smb1.echo_handler.trusted_fd;
+			} else if (!fd_is_readable(fd)) {
+				DEBUG(10,("the echo listener was faster\n"));
+				smbd_unlock_socket(sconn);
+				return;
+			}
 		}
 
 		/* TODO: make this completely nonblocking */
@@ -2432,6 +2444,160 @@ static int create_unlink_tmp(const char *dir)
 	return fd;
 }
 
+/*
+ * Read an smb packet in the echo handler child, giving the parent
+ * smbd one second to react once the socket becomes readable.
+ */
+
+struct smbd_echo_read_state {
+	struct tevent_context *ev;
+	struct smbd_server_connection *sconn;
+
+	char *buf;
+	size_t buflen;
+	uint32_t seqnum;
+};
+
+static void smbd_echo_read_readable(struct tevent_req *subreq);
+static void smbd_echo_read_waited(struct tevent_req *subreq);
+
+static struct tevent_req *smbd_echo_read_send(
+	TALLOC_CTX *mem_ctx, struct tevent_context *ev,
+	struct smbd_server_connection *sconn)
+{
+	struct tevent_req *req, *subreq;
+	struct smbd_echo_read_state *state;
+
+	req = tevent_req_create(mem_ctx, &state,
+				struct smbd_echo_read_state);
+	if (req == NULL) {
+		return NULL;
+	}
+	state->ev = ev;
+	state->sconn = sconn;
+
+	subreq = wait_for_read_send(state, ev, sconn->sock);
+	if (tevent_req_nomem(subreq, req)) {
+		return tevent_req_post(req, ev);
+	}
+	tevent_req_set_callback(subreq, smbd_echo_read_readable, req);
+	return req;
+}
+
+static void smbd_echo_read_readable(struct tevent_req *subreq)
+{
+	struct tevent_req *req = tevent_req_callback_data(
+		subreq, struct tevent_req);
+	struct smbd_echo_read_state *state = tevent_req_data(
+		req, struct smbd_echo_read_state);
+	bool ok;
+	int err;
+
+	ok = wait_for_read_recv(subreq, &err);
+	TALLOC_FREE(subreq);
+	if (!ok) {
+		tevent_req_nterror(req, map_nt_error_from_unix(err));
+		return;
+	}
+
+	/*
+	 * Give the parent smbd one second to step in
+	 */
+
+	subreq = tevent_wakeup_send(
+		state, state->ev, timeval_current_ofs(1, 0));
+	if (tevent_req_nomem(subreq, req)) {
+		return;
+	}
+	tevent_req_set_callback(subreq, smbd_echo_read_waited, req);
+}
+
+static void smbd_echo_read_waited(struct tevent_req *subreq)
+{
+	struct tevent_req *req = tevent_req_callback_data(
+		subreq, struct tevent_req);
+	struct smbd_echo_read_state *state = tevent_req_data(
+		req, struct smbd_echo_read_state);
+	struct smbd_server_connection *sconn = state->sconn;
+	bool ok;
+	NTSTATUS status;
+	size_t unread = 0;
+	bool encrypted;
+
+	ok = tevent_wakeup_recv(subreq);
+	TALLOC_FREE(subreq);
+	if (!ok) {
+		tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
+		return;
+	}
+
+	ok = smbd_lock_socket_internal(sconn);
+	if (!ok) {
+		tevent_req_nterror(req, map_nt_error_from_unix(errno));
+		DEBUG(0, ("%s: failed to lock socket\n", __location__));
+		return;
+	}
+
+	if (!fd_is_readable(sconn->sock)) {
+		DEBUG(10,("echo_handler[%d] the parent smbd was faster\n",
+			  (int)sys_getpid()));
+
+		ok = smbd_unlock_socket_internal(sconn);
+		if (!ok) {
+			tevent_req_nterror(req, map_nt_error_from_unix(errno));
+			DEBUG(1, ("%s: failed to unlock socket\n",
+				__location__));
+			return;
+		}
+
+		subreq = wait_for_read_send(state, state->ev, sconn->sock);
+		if (tevent_req_nomem(subreq, req)) {
+			return;
+		}
+		tevent_req_set_callback(subreq, smbd_echo_read_readable, req);
+		return;
+	}
+
+	status = receive_smb_talloc(state, sconn, sconn->sock, &state->buf,
+				    0 /* timeout */,
+				    &unread,
+				    &encrypted,
+				    &state->buflen,
+				    &state->seqnum,
+				    false /* trusted_channel*/);
+
+	if (tevent_req_nterror(req, status)) {
+		tevent_req_nterror(req, status);
+		DEBUG(1, ("echo_handler[%d]: receive_smb_raw_talloc failed: %s\n",
+			  (int)sys_getpid(), nt_errstr(status)));
+		return;
+	}
+
+	ok = smbd_unlock_socket_internal(sconn);
+	if (!ok) {
+		tevent_req_nterror(req, map_nt_error_from_unix(errno));
+		DEBUG(1, ("%s: failed to unlock socket\n", __location__));
+		return;
+	}
+	tevent_req_done(req);
+}
+
+static NTSTATUS smbd_echo_read_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
+				    char **pbuf, size_t *pbuflen, uint32_t *pseqnum)
+{
+	struct smbd_echo_read_state *state = tevent_req_data(
+		req, struct smbd_echo_read_state);
+	NTSTATUS status;
+
+	if (tevent_req_is_nterror(req, &status)) {
+		return status;
+	}
+	*pbuf = talloc_move(mem_ctx, &state->buf);
+	*pbuflen = state->buflen;
+	*pseqnum = state->seqnum;
+	return NT_STATUS_OK;
+}
+
 struct smbd_echo_state {
 	struct tevent_context *ev;
 	struct iovec *pending;
@@ -2440,7 +2606,6 @@ struct smbd_echo_state {
 
 	struct tevent_fd *parent_fde;
 
-	struct tevent_fd *read_fde;
 	struct tevent_req *write_req;
 };
 
@@ -2576,107 +2741,13 @@ static void smbd_echo_exit(struct tevent_context *ev,
 	exit(0);
 }
 
-static void smbd_echo_reader(struct tevent_context *ev,
-			     struct tevent_fd *fde, uint16_t flags,
-			     void *private_data)
-{
-	struct smbd_echo_state *state = talloc_get_type_abort(
-		private_data, struct smbd_echo_state);
-	struct smbd_server_connection *sconn = state->sconn;
-	size_t unread, num_pending;
-	NTSTATUS status;
-	struct iovec *tmp;
-	size_t iov_len;
-	uint32_t seqnum = 0;
-	bool reply;
-	bool ok;
-	bool encrypted = false;
-
-	smb_msleep(1000);
-
-	ok = smbd_lock_socket_internal(sconn);
-	if (!ok) {
-		DEBUG(0, ("%s: failed to lock socket\n",
-			__location__));
-		exit(1);
-	}
-
-	if (!fd_is_readable(sconn->sock)) {
-		DEBUG(10,("echo_handler[%d] the parent smbd was faster\n",
-			  (int)sys_getpid()));
-		ok = smbd_unlock_socket_internal(sconn);
-		if (!ok) {
-			DEBUG(1, ("%s: failed to unlock socket in\n",
-				__location__));
-			exit(1);
-		}
-		return;
-	}
-
-	num_pending = talloc_array_length(state->pending);
-	tmp = talloc_realloc(state, state->pending, struct iovec,
-			     num_pending+1);
-	if (tmp == NULL) {
-		DEBUG(1, ("talloc_realloc failed\n"));
-		exit(1);
-	}
-	state->pending = tmp;
-
-	DEBUG(10,("echo_handler[%d]: reading pdu\n", (int)sys_getpid()));
-
-	status = receive_smb_talloc(state->pending, sconn, sconn->sock,
-				    (char **)(void *)&state->pending[num_pending].iov_base,
-				    0 /* timeout */,
-				    &unread,
-				    &encrypted,
-				    &iov_len,
-				    &seqnum,
-				    false /* trusted_channel*/);
-	if (!NT_STATUS_IS_OK(status)) {
-		DEBUG(1, ("echo_handler[%d]: receive_smb_raw_talloc failed: %s\n",
-			  (int)sys_getpid(), nt_errstr(status)));
-		exit(1);
-	}
-	state->pending[num_pending].iov_len = iov_len;
-
-	ok = smbd_unlock_socket_internal(sconn);
-	if (!ok) {
-		DEBUG(1, ("%s: failed to unlock socket in\n",
-			__location__));
-		exit(1);
-	}
-
-	reply = smbd_echo_reply((uint8_t *)state->pending[num_pending].iov_base,
-				state->pending[num_pending].iov_len,
-				seqnum);
-	if (reply) {
-		DEBUG(10,("echo_handler[%d]: replied to client\n", (int)sys_getpid()));
-		/* no check, shrinking by some bytes does not fail */
-		state->pending = talloc_realloc(state, state->pending,
-						struct iovec,
-						num_pending);
-		return;
-	}
-
-	if (state->pending[num_pending].iov_len >= smb_size) {
-		/*
-		 * place the seqnum in the packet so that the main process
-		 * can reply with signing
-		 */
-		SIVAL((uint8_t *)state->pending[num_pending].iov_base,
-		      smb_ss_field, seqnum);
-		SIVAL((uint8_t *)state->pending[num_pending].iov_base,
-		      smb_ss_field+4, NT_STATUS_V(NT_STATUS_OK));
-	}
-
-	DEBUG(10,("echo_handler[%d]: forward to main\n", (int)sys_getpid()));
-	smbd_echo_activate_writer(state);
-}
+static void smbd_echo_got_packet(struct tevent_req *req);
 
 static void smbd_echo_loop(struct smbd_server_connection *sconn,
 			   int parent_pipe)
 {
 	struct smbd_echo_state *state;
+	struct tevent_req *read_req;
 
 	state = talloc_zero(sconn, struct smbd_echo_state);
 	if (state == NULL) {
@@ -2699,14 +2770,14 @@ static void smbd_echo_loop(struct smbd_server_connection *sconn,
 		TALLOC_FREE(state);
 		return;
 	}
-	state->read_fde = tevent_add_fd(state->ev, state, sconn->sock,
-					TEVENT_FD_READ, smbd_echo_reader,
-					state);
-	if (state->read_fde == NULL) {
-		DEBUG(1, ("tevent_add_fd failed\n"));
+
+	read_req = smbd_echo_read_send(state, state->ev, sconn);
+	if (read_req == NULL) {
+		DEBUG(1, ("smbd_echo_read_send failed\n"));
 		TALLOC_FREE(state);
 		return;
 	}
+	tevent_req_set_callback(read_req, smbd_echo_got_packet, state);
 
 	while (true) {
 		if (tevent_loop_once(state->ev) == -1) {
@@ -2718,6 +2789,66 @@ static void smbd_echo_loop(struct smbd_server_connection *sconn,
 	TALLOC_FREE(state);
 }


-- 
Samba Shared Repository


More information about the samba-cvs mailing list