diff options
author | Stefan Metzmacher <metze@samba.org> | 2009-01-08 15:38:47 +0100 |
---|---|---|
committer | Stefan Metzmacher <metze@samba.org> | 2009-01-09 08:45:40 +0100 |
commit | aeb798c325cc33072ad090a1f8610bba4fdebaaa (patch) | |
tree | 09592984adf0139b8e69fc9fc3d23b84cc69952d /source3/smbd | |
parent | d524e5f4174e4f7578595bf6cd22a6d161b6e324 (diff) | |
download | samba-aeb798c325cc33072ad090a1f8610bba4fdebaaa.tar.gz samba-aeb798c325cc33072ad090a1f8610bba4fdebaaa.tar.bz2 samba-aeb798c325cc33072ad090a1f8610bba4fdebaaa.zip |
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
Diffstat (limited to 'source3/smbd')
-rw-r--r-- | source3/smbd/globals.c | 2 | ||||
-rw-r--r-- | source3/smbd/globals.h | 6 | ||||
-rw-r--r-- | source3/smbd/process.c | 263 |
3 files changed, 163 insertions, 108 deletions
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); } } |