[SCM] Samba Shared Repository - branch master updated - aeb798c325cc33072ad090a1f8610bba4fdebaaa

Stefan Metzmacher metze at samba.org
Fri Jan 9 07:46:25 GMT 2009


The branch, master has been updated
       via  aeb798c325cc33072ad090a1f8610bba4fdebaaa (commit)
       via  d524e5f4174e4f7578595bf6cd22a6d161b6e324 (commit)
       via  def5e8e889e0ffe1cf55462ca32b69b627c5ff96 (commit)
      from  447f2668879e91990c985bdb8f0c5d5db2719a91 (commit)

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


- Log -----------------------------------------------------------------
commit aeb798c325cc33072ad090a1f8610bba4fdebaaa
Author: Stefan Metzmacher <metze at samba.org>
Date:   Thu Jan 8 15:38:47 2009 +0100

    s3:smbd: handle incoming smb requests via event handlers
    
    We use a fd event and receive incoming smb requests
    when the fd becomes readable. It's not completely
    nonblocking yet, but it should behave like the old code.
    
    We use timed events to trigger retries for deferred open calls.
    
    metze

commit d524e5f4174e4f7578595bf6cd22a6d161b6e324
Author: Stefan Metzmacher <metze at samba.org>
Date:   Thu Jan 8 19:45:13 2009 +0100

    s3:events: debug sys_select() errors
    
    metze

commit def5e8e889e0ffe1cf55462ca32b69b627c5ff96
Author: Stefan Metzmacher <metze at samba.org>
Date:   Thu Jan 8 15:16:51 2009 +0100

    s3:events: install a tevent debug handler that calls DEBUG()
    
    metze

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

Summary of changes:
 source3/include/smb.h  |    2 +-
 source3/lib/events.c   |   46 ++++++++-
 source3/smbd/globals.c |    2 +
 source3/smbd/globals.h |    6 +
 source3/smbd/process.c |  263 ++++++++++++++++++++++++++++--------------------
 5 files changed, 209 insertions(+), 110 deletions(-)


Changeset truncated at 500 lines:

diff --git a/source3/include/smb.h b/source3/include/smb.h
index 9f6a6f0..4d7d4b2 100644
--- a/source3/include/smb.h
+++ b/source3/include/smb.h
@@ -690,7 +690,7 @@ struct interface {
 struct pending_message_list {
 	struct pending_message_list *next, *prev;
 	struct timeval request_time; /* When was this first issued? */
-	struct timeval end_time; /* When does this time out? */
+	struct timed_event *te;
 	bool encrypted;
 	DATA_BLOB buf;
 	DATA_BLOB private_data;
diff --git a/source3/lib/events.c b/source3/lib/events.c
index c1feff8..8deaa18 100644
--- a/source3/lib/events.c
+++ b/source3/lib/events.c
@@ -189,6 +189,9 @@ static int s3_event_loop_once(struct tevent_context *ev)
 	ret = sys_select(maxfd+1, &r_fds, &w_fds, NULL, &to);
 
 	if (ret == -1 && errno != EINTR) {
+		tevent_debug(ev, TEVENT_DEBUG_FATAL,
+			     "sys_select() failed: %d:%s\n",
+			     errno, strerror(errno));
 		return -1;
 	}
 
@@ -274,8 +277,49 @@ static bool s3_tevent_init(void)
 	return initialized;
 }
 
+/*
+  this is used to catch debug messages from events
+*/
+static void s3_event_debug(void *context, enum tevent_debug_level level,
+			   const char *fmt, va_list ap)  PRINTF_ATTRIBUTE(3,0);
+
+static void s3_event_debug(void *context, enum tevent_debug_level level,
+			   const char *fmt, va_list ap)
+{
+	int samba_level = -1;
+	char *s = NULL;
+	switch (level) {
+	case TEVENT_DEBUG_FATAL:
+		samba_level = 0;
+		break;
+	case TEVENT_DEBUG_ERROR:
+		samba_level = 1;
+		break;
+	case TEVENT_DEBUG_WARNING:
+		samba_level = 2;
+		break;
+	case TEVENT_DEBUG_TRACE:
+		samba_level = 5;
+		break;
+
+	};
+	vasprintf(&s, fmt, ap);
+	if (!s) return;
+	DEBUG(samba_level, ("s3_event: %s", s));
+	free(s);
+}
+
 struct tevent_context *s3_tevent_context_init(TALLOC_CTX *mem_ctx)
 {
+	struct tevent_context *ev;
+
 	s3_tevent_init();
-	return tevent_context_init_byname(mem_ctx, "s3");
+
+	ev = tevent_context_init_byname(mem_ctx, "s3");
+	if (ev) {
+		tevent_set_debug(ev, s3_event_debug, NULL);
+	}
+
+	return ev;
 }
+
diff --git a/source3/smbd/globals.c b/source3/smbd/globals.c
index ad017f5..6fcf18d 100644
--- a/source3/smbd/globals.c
+++ b/source3/smbd/globals.c
@@ -202,6 +202,8 @@ bool exit_firsttime = true;
 struct child_pid *children = 0;
 int num_children = 0;
 
+struct smbd_server_connection *smbd_server_conn = NULL;
+
 void smbd_init_globals(void)
 {
 	ZERO_STRUCT(char_flags);
diff --git a/source3/smbd/globals.h b/source3/smbd/globals.h
index 178263b..157089f 100644
--- a/source3/smbd/globals.h
+++ b/source3/smbd/globals.h
@@ -216,4 +216,10 @@ struct child_pid;
 extern struct child_pid *children;
 extern int num_children;
 
+struct smbd_server_connection {
+	struct fd_event *fde;
+	uint64_t num_requests;
+};
+extern struct smbd_server_connection *smbd_server_conn;
+
 void smbd_init_globals(void);
diff --git a/source3/smbd/process.c b/source3/smbd/process.c
index 6f0a10d..1f24058 100644
--- a/source3/smbd/process.c
+++ b/source3/smbd/process.c
@@ -392,6 +392,36 @@ void init_smb_request(struct smb_request *req,
 	req->outbuf = NULL;
 }
 
+static void process_smb(struct smbd_server_connection *conn,
+			uint8_t *inbuf, size_t nread, size_t unread_bytes,
+			bool encrypted);
+
+static void smbd_deferred_open_timer(struct event_context *ev,
+				     struct timed_event *te,
+				     struct timeval _tval,
+				     void *private_data)
+{
+	struct pending_message_list *msg = talloc_get_type(private_data,
+					   struct pending_message_list);
+	TALLOC_CTX *mem_ctx = talloc_tos();
+	uint8_t *inbuf;
+
+	inbuf = talloc_memdup(mem_ctx, msg->buf.data,
+			      msg->buf.length);
+	if (inbuf == NULL) {
+		exit_server("smbd_deferred_open_timer: talloc failed\n");
+		return;
+	}
+
+	/* We leave this message on the queue so the open code can
+	   know this is a retry. */
+	DEBUG(5,("smbd_deferred_open_timer: trigger mid %u.\n",
+		(unsigned int)SVAL(msg->buf.data,smb_mid)));
+
+	process_smb(smbd_server_conn, inbuf,
+		    msg->buf.length, 0,
+		    msg->encrypted);
+}
 
 /****************************************************************************
  Function to push a message onto the tail of a linked list of smb messages ready
@@ -421,7 +451,6 @@ static bool push_queued_message(struct smb_request *req,
 	}
 
 	msg->request_time = request_time;
-	msg->end_time = end_time;
 	msg->encrypted = req->encrypted;
 
 	if (private_data) {
@@ -434,6 +463,17 @@ static bool push_queued_message(struct smb_request *req,
 		}
 	}
 
+	msg->te = event_add_timed(smbd_event_context(),
+				  msg,
+				  end_time,
+				  smbd_deferred_open_timer,
+				  msg);
+	if (!msg->te) {
+		DEBUG(0,("push_message: event_add_timed failed\n"));
+		TALLOC_FREE(msg);
+		return false;
+	}
+
 	DLIST_ADD_END(deferred_open_queue, msg, struct pending_message_list *);
 
 	DEBUG(10,("push_message: pushed message length %u on "
@@ -475,13 +515,29 @@ void schedule_deferred_open_smb_message(uint16 mid)
 
 	for (pml = deferred_open_queue; pml; pml = pml->next) {
 		uint16 msg_mid = SVAL(pml->buf.data,smb_mid);
+
 		DEBUG(10,("schedule_deferred_open_smb_message: [%d] msg_mid = %u\n", i++,
 			(unsigned int)msg_mid ));
+
 		if (mid == msg_mid) {
+			struct timed_event *te;
+
 			DEBUG(10,("schedule_deferred_open_smb_message: scheduling mid %u\n",
 				mid ));
-			pml->end_time.tv_sec = 0;
-			pml->end_time.tv_usec = 0;
+
+			te = event_add_timed(smbd_event_context(),
+					     pml,
+					     timeval_zero(),
+					     smbd_deferred_open_timer,
+					     pml);
+			if (!te) {
+				DEBUG(10,("schedule_deferred_open_smb_message: "
+					  "event_add_timed() failed, skipping mid %u\n",
+					  mid ));
+			}
+
+			TALLOC_FREE(pml->te);
+			pml->te = te;
 			DLIST_PROMOTE(deferred_open_queue, pml);
 			return;
 		}
@@ -701,18 +757,12 @@ static int select_on_fd(int fd, int maxfd, fd_set *fds)
 The timeout is in milliseconds
 ****************************************************************************/
 
-static NTSTATUS receive_message_or_smb(TALLOC_CTX *mem_ctx, char **buffer,
-				       size_t *buffer_len,
-				       size_t *p_unread, bool *p_encrypted)
+static NTSTATUS smbd_server_connection_loop_once(struct smbd_server_connection *conn)
 {
 	fd_set r_fds, w_fds;
 	int selrtn;
 	struct timeval to;
 	int maxfd = 0;
-	size_t len = 0;
-	NTSTATUS status;
-
-	*p_unread = 0;
 
 	to.tv_sec = SMBD_SELECT_TIMEOUT;
 	to.tv_usec = 0;
@@ -725,53 +775,6 @@ static NTSTATUS receive_message_or_smb(TALLOC_CTX *mem_ctx, char **buffer,
 	message_dispatch(smbd_messaging_context());
 
 	/*
-	 * Check to see if we already have a message on the deferred open queue
-	 * and it's time to schedule.
-	 */
-  	if(deferred_open_queue != NULL) {
-		bool pop_message = False;
-		struct pending_message_list *msg = deferred_open_queue;
-
-		if (timeval_is_zero(&msg->end_time)) {
-			pop_message = True;
-		} else {
-			struct timeval tv;
-			int64_t tdif;
-
-			GetTimeOfDay(&tv);
-			tdif = usec_time_diff(&msg->end_time, &tv);
-			if (tdif <= 0) {
-				/* Timed out. Schedule...*/
-				pop_message = True;
-				DEBUG(10,("receive_message_or_smb: queued message timed out.\n"));
-			} else {
-				/* Make a more accurate select timeout. */
-				to.tv_sec = tdif / 1000000;
-				to.tv_usec = tdif % 1000000;
-				DEBUG(10,("receive_message_or_smb: select with timeout of [%u.%06u]\n",
-					(unsigned int)to.tv_sec, (unsigned int)to.tv_usec ));
-			}
-		}
-
-		if (pop_message) {
-
-			*buffer = (char *)talloc_memdup(mem_ctx, msg->buf.data,
-							msg->buf.length);
-			if (*buffer == NULL) {
-				DEBUG(0, ("talloc failed\n"));
-				return NT_STATUS_NO_MEMORY;
-			}
-			*buffer_len = msg->buf.length;
-			*p_encrypted = msg->encrypted;
-
-			/* We leave this message on the queue so the open code can
-			   know this is a retry. */
-			DEBUG(5,("receive_message_or_smb: returning deferred open smb message.\n"));
-			return NT_STATUS_OK;
-		}
-	}
-
-	/*
 	 * Setup the select fd sets.
 	 */
 
@@ -822,7 +825,6 @@ static NTSTATUS receive_message_or_smb(TALLOC_CTX *mem_ctx, char **buffer,
 		int sav;
 		START_PROFILE(smbd_idle);
 
-		maxfd = select_on_fd(smbd_server_fd(), maxfd, &r_fds);
 		maxfd = select_on_fd(oplock_notify_fd(), maxfd, &r_fds);
 
 		selrtn = sys_select(maxfd+1,&r_fds,&w_fds,NULL,&to);
@@ -886,15 +888,6 @@ static NTSTATUS receive_message_or_smb(TALLOC_CTX *mem_ctx, char **buffer,
 	 */
 	message_dispatch(smbd_messaging_context());
 
-	status = receive_smb_talloc(mem_ctx, smbd_server_fd(), buffer, 0,
-				    p_unread, p_encrypted, &len);
-
-	if (!NT_STATUS_IS_OK(status)) {
-		return status;
-	}
-
-	*buffer_len = len;
-
 	return NT_STATUS_OK;
 }
 
@@ -1519,7 +1512,9 @@ static void construct_reply(char *inbuf, int size, size_t unread_bytes, bool enc
  Process an smb from the client
 ****************************************************************************/
 
-static void process_smb(char *inbuf, size_t nread, size_t unread_bytes, bool encrypted)
+static void process_smb(struct smbd_server_connection *conn,
+			uint8_t *inbuf, size_t nread, size_t unread_bytes,
+			bool encrypted)
 {
 	int msg_type = CVAL(inbuf,0);
 
@@ -1535,15 +1530,31 @@ static void process_smb(char *inbuf, size_t nread, size_t unread_bytes, bool enc
 		/*
 		 * NetBIOS session request, keepalive, etc.
 		 */
-		reply_special(inbuf);
-		return;
+		reply_special((char *)inbuf);
+		goto done;
 	}
 
-	show_msg(inbuf);
+	show_msg((char *)inbuf);
 
-	construct_reply(inbuf,nread,unread_bytes,encrypted);
+	construct_reply((char *)inbuf,nread,unread_bytes,encrypted);
 
 	trans_num++;
+
+done:
+	conn->num_requests++;
+
+	/* The timeout_processing function isn't run nearly
+	   often enough to implement 'max log size' without
+	   overrunning the size of the file by many megabytes.
+	   This is especially true if we are running at debug
+	   level 10.  Checking every 50 SMBs is a nice
+	   tradeoff of performance vs log file size overrun. */
+
+	if ((conn->num_requests % 50) == 0 &&
+	    need_to_check_log_size()) {
+		change_to_root_user();
+		check_log_size();
+	}
 }
 
 /****************************************************************************
@@ -1856,17 +1867,63 @@ void check_reload(time_t t)
 	}
 }
 
+static void smbd_server_connection_write_handler(struct smbd_server_connection *conn)
+{
+	/* TODO: make write nonblocking */
+}
+
+static void smbd_server_connection_read_handler(struct smbd_server_connection *conn)
+{
+	uint8_t *inbuf = NULL;
+	size_t inbuf_len = 0;
+	size_t unread_bytes = 0;
+	bool encrypted = false;
+	TALLOC_CTX *mem_ctx = talloc_tos();
+	NTSTATUS status;
+
+	/* TODO: make this completely nonblocking */
+
+	status = receive_smb_talloc(mem_ctx, smbd_server_fd(),
+				    (char **)&inbuf,
+				    0, /* timeout */
+				    &unread_bytes,
+				    &encrypted,
+				    &inbuf_len);
+	if (NT_STATUS_EQUAL(status, NT_STATUS_RETRY)) {
+		goto process;
+	}
+	if (NT_STATUS_IS_ERR(status)) {
+		exit_server_cleanly("failed to receive smb request");
+	}
+	if (!NT_STATUS_IS_OK(status)) {
+		return;
+	}
+
+process:
+	process_smb(conn, inbuf, inbuf_len, unread_bytes, encrypted);
+}
+
+static void smbd_server_connection_handler(struct event_context *ev,
+					   struct fd_event *fde,
+					   uint16_t flags,
+					   void *private_data)
+{
+	struct smbd_server_connection *conn = talloc_get_type(private_data,
+					      struct smbd_server_connection);
+
+	if (flags & EVENT_FD_WRITE) {
+		smbd_server_connection_write_handler(conn);
+	} else if (flags & EVENT_FD_READ) {
+		smbd_server_connection_read_handler(conn);
+	}
+}
+
 /****************************************************************************
  Process commands from the client
 ****************************************************************************/
 
 void smbd_process(void)
 {
-	unsigned int num_smbs = 0;
-	size_t unread_bytes = 0;
-
-	char addr[INET6_ADDRSTRLEN];
-
 	/*
 	 * Before the first packet, check the global hosts allow/ hosts deny
 	 * parameters before doing any parsing of packets passed to us by the
@@ -1876,6 +1933,8 @@ void smbd_process(void)
 
 	if (!check_access(smbd_server_fd(), lp_hostsallow(-1),
 			  lp_hostsdeny(-1))) {
+		char addr[INET6_ADDRSTRLEN];
+
 		/*
 		 * send a negative session response "not listening on calling
 		 * name"
@@ -1889,46 +1948,34 @@ void smbd_process(void)
 
 	max_recv = MIN(lp_maxxmit(),BUFFER_SIZE);
 
+	smbd_server_conn = talloc_zero(smbd_event_context(), struct smbd_server_connection);
+	if (!smbd_server_conn) {
+		exit_server("failed to create smbd_server_connection");
+	}
+	smbd_server_conn->fde = event_add_fd(smbd_event_context(),
+					     smbd_server_conn,
+					     smbd_server_fd(),
+					     EVENT_FD_READ,
+					     smbd_server_connection_handler,
+					     smbd_server_conn);
+	if (!smbd_server_conn->fde) {
+		exit_server("failed to create smbd_server_connection fde");
+	}
+
 	while (True) {
 		NTSTATUS status;
-		char *inbuf = NULL;
-		size_t inbuf_len = 0;
-		bool encrypted = false;
 		TALLOC_CTX *frame = talloc_stackframe_pool(8192);
 
 		errno = 0;
 
-		run_events(smbd_event_context(), 0, NULL, NULL);
-
-		status = NT_STATUS_RETRY;
-
-		while (NT_STATUS_EQUAL(status, NT_STATUS_RETRY)) {
-			status = receive_message_or_smb(
-				talloc_tos(), &inbuf, &inbuf_len,
-				&unread_bytes, &encrypted);
-		}
-
-		if (!NT_STATUS_IS_OK(status)) {
-			DEBUG(3, ("receive_message_or_smb failed: %s, "
-				  "exiting\n", nt_errstr(status)));
+		status = smbd_server_connection_loop_once(smbd_server_conn);
+		if (!NT_STATUS_EQUAL(status, NT_STATUS_RETRY) &&
+		    !NT_STATUS_IS_OK(status)) {
+			DEBUG(3, ("smbd_server_connection_loop_once failed: %s,"
+				  " exiting\n", nt_errstr(status)));
 			return;
 		}
 
-		process_smb(inbuf, inbuf_len, unread_bytes, encrypted);
-
-		num_smbs++;
-
-		/* The timeout_processing function isn't run nearly
-		   often enough to implement 'max log size' without
-		   overrunning the size of the file by many megabytes.
-		   This is especially true if we are running at debug
-		   level 10.  Checking every 50 SMBs is a nice
-		   tradeoff of performance vs log file size overrun. */
-
-		if ((num_smbs % 50) == 0 && need_to_check_log_size()) {
-			change_to_root_user();
-			check_log_size();
-		}
 		TALLOC_FREE(frame);
 	}
 }


-- 
Samba Shared Repository


More information about the samba-cvs mailing list