lib/util: new merged debug system
[Samba.git] / source3 / lib / messages_local.c
blob8cc060b9e2bf26506ce19129d7789ad0c021d165
1 /*
2 Unix SMB/CIFS implementation.
3 Samba internal messaging functions
4 Copyright (C) 2007 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 /**
21 @defgroup messages Internal messaging framework
23 @file messages.c
25 @brief Module for internal messaging between Samba daemons.
27 The idea is that if a part of Samba wants to do communication with
28 another Samba process then it will do a message_register() of a
29 dispatch function, and use message_send_pid() to send messages to
30 that process.
32 The dispatch function is given the pid of the sender, and it can
33 use that to reply by message_send_pid(). See ping_message() for a
34 simple example.
36 @caution Dispatch functions must be able to cope with incoming
37 messages on an *odd* byte boundary.
39 This system doesn't have any inherent size limitations but is not
40 very efficient for large messages or when messages are sent in very
41 quick succession.
45 #include "includes.h"
46 #include "librpc/gen_ndr/messaging.h"
47 #include "librpc/gen_ndr/ndr_messaging.h"
49 struct messaging_tdb_context {
50 struct messaging_context *msg_ctx;
51 struct tdb_wrap *tdb;
52 struct tevent_signal *se;
53 int received_messages;
56 static NTSTATUS messaging_tdb_send(struct messaging_context *msg_ctx,
57 struct server_id pid, int msg_type,
58 const DATA_BLOB *data,
59 struct messaging_backend *backend);
60 static void message_dispatch(struct messaging_context *msg_ctx);
62 static void messaging_tdb_signal_handler(struct tevent_context *ev_ctx,
63 struct tevent_signal *se,
64 int signum, int count,
65 void *_info, void *private_data)
67 struct messaging_tdb_context *ctx = talloc_get_type(private_data,
68 struct messaging_tdb_context);
70 ctx->received_messages++;
72 DEBUG(10, ("messaging_tdb_signal_handler: sig[%d] count[%d] msgs[%d]\n",
73 signum, count, ctx->received_messages));
75 message_dispatch(ctx->msg_ctx);
78 /****************************************************************************
79 Initialise the messaging functions.
80 ****************************************************************************/
82 NTSTATUS messaging_tdb_init(struct messaging_context *msg_ctx,
83 TALLOC_CTX *mem_ctx,
84 struct messaging_backend **presult)
86 struct messaging_backend *result;
87 struct messaging_tdb_context *ctx;
89 if (!(result = TALLOC_P(mem_ctx, struct messaging_backend))) {
90 DEBUG(0, ("talloc failed\n"));
91 return NT_STATUS_NO_MEMORY;
94 ctx = TALLOC_ZERO_P(result, struct messaging_tdb_context);
95 if (!ctx) {
96 DEBUG(0, ("talloc failed\n"));
97 TALLOC_FREE(result);
98 return NT_STATUS_NO_MEMORY;
100 result->private_data = ctx;
101 result->send_fn = messaging_tdb_send;
103 ctx->msg_ctx = msg_ctx;
105 ctx->tdb = tdb_wrap_open(ctx, lock_path("messages.tdb"), 0,
106 TDB_CLEAR_IF_FIRST|TDB_DEFAULT|TDB_VOLATILE|TDB_INCOMPATIBLE_HASH,
107 O_RDWR|O_CREAT,0600);
109 if (!ctx->tdb) {
110 NTSTATUS status = map_nt_error_from_unix(errno);
111 DEBUG(2, ("ERROR: Failed to initialise messages database: "
112 "%s\n", strerror(errno)));
113 TALLOC_FREE(result);
114 return status;
117 ctx->se = tevent_add_signal(msg_ctx->event_ctx,
118 ctx,
119 SIGUSR1, 0,
120 messaging_tdb_signal_handler,
121 ctx);
122 if (!ctx->se) {
123 NTSTATUS status = map_nt_error_from_unix(errno);
124 DEBUG(0, ("ERROR: Failed to initialise messages signal handler: "
125 "%s\n", strerror(errno)));
126 TALLOC_FREE(result);
127 return status;
130 sec_init();
132 *presult = result;
133 return NT_STATUS_OK;
136 bool messaging_tdb_parent_init(TALLOC_CTX *mem_ctx)
138 struct tdb_wrap *db;
141 * Open the tdb in the parent process (smbd) so that our
142 * CLEAR_IF_FIRST optimization in tdb_reopen_all can properly
143 * work.
146 db = tdb_wrap_open(mem_ctx, lock_path("messages.tdb"), 0,
147 TDB_CLEAR_IF_FIRST|TDB_DEFAULT|TDB_VOLATILE|TDB_INCOMPATIBLE_HASH,
148 O_RDWR|O_CREAT,0600);
149 if (db == NULL) {
150 DEBUG(1, ("could not open messaging.tdb: %s\n",
151 strerror(errno)));
152 return false;
154 return true;
157 /*******************************************************************
158 Form a static tdb key from a pid.
159 ******************************************************************/
161 static TDB_DATA message_key_pid(TALLOC_CTX *mem_ctx, struct server_id pid)
163 char *key;
164 TDB_DATA kbuf;
166 key = talloc_asprintf(talloc_tos(), "PID/%s", procid_str_static(&pid));
168 SMB_ASSERT(key != NULL);
170 kbuf.dptr = (uint8 *)key;
171 kbuf.dsize = strlen(key)+1;
172 return kbuf;
176 Fetch the messaging array for a process
179 static NTSTATUS messaging_tdb_fetch(TDB_CONTEXT *msg_tdb,
180 TDB_DATA key,
181 TALLOC_CTX *mem_ctx,
182 struct messaging_array **presult)
184 struct messaging_array *result;
185 TDB_DATA data;
186 DATA_BLOB blob;
187 enum ndr_err_code ndr_err;
189 if (!(result = TALLOC_ZERO_P(mem_ctx, struct messaging_array))) {
190 return NT_STATUS_NO_MEMORY;
193 data = tdb_fetch(msg_tdb, key);
195 if (data.dptr == NULL) {
196 *presult = result;
197 return NT_STATUS_OK;
200 blob = data_blob_const(data.dptr, data.dsize);
202 ndr_err = ndr_pull_struct_blob(
203 &blob, result, result,
204 (ndr_pull_flags_fn_t)ndr_pull_messaging_array);
206 SAFE_FREE(data.dptr);
208 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
209 TALLOC_FREE(result);
210 return ndr_map_error2ntstatus(ndr_err);
213 if (DEBUGLEVEL >= 10) {
214 DEBUG(10, ("messaging_tdb_fetch:\n"));
215 NDR_PRINT_DEBUG(messaging_array, result);
218 *presult = result;
219 return NT_STATUS_OK;
223 Store a messaging array for a pid
226 static NTSTATUS messaging_tdb_store(TDB_CONTEXT *msg_tdb,
227 TDB_DATA key,
228 struct messaging_array *array)
230 TDB_DATA data;
231 DATA_BLOB blob;
232 enum ndr_err_code ndr_err;
233 TALLOC_CTX *mem_ctx;
234 int ret;
236 if (array->num_messages == 0) {
237 tdb_delete(msg_tdb, key);
238 return NT_STATUS_OK;
241 if (!(mem_ctx = talloc_new(array))) {
242 return NT_STATUS_NO_MEMORY;
245 ndr_err = ndr_push_struct_blob(&blob, mem_ctx, array,
246 (ndr_push_flags_fn_t)ndr_push_messaging_array);
248 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
249 talloc_free(mem_ctx);
250 return ndr_map_error2ntstatus(ndr_err);
253 if (DEBUGLEVEL >= 10) {
254 DEBUG(10, ("messaging_tdb_store:\n"));
255 NDR_PRINT_DEBUG(messaging_array, array);
258 data.dptr = blob.data;
259 data.dsize = blob.length;
261 ret = tdb_store(msg_tdb, key, data, TDB_REPLACE);
262 TALLOC_FREE(mem_ctx);
264 return (ret == 0) ? NT_STATUS_OK : NT_STATUS_INTERNAL_DB_CORRUPTION;
267 /****************************************************************************
268 Notify a process that it has a message. If the process doesn't exist
269 then delete its record in the database.
270 ****************************************************************************/
272 static NTSTATUS message_notify(struct server_id procid)
274 pid_t pid = procid.pid;
275 int ret;
276 uid_t euid = geteuid();
279 * Doing kill with a non-positive pid causes messages to be
280 * sent to places we don't want.
283 SMB_ASSERT(pid > 0);
285 if (euid != 0) {
286 /* If we're not root become so to send the message. */
287 save_re_uid();
288 set_effective_uid(0);
291 ret = kill(pid, SIGUSR1);
293 if (euid != 0) {
294 /* Go back to who we were. */
295 int saved_errno = errno;
296 restore_re_uid_fromroot();
297 errno = saved_errno;
300 if (ret == 0) {
301 return NT_STATUS_OK;
305 * Something has gone wrong
308 DEBUG(2,("message to process %d failed - %s\n", (int)pid,
309 strerror(errno)));
312 * No call to map_nt_error_from_unix -- don't want to link in
313 * errormap.o into lots of utils.
316 if (errno == ESRCH) return NT_STATUS_INVALID_HANDLE;
317 if (errno == EINVAL) return NT_STATUS_INVALID_PARAMETER;
318 if (errno == EPERM) return NT_STATUS_ACCESS_DENIED;
319 return NT_STATUS_UNSUCCESSFUL;
322 /****************************************************************************
323 Send a message to a particular pid.
324 ****************************************************************************/
326 static NTSTATUS messaging_tdb_send(struct messaging_context *msg_ctx,
327 struct server_id pid, int msg_type,
328 const DATA_BLOB *data,
329 struct messaging_backend *backend)
331 struct messaging_tdb_context *ctx = talloc_get_type(backend->private_data,
332 struct messaging_tdb_context);
333 struct messaging_array *msg_array;
334 struct messaging_rec *rec;
335 NTSTATUS status;
336 TDB_DATA key;
337 struct tdb_wrap *tdb = ctx->tdb;
338 TALLOC_CTX *frame = talloc_stackframe();
340 /* NULL pointer means implicit length zero. */
341 if (!data->data) {
342 SMB_ASSERT(data->length == 0);
346 * Doing kill with a non-positive pid causes messages to be
347 * sent to places we don't want.
350 SMB_ASSERT(procid_to_pid(&pid) > 0);
352 key = message_key_pid(frame, pid);
354 if (tdb_chainlock(tdb->tdb, key) == -1) {
355 TALLOC_FREE(frame);
356 return NT_STATUS_LOCK_NOT_GRANTED;
359 status = messaging_tdb_fetch(tdb->tdb, key, talloc_tos(), &msg_array);
361 if (!NT_STATUS_IS_OK(status)) {
362 goto done;
365 if ((msg_type & MSG_FLAG_LOWPRIORITY)
366 && (msg_array->num_messages > 1000)) {
367 DEBUG(5, ("Dropping message for PID %s\n",
368 procid_str_static(&pid)));
369 status = NT_STATUS_INSUFFICIENT_RESOURCES;
370 goto done;
373 if (!(rec = TALLOC_REALLOC_ARRAY(talloc_tos(), msg_array->messages,
374 struct messaging_rec,
375 msg_array->num_messages+1))) {
376 status = NT_STATUS_NO_MEMORY;
377 goto done;
380 rec[msg_array->num_messages].msg_version = MESSAGE_VERSION;
381 rec[msg_array->num_messages].msg_type = msg_type & MSG_TYPE_MASK;
382 rec[msg_array->num_messages].dest = pid;
383 rec[msg_array->num_messages].src = msg_ctx->id;
384 rec[msg_array->num_messages].buf = *data;
386 msg_array->messages = rec;
387 msg_array->num_messages += 1;
389 status = messaging_tdb_store(tdb->tdb, key, msg_array);
391 if (!NT_STATUS_IS_OK(status)) {
392 goto done;
395 status = message_notify(pid);
397 if (NT_STATUS_EQUAL(status, NT_STATUS_INVALID_HANDLE)) {
398 DEBUG(2, ("pid %s doesn't exist - deleting messages record\n",
399 procid_str_static(&pid)));
400 tdb_delete(tdb->tdb, message_key_pid(talloc_tos(), pid));
403 done:
404 tdb_chainunlock(tdb->tdb, key);
405 TALLOC_FREE(frame);
406 return status;
409 /****************************************************************************
410 Retrieve all messages for a process.
411 ****************************************************************************/
413 static NTSTATUS retrieve_all_messages(TDB_CONTEXT *msg_tdb,
414 struct server_id id,
415 TALLOC_CTX *mem_ctx,
416 struct messaging_array **presult)
418 struct messaging_array *result;
419 TDB_DATA key = message_key_pid(mem_ctx, id);
420 NTSTATUS status;
422 if (tdb_chainlock(msg_tdb, key) == -1) {
423 TALLOC_FREE(key.dptr);
424 return NT_STATUS_LOCK_NOT_GRANTED;
427 status = messaging_tdb_fetch(msg_tdb, key, mem_ctx, &result);
430 * We delete the record here, tdb_set_max_dead keeps it around
432 tdb_delete(msg_tdb, key);
433 tdb_chainunlock(msg_tdb, key);
435 if (NT_STATUS_IS_OK(status)) {
436 *presult = result;
439 TALLOC_FREE(key.dptr);
441 return status;
444 /****************************************************************************
445 Receive and dispatch any messages pending for this process.
446 JRA changed Dec 13 2006. Only one message handler now permitted per type.
447 *NOTE*: Dispatch functions must be able to cope with incoming
448 messages on an *odd* byte boundary.
449 ****************************************************************************/
451 static void message_dispatch(struct messaging_context *msg_ctx)
453 struct messaging_tdb_context *ctx = talloc_get_type(msg_ctx->local->private_data,
454 struct messaging_tdb_context);
455 struct messaging_array *msg_array = NULL;
456 struct tdb_wrap *tdb = ctx->tdb;
457 NTSTATUS status;
458 uint32 i;
460 if (ctx->received_messages == 0) {
461 return;
464 DEBUG(10, ("message_dispatch: received_messages = %d\n",
465 ctx->received_messages));
467 status = retrieve_all_messages(tdb->tdb, msg_ctx->id, NULL, &msg_array);
468 if (!NT_STATUS_IS_OK(status)) {
469 DEBUG(0, ("message_dispatch: failed to retrieve messages: %s\n",
470 nt_errstr(status)));
471 return;
474 ctx->received_messages = 0;
476 for (i=0; i<msg_array->num_messages; i++) {
477 messaging_dispatch_rec(msg_ctx, &msg_array->messages[i]);
480 TALLOC_FREE(msg_array);
483 /** @} **/