2 Unix SMB/CIFS implementation.
3 Samba internal messaging functions
4 Copyright (C) Andrew Tridgell 2000
5 Copyright (C) 2001 by Martin Pool
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 @defgroups messages Internal messaging framework
27 This module is used for internal messaging between Samba daemons.
29 The idea is that if a part of Samba wants to do communication with
30 another Samba process then it will do a message_register() of a
31 dispatch function, and use message_send_pid() to send messages to
34 The dispatch function is given the pid of the sender, and it can
35 use that to reply by message_send_pid(). See ping_message() for a
38 This system doesn't have any inherent size limitations but is not
39 very efficient for large messages or when messages are sent in very
46 /* the locking database handle */
47 static TDB_CONTEXT
*tdb
;
48 static int received_signal
;
50 /* change the message version with any incompatible changes in the protocol */
51 #define MESSAGE_VERSION 1
61 /* we have a linked list of dispatch handlers */
62 static struct dispatch_fns
{
63 struct dispatch_fns
*next
, *prev
;
65 void (*fn
)(int msg_type
, pid_t pid
, void *buf
, size_t len
);
68 /****************************************************************************
69 Notifications come in as signals.
70 ****************************************************************************/
72 static void sig_usr1(void)
78 /****************************************************************************
79 A useful function for testing the message system.
80 ****************************************************************************/
82 void ping_message(int msg_type
, pid_t src
, void *buf
, size_t len
)
84 const char *msg
= buf
? buf
: "none";
85 DEBUG(1,("INFO: Received PING message from PID %u [%s]\n",(unsigned int)src
, msg
));
86 message_send_pid(src
, MSG_PONG
, buf
, len
, True
);
89 /****************************************************************************
90 Return current debug level.
91 ****************************************************************************/
93 void debuglevel_message(int msg_type
, pid_t src
, void *buf
, size_t len
)
95 DEBUG(1,("INFO: Received REQ_DEBUGLEVEL message from PID %u\n",(unsigned int)src
));
96 message_send_pid(src
, MSG_DEBUGLEVEL
, DEBUGLEVEL_CLASS
, sizeof(DEBUGLEVEL_CLASS
), True
);
99 /****************************************************************************
100 Initialise the messaging functions.
101 ****************************************************************************/
103 BOOL
message_init(void)
105 if (tdb
) return True
;
107 tdb
= tdb_open_log(lock_path("messages.tdb"),
108 0, TDB_CLEAR_IF_FIRST
|TDB_DEFAULT
,
109 O_RDWR
|O_CREAT
,0600);
112 DEBUG(0,("ERROR: Failed to initialise messages database\n"));
116 CatchSignal(SIGUSR1
, SIGNAL_CAST sig_usr1
);
118 message_register(MSG_PING
, ping_message
);
119 message_register(MSG_REQ_DEBUGLEVEL
, debuglevel_message
);
124 /*******************************************************************
125 Form a static tdb key from a pid.
126 ******************************************************************/
128 static TDB_DATA
message_key_pid(pid_t pid
)
133 slprintf(key
, sizeof(key
)-1, "PID/%d", (int)pid
);
135 kbuf
.dptr
= (char *)key
;
136 kbuf
.dsize
= strlen(key
)+1;
140 /****************************************************************************
141 Notify a process that it has a message. If the process doesn't exist
142 then delete its record in the database.
143 ****************************************************************************/
145 static BOOL
message_notify(pid_t pid
)
147 if (kill(pid
, SIGUSR1
) == -1) {
148 if (errno
== ESRCH
) {
149 DEBUG(2,("pid %d doesn't exist - deleting messages record\n", (int)pid
));
150 tdb_delete(tdb
, message_key_pid(pid
));
152 DEBUG(2,("message to process %d failed - %s\n", (int)pid
, strerror(errno
)));
159 /****************************************************************************
160 Send a message to a particular pid.
161 ****************************************************************************/
163 BOOL
message_send_pid(pid_t pid
, int msg_type
, const void *buf
, size_t len
,
164 BOOL duplicates_allowed
)
168 struct message_rec rec
;
171 rec
.msg_version
= MESSAGE_VERSION
;
172 rec
.msg_type
= msg_type
;
174 rec
.src
= sys_getpid();
177 kbuf
= message_key_pid(pid
);
179 /* lock the record for the destination */
180 tdb_chainlock(tdb
, kbuf
);
182 dbuf
= tdb_fetch(tdb
, kbuf
);
185 /* its a new record */
186 p
= (void *)malloc(len
+ sizeof(rec
));
189 memcpy(p
, &rec
, sizeof(rec
));
190 if (len
> 0) memcpy((void *)((char*)p
+sizeof(rec
)), buf
, len
);
193 dbuf
.dsize
= len
+ sizeof(rec
);
194 tdb_store(tdb
, kbuf
, dbuf
, TDB_REPLACE
);
199 if (!duplicates_allowed
) {
201 struct message_rec prec
;
203 for(ptr
= (char *)dbuf
.dptr
; ptr
< dbuf
.dptr
+ dbuf
.dsize
; ) {
205 * First check if the message header matches, then, if it's a non-zero
206 * sized message, check if the data matches. If so it's a duplicate and
207 * we can discard it. JRA.
210 if (!memcmp(ptr
, &rec
, sizeof(rec
))) {
211 if (!len
|| (len
&& !memcmp( ptr
+ sizeof(rec
), buf
, len
))) {
212 DEBUG(10,("message_send_pid: discarding duplicate message.\n"));
213 SAFE_FREE(dbuf
.dptr
);
214 tdb_chainunlock(tdb
, kbuf
);
218 memcpy(&prec
, ptr
, sizeof(prec
));
219 ptr
+= sizeof(rec
) + prec
.len
;
223 /* we're adding to an existing entry */
224 p
= (void *)malloc(dbuf
.dsize
+ len
+ sizeof(rec
));
227 memcpy(p
, dbuf
.dptr
, dbuf
.dsize
);
228 memcpy((void *)((char*)p
+dbuf
.dsize
), &rec
, sizeof(rec
));
229 if (len
> 0) memcpy((void *)((char*)p
+dbuf
.dsize
+sizeof(rec
)), buf
, len
);
231 SAFE_FREE(dbuf
.dptr
);
233 dbuf
.dsize
+= len
+ sizeof(rec
);
234 tdb_store(tdb
, kbuf
, dbuf
, TDB_REPLACE
);
235 SAFE_FREE(dbuf
.dptr
);
238 tdb_chainunlock(tdb
, kbuf
);
239 errno
= 0; /* paranoia */
240 return message_notify(pid
);
243 tdb_chainunlock(tdb
, kbuf
);
244 errno
= 0; /* paranoia */
248 /****************************************************************************
249 Retrieve the next message for the current process.
250 ****************************************************************************/
252 static BOOL
message_recv(int *msg_type
, pid_t
*src
, void **buf
, size_t *len
)
256 struct message_rec rec
;
258 kbuf
= message_key_pid(sys_getpid());
260 tdb_chainlock(tdb
, kbuf
);
262 dbuf
= tdb_fetch(tdb
, kbuf
);
263 if (dbuf
.dptr
== NULL
|| dbuf
.dsize
== 0) goto failed
;
265 memcpy(&rec
, dbuf
.dptr
, sizeof(rec
));
267 if (rec
.msg_version
!= MESSAGE_VERSION
) {
268 DEBUG(0,("message version %d received (expected %d)\n", rec
.msg_version
, MESSAGE_VERSION
));
273 (*buf
) = (void *)malloc(rec
.len
);
274 if (!(*buf
)) goto failed
;
276 memcpy(*buf
, dbuf
.dptr
+sizeof(rec
), rec
.len
);
282 *msg_type
= rec
.msg_type
;
285 if (dbuf
.dsize
- (sizeof(rec
)+rec
.len
) > 0)
286 memmove(dbuf
.dptr
, dbuf
.dptr
+sizeof(rec
)+rec
.len
, dbuf
.dsize
- (sizeof(rec
)+rec
.len
));
287 dbuf
.dsize
-= sizeof(rec
)+rec
.len
;
290 tdb_delete(tdb
, kbuf
);
292 tdb_store(tdb
, kbuf
, dbuf
, TDB_REPLACE
);
294 SAFE_FREE(dbuf
.dptr
);
295 tdb_chainunlock(tdb
, kbuf
);
299 tdb_chainunlock(tdb
, kbuf
);
303 /****************************************************************************
304 Receive and dispatch any messages pending for this process.
305 Notice that all dispatch handlers for a particular msg_type get called,
306 so you can register multiple handlers for a message.
307 ****************************************************************************/
309 void message_dispatch(void)
315 struct dispatch_fns
*dfn
;
318 if (!received_signal
) return;
320 DEBUG(10,("message_dispatch: received_signal = %d\n", received_signal
));
324 while (message_recv(&msg_type
, &src
, &buf
, &len
)) {
325 DEBUG(10,("message_dispatch: received msg_type=%d src_pid=%u\n",
326 msg_type
, (unsigned int) src
));
328 for (dfn
= dispatch_fns
; dfn
; dfn
= dfn
->next
) {
329 if (dfn
->msg_type
== msg_type
) {
330 DEBUG(10,("message_dispatch: processing message of type %d.\n", msg_type
));
331 dfn
->fn(msg_type
, src
, buf
, len
);
336 DEBUG(5,("message_dispatch: warning: no handlers registed for "
337 "msg_type %d in pid%u\n",
338 msg_type
, (unsigned int)getpid()));
344 /****************************************************************************
345 Register a dispatch function for a particular message type.
346 ****************************************************************************/
348 void message_register(int msg_type
,
349 void (*fn
)(int msg_type
, pid_t pid
, void *buf
, size_t len
))
351 struct dispatch_fns
*dfn
;
353 dfn
= (struct dispatch_fns
*)malloc(sizeof(*dfn
));
359 dfn
->msg_type
= msg_type
;
362 DLIST_ADD(dispatch_fns
, dfn
);
366 DEBUG(0,("message_register: Not enough memory. malloc failed!\n"));
370 /****************************************************************************
371 De-register the function for a particular message type.
372 ****************************************************************************/
374 void message_deregister(int msg_type
)
376 struct dispatch_fns
*dfn
, *next
;
378 for (dfn
= dispatch_fns
; dfn
; dfn
= next
) {
380 if (dfn
->msg_type
== msg_type
) {
381 DLIST_REMOVE(dispatch_fns
, dfn
);
395 /****************************************************************************
396 Send one of the messages for the broadcast.
397 ****************************************************************************/
399 static int traverse_fn(TDB_CONTEXT
*the_tdb
, TDB_DATA kbuf
, TDB_DATA dbuf
, void *state
)
401 struct connections_data crec
;
402 struct msg_all
*msg_all
= (struct msg_all
*)state
;
404 if (dbuf
.dsize
!= sizeof(crec
))
407 memcpy(&crec
, dbuf
.dptr
, sizeof(crec
));
412 /* if the msg send fails because the pid was not found (i.e. smbd died),
413 * the msg has already been deleted from the messages.tdb.*/
414 if (!message_send_pid(crec
.pid
, msg_all
->msg_type
,
415 msg_all
->buf
, msg_all
->len
,
416 msg_all
->duplicates
)) {
418 /* if the pid was not found delete the entry from connections.tdb */
419 if (errno
== ESRCH
) {
420 DEBUG(2,("pid %u doesn't exist - deleting connections %d [%s]\n",
421 (unsigned int)crec
.pid
, crec
.cnum
, crec
.name
));
422 tdb_delete(the_tdb
, kbuf
);
430 * Send a message to all smbd processes.
432 * It isn't very efficient, but should be OK for the sorts of
433 * applications that use it. When we need efficient broadcast we can add
436 * @param n_sent Set to the number of messages sent. This should be
437 * equal to the number of processes, but be careful for races.
439 * @return True for success.
441 BOOL
message_send_all(TDB_CONTEXT
*conn_tdb
, int msg_type
,
442 const void *buf
, size_t len
,
443 BOOL duplicates_allowed
,
446 struct msg_all msg_all
;
448 msg_all
.msg_type
= msg_type
;
451 msg_all
.duplicates
= duplicates_allowed
;
454 tdb_traverse(conn_tdb
, traverse_fn
, &msg_all
);
456 *n_sent
= msg_all
.n_sent
;