[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