The branch, master has been updated via ea27382 s3: torture - Fix racy assumption in original messaging test. via 4fa1235 s3: torture - Add required talloc frame for msgtest.c via eaa45a5 s3: winbindd: Call dgram cleanup init background setup. via 6c60ff3 s3: nmbd: Call dgram cleanup init background setup. via a35c9d6 s3: smbd: Call dgram cleanup init background setup. via 843f094 s3: messaging: Add infrastructure to clean up orphaned sockets every 15 minutes as a background task. via 5ae7550 s3 : build system : Move lib/background.c from smbd_base to samba3core. via 895d0ac smbd: Call the msg_ctx destructor for background jobs via e22433a smbcontrol: Add dgm-cleanup command via 6874e4a messaging_dgm: Add messaging_dgm_wipe via dac9b3d smbd: Always clean up the child's msg_ctx via 78543b9 smbcontrol: Clean up the msg_ctx via 758b057 printing_cups: Call the msg_ctx destructor on exit via c6a2734 smbd: Sort notify events by timestamp via 3218c73 smbd: Pass on a timestamp in MSG_PVFS_NOTIFY via cdc99c1 messaging3: Add messaging_send_iov via e268360 lib: Add iov_buf via 7009b49 lib: Introduce iov_buflen via da1778f smbd: Pass timespec_current through the notify_callback via 892bec8 smbd: Pass timespec_current to notify_fsp via e616e3c smbd: Add a timestamp to queued notify events via b022038 lib: Remove messages_local via 29603d1 lib: Add messaging_dgm via 3e24e07 lib: Move full_path_tos to util_str.c via 6dcf2c7 lib: Add unix_msg via bafdecd lib: Add poll_funcs from 463ea9e ctdb-recoverd: Detach database from recovery daemon
http://gitweb.samba.org/?p=samba.git;a=shortlog;h=master - Log ----------------------------------------------------------------- commit ea27382ef40650f1a8310bce02fe60c0a94fa121 Author: Jeremy Allison <j...@samba.org> Date: Tue Apr 22 16:07:18 2014 -0700 s3: torture - Fix racy assumption in original messaging test. Signed-off-by: Jeremy Allison <j...@samba.org> Reviewed-by: "Stefan (metze) Metzmacher" <me...@samba.org> Autobuild-User(master): Jeremy Allison <j...@samba.org> Autobuild-Date(master): Thu Apr 24 00:50:55 CEST 2014 on sn-devel-104 commit 4fa1235cda2d9e1c98e80c5e451aef5be51ffd35 Author: Jeremy Allison <j...@samba.org> Date: Tue Apr 22 15:55:53 2014 -0700 s3: torture - Add required talloc frame for msgtest.c Signed-off-by: Jeremy Allison <j...@samba.org> Reviewed-by: "Stefan (metze) Metzmacher" <me...@samba.org> commit eaa45a578079f583ada85feafa54c41faccc8da9 Author: Jeremy Allison <j...@samba.org> Date: Fri Apr 18 15:09:28 2014 -0700 s3: winbindd: Call dgram cleanup init background setup. Signed-off-by: Jeremy Allison <j...@samba.org> Reviewed-by: Michael Adam <ob...@samba.org> commit 6c60ff3bd5243e441c82769a51afa94db0c863e2 Author: Jeremy Allison <j...@samba.org> Date: Fri Apr 18 15:08:19 2014 -0700 s3: nmbd: Call dgram cleanup init background setup. Signed-off-by: Jeremy Allison <j...@samba.org> Reviewed-by: Michael Adam <ob...@samba.org> commit a35c9d6a638e20c1f9ea81602805722561887c60 Author: Jeremy Allison <j...@samba.org> Date: Fri Apr 18 15:06:05 2014 -0700 s3: smbd: Call dgram cleanup init background setup. Signed-off-by: Jeremy Allison <j...@samba.org> Reviewed-by: Michael Adam <ob...@samba.org> commit 843f0946289343b6fcc6f41ad5ff5bd090a9399b Author: Volker Lendecke <v...@samba.org> Date: Fri Apr 11 11:08:56 2014 +0000 s3: messaging: Add infrastructure to clean up orphaned sockets every 15 minutes as a background task. Signed-off-by: Volker Lendecke <v...@samba.org> Reviewed-by: Jeremy Allison <j...@samba.org> commit 5ae7550ab41ac25e081f5b616865222e7e5558ae Author: Jeremy Allison <j...@samba.org> Date: Fri Apr 18 14:47:39 2014 -0700 s3 : build system : Move lib/background.c from smbd_base to samba3core. Allows background jobs to be run from winbindd and nmbd. Signed-off-by: Jeremy Allison <j...@samba.org> Reviewed-by: Michael Adam <ob...@samba.org> commit 895d0ac56d70692af6333880cac6320e873c7ab2 Author: Volker Lendecke <v...@samba.org> Date: Fri Apr 11 11:07:10 2014 +0000 smbd: Call the msg_ctx destructor for background jobs Signed-off-by: Volker Lendecke <v...@samba.org> Reviewed-by: Jeremy Allison <j...@samba.org> commit e22433aea1fe08ecd62a8d25b525cd9e95088449 Author: Volker Lendecke <v...@samba.org> Date: Thu Apr 10 22:09:04 2014 +0200 smbcontrol: Add dgm-cleanup command Signed-off-by: Volker Lendecke <v...@samba.org> Reviewed-by: Jeremy Allison <j...@samba.org> commit 6874e4a0f2b2bce120f2eea4563239b90c968dd7 Author: Volker Lendecke <v...@samba.org> Date: Thu Apr 10 22:07:11 2014 +0200 messaging_dgm: Add messaging_dgm_wipe This walks all sockets and wipes the left-overs Signed-off-by: Volker Lendecke <v...@samba.org> Reviewed-by: Jeremy Allison <j...@samba.org> commit dac9b3d73f94e86acb3770bf5ca728f107505b0b Author: Volker Lendecke <v...@samba.org> Date: Fri Apr 11 09:13:10 2014 +0200 smbd: Always clean up the child's msg_ctx This is a bit lazy programming, we could and possibly should do this in exit_server() in the child. But this way we make sure the cleanup works. If it only was executed for unclean exits, we might not detect failure of this code in the parent. Signed-off-by: Volker Lendecke <v...@samba.org> Reviewed-by: Jeremy Allison <j...@samba.org> commit 78543b9bce5f823f44963e76638b02d55d76633e Author: Volker Lendecke <v...@samba.org> Date: Fri Apr 11 09:12:46 2014 +0200 smbcontrol: Clean up the msg_ctx Signed-off-by: Volker Lendecke <v...@samba.org> Reviewed-by: Jeremy Allison <j...@samba.org> commit 758b057700faced256e265984d0088f30d2a28e1 Author: Volker Lendecke <v...@samba.org> Date: Fri Apr 11 09:09:49 2014 +0200 printing_cups: Call the msg_ctx destructor on exit With the new messaging, if we don't do this, we'll leave sockets around. I'm sure we will not catch everything, so a periodic cleanup will be required. Signed-off-by: Volker Lendecke <v...@samba.org> Reviewed-by: Jeremy Allison <j...@samba.org> commit c6a27340107854bbcd48ef0a83ee7d3be807445f Author: Volker Lendecke <v...@samba.org> Date: Fri Apr 4 21:12:06 2014 +0200 smbd: Sort notify events by timestamp This will fix the raw.notify test with the new messaging system. With the new messaging system messages come in via yet another fd that has to line up in poll next to the incoming client TCP socket. With the signal-based messaging messages were always handled before client requests. The new scheme means that notify messages might be deferred a bit (something which can happen in a cluster already now), which then means that notify_marshall_changes() will coalesce entries, which in turn makes raw.notify unhappy. Signed-off-by: Volker Lendecke <v...@samba.org> Reviewed-by: Jeremy Allison <j...@samba.org> commit 3218c73da516b653916e161afc8fbeba0691858c Author: Volker Lendecke <v...@samba.org> Date: Fri Apr 4 21:01:01 2014 +0200 smbd: Pass on a timestamp in MSG_PVFS_NOTIFY Signed-off-by: Volker Lendecke <v...@samba.org> Reviewed-by: Jeremy Allison <j...@samba.org> commit cdc99c145d91aaac08886862a38a0e320e10be85 Author: Volker Lendecke <v...@samba.org> Date: Tue Feb 25 12:15:58 2014 +0000 messaging3: Add messaging_send_iov This uses a copy, will be replaced by a direct iovec call through to sendmsg on the unix domain socket Signed-off-by: Volker Lendecke <v...@samba.org> Reviewed-by: Jeremy Allison <j...@samba.org> commit e2683605b0c00a0911d59a9123210fe55400a732 Author: Volker Lendecke <v...@samba.org> Date: Sun Mar 2 19:33:08 2014 +0100 lib: Add iov_buf Signed-off-by: Volker Lendecke <v...@samba.org> Reviewed-by: Jeremy Allison <j...@samba.org> commit 7009b4921c6b05af2e27457500b9b2d838d40b28 Author: Volker Lendecke <v...@samba.org> Date: Sun Mar 2 18:34:53 2014 +0100 lib: Introduce iov_buflen .. with overflow protection Signed-off-by: Volker Lendecke <v...@samba.org> Reviewed-by: Jeremy Allison <j...@samba.org> commit da1778f4458d6be61b1a1b74c18367e98d6065e0 Author: Volker Lendecke <v...@samba.org> Date: Fri Apr 4 15:11:51 2014 +0000 smbd: Pass timespec_current through the notify_callback Signed-off-by: Volker Lendecke <v...@samba.org> Reviewed-by: Jeremy Allison <j...@samba.org> commit 892bec88a3c4842d1b8d43dd9984eada99eab810 Author: Volker Lendecke <v...@samba.org> Date: Fri Apr 4 15:03:44 2014 +0000 smbd: Pass timespec_current to notify_fsp Signed-off-by: Volker Lendecke <v...@samba.org> Reviewed-by: Jeremy Allison <j...@samba.org> commit e616e3c9372bfffb99260ddc310890cbcdbd08c5 Author: Volker Lendecke <v...@samba.org> Date: Fri Apr 4 15:00:16 2014 +0000 smbd: Add a timestamp to queued notify events In a cluster and with changed messaging it can happen that messages are scheduled after new SMB requests. This re-ordering breaks a few notify tests. This starts the infrastructure to add timestamps to notify events, so that they can be sorted before they are sent out. The timestamp will be the current local time of notify_fname, that's all we can do. Signed-off-by: Volker Lendecke <v...@samba.org> Reviewed-by: Jeremy Allison <j...@samba.org> commit b022038cdc17cf02710cd77c7daa80dbfcbece8c Author: Volker Lendecke <v...@samba.org> Date: Mon Feb 24 13:20:16 2014 +0000 lib: Remove messages_local Signed-off-by: Volker Lendecke <v...@samba.org> Reviewed-by: Jeremy Allison <j...@samba.org> commit 29603d1cd9072bf32adfe13ee3d764fd13d12bd0 Author: Volker Lendecke <v...@samba.org> Date: Mon Feb 24 12:23:49 2014 +0000 lib: Add messaging_dgm Messaging based on unix domain datagram sockets This makes every process participating in messaging bind on a unix domain datagram socket, similar to the source4 based messaging. The details are a bit different though: Retry after EWOULDBLOCK is done with a blocking thread, not by polling. This was the only way I could in experiments avoid a thundering herd or high load under Linux in extreme overload situations like many thousands of processes sending to one blocked process. If there are better ideas to do this in a simple way, I'm more than happy to remove the pthreadpool dependency again. There is only one socket per process, not per task. I don't think that per-task sockets are really necessary, we can do filtering in user space. The message contains the destination server_id, which contains the destination task_id. I think we can rebase the source4 based imessaging on top of this, allowing multiple imessaging contexts on top of one messaging_context. I had planned to do this conversion before this goes in, but Jeremy convinced me that this has value in itself :-) Per socket we also create a fcntl-based lockfile to allow race-free cleanup of orphaned sockets. This lockfile contains the unique_id, which in the future will make the server_id.tdb obsolete. Signed-off-by: Volker Lendecke <v...@samba.org> Reviewed-by: Jeremy Allison <j...@samba.org> commit 3e24e07467962436fa505f3b8e591f1af6cafdc0 Author: Volker Lendecke <v...@samba.org> Date: Sun Dec 29 13:56:44 2013 +0100 lib: Move full_path_tos to util_str.c This can be useful elsewhere Signed-off-by: Volker Lendecke <v...@samba.org> Reviewed-by: Jeremy Allison <j...@samba.org> commit 6dcf2c7eab0f39a17f22b09df94e5fcdac8726d1 Author: Volker Lendecke <v...@samba.org> Date: Mon Feb 24 11:48:16 2014 +0000 lib: Add unix_msg This is a messaging layer based on unix domain datagram sockets. Sending to an idle socket is just one single nonblocking sendmsg call. If the recv queue is full, we start a background thread to do a blocking call. The source4 based imessaging uses a polling fallback. In a situation where thousands of senders beat one single blocked socket, this will generate load on the system due to the constant polling. This does not happen with a threaded blocking send call. The threaded approach has another advantage: We save become_root() calls on the retries. The access checks are done when the blocking socket is connected, the threaded blocking send call does not check permissions anymore. Signed-off-by: Volker Lendecke <v...@samba.org> Reviewed-by: Jeremy Allison <j...@samba.org> commit bafdecdf1fb110b02796a6357b1501777195f9d9 Author: Volker Lendecke <v...@samba.org> Date: Mon Feb 24 11:43:51 2014 +0000 lib: Add poll_funcs This is an abstraction for a tevent loop. It will be used in low-level messaging with the goal to make low-leve our low-level messaging routines usable also for other projects which are not based on tevent. Signed-off-by: Volker Lendecke <v...@samba.org> Reviewed-by: Jeremy Allison <j...@samba.org> ----------------------------------------------------------------------- Summary of changes: source3/include/messages.h | 15 +- source3/include/proto.h | 5 + source3/lib/background.c | 1 + source3/lib/messages.c | 82 +++- source3/lib/messages_dgm.c | 463 +++++++++++++++ source3/lib/messages_local.c | 573 ------------------- source3/lib/poll_funcs/poll_funcs.h | 131 +++++ source3/lib/poll_funcs/poll_funcs_tevent.c | 143 +++++ source3/lib/poll_funcs/poll_funcs_tevent.h | 27 + source3/lib/poll_funcs/wscript_build | 5 + source3/lib/unix_msg/test_drain.c | 70 +++ source3/lib/unix_msg/test_source.c | 79 +++ source3/lib/unix_msg/tests.c | 225 ++++++++ source3/lib/unix_msg/unix_msg.c | 858 ++++++++++++++++++++++++++++ source3/lib/unix_msg/unix_msg.h | 107 ++++ source3/lib/unix_msg/wscript_build | 18 + source3/lib/util_sock.c | 53 ++- source3/lib/util_str.c | 39 ++ source3/nmbd/nmbd.c | 4 + source3/printing/print_cups.c | 1 + source3/smbd/files.c | 39 -- source3/smbd/notify.c | 51 ++- source3/smbd/notify_internal.c | 71 ++-- source3/smbd/proto.h | 6 +- source3/smbd/server.c | 20 +- source3/torture/msgtest.c | 22 +- source3/utils/smbcontrol.c | 21 + source3/winbindd/winbindd.c | 4 + source3/wscript_build | 10 +- 29 files changed, 2434 insertions(+), 709 deletions(-) create mode 100644 source3/lib/messages_dgm.c delete mode 100644 source3/lib/messages_local.c create mode 100644 source3/lib/poll_funcs/poll_funcs.h create mode 100644 source3/lib/poll_funcs/poll_funcs_tevent.c create mode 100644 source3/lib/poll_funcs/poll_funcs_tevent.h create mode 100644 source3/lib/poll_funcs/wscript_build create mode 100644 source3/lib/unix_msg/test_drain.c create mode 100644 source3/lib/unix_msg/test_source.c create mode 100644 source3/lib/unix_msg/tests.c create mode 100644 source3/lib/unix_msg/unix_msg.c create mode 100644 source3/lib/unix_msg/unix_msg.h create mode 100644 source3/lib/unix_msg/wscript_build Changeset truncated at 500 lines: diff --git a/source3/include/messages.h b/source3/include/messages.h index 47c5f7a..1681ec9 100644 --- a/source3/include/messages.h +++ b/source3/include/messages.h @@ -91,14 +91,11 @@ struct messaging_backend { void *private_data; }; -NTSTATUS messaging_tdb_init(struct messaging_context *msg_ctx, +NTSTATUS messaging_dgm_init(struct messaging_context *msg_ctx, TALLOC_CTX *mem_ctx, struct messaging_backend **presult); - -bool messaging_tdb_parent_init(TALLOC_CTX *mem_ctx); - -NTSTATUS messaging_tdb_cleanup(struct messaging_context *msg_ctx, - struct server_id pid); +NTSTATUS messaging_dgm_cleanup(struct messaging_context *msg_ctx, pid_t pid); +NTSTATUS messaging_dgm_wipe(struct messaging_context *msg_ctx); NTSTATUS messaging_ctdbd_init(struct messaging_context *msg_ctx, TALLOC_CTX *mem_ctx, @@ -136,6 +133,9 @@ NTSTATUS messaging_send(struct messaging_context *msg_ctx, NTSTATUS messaging_send_buf(struct messaging_context *msg_ctx, struct server_id server, uint32_t msg_type, const uint8_t *buf, size_t len); +NTSTATUS messaging_send_iov(struct messaging_context *msg_ctx, + struct server_id server, uint32_t msg_type, + const struct iovec *iov, int iovlen); void messaging_dispatch_rec(struct messaging_context *msg_ctx, struct messaging_rec *rec); @@ -146,8 +146,7 @@ struct tevent_req *messaging_read_send(TALLOC_CTX *mem_ctx, int messaging_read_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx, struct messaging_rec **presult); -void messaging_cleanup_server(struct messaging_context *msg_ctx, - struct server_id pid); +bool messaging_parent_dgm_cleanup_init(struct messaging_context *msg); #include "librpc/gen_ndr/ndr_messaging.h" diff --git a/source3/include/proto.h b/source3/include/proto.h index 3197b76..0a4db86 100644 --- a/source3/include/proto.h +++ b/source3/include/proto.h @@ -583,6 +583,8 @@ NTSTATUS read_fd_with_timeout(int fd, char *buf, size_t *size_ret); NTSTATUS read_data(int fd, char *buffer, size_t N); ssize_t write_data(int fd, const char *buffer, size_t N); +ssize_t iov_buflen(const struct iovec *iov, int iovlen); +uint8_t *iov_buf(TALLOC_CTX *mem_ctx, const struct iovec *iov, int iovcnt); ssize_t write_data_iov(int fd, const struct iovec *orig_iov, int iovcnt); bool send_keepalive(int client); NTSTATUS read_smb_length_return_keepalive(int fd, char *inbuf, @@ -724,6 +726,9 @@ bool validate_net_name( const char *name, int max_len); char *escape_shell_string(const char *src); char **str_list_make_v3(TALLOC_CTX *mem_ctx, const char *string, const char *sep); +ssize_t full_path_tos(const char *dir, const char *name, + char *tmpbuf, size_t tmpbuf_len, + char **pdst, char **to_free); /* The following definitions come from lib/version.c */ diff --git a/source3/lib/background.c b/source3/lib/background.c index 6a91783..a9fd04f 100644 --- a/source3/lib/background.c +++ b/source3/lib/background.c @@ -181,6 +181,7 @@ static void background_job_waited(struct tevent_req *subreq) if (written == -1) { _exit(1); } + TALLOC_FREE(state->msg); _exit(0); } diff --git a/source3/lib/messages.c b/source3/lib/messages.c index 4ff933d..b6fe423 100644 --- a/source3/lib/messages.c +++ b/source3/lib/messages.c @@ -50,6 +50,7 @@ #include "serverid.h" #include "messages.h" #include "lib/util/tevent_unix.h" +#include "lib/background.h" struct messaging_callback { struct messaging_callback *prev, *next; @@ -197,10 +198,10 @@ struct messaging_context *messaging_init(TALLOC_CTX *mem_ctx, ctx->id = procid_self(); ctx->event_ctx = ev; - status = messaging_tdb_init(ctx, ctx, &ctx->local); + status = messaging_dgm_init(ctx, ctx, &ctx->local); if (!NT_STATUS_IS_OK(status)) { - DEBUG(2, ("messaging_tdb_init failed: %s\n", + DEBUG(2, ("messaging_dgm_init failed: %s\n", nt_errstr(status))); TALLOC_FREE(ctx); return NULL; @@ -245,9 +246,9 @@ NTSTATUS messaging_reinit(struct messaging_context *msg_ctx) msg_ctx->id = procid_self(); - status = messaging_tdb_init(msg_ctx, msg_ctx, &msg_ctx->local); + status = messaging_dgm_init(msg_ctx, msg_ctx, &msg_ctx->local); if (!NT_STATUS_IS_OK(status)) { - DEBUG(0, ("messaging_tdb_init failed: %s\n", + DEBUG(0, ("messaging_dgm_init failed: %s\n", nt_errstr(status))); return status; } @@ -419,6 +420,25 @@ NTSTATUS messaging_send_buf(struct messaging_context *msg_ctx, return messaging_send(msg_ctx, server, msg_type, &blob); } +NTSTATUS messaging_send_iov(struct messaging_context *msg_ctx, + struct server_id server, uint32_t msg_type, + const struct iovec *iov, int iovlen) +{ + uint8_t *buf; + NTSTATUS status; + + buf = iov_buf(talloc_tos(), iov, iovlen); + if (buf == NULL) { + return NT_STATUS_NO_MEMORY; + } + + status = messaging_send_buf(msg_ctx, server, msg_type, + buf, talloc_get_size(buf)); + + TALLOC_FREE(buf); + return status; +} + static struct messaging_rec *messaging_rec_dup(TALLOC_CTX *mem_ctx, struct messaging_rec *rec) { @@ -567,21 +587,53 @@ void messaging_dispatch_rec(struct messaging_context *msg_ctx, return; } -/* - Call when a process has terminated abnormally. -*/ -void messaging_cleanup_server(struct messaging_context *msg_ctx, - struct server_id server) +static int mess_parent_dgm_cleanup(void *private_data); +static void mess_parent_dgm_cleanup_done(struct tevent_req *req); + +bool messaging_parent_dgm_cleanup_init(struct messaging_context *msg) { - if (server_id_is_disconnected(&server)) { - return; - } + struct tevent_req *req; - if (!procid_is_local(&server)) { - return; + req = background_job_send( + msg, msg->event_ctx, msg, NULL, 0, + lp_parm_int(-1, "messaging", "messaging dgm cleanup interval", 60*15), + mess_parent_dgm_cleanup, msg); + if (req == NULL) { + return false; } + tevent_req_set_callback(req, mess_parent_dgm_cleanup_done, msg); + return true; +} - (void)messaging_tdb_cleanup(msg_ctx, server); +static int mess_parent_dgm_cleanup(void *private_data) +{ + struct messaging_context *msg_ctx = talloc_get_type_abort( + private_data, struct messaging_context); + NTSTATUS status; + status = messaging_dgm_wipe(msg_ctx); + DEBUG(10, ("messaging_dgm_wipe returned %s\n", nt_errstr(status))); + return lp_parm_int(-1, "messaging", "messaging dgm cleanup interval", 60*15); } + +static void mess_parent_dgm_cleanup_done(struct tevent_req *req) +{ + struct messaging_context *msg = tevent_req_callback_data( + req, struct messaging_context); + NTSTATUS status; + + status = background_job_recv(req); + TALLOC_FREE(req); + DEBUG(1, ("messaging dgm cleanup job ended with %s\n", nt_errstr(status))); + + req = background_job_send( + msg, msg->event_ctx, msg, NULL, 0, + lp_parm_int(-1, "messaging", "messaging dgm cleanup interval", 60*15), + mess_parent_dgm_cleanup, msg); + if (req == NULL) { + DEBUG(1, ("background_job_send failed\n")); + } + tevent_req_set_callback(req, mess_parent_dgm_cleanup_done, msg); +} + /** @} **/ diff --git a/source3/lib/messages_dgm.c b/source3/lib/messages_dgm.c new file mode 100644 index 0000000..354dac3 --- /dev/null +++ b/source3/lib/messages_dgm.c @@ -0,0 +1,463 @@ +/* + * Unix SMB/CIFS implementation. + * Samba internal messaging functions + * Copyright (C) 2013 by Volker Lendecke + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "includes.h" +#include "lib/util/data_blob.h" +#include "lib/util/debug.h" +#include "lib/unix_msg/unix_msg.h" +#include "system/filesys.h" +#include "messages.h" +#include "lib/param/param.h" +#include "poll_funcs/poll_funcs_tevent.h" +#include "unix_msg/unix_msg.h" +#include "librpc/gen_ndr/messaging.h" + +struct messaging_dgm_context { + struct messaging_context *msg_ctx; + struct poll_funcs msg_callbacks; + struct unix_msg_ctx *dgm_ctx; + char *cache_dir; + int lockfile_fd; +}; + +struct messaging_dgm_hdr { + uint32_t msg_version; + enum messaging_type msg_type; + struct server_id dst; + struct server_id src; +}; + +static NTSTATUS messaging_dgm_send(struct messaging_context *msg_ctx, + struct server_id pid, int msg_type, + const DATA_BLOB *data, + struct messaging_backend *backend); +static void messaging_dgm_recv(struct unix_msg_ctx *ctx, + uint8_t *msg, size_t msg_len, + void *private_data); + +static int messaging_dgm_context_destructor(struct messaging_dgm_context *c); + +static int messaging_dgm_lockfile_create(const char *cache_dir, pid_t pid, + int *plockfile_fd, uint64_t unique) +{ + char buf[PATH_MAX]; + char *dir, *to_free; + ssize_t dirlen; + char *lockfile_name; + int lockfile_fd; + struct flock lck = {}; + int unique_len, ret; + ssize_t written; + bool ok; + + dirlen = full_path_tos(cache_dir, "lck", buf, sizeof(buf), + &dir, &to_free); + if (dirlen == -1) { + return ENOMEM; + } + + ok = directory_create_or_exist_strict(dir, sec_initial_uid(), 0755); + if (!ok) { + ret = errno; + DEBUG(1, ("%s: Could not create lock directory: %s\n", + __func__, strerror(ret))); + TALLOC_FREE(to_free); + return ret; + } + + lockfile_name = talloc_asprintf(talloc_tos(), "%s/%u", dir, + (unsigned)pid); + TALLOC_FREE(to_free); + if (lockfile_name == NULL) { + DEBUG(1, ("%s: talloc_asprintf failed\n", __func__)); + return ENOMEM; + } + + /* no O_EXCL, existence check is via the fcntl lock */ + + lockfile_fd = open(lockfile_name, O_NONBLOCK|O_CREAT|O_WRONLY, 0644); + if (lockfile_fd == -1) { + ret = errno; + DEBUG(1, ("%s: open failed: %s\n", __func__, strerror(errno))); + goto fail_free; + } + + lck.l_type = F_WRLCK; + lck.l_whence = SEEK_SET; + lck.l_start = 0; + lck.l_len = 0; + + ret = fcntl(lockfile_fd, F_SETLK, &lck); + if (ret == -1) { + ret = errno; + DEBUG(1, ("%s: fcntl failed: %s\n", __func__, strerror(ret))); + goto fail_close; + } + + unique_len = snprintf(buf, sizeof(buf), "%"PRIu64, unique); + + /* shorten a potentially preexisting file */ + + ret = ftruncate(lockfile_fd, unique_len); + if (ret == -1) { + ret = errno; + DEBUG(1, ("%s: ftruncate failed: %s\n", __func__, + strerror(ret))); + goto fail_unlink; + } + + written = write(lockfile_fd, buf, unique_len); + if (written != unique_len) { + ret = errno; + DEBUG(1, ("%s: write failed: %s\n", __func__, strerror(ret))); + goto fail_unlink; + } + + *plockfile_fd = lockfile_fd; + return 0; + +fail_unlink: + unlink(lockfile_name); +fail_close: + close(lockfile_fd); +fail_free: + TALLOC_FREE(lockfile_name); + return ret; +} + +static int messaging_dgm_lockfile_remove(const char *cache_dir, pid_t pid) +{ + fstring fname; + char buf[PATH_MAX]; + char *lockfile_name, *to_free; + ssize_t len; + int ret; + + fstr_sprintf(fname, "lck/%u", (unsigned)pid); + + len = full_path_tos(cache_dir, fname, buf, sizeof(buf), + &lockfile_name, &to_free); + if (len == -1) { + return ENOMEM; + } + + ret = unlink(lockfile_name); + if (ret == -1) { + ret = errno; + DEBUG(10, ("%s: unlink failed: %s\n", __func__, + strerror(ret))); + } + TALLOC_FREE(to_free); + return ret; +} + +NTSTATUS messaging_dgm_init(struct messaging_context *msg_ctx, + TALLOC_CTX *mem_ctx, + struct messaging_backend **presult) +{ + struct messaging_backend *result; + struct messaging_dgm_context *ctx; + struct server_id pid = messaging_server_id(msg_ctx); + int ret; + bool ok; + const char *cache_dir; + char *socket_dir, *socket_name; + uint64_t cookie; + + cache_dir = lp_cache_directory(); + if (cache_dir == NULL) { + NTSTATUS status = map_nt_error_from_unix(errno); + return status; + } + + result = talloc(mem_ctx, struct messaging_backend); + if (result == NULL) { + goto fail_nomem; + } + ctx = talloc_zero(result, struct messaging_dgm_context); + if (ctx == NULL) { + goto fail_nomem; + } + + result->private_data = ctx; + result->send_fn = messaging_dgm_send; + ctx->msg_ctx = msg_ctx; + + ctx->cache_dir = talloc_strdup(ctx, cache_dir); + if (ctx->cache_dir == NULL) { + goto fail_nomem; + } + socket_dir = talloc_asprintf(ctx, "%s/msg", cache_dir); + if (socket_dir == NULL) { + goto fail_nomem; + } + socket_name = talloc_asprintf(ctx, "%s/%u", socket_dir, + (unsigned)pid.pid); + if (socket_name == NULL) { + goto fail_nomem; + } + + sec_init(); + + ret = messaging_dgm_lockfile_create(cache_dir, pid.pid, + &ctx->lockfile_fd, pid.unique_id); + if (ret != 0) { + DEBUG(1, ("%s: messaging_dgm_create_lockfile failed: %s\n", + __func__, strerror(ret))); + TALLOC_FREE(result); + return map_nt_error_from_unix(ret); + } + + poll_funcs_init_tevent(&ctx->msg_callbacks, msg_ctx->event_ctx); + + ok = directory_create_or_exist_strict(socket_dir, sec_initial_uid(), + 0700); + if (!ok) { + DEBUG(1, ("Could not create socket directory\n")); + TALLOC_FREE(result); + return NT_STATUS_ACCESS_DENIED; + } + TALLOC_FREE(socket_dir); + + unlink(socket_name); + + generate_random_buffer((uint8_t *)&cookie, sizeof(cookie)); + + ret = unix_msg_init(socket_name, &ctx->msg_callbacks, 1024, cookie, + messaging_dgm_recv, ctx, &ctx->dgm_ctx); + TALLOC_FREE(socket_name); + if (ret != 0) { + DEBUG(1, ("unix_msg_init failed: %s\n", strerror(ret))); + TALLOC_FREE(result); + return map_nt_error_from_unix(ret); + } + talloc_set_destructor(ctx, messaging_dgm_context_destructor); + + *presult = result; + return NT_STATUS_OK; + +fail_nomem: + TALLOC_FREE(result); + return NT_STATUS_NO_MEMORY; +} + +static int messaging_dgm_context_destructor(struct messaging_dgm_context *c) +{ + struct server_id pid = messaging_server_id(c->msg_ctx); + + /* + * First delete the socket to avoid races. The lockfile is the + * indicator that we're still around. + */ + unix_msg_free(c->dgm_ctx); + + if (getpid() == pid.pid) { + (void)messaging_dgm_lockfile_remove(c->cache_dir, pid.pid); + } + close(c->lockfile_fd); + return 0; +} + +static NTSTATUS messaging_dgm_send(struct messaging_context *msg_ctx, + struct server_id pid, int msg_type, + const DATA_BLOB *data, + struct messaging_backend *backend) +{ + struct messaging_dgm_context *ctx = talloc_get_type_abort( + backend->private_data, struct messaging_dgm_context); + fstring pid_str; + char buf[PATH_MAX]; + char *dst_sock, *to_free; + struct messaging_dgm_hdr hdr; + struct iovec iov[2]; + ssize_t pathlen; -- Samba Shared Repository