2 Unix SMB/CIFS implementation.
3 Samba internal messaging functions
4 Copyright (C) Andrew Tridgell 2000
5 Copyright (C) 2001 by Martin Pool
6 Copyright (C) 2002 by Jeremy Allison
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 @defgroup messages Internal messaging framework
28 @brief Module for internal messaging between Samba daemons.
30 The idea is that if a part of Samba wants to do communication with
31 another Samba process then it will do a message_register() of a
32 dispatch function, and use message_send_pid() to send messages to
35 The dispatch function is given the pid of the sender, and it can
36 use that to reply by message_send_pid(). See ping_message() for a
39 @caution Dispatch functions must be able to cope with incoming
40 messages on an *odd* byte boundary.
42 This system doesn't have any inherent size limitations but is not
43 very efficient for large messages or when messages are sent in very
50 /* the locking database handle */
51 static TDB_CONTEXT
*tdb
;
52 static int received_signal
;
54 /* change the message version with any incompatible changes in the protocol */
55 #define MESSAGE_VERSION 1
60 struct process_id dest
;
61 struct process_id src
;
65 /* we have a linked list of dispatch handlers */
66 static struct dispatch_fns
{
67 struct dispatch_fns
*next
, *prev
;
69 void (*fn
)(int msg_type
, struct process_id pid
, void *buf
, size_t len
);
72 /****************************************************************************
74 ****************************************************************************/
76 void gfree_messages(void)
78 struct dispatch_fns
*dfn
, *next
;
80 /* delete the dispatch_fns list */
84 DLIST_REMOVE(dispatch_fns
, dfn
);
90 /****************************************************************************
91 Notifications come in as signals.
92 ****************************************************************************/
94 static void sig_usr1(void)
97 sys_select_signal(SIGUSR1
);
100 /****************************************************************************
101 A useful function for testing the message system.
102 ****************************************************************************/
104 static void ping_message(int msg_type
, struct process_id src
,
105 void *buf
, size_t len
)
107 const char *msg
= buf
? buf
: "none";
109 DEBUG(1,("INFO: Received PING message from PID %s [%s]\n",
110 procid_str_static(&src
), msg
));
111 message_send_pid(src
, MSG_PONG
, buf
, len
, True
);
114 /****************************************************************************
115 Initialise the messaging functions.
116 ****************************************************************************/
118 BOOL
message_init(void)
125 tdb
= tdb_open_log(lock_path("messages.tdb"),
126 0, TDB_CLEAR_IF_FIRST
|TDB_DEFAULT
,
127 O_RDWR
|O_CREAT
,0600);
130 DEBUG(0,("ERROR: Failed to initialise messages database\n"));
134 CatchSignal(SIGUSR1
, SIGNAL_CAST sig_usr1
);
136 message_register(MSG_PING
, ping_message
);
138 /* Register some debugging related messages */
140 register_msg_pool_usage();
141 register_dmalloc_msgs();
146 /*******************************************************************
147 Form a static tdb key from a pid.
148 ******************************************************************/
150 static TDB_DATA
message_key_pid(struct process_id pid
)
155 slprintf(key
, sizeof(key
)-1, "PID/%s", procid_str_static(&pid
));
157 kbuf
.dptr
= (char *)key
;
158 kbuf
.dsize
= strlen(key
)+1;
162 /****************************************************************************
163 Notify a process that it has a message. If the process doesn't exist
164 then delete its record in the database.
165 ****************************************************************************/
167 static BOOL
message_notify(struct process_id procid
)
169 pid_t pid
= procid
.pid
;
171 uid_t euid
= geteuid();
174 * Doing kill with a non-positive pid causes messages to be
175 * sent to places we don't want.
181 become_root_uid_only();
184 ret
= kill(pid
, SIGUSR1
);
187 unbecome_root_uid_only();
191 if (errno
== ESRCH
) {
192 DEBUG(2,("pid %d doesn't exist - deleting messages record\n", (int)pid
));
193 tdb_delete(tdb
, message_key_pid(procid
));
195 DEBUG(2,("message to process %d failed - %s\n", (int)pid
, strerror(errno
)));
203 /****************************************************************************
204 Send a message to a particular pid.
205 ****************************************************************************/
207 static BOOL
message_send_pid_internal(struct process_id pid
, int msg_type
,
208 const void *buf
, size_t len
,
209 BOOL duplicates_allowed
,
210 unsigned int timeout
)
215 struct message_rec rec
;
217 struct message_rec prec
;
219 /* NULL pointer means implicit length zero. */
221 SMB_ASSERT(len
== 0);
225 * Doing kill with a non-positive pid causes messages to be
226 * sent to places we don't want.
229 SMB_ASSERT(procid_to_pid(&pid
) > 0);
231 rec
.msg_version
= MESSAGE_VERSION
;
232 rec
.msg_type
= msg_type
;
234 rec
.src
= procid_self();
235 rec
.len
= buf
? len
: 0;
237 kbuf
= message_key_pid(pid
);
239 dbuf
.dptr
= (void *)SMB_MALLOC(len
+ sizeof(rec
));
243 memcpy(dbuf
.dptr
, &rec
, sizeof(rec
));
245 memcpy((void *)((char*)dbuf
.dptr
+sizeof(rec
)), buf
, len
);
247 dbuf
.dsize
= len
+ sizeof(rec
);
249 if (duplicates_allowed
) {
251 /* If duplicates are allowed we can just append the message and return. */
253 /* lock the record for the destination */
255 if (tdb_chainlock_with_timeout(tdb
, kbuf
, timeout
) == -1) {
256 DEBUG(0,("message_send_pid_internal: failed to get chainlock with timeout %ul.\n", timeout
));
260 if (tdb_chainlock(tdb
, kbuf
) == -1) {
261 DEBUG(0,("message_send_pid_internal: failed to get chainlock.\n"));
265 tdb_append(tdb
, kbuf
, dbuf
);
266 tdb_chainunlock(tdb
, kbuf
);
268 SAFE_FREE(dbuf
.dptr
);
269 errno
= 0; /* paranoia */
270 return message_notify(pid
);
273 /* lock the record for the destination */
275 if (tdb_chainlock_with_timeout(tdb
, kbuf
, timeout
) == -1) {
276 DEBUG(0,("message_send_pid_internal: failed to get chainlock with timeout %ul.\n", timeout
));
280 if (tdb_chainlock(tdb
, kbuf
) == -1) {
281 DEBUG(0,("message_send_pid_internal: failed to get chainlock.\n"));
286 old_dbuf
= tdb_fetch(tdb
, kbuf
);
288 if (!old_dbuf
.dptr
) {
289 /* its a new record */
291 tdb_store(tdb
, kbuf
, dbuf
, TDB_REPLACE
);
292 tdb_chainunlock(tdb
, kbuf
);
294 SAFE_FREE(dbuf
.dptr
);
295 errno
= 0; /* paranoia */
296 return message_notify(pid
);
299 /* Not a new record. Check for duplicates. */
301 for(ptr
= (char *)old_dbuf
.dptr
; ptr
< old_dbuf
.dptr
+ old_dbuf
.dsize
; ) {
303 * First check if the message header matches, then, if it's a non-zero
304 * sized message, check if the data matches. If so it's a duplicate and
305 * we can discard it. JRA.
308 if (!memcmp(ptr
, &rec
, sizeof(rec
))) {
309 if (!len
|| (len
&& !memcmp( ptr
+ sizeof(rec
), buf
, len
))) {
310 tdb_chainunlock(tdb
, kbuf
);
311 DEBUG(10,("message_send_pid_internal: discarding duplicate message.\n"));
312 SAFE_FREE(dbuf
.dptr
);
313 SAFE_FREE(old_dbuf
.dptr
);
317 memcpy(&prec
, ptr
, sizeof(prec
));
318 ptr
+= sizeof(rec
) + prec
.len
;
321 /* we're adding to an existing entry */
323 tdb_append(tdb
, kbuf
, dbuf
);
324 tdb_chainunlock(tdb
, kbuf
);
326 SAFE_FREE(old_dbuf
.dptr
);
327 SAFE_FREE(dbuf
.dptr
);
329 errno
= 0; /* paranoia */
330 return message_notify(pid
);
333 /****************************************************************************
334 Send a message to a particular pid - no timeout.
335 ****************************************************************************/
337 BOOL
message_send_pid(struct process_id pid
, int msg_type
, const void *buf
, size_t len
, BOOL duplicates_allowed
)
339 return message_send_pid_internal(pid
, msg_type
, buf
, len
, duplicates_allowed
, 0);
342 /****************************************************************************
343 Send a message to a particular pid, with timeout in seconds.
344 ****************************************************************************/
346 BOOL
message_send_pid_with_timeout(struct process_id pid
, int msg_type
, const void *buf
, size_t len
,
347 BOOL duplicates_allowed
, unsigned int timeout
)
349 return message_send_pid_internal(pid
, msg_type
, buf
, len
, duplicates_allowed
, timeout
);
352 /****************************************************************************
353 Count the messages pending for a particular pid. Expensive....
354 ****************************************************************************/
356 unsigned int messages_pending_for_pid(struct process_id pid
)
361 unsigned int message_count
= 0;
363 kbuf
= message_key_pid(pid
);
365 dbuf
= tdb_fetch(tdb
, kbuf
);
366 if (dbuf
.dptr
== NULL
|| dbuf
.dsize
== 0) {
367 SAFE_FREE(dbuf
.dptr
);
371 for (buf
= dbuf
.dptr
; dbuf
.dsize
> sizeof(struct message_rec
);) {
372 struct message_rec rec
;
373 memcpy(&rec
, buf
, sizeof(rec
));
374 buf
+= (sizeof(rec
) + rec
.len
);
375 dbuf
.dsize
-= (sizeof(rec
) + rec
.len
);
379 SAFE_FREE(dbuf
.dptr
);
380 return message_count
;
383 /****************************************************************************
384 Retrieve all messages for the current process.
385 ****************************************************************************/
387 static BOOL
retrieve_all_messages(char **msgs_buf
, size_t *total_len
)
393 ZERO_STRUCT(null_dbuf
);
398 kbuf
= message_key_pid(pid_to_procid(sys_getpid()));
400 if (tdb_chainlock(tdb
, kbuf
) == -1)
403 dbuf
= tdb_fetch(tdb
, kbuf
);
405 * Replace with an empty record to keep the allocated
408 tdb_store(tdb
, kbuf
, null_dbuf
, TDB_REPLACE
);
409 tdb_chainunlock(tdb
, kbuf
);
411 if (dbuf
.dptr
== NULL
|| dbuf
.dsize
== 0) {
412 SAFE_FREE(dbuf
.dptr
);
416 *msgs_buf
= dbuf
.dptr
;
417 *total_len
= dbuf
.dsize
;
422 /****************************************************************************
423 Parse out the next message for the current process.
424 ****************************************************************************/
426 static BOOL
message_recv(char *msgs_buf
, size_t total_len
, int *msg_type
,
427 struct process_id
*src
, char **buf
, size_t *len
)
429 struct message_rec rec
;
430 char *ret_buf
= *buf
;
435 if (total_len
- (ret_buf
- msgs_buf
) < sizeof(rec
))
438 memcpy(&rec
, ret_buf
, sizeof(rec
));
439 ret_buf
+= sizeof(rec
);
441 if (rec
.msg_version
!= MESSAGE_VERSION
) {
442 DEBUG(0,("message version %d received (expected %d)\n", rec
.msg_version
, MESSAGE_VERSION
));
447 if (total_len
- (ret_buf
- msgs_buf
) < rec
.len
)
452 *msg_type
= rec
.msg_type
;
459 /****************************************************************************
460 Receive and dispatch any messages pending for this process.
461 Notice that all dispatch handlers for a particular msg_type get called,
462 so you can register multiple handlers for a message.
463 *NOTE*: Dispatch functions must be able to cope with incoming
464 messages on an *odd* byte boundary.
465 ****************************************************************************/
467 void message_dispatch(void)
470 struct process_id src
;
473 size_t len
, total_len
;
474 struct dispatch_fns
*dfn
;
477 if (!received_signal
)
480 DEBUG(10,("message_dispatch: received_signal = %d\n", received_signal
));
484 if (!retrieve_all_messages(&msgs_buf
, &total_len
))
487 for (buf
= msgs_buf
; message_recv(msgs_buf
, total_len
, &msg_type
, &src
, &buf
, &len
); buf
+= len
) {
488 DEBUG(10,("message_dispatch: received msg_type=%d "
489 "src_pid=%u\n", msg_type
,
490 (unsigned int) procid_to_pid(&src
)));
492 for (dfn
= dispatch_fns
; dfn
; dfn
= dfn
->next
) {
493 if (dfn
->msg_type
== msg_type
) {
494 DEBUG(10,("message_dispatch: processing message of type %d.\n", msg_type
));
495 dfn
->fn(msg_type
, src
, len
? (void *)buf
: NULL
, len
);
500 DEBUG(5,("message_dispatch: warning: no handlers registed for "
501 "msg_type %d in pid %u\n",
502 msg_type
, (unsigned int)sys_getpid()));
508 /****************************************************************************
509 Register a dispatch function for a particular message type.
510 *NOTE*: Dispatch functions must be able to cope with incoming
511 messages on an *odd* byte boundary.
512 ****************************************************************************/
514 void message_register(int msg_type
,
515 void (*fn
)(int msg_type
, struct process_id pid
,
516 void *buf
, size_t len
))
518 struct dispatch_fns
*dfn
;
520 dfn
= SMB_MALLOC_P(struct dispatch_fns
);
526 dfn
->msg_type
= msg_type
;
529 DLIST_ADD(dispatch_fns
, dfn
);
533 DEBUG(0,("message_register: Not enough memory. malloc failed!\n"));
537 /****************************************************************************
538 De-register the function for a particular message type.
539 ****************************************************************************/
541 void message_deregister(int msg_type
)
543 struct dispatch_fns
*dfn
, *next
;
545 for (dfn
= dispatch_fns
; dfn
; dfn
= next
) {
547 if (dfn
->msg_type
== msg_type
) {
548 DLIST_REMOVE(dispatch_fns
, dfn
);
563 /****************************************************************************
564 Send one of the messages for the broadcast.
565 ****************************************************************************/
567 static int traverse_fn(TDB_CONTEXT
*the_tdb
, TDB_DATA kbuf
, TDB_DATA dbuf
, void *state
)
569 struct connections_data crec
;
570 struct msg_all
*msg_all
= (struct msg_all
*)state
;
572 if (dbuf
.dsize
!= sizeof(crec
))
575 memcpy(&crec
, dbuf
.dptr
, sizeof(crec
));
580 /* Don't send if the receiver hasn't registered an interest. */
582 if(!(crec
.bcast_msg_flags
& msg_all
->msg_flag
))
585 /* If the msg send fails because the pid was not found (i.e. smbd died),
586 * the msg has already been deleted from the messages.tdb.*/
588 if (!message_send_pid(crec
.pid
, msg_all
->msg_type
,
589 msg_all
->buf
, msg_all
->len
,
590 msg_all
->duplicates
)) {
592 /* If the pid was not found delete the entry from connections.tdb */
594 if (errno
== ESRCH
) {
595 DEBUG(2,("pid %s doesn't exist - deleting connections %d [%s]\n",
596 procid_str_static(&crec
.pid
),
597 crec
.cnum
, crec
.name
));
598 tdb_delete(the_tdb
, kbuf
);
606 * Send a message to all smbd processes.
608 * It isn't very efficient, but should be OK for the sorts of
609 * applications that use it. When we need efficient broadcast we can add
612 * @param n_sent Set to the number of messages sent. This should be
613 * equal to the number of processes, but be careful for races.
615 * @retval True for success.
617 BOOL
message_send_all(TDB_CONTEXT
*conn_tdb
, int msg_type
,
618 const void *buf
, size_t len
,
619 BOOL duplicates_allowed
,
622 struct msg_all msg_all
;
624 msg_all
.msg_type
= msg_type
;
626 msg_all
.msg_flag
= FLAG_MSG_GENERAL
;
627 else if (msg_type
> 1000 && msg_type
< 2000)
628 msg_all
.msg_flag
= FLAG_MSG_NMBD
;
629 else if (msg_type
> 2000 && msg_type
< 2100)
630 msg_all
.msg_flag
= FLAG_MSG_PRINT_NOTIFY
;
631 else if (msg_type
> 2100 && msg_type
< 3000)
632 msg_all
.msg_flag
= FLAG_MSG_PRINT_GENERAL
;
633 else if (msg_type
> 3000 && msg_type
< 4000)
634 msg_all
.msg_flag
= FLAG_MSG_SMBD
;
640 msg_all
.duplicates
= duplicates_allowed
;
643 tdb_traverse(conn_tdb
, traverse_fn
, &msg_all
);
645 *n_sent
= msg_all
.n_sent
;
650 * Block and unblock receiving of messages. Allows removal of race conditions
651 * when doing a fork and changing message disposition.
654 void message_block(void)
656 BlockSignals(True
, SIGUSR1
);
659 void message_unblock(void)
661 BlockSignals(False
, SIGUSR1
);