summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--source3/include/smb.h2
-rw-r--r--source3/smbd/globals.c2
-rw-r--r--source3/smbd/globals.h6
-rw-r--r--source3/smbd/process.c263
4 files changed, 164 insertions, 109 deletions
diff --git a/source3/include/smb.h b/source3/include/smb.h
index 9f6a6f02d7..4d7d4b2f38 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/smbd/globals.c b/source3/smbd/globals.c
index ad017f5a23..6fcf18da09 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 178263ba2c..157089f37c 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 6f0a10da4a..1f24058f25 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);
}
}