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 <[email protected]>
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 <[email protected]>
    Autobuild-Date: Thu Jul 28 18:53:38 CEST 2011 on sn-devel-104

commit 83740555ea8664da0830f88a1dd5afa69880bb40
Author: Volker Lendecke <[email protected]>
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 <[email protected]>
Date:   Tue Jul 26 15:39:58 2011 +0200

    s3: Remove unused smbd_echo_reader()

commit 710e5d92562b2f43a20a33575ea0ec44e9b49a0a
Author: Volker Lendecke <[email protected]>
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 <[email protected]>
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 <[email protected]>
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

Reply via email to