s3: Add an async smbsock_connect
[Samba.git] / source3 / lib / messages_local.c
blobbe848ac8baca93903076bcfc888b4b19150a1bd0
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"),
106 0, TDB_CLEAR_IF_FIRST|TDB_DEFAULT,
107 O_RDWR|O_CREAT,0600);
109 if (!ctx->tdb) {
110 NTSTATUS status = map_nt_error_from_unix(errno);
111 DEBUG(0, ("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 /* Activate the per-hashchain freelist */
133 tdb_set_max_dead(ctx->tdb->tdb, 5);
135 *presult = result;
136 return NT_STATUS_OK;
139 /*******************************************************************
140 Form a static tdb key from a pid.
141 ******************************************************************/
143 static TDB_DATA message_key_pid(TALLOC_CTX *mem_ctx, struct server_id pid)
145 char *key;
146 TDB_DATA kbuf;
148 key = talloc_asprintf(talloc_tos(), "PID/%s", procid_str_static(&pid));
150 SMB_ASSERT(key != NULL);
152 kbuf.dptr = (uint8 *)key;
153 kbuf.dsize = strlen(key)+1;
154 return kbuf;
158 Fetch the messaging array for a process
161 static NTSTATUS messaging_tdb_fetch(TDB_CONTEXT *msg_tdb,
162 TDB_DATA key,
163 TALLOC_CTX *mem_ctx,
164 struct messaging_array **presult)
166 struct messaging_array *result;
167 TDB_DATA data;
168 DATA_BLOB blob;
169 enum ndr_err_code ndr_err;
171 if (!(result = TALLOC_ZERO_P(mem_ctx, struct messaging_array))) {
172 return NT_STATUS_NO_MEMORY;
175 data = tdb_fetch(msg_tdb, key);
177 if (data.dptr == NULL) {
178 *presult = result;
179 return NT_STATUS_OK;
182 blob = data_blob_const(data.dptr, data.dsize);
184 ndr_err = ndr_pull_struct_blob(
185 &blob, result, NULL, result,
186 (ndr_pull_flags_fn_t)ndr_pull_messaging_array);
188 SAFE_FREE(data.dptr);
190 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
191 TALLOC_FREE(result);
192 return ndr_map_error2ntstatus(ndr_err);
195 if (DEBUGLEVEL >= 10) {
196 DEBUG(10, ("messaging_tdb_fetch:\n"));
197 NDR_PRINT_DEBUG(messaging_array, result);
200 *presult = result;
201 return NT_STATUS_OK;
205 Store a messaging array for a pid
208 static NTSTATUS messaging_tdb_store(TDB_CONTEXT *msg_tdb,
209 TDB_DATA key,
210 struct messaging_array *array)
212 TDB_DATA data;
213 DATA_BLOB blob;
214 enum ndr_err_code ndr_err;
215 TALLOC_CTX *mem_ctx;
216 int ret;
218 if (array->num_messages == 0) {
219 tdb_delete(msg_tdb, key);
220 return NT_STATUS_OK;
223 if (!(mem_ctx = talloc_new(array))) {
224 return NT_STATUS_NO_MEMORY;
227 ndr_err = ndr_push_struct_blob(
228 &blob, mem_ctx, NULL, array,
229 (ndr_push_flags_fn_t)ndr_push_messaging_array);
231 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
232 talloc_free(mem_ctx);
233 return ndr_map_error2ntstatus(ndr_err);
236 if (DEBUGLEVEL >= 10) {
237 DEBUG(10, ("messaging_tdb_store:\n"));
238 NDR_PRINT_DEBUG(messaging_array, array);
241 data.dptr = blob.data;
242 data.dsize = blob.length;
244 ret = tdb_store(msg_tdb, key, data, TDB_REPLACE);
245 TALLOC_FREE(mem_ctx);
247 return (ret == 0) ? NT_STATUS_OK : NT_STATUS_INTERNAL_DB_CORRUPTION;
250 /****************************************************************************
251 Notify a process that it has a message. If the process doesn't exist
252 then delete its record in the database.
253 ****************************************************************************/
255 static NTSTATUS message_notify(struct server_id procid)
257 pid_t pid = procid.pid;
258 int ret;
259 uid_t euid = geteuid();
262 * Doing kill with a non-positive pid causes messages to be
263 * sent to places we don't want.
266 SMB_ASSERT(pid > 0);
268 if (euid != 0) {
269 /* If we're not root become so to send the message. */
270 save_re_uid();
271 set_effective_uid(0);
274 ret = kill(pid, SIGUSR1);
276 if (euid != 0) {
277 /* Go back to who we were. */
278 int saved_errno = errno;
279 restore_re_uid_fromroot();
280 errno = saved_errno;
283 if (ret == 0) {
284 return NT_STATUS_OK;
288 * Something has gone wrong
291 DEBUG(2,("message to process %d failed - %s\n", (int)pid,
292 strerror(errno)));
295 * No call to map_nt_error_from_unix -- don't want to link in
296 * errormap.o into lots of utils.
299 if (errno == ESRCH) return NT_STATUS_INVALID_HANDLE;
300 if (errno == EINVAL) return NT_STATUS_INVALID_PARAMETER;
301 if (errno == EPERM) return NT_STATUS_ACCESS_DENIED;
302 return NT_STATUS_UNSUCCESSFUL;
305 /****************************************************************************
306 Send a message to a particular pid.
307 ****************************************************************************/
309 static NTSTATUS messaging_tdb_send(struct messaging_context *msg_ctx,
310 struct server_id pid, int msg_type,
311 const DATA_BLOB *data,
312 struct messaging_backend *backend)
314 struct messaging_tdb_context *ctx = talloc_get_type(backend->private_data,
315 struct messaging_tdb_context);
316 struct messaging_array *msg_array;
317 struct messaging_rec *rec;
318 NTSTATUS status;
319 TDB_DATA key;
320 struct tdb_wrap *tdb = ctx->tdb;
321 TALLOC_CTX *frame = talloc_stackframe();
323 /* NULL pointer means implicit length zero. */
324 if (!data->data) {
325 SMB_ASSERT(data->length == 0);
329 * Doing kill with a non-positive pid causes messages to be
330 * sent to places we don't want.
333 SMB_ASSERT(procid_to_pid(&pid) > 0);
335 key = message_key_pid(frame, pid);
337 if (tdb_chainlock(tdb->tdb, key) == -1) {
338 TALLOC_FREE(frame);
339 return NT_STATUS_LOCK_NOT_GRANTED;
342 status = messaging_tdb_fetch(tdb->tdb, key, talloc_tos(), &msg_array);
344 if (!NT_STATUS_IS_OK(status)) {
345 goto done;
348 if ((msg_type & MSG_FLAG_LOWPRIORITY)
349 && (msg_array->num_messages > 1000)) {
350 DEBUG(5, ("Dropping message for PID %s\n",
351 procid_str_static(&pid)));
352 status = NT_STATUS_INSUFFICIENT_RESOURCES;
353 goto done;
356 if (!(rec = TALLOC_REALLOC_ARRAY(talloc_tos(), msg_array->messages,
357 struct messaging_rec,
358 msg_array->num_messages+1))) {
359 status = NT_STATUS_NO_MEMORY;
360 goto done;
363 rec[msg_array->num_messages].msg_version = MESSAGE_VERSION;
364 rec[msg_array->num_messages].msg_type = msg_type & MSG_TYPE_MASK;
365 rec[msg_array->num_messages].dest = pid;
366 rec[msg_array->num_messages].src = procid_self();
367 rec[msg_array->num_messages].buf = *data;
369 msg_array->messages = rec;
370 msg_array->num_messages += 1;
372 status = messaging_tdb_store(tdb->tdb, key, msg_array);
374 if (!NT_STATUS_IS_OK(status)) {
375 goto done;
378 status = message_notify(pid);
380 if (NT_STATUS_EQUAL(status, NT_STATUS_INVALID_HANDLE)) {
381 DEBUG(2, ("pid %s doesn't exist - deleting messages record\n",
382 procid_str_static(&pid)));
383 tdb_delete(tdb->tdb, message_key_pid(talloc_tos(), pid));
386 done:
387 tdb_chainunlock(tdb->tdb, key);
388 TALLOC_FREE(frame);
389 return status;
392 /****************************************************************************
393 Retrieve all messages for the current process.
394 ****************************************************************************/
396 static NTSTATUS retrieve_all_messages(TDB_CONTEXT *msg_tdb,
397 TALLOC_CTX *mem_ctx,
398 struct messaging_array **presult)
400 struct messaging_array *result;
401 TDB_DATA key = message_key_pid(mem_ctx, procid_self());
402 NTSTATUS status;
404 if (tdb_chainlock(msg_tdb, key) == -1) {
405 TALLOC_FREE(key.dptr);
406 return NT_STATUS_LOCK_NOT_GRANTED;
409 status = messaging_tdb_fetch(msg_tdb, key, mem_ctx, &result);
412 * We delete the record here, tdb_set_max_dead keeps it around
414 tdb_delete(msg_tdb, key);
415 tdb_chainunlock(msg_tdb, key);
417 if (NT_STATUS_IS_OK(status)) {
418 *presult = result;
421 TALLOC_FREE(key.dptr);
423 return status;
426 /****************************************************************************
427 Receive and dispatch any messages pending for this process.
428 JRA changed Dec 13 2006. Only one message handler now permitted per type.
429 *NOTE*: Dispatch functions must be able to cope with incoming
430 messages on an *odd* byte boundary.
431 ****************************************************************************/
433 static void message_dispatch(struct messaging_context *msg_ctx)
435 struct messaging_tdb_context *ctx = talloc_get_type(msg_ctx->local->private_data,
436 struct messaging_tdb_context);
437 struct messaging_array *msg_array = NULL;
438 struct tdb_wrap *tdb = ctx->tdb;
439 NTSTATUS status;
440 uint32 i;
442 if (ctx->received_messages == 0) {
443 return;
446 DEBUG(10, ("message_dispatch: received_messages = %d\n",
447 ctx->received_messages));
449 status = retrieve_all_messages(tdb->tdb, NULL, &msg_array);
450 if (!NT_STATUS_IS_OK(status)) {
451 DEBUG(0, ("message_dispatch: failed to retrieve messages: %s\n",
452 nt_errstr(status)));
453 return;
456 ctx->received_messages = 0;
458 for (i=0; i<msg_array->num_messages; i++) {
459 messaging_dispatch_rec(msg_ctx, &msg_array->messages[i]);
462 TALLOC_FREE(msg_array);
465 /** @} **/