Fix some "nexted extern" warnins
[Samba.git] / source / lib / messages_local.c
blob0cd482647af5d73b40726bf4c35fb0544c6cd9d3
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 static sig_atomic_t received_signal;
51 static NTSTATUS messaging_tdb_send(struct messaging_context *msg_ctx,
52 struct server_id pid, int msg_type,
53 const DATA_BLOB *data,
54 struct messaging_backend *backend);
56 /****************************************************************************
57 Notifications come in as signals.
58 ****************************************************************************/
60 static void sig_usr1(void)
62 received_signal = 1;
63 sys_select_signal(SIGUSR1);
66 static int messaging_tdb_destructor(struct messaging_backend *tdb_ctx)
68 TDB_CONTEXT *tdb = (TDB_CONTEXT *)tdb_ctx->private_data;
69 tdb_close(tdb);
70 return 0;
73 /****************************************************************************
74 Initialise the messaging functions.
75 ****************************************************************************/
77 NTSTATUS messaging_tdb_init(struct messaging_context *msg_ctx,
78 TALLOC_CTX *mem_ctx,
79 struct messaging_backend **presult)
81 struct messaging_backend *result;
82 TDB_CONTEXT *tdb;
84 if (!(result = TALLOC_P(mem_ctx, struct messaging_backend))) {
85 DEBUG(0, ("talloc failed\n"));
86 return NT_STATUS_NO_MEMORY;
89 tdb = tdb_open_log(lock_path("messages.tdb"),
90 0, TDB_CLEAR_IF_FIRST|TDB_DEFAULT,
91 O_RDWR|O_CREAT,0600);
93 if (!tdb) {
94 NTSTATUS status = map_nt_error_from_unix(errno);
95 DEBUG(0, ("ERROR: Failed to initialise messages database: "
96 "%s\n", strerror(errno)));
97 TALLOC_FREE(result);
98 return status;
101 sec_init();
103 /* Activate the per-hashchain freelist */
104 tdb_set_max_dead(tdb, 5);
106 CatchSignal(SIGUSR1, SIGNAL_CAST sig_usr1);
108 result->private_data = (void *)tdb;
109 result->send_fn = messaging_tdb_send;
111 talloc_set_destructor(result, messaging_tdb_destructor);
113 *presult = result;
114 return NT_STATUS_OK;
117 /*******************************************************************
118 Form a static tdb key from a pid.
119 ******************************************************************/
121 static TDB_DATA message_key_pid(TALLOC_CTX *mem_ctx, struct server_id pid)
123 char *key;
124 TDB_DATA kbuf;
126 key = talloc_asprintf(talloc_tos(), "PID/%s", procid_str_static(&pid));
128 SMB_ASSERT(key != NULL);
130 kbuf.dptr = (uint8 *)key;
131 kbuf.dsize = strlen(key)+1;
132 return kbuf;
136 Fetch the messaging array for a process
139 static NTSTATUS messaging_tdb_fetch(TDB_CONTEXT *msg_tdb,
140 TDB_DATA key,
141 TALLOC_CTX *mem_ctx,
142 struct messaging_array **presult)
144 struct messaging_array *result;
145 TDB_DATA data;
146 DATA_BLOB blob;
147 enum ndr_err_code ndr_err;
149 if (!(result = TALLOC_ZERO_P(mem_ctx, struct messaging_array))) {
150 return NT_STATUS_NO_MEMORY;
153 data = tdb_fetch(msg_tdb, key);
155 if (data.dptr == NULL) {
156 *presult = result;
157 return NT_STATUS_OK;
160 blob = data_blob_const(data.dptr, data.dsize);
162 ndr_err = ndr_pull_struct_blob(
163 &blob, result, result,
164 (ndr_pull_flags_fn_t)ndr_pull_messaging_array);
166 SAFE_FREE(data.dptr);
168 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
169 TALLOC_FREE(result);
170 return ndr_map_error2ntstatus(ndr_err);
173 if (DEBUGLEVEL >= 10) {
174 DEBUG(10, ("messaging_tdb_fetch:\n"));
175 NDR_PRINT_DEBUG(messaging_array, result);
178 *presult = result;
179 return NT_STATUS_OK;
183 Store a messaging array for a pid
186 static NTSTATUS messaging_tdb_store(TDB_CONTEXT *msg_tdb,
187 TDB_DATA key,
188 struct messaging_array *array)
190 TDB_DATA data;
191 DATA_BLOB blob;
192 enum ndr_err_code ndr_err;
193 TALLOC_CTX *mem_ctx;
194 int ret;
196 if (array->num_messages == 0) {
197 tdb_delete(msg_tdb, key);
198 return NT_STATUS_OK;
201 if (!(mem_ctx = talloc_new(array))) {
202 return NT_STATUS_NO_MEMORY;
205 ndr_err = ndr_push_struct_blob(
206 &blob, mem_ctx, array,
207 (ndr_push_flags_fn_t)ndr_push_messaging_array);
209 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
210 talloc_free(mem_ctx);
211 return ndr_map_error2ntstatus(ndr_err);
214 if (DEBUGLEVEL >= 10) {
215 DEBUG(10, ("messaging_tdb_store:\n"));
216 NDR_PRINT_DEBUG(messaging_array, array);
219 data.dptr = blob.data;
220 data.dsize = blob.length;
222 ret = tdb_store(msg_tdb, key, data, TDB_REPLACE);
223 TALLOC_FREE(mem_ctx);
225 return (ret == 0) ? NT_STATUS_OK : NT_STATUS_INTERNAL_DB_CORRUPTION;
228 /****************************************************************************
229 Notify a process that it has a message. If the process doesn't exist
230 then delete its record in the database.
231 ****************************************************************************/
233 static NTSTATUS message_notify(struct server_id procid)
235 pid_t pid = procid.pid;
236 int ret;
237 uid_t euid = geteuid();
240 * Doing kill with a non-positive pid causes messages to be
241 * sent to places we don't want.
244 SMB_ASSERT(pid > 0);
246 if (euid != 0) {
247 /* If we're not root become so to send the message. */
248 save_re_uid();
249 set_effective_uid(0);
252 ret = kill(pid, SIGUSR1);
254 if (euid != 0) {
255 /* Go back to who we were. */
256 int saved_errno = errno;
257 restore_re_uid_fromroot();
258 errno = saved_errno;
261 if (ret == 0) {
262 return NT_STATUS_OK;
266 * Something has gone wrong
269 DEBUG(2,("message to process %d failed - %s\n", (int)pid,
270 strerror(errno)));
273 * No call to map_nt_error_from_unix -- don't want to link in
274 * errormap.o into lots of utils.
277 if (errno == ESRCH) return NT_STATUS_INVALID_HANDLE;
278 if (errno == EINVAL) return NT_STATUS_INVALID_PARAMETER;
279 if (errno == EPERM) return NT_STATUS_ACCESS_DENIED;
280 return NT_STATUS_UNSUCCESSFUL;
283 /****************************************************************************
284 Send a message to a particular pid.
285 ****************************************************************************/
287 static NTSTATUS messaging_tdb_send(struct messaging_context *msg_ctx,
288 struct server_id pid, int msg_type,
289 const DATA_BLOB *data,
290 struct messaging_backend *backend)
292 struct messaging_array *msg_array;
293 struct messaging_rec *rec;
294 NTSTATUS status;
295 TDB_DATA key;
296 TDB_CONTEXT *tdb = (TDB_CONTEXT *)backend->private_data;
297 TALLOC_CTX *frame = talloc_stackframe();
299 /* NULL pointer means implicit length zero. */
300 if (!data->data) {
301 SMB_ASSERT(data->length == 0);
305 * Doing kill with a non-positive pid causes messages to be
306 * sent to places we don't want.
309 SMB_ASSERT(procid_to_pid(&pid) > 0);
311 key = message_key_pid(frame, pid);
313 if (tdb_chainlock(tdb, key) == -1) {
314 TALLOC_FREE(frame);
315 return NT_STATUS_LOCK_NOT_GRANTED;
318 status = messaging_tdb_fetch(tdb, key, talloc_tos(), &msg_array);
320 if (!NT_STATUS_IS_OK(status)) {
321 goto done;
324 if ((msg_type & MSG_FLAG_LOWPRIORITY)
325 && (msg_array->num_messages > 1000)) {
326 DEBUG(5, ("Dropping message for PID %s\n",
327 procid_str_static(&pid)));
328 status = NT_STATUS_INSUFFICIENT_RESOURCES;
329 goto done;
332 if (!(rec = TALLOC_REALLOC_ARRAY(talloc_tos(), msg_array->messages,
333 struct messaging_rec,
334 msg_array->num_messages+1))) {
335 status = NT_STATUS_NO_MEMORY;
336 goto done;
339 rec[msg_array->num_messages].msg_version = MESSAGE_VERSION;
340 rec[msg_array->num_messages].msg_type = msg_type & MSG_TYPE_MASK;
341 rec[msg_array->num_messages].dest = pid;
342 rec[msg_array->num_messages].src = procid_self();
343 rec[msg_array->num_messages].buf = *data;
345 msg_array->messages = rec;
346 msg_array->num_messages += 1;
348 status = messaging_tdb_store(tdb, key, msg_array);
350 if (!NT_STATUS_IS_OK(status)) {
351 goto done;
354 status = message_notify(pid);
356 if (NT_STATUS_EQUAL(status, NT_STATUS_INVALID_HANDLE)) {
357 DEBUG(2, ("pid %s doesn't exist - deleting messages record\n",
358 procid_str_static(&pid)));
359 tdb_delete(tdb, message_key_pid(talloc_tos(), pid));
362 done:
363 tdb_chainunlock(tdb, key);
364 TALLOC_FREE(frame);
365 return status;
368 /****************************************************************************
369 Retrieve all messages for the current process.
370 ****************************************************************************/
372 static NTSTATUS retrieve_all_messages(TDB_CONTEXT *msg_tdb,
373 TALLOC_CTX *mem_ctx,
374 struct messaging_array **presult)
376 struct messaging_array *result;
377 TDB_DATA key = message_key_pid(mem_ctx, procid_self());
378 NTSTATUS status;
380 if (tdb_chainlock(msg_tdb, key) == -1) {
381 TALLOC_FREE(key.dptr);
382 return NT_STATUS_LOCK_NOT_GRANTED;
385 status = messaging_tdb_fetch(msg_tdb, key, mem_ctx, &result);
388 * We delete the record here, tdb_set_max_dead keeps it around
390 tdb_delete(msg_tdb, key);
391 tdb_chainunlock(msg_tdb, key);
393 if (NT_STATUS_IS_OK(status)) {
394 *presult = result;
397 TALLOC_FREE(key.dptr);
399 return status;
402 /****************************************************************************
403 Receive and dispatch any messages pending for this process.
404 JRA changed Dec 13 2006. Only one message handler now permitted per type.
405 *NOTE*: Dispatch functions must be able to cope with incoming
406 messages on an *odd* byte boundary.
407 ****************************************************************************/
409 void message_dispatch(struct messaging_context *msg_ctx)
411 struct messaging_array *msg_array = NULL;
412 TDB_CONTEXT *tdb = (TDB_CONTEXT *)(msg_ctx->local->private_data);
413 uint32 i;
415 if (!received_signal)
416 return;
418 DEBUG(10, ("message_dispatch: received_signal = %d\n",
419 received_signal));
421 received_signal = 0;
423 if (!NT_STATUS_IS_OK(retrieve_all_messages(tdb, NULL, &msg_array))) {
424 return;
427 for (i=0; i<msg_array->num_messages; i++) {
428 messaging_dispatch_rec(msg_ctx, &msg_array->messages[i]);
431 TALLOC_FREE(msg_array);
434 /** @} **/