ctdb-common: Keep debug level related functions with logging code
[Samba.git] / source3 / lib / messages_dgm.c
blobba13fc98144a7c1d3d07e35fe6c809f0196a877f
1 /*
2 * Unix SMB/CIFS implementation.
3 * Samba internal messaging functions
4 * Copyright (C) 2013 by Volker Lendecke
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 3 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
20 #include "includes.h"
21 #include "lib/util/data_blob.h"
22 #include "lib/util/debug.h"
23 #include "lib/unix_msg/unix_msg.h"
24 #include "system/filesys.h"
25 #include "messages.h"
26 #include "lib/param/param.h"
27 #include "poll_funcs/poll_funcs_tevent.h"
28 #include "unix_msg/unix_msg.h"
29 #include "librpc/gen_ndr/messaging.h"
31 struct messaging_dgm_context {
32 struct messaging_context *msg_ctx;
33 struct poll_funcs *msg_callbacks;
34 void *tevent_handle;
35 struct unix_msg_ctx *dgm_ctx;
36 char *cache_dir;
37 int lockfile_fd;
40 struct messaging_dgm_hdr {
41 uint32_t msg_version;
42 enum messaging_type msg_type;
43 struct server_id dst;
44 struct server_id src;
47 static NTSTATUS messaging_dgm_send(struct server_id src,
48 struct server_id pid, int msg_type,
49 const struct iovec *iov, int iovlen,
50 struct messaging_backend *backend);
51 static void messaging_dgm_recv(struct unix_msg_ctx *ctx,
52 uint8_t *msg, size_t msg_len,
53 void *private_data);
55 static int messaging_dgm_context_destructor(struct messaging_dgm_context *c);
57 static int messaging_dgm_lockfile_create(const char *cache_dir, pid_t pid,
58 int *plockfile_fd, uint64_t unique)
60 char buf[PATH_MAX];
61 char *dir, *to_free;
62 ssize_t dirlen;
63 char *lockfile_name;
64 int lockfile_fd;
65 struct flock lck = {};
66 int unique_len, ret;
67 ssize_t written;
68 bool ok;
70 dirlen = full_path_tos(cache_dir, "lck", buf, sizeof(buf),
71 &dir, &to_free);
72 if (dirlen == -1) {
73 return ENOMEM;
76 ok = directory_create_or_exist_strict(dir, sec_initial_uid(), 0755);
77 if (!ok) {
78 ret = errno;
79 DEBUG(1, ("%s: Could not create lock directory: %s\n",
80 __func__, strerror(ret)));
81 TALLOC_FREE(to_free);
82 return ret;
85 lockfile_name = talloc_asprintf(talloc_tos(), "%s/%u", dir,
86 (unsigned)pid);
87 TALLOC_FREE(to_free);
88 if (lockfile_name == NULL) {
89 DEBUG(1, ("%s: talloc_asprintf failed\n", __func__));
90 return ENOMEM;
93 /* no O_EXCL, existence check is via the fcntl lock */
95 lockfile_fd = open(lockfile_name, O_NONBLOCK|O_CREAT|O_WRONLY, 0644);
96 if (lockfile_fd == -1) {
97 ret = errno;
98 DEBUG(1, ("%s: open failed: %s\n", __func__, strerror(errno)));
99 goto fail_free;
102 lck.l_type = F_WRLCK;
103 lck.l_whence = SEEK_SET;
104 lck.l_start = 0;
105 lck.l_len = 0;
107 ret = fcntl(lockfile_fd, F_SETLK, &lck);
108 if (ret == -1) {
109 ret = errno;
110 DEBUG(1, ("%s: fcntl failed: %s\n", __func__, strerror(ret)));
111 goto fail_close;
114 unique_len = snprintf(buf, sizeof(buf), "%"PRIu64, unique);
116 /* shorten a potentially preexisting file */
118 ret = ftruncate(lockfile_fd, unique_len);
119 if (ret == -1) {
120 ret = errno;
121 DEBUG(1, ("%s: ftruncate failed: %s\n", __func__,
122 strerror(ret)));
123 goto fail_unlink;
126 written = write(lockfile_fd, buf, unique_len);
127 if (written != unique_len) {
128 ret = errno;
129 DEBUG(1, ("%s: write failed: %s\n", __func__, strerror(ret)));
130 goto fail_unlink;
133 TALLOC_FREE(lockfile_name);
134 *plockfile_fd = lockfile_fd;
135 return 0;
137 fail_unlink:
138 unlink(lockfile_name);
139 fail_close:
140 close(lockfile_fd);
141 fail_free:
142 TALLOC_FREE(lockfile_name);
143 return ret;
146 static int messaging_dgm_lockfile_remove(const char *cache_dir, pid_t pid)
148 fstring fname;
149 char buf[PATH_MAX];
150 char *lockfile_name, *to_free;
151 ssize_t len;
152 int ret;
154 fstr_sprintf(fname, "lck/%u", (unsigned)pid);
156 len = full_path_tos(cache_dir, fname, buf, sizeof(buf),
157 &lockfile_name, &to_free);
158 if (len == -1) {
159 return ENOMEM;
162 ret = unlink(lockfile_name);
163 if (ret == -1) {
164 ret = errno;
165 DEBUG(10, ("%s: unlink failed: %s\n", __func__,
166 strerror(ret)));
168 TALLOC_FREE(to_free);
169 return ret;
172 NTSTATUS messaging_dgm_init(struct messaging_context *msg_ctx,
173 TALLOC_CTX *mem_ctx,
174 struct messaging_backend **presult)
176 struct messaging_backend *result;
177 struct messaging_dgm_context *ctx;
178 struct server_id pid = messaging_server_id(msg_ctx);
179 int ret;
180 bool ok;
181 const char *cache_dir;
182 char *socket_dir, *socket_name;
183 uint64_t cookie;
185 cache_dir = lp_cache_directory();
186 if (cache_dir == NULL) {
187 NTSTATUS status = map_nt_error_from_unix(errno);
188 return status;
191 result = talloc(mem_ctx, struct messaging_backend);
192 if (result == NULL) {
193 goto fail_nomem;
195 ctx = talloc_zero(result, struct messaging_dgm_context);
196 if (ctx == NULL) {
197 goto fail_nomem;
200 result->private_data = ctx;
201 result->send_fn = messaging_dgm_send;
202 ctx->msg_ctx = msg_ctx;
204 ctx->cache_dir = talloc_strdup(ctx, cache_dir);
205 if (ctx->cache_dir == NULL) {
206 goto fail_nomem;
208 socket_dir = talloc_asprintf(ctx, "%s/msg", cache_dir);
209 if (socket_dir == NULL) {
210 goto fail_nomem;
212 socket_name = talloc_asprintf(ctx, "%s/%u", socket_dir,
213 (unsigned)pid.pid);
214 if (socket_name == NULL) {
215 goto fail_nomem;
218 sec_init();
220 ret = messaging_dgm_lockfile_create(cache_dir, pid.pid,
221 &ctx->lockfile_fd, pid.unique_id);
222 if (ret != 0) {
223 DEBUG(1, ("%s: messaging_dgm_create_lockfile failed: %s\n",
224 __func__, strerror(ret)));
225 TALLOC_FREE(result);
226 return map_nt_error_from_unix(ret);
229 ctx->msg_callbacks = poll_funcs_init_tevent(ctx);
230 if (ctx->msg_callbacks == NULL) {
231 TALLOC_FREE(result);
232 return NT_STATUS_NO_MEMORY;
235 ctx->tevent_handle = poll_funcs_tevent_register(
236 ctx, ctx->msg_callbacks,
237 messaging_tevent_context(msg_ctx));
238 if (ctx->tevent_handle == NULL) {
239 TALLOC_FREE(result);
240 return NT_STATUS_NO_MEMORY;
243 ok = directory_create_or_exist_strict(socket_dir, sec_initial_uid(),
244 0700);
245 if (!ok) {
246 DEBUG(1, ("Could not create socket directory\n"));
247 TALLOC_FREE(result);
248 return NT_STATUS_ACCESS_DENIED;
250 TALLOC_FREE(socket_dir);
252 unlink(socket_name);
254 generate_random_buffer((uint8_t *)&cookie, sizeof(cookie));
256 ret = unix_msg_init(socket_name, ctx->msg_callbacks, 1024, cookie,
257 messaging_dgm_recv, ctx, &ctx->dgm_ctx);
258 TALLOC_FREE(socket_name);
259 if (ret != 0) {
260 DEBUG(1, ("unix_msg_init failed: %s\n", strerror(ret)));
261 TALLOC_FREE(result);
262 return map_nt_error_from_unix(ret);
264 talloc_set_destructor(ctx, messaging_dgm_context_destructor);
266 *presult = result;
267 return NT_STATUS_OK;
269 fail_nomem:
270 TALLOC_FREE(result);
271 return NT_STATUS_NO_MEMORY;
274 static int messaging_dgm_context_destructor(struct messaging_dgm_context *c)
276 struct server_id pid = messaging_server_id(c->msg_ctx);
279 * First delete the socket to avoid races. The lockfile is the
280 * indicator that we're still around.
282 unix_msg_free(c->dgm_ctx);
284 if (getpid() == pid.pid) {
285 (void)messaging_dgm_lockfile_remove(c->cache_dir, pid.pid);
287 close(c->lockfile_fd);
288 return 0;
291 static NTSTATUS messaging_dgm_send(struct server_id src,
292 struct server_id pid, int msg_type,
293 const struct iovec *iov, int iovlen,
294 struct messaging_backend *backend)
296 struct messaging_dgm_context *ctx = talloc_get_type_abort(
297 backend->private_data, struct messaging_dgm_context);
298 fstring pid_str;
299 char buf[PATH_MAX];
300 char *dst_sock, *to_free;
301 struct messaging_dgm_hdr hdr;
302 struct iovec iov2[iovlen + 1];
303 ssize_t pathlen;
304 int ret;
306 fstr_sprintf(pid_str, "msg/%u", (unsigned)pid.pid);
308 pathlen = full_path_tos(ctx->cache_dir, pid_str, buf, sizeof(buf),
309 &dst_sock, &to_free);
310 if (pathlen == -1) {
311 return NT_STATUS_NO_MEMORY;
314 hdr.msg_version = MESSAGE_VERSION;
315 hdr.msg_type = msg_type & MSG_TYPE_MASK;
316 hdr.dst = pid;
317 hdr.src = src;
319 DEBUG(10, ("%s: Sending message 0x%x to %s\n", __func__,
320 (unsigned)hdr.msg_type,
321 server_id_str(talloc_tos(), &pid)));
323 iov2[0].iov_base = &hdr;
324 iov2[0].iov_len = sizeof(hdr);
325 memcpy(iov2+1, iov, iovlen*sizeof(struct iovec));
327 become_root();
328 ret = unix_msg_send(ctx->dgm_ctx, dst_sock, iov2, iovlen + 1);
329 unbecome_root();
331 TALLOC_FREE(to_free);
333 if (ret != 0) {
334 return map_nt_error_from_unix(ret);
336 return NT_STATUS_OK;
339 static void messaging_dgm_recv(struct unix_msg_ctx *ctx,
340 uint8_t *msg, size_t msg_len,
341 void *private_data)
343 struct messaging_dgm_context *dgm_ctx = talloc_get_type_abort(
344 private_data, struct messaging_dgm_context);
345 struct messaging_dgm_hdr *hdr;
346 struct messaging_rec rec;
348 if (msg_len < sizeof(*hdr)) {
349 DEBUG(1, ("message too short: %u\n", (unsigned)msg_len));
350 return;
354 * unix_msg guarantees alignment, so we can cast here
356 hdr = (struct messaging_dgm_hdr *)msg;
358 rec.msg_version = hdr->msg_version;
359 rec.msg_type = hdr->msg_type;
360 rec.dest = hdr->dst;
361 rec.src = hdr->src;
362 rec.buf.data = msg + sizeof(*hdr);
363 rec.buf.length = msg_len - sizeof(*hdr);
365 DEBUG(10, ("%s: Received message 0x%x len %u from %s\n", __func__,
366 (unsigned)hdr->msg_type, (unsigned)rec.buf.length,
367 server_id_str(talloc_tos(), &rec.src)));
369 messaging_dispatch_rec(dgm_ctx->msg_ctx, &rec);
372 NTSTATUS messaging_dgm_cleanup(struct messaging_context *msg_ctx, pid_t pid)
374 struct messaging_backend *be = messaging_local_backend(msg_ctx);
375 struct messaging_dgm_context *ctx = talloc_get_type_abort(
376 be->private_data, struct messaging_dgm_context);
377 char *lockfile_name, *socket_name;
378 int fd, ret;
379 struct flock lck = {};
380 NTSTATUS status = NT_STATUS_OK;
382 lockfile_name = talloc_asprintf(talloc_tos(), "%s/lck/%u",
383 ctx->cache_dir, (unsigned)pid);
384 if (lockfile_name == NULL) {
385 return NT_STATUS_NO_MEMORY;
387 socket_name = talloc_asprintf(lockfile_name, "%s/msg/%u",
388 ctx->cache_dir, (unsigned)pid);
389 if (socket_name == NULL) {
390 TALLOC_FREE(lockfile_name);
391 return NT_STATUS_NO_MEMORY;
394 fd = open(lockfile_name, O_NONBLOCK|O_WRONLY, 0);
395 if (fd == -1) {
396 status = map_nt_error_from_unix(errno);
397 DEBUG(10, ("%s: open(%s) failed: %s\n", __func__,
398 lockfile_name, strerror(errno)));
399 return status;
402 lck.l_type = F_WRLCK;
403 lck.l_whence = SEEK_SET;
404 lck.l_start = 0;
405 lck.l_len = 0;
407 ret = fcntl(fd, F_SETLK, &lck);
408 if (ret != 0) {
409 status = map_nt_error_from_unix(errno);
410 DEBUG(10, ("%s: Could not get lock: %s\n", __func__,
411 strerror(errno)));
412 TALLOC_FREE(lockfile_name);
413 close(fd);
414 return status;
417 (void)unlink(socket_name);
418 (void)unlink(lockfile_name);
419 (void)close(fd);
421 TALLOC_FREE(lockfile_name);
422 return NT_STATUS_OK;
425 NTSTATUS messaging_dgm_wipe(struct messaging_context *msg_ctx)
427 struct messaging_backend *be = messaging_local_backend(msg_ctx);
428 struct messaging_dgm_context *ctx = talloc_get_type_abort(
429 be->private_data, struct messaging_dgm_context);
430 char *msgdir_name;
431 DIR *msgdir;
432 struct dirent *dp;
433 pid_t our_pid = getpid();
436 * We scan the socket directory and not the lock directory. Otherwise
437 * we would race against messaging_dgm_lockfile_create's open(O_CREAT)
438 * and fcntl(SETLK).
441 msgdir_name = talloc_asprintf(talloc_tos(), "%s/msg", ctx->cache_dir);
442 if (msgdir_name == NULL) {
443 return NT_STATUS_NO_MEMORY;
446 msgdir = opendir(msgdir_name);
447 TALLOC_FREE(msgdir_name);
448 if (msgdir == NULL) {
449 return map_nt_error_from_unix(errno);
452 while ((dp = readdir(msgdir)) != NULL) {
453 NTSTATUS status;
454 unsigned long pid;
456 pid = strtoul(dp->d_name, NULL, 10);
457 if (pid == 0) {
459 * . and .. and other malformed entries
461 continue;
463 if (pid == our_pid) {
465 * fcntl(F_GETLK) will succeed for ourselves, we hold
466 * that lock ourselves.
468 continue;
471 status = messaging_dgm_cleanup(msg_ctx, pid);
472 DEBUG(10, ("messaging_dgm_cleanup(%lu) returned %s\n",
473 pid, nt_errstr(status)));
475 closedir(msgdir);
477 return NT_STATUS_OK;
480 void *messaging_dgm_register_tevent_context(TALLOC_CTX *mem_ctx,
481 struct messaging_context *msg_ctx,
482 struct tevent_context *ev)
484 struct messaging_backend *be = messaging_local_backend(msg_ctx);
485 struct messaging_dgm_context *ctx = talloc_get_type_abort(
486 be->private_data, struct messaging_dgm_context);
487 return poll_funcs_tevent_register(mem_ctx, ctx->msg_callbacks, ev);