2 Unix SMB/Netbios implementation.
4 Samba internal messaging functions
5 Copyright (C) Andrew Tridgell 2000
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.
22 /* this module is used for internal messaging between Samba daemons.
24 The idea is that if a part of Samba wants to do communication with
25 another Samba process then it will do a message_register() of a
26 dispatch function, and use message_send_pid() to send messages to
29 This system doesn't have any inherent size limitations but is not
30 very efficient for large messages or when messages are sent in very
37 /* the locking database handle */
38 static TDB_CONTEXT *tdb;
39 static int received_signal;
41 /* change the message version with any incompatible changes in the protocol */
42 #define MESSAGE_VERSION 1
52 /* we have a linked list of dispatch handlers */
53 static struct dispatch_fns {
54 struct dispatch_fns *next, *prev;
56 void (*fn)(int msg_type, pid_t pid, void *buf, size_t len);
59 /****************************************************************************
60 notifications come in as signals
61 ****************************************************************************/
62 static void sig_usr1(void)
68 /****************************************************************************
69 a useful function for testing the message system
70 ****************************************************************************/
71 void ping_message(int msg_type, pid_t src, void *buf, size_t len)
73 DEBUG(1,("INFO: Received PING message from PID %d\n",src));
74 message_send_pid(src, MSG_PONG, buf, len, True);
77 /****************************************************************************
78 return current debug level
79 ****************************************************************************/
80 void debuglevel_message(int msg_type, pid_t src, void *buf, size_t len)
84 DEBUG(1,("INFO: Received REQ_DEBUGLEVEL message from PID %d\n",src));
86 message_send_pid(src, MSG_DEBUGLEVEL, &level, sizeof(int), True);
89 /****************************************************************************
90 Initialise the messaging functions.
91 ****************************************************************************/
92 BOOL message_init(void)
96 tdb = tdb_open(lock_path("messages.tdb"),
97 0, TDB_CLEAR_IF_FIRST,
101 DEBUG(0,("ERROR: Failed to initialise messages database\n"));
105 CatchSignal(SIGUSR1, SIGNAL_CAST sig_usr1);
107 message_register(MSG_PING, ping_message);
108 message_register(MSG_REQ_DEBUGLEVEL, debuglevel_message);
114 /*******************************************************************
115 form a static tdb key from a pid
116 ******************************************************************/
117 static TDB_DATA message_key_pid(pid_t pid)
122 slprintf(key, sizeof(key), "PID/%d", (int)pid);
124 kbuf.dptr = (char *)key;
125 kbuf.dsize = strlen(key)+1;
130 /****************************************************************************
131 notify a process that it has a message. If the process doesn't exist
132 then delete its record in the database
133 ****************************************************************************/
134 static BOOL message_notify(pid_t pid)
136 if (kill(pid, SIGUSR1) == -1) {
137 if (errno == ESRCH) {
138 DEBUG(2,("pid %d doesn't exist - deleting messages record\n", (int)pid));
139 tdb_delete(tdb, message_key_pid(pid));
141 DEBUG(2,("message to process %d failed - %s\n", (int)pid, strerror(errno)));
148 /****************************************************************************
149 send a message to a particular pid
150 ****************************************************************************/
151 BOOL message_send_pid(pid_t pid, int msg_type, void *buf, size_t len, BOOL duplicates_allowed)
155 struct message_rec rec;
159 * Do an early check for process exists - saves adding into a tdb
160 * and deleting again if the target is not present. JRA.
163 if (!process_exists(pid)) {
164 DEBUG(2,("message_send_pid: pid %d doesn't exist\n", (int)pid));
168 rec.msg_version = MESSAGE_VERSION;
169 rec.msg_type = msg_type;
171 rec.src = sys_getpid();
174 kbuf = message_key_pid(pid);
176 /* lock the record for the destination */
177 tdb_lockchain(tdb, kbuf);
179 dbuf = tdb_fetch(tdb, kbuf);
182 /* its a new record */
183 p = (void *)malloc(len + sizeof(rec));
186 memcpy(p, &rec, sizeof(rec));
187 if (len > 0) memcpy((void *)((char*)p+sizeof(rec)), buf, len);
190 dbuf.dsize = len + sizeof(rec);
191 tdb_store(tdb, kbuf, dbuf, TDB_REPLACE);
196 if (!duplicates_allowed) {
198 struct message_rec prec;
200 for(ptr = (char *)dbuf.dptr; ptr < dbuf.dptr + dbuf.dsize; ) {
202 * First check if the message header matches, then, if it's a non-zero
203 * sized message, check if the data matches. If so it's a duplicate and
204 * we can discard it. JRA.
207 if (!memcmp(ptr, &rec, sizeof(rec))) {
208 if (!len || (len && !memcmp( ptr + sizeof(rec), (char *)buf, len))) {
209 DEBUG(10,("message_send_pid: discarding duplicate message.\n"));
211 tdb_unlockchain(tdb, kbuf);
215 memcpy(&prec, ptr, sizeof(prec));
216 ptr += sizeof(rec) + prec.len;
220 /* we're adding to an existing entry */
221 p = (void *)malloc(dbuf.dsize + len + sizeof(rec));
224 memcpy(p, dbuf.dptr, dbuf.dsize);
225 memcpy((void *)((char*)p+dbuf.dsize), &rec, sizeof(rec));
226 if (len > 0) memcpy((void *)((char*)p+dbuf.dsize+sizeof(rec)), buf, len);
230 dbuf.dsize += len + sizeof(rec);
231 tdb_store(tdb, kbuf, dbuf, TDB_REPLACE);
235 tdb_unlockchain(tdb, kbuf);
236 return message_notify(pid);
239 tdb_unlockchain(tdb, kbuf);
245 /****************************************************************************
246 retrieve the next message for the current process
247 ****************************************************************************/
248 static BOOL message_recv(int *msg_type, pid_t *src, void **buf, size_t *len)
252 struct message_rec rec;
254 kbuf = message_key_pid(sys_getpid());
256 tdb_lockchain(tdb, kbuf);
258 dbuf = tdb_fetch(tdb, kbuf);
259 if (dbuf.dptr == NULL || dbuf.dsize == 0) goto failed;
261 memcpy(&rec, dbuf.dptr, sizeof(rec));
263 if (rec.msg_version != MESSAGE_VERSION) {
264 DEBUG(0,("message version %d received (expected %d)\n", rec.msg_version, MESSAGE_VERSION));
269 (*buf) = (void *)malloc(rec.len);
270 if (!(*buf)) goto failed;
272 memcpy(*buf, dbuf.dptr+sizeof(rec), rec.len);
278 *msg_type = rec.msg_type;
281 if (dbuf.dsize - (sizeof(rec)+rec.len) > 0)
282 memmove(dbuf.dptr, dbuf.dptr+sizeof(rec)+rec.len, dbuf.dsize - (sizeof(rec)+rec.len));
283 dbuf.dsize -= sizeof(rec)+rec.len;
286 tdb_delete(tdb, kbuf);
288 tdb_store(tdb, kbuf, dbuf, TDB_REPLACE);
291 tdb_unlockchain(tdb, kbuf);
295 tdb_unlockchain(tdb, kbuf);
300 /****************************************************************************
301 receive and dispatch any messages pending for this process
302 notice that all dispatch handlers for a particular msg_type get called,
303 so you can register multiple handlers for a message
304 ****************************************************************************/
305 void message_dispatch(void)
311 struct dispatch_fns *dfn;
313 if (!received_signal) return;
316 while (message_recv(&msg_type, &src, &buf, &len)) {
317 for (dfn = dispatch_fns; dfn; dfn = dfn->next) {
318 if (dfn->msg_type == msg_type) {
319 dfn->fn(msg_type, src, buf, len);
327 /****************************************************************************
328 register a dispatch function for a particular message type
329 ****************************************************************************/
330 void message_register(int msg_type,
331 void (*fn)(int msg_type, pid_t pid, void *buf, size_t len))
333 struct dispatch_fns *dfn;
335 dfn = (struct dispatch_fns *)malloc(sizeof(*dfn));
339 dfn->msg_type = msg_type;
342 DLIST_ADD(dispatch_fns, dfn);
345 /****************************************************************************
346 de-register the function for a particular message type
347 ****************************************************************************/
348 void message_deregister(int msg_type)
350 struct dispatch_fns *dfn, *next;
352 for (dfn = dispatch_fns; dfn; dfn = next) {
354 if (dfn->msg_type == msg_type) {
355 DLIST_REMOVE(dispatch_fns, dfn);
368 /****************************************************************************
369 send one of the messages for the broadcast
370 ****************************************************************************/
371 static int traverse_fn(TDB_CONTEXT *the_tdb, TDB_DATA kbuf, TDB_DATA dbuf, void *state)
373 struct connections_data crec;
375 memcpy(&crec, dbuf.dptr, sizeof(crec));
377 if (crec.cnum != -1) return 0;
378 message_send_pid(crec.pid, msg_all.msg_type, msg_all.buf, msg_all.len, msg_all.duplicates);
382 /****************************************************************************
383 this is a useful function for sending messages to all smbd processes.
384 It isn't very efficient, but should be OK for the sorts of applications that
385 use it. When we need efficient broadcast we can add it.
386 ****************************************************************************/
387 BOOL message_send_all(int msg_type, void *buf, size_t len, BOOL duplicates_allowed)
389 TDB_CONTEXT *the_tdb;
391 the_tdb = tdb_open(lock_path("connections.tdb"), 0, 0, O_RDONLY, 0);
393 DEBUG(2,("Failed to open connections database in message_send_all\n"));
397 msg_all.msg_type = msg_type;
400 msg_all.duplicates = duplicates_allowed;
402 tdb_traverse(the_tdb, traverse_fn, NULL);