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 message_send_pid(src, MSG_PONG, buf, len);
76 /****************************************************************************
77 Initialise the messaging functions.
78 ****************************************************************************/
79 BOOL message_init(void)
83 tdb = tdb_open(lock_path("messages.tdb"),
84 0, TDB_CLEAR_IF_FIRST,
88 DEBUG(0,("ERROR: Failed to initialise messages database\n"));
92 CatchSignal(SIGUSR1, sig_usr1);
94 message_register(MSG_PING, ping_message);
100 /*******************************************************************
101 form a static tdb key from a pid
102 ******************************************************************/
103 static TDB_DATA message_key_pid(pid_t pid)
108 slprintf(key, sizeof(key), "PID/%d", (int)pid);
110 kbuf.dptr = (char *)key;
111 kbuf.dsize = sizeof(key);
116 /****************************************************************************
117 notify a process that it has a message. If the process doesn't exist
118 then delete its record in the database
119 ****************************************************************************/
120 static BOOL message_notify(pid_t pid)
122 if (kill(pid, SIGUSR1) == -1) {
123 if (errno == ESRCH) {
124 DEBUG(2,("pid %d doesn't exist - deleting messages record\n", (int)pid));
125 tdb_delete(tdb, message_key_pid(pid));
127 DEBUG(2,("message to process %d failed - %s\n", (int)pid, strerror(errno)));
134 /****************************************************************************
135 send a message to a particular pid
136 ****************************************************************************/
137 BOOL message_send_pid(pid_t pid, int msg_type, void *buf, size_t len)
141 struct message_rec rec;
144 rec.msg_version = MESSAGE_VERSION;
145 rec.msg_type = msg_type;
147 rec.src = sys_getpid();
150 kbuf = message_key_pid(pid);
152 /* lock the record for the destination */
153 tdb_lockchain(tdb, kbuf);
155 dbuf = tdb_fetch(tdb, kbuf);
158 /* its a new record */
159 p = (void *)malloc(len + sizeof(rec));
162 memcpy(p, &rec, sizeof(rec));
163 if (len > 0) memcpy((void *)((unsigned)p+sizeof(rec)), buf, len);
166 dbuf.dsize = len + sizeof(rec);
167 tdb_store(tdb, kbuf, dbuf, TDB_REPLACE);
172 /* we're adding to an existing entry */
173 p = (void *)malloc(dbuf.dsize + len + sizeof(rec));
176 memcpy(p, dbuf.dptr, dbuf.dsize);
177 memcpy((void *)((unsigned)p+dbuf.dsize), &rec, sizeof(rec));
178 if (len > 0) memcpy((void *)((unsigned)p+dbuf.dsize+sizeof(rec)), buf, len);
182 dbuf.dsize += len + sizeof(rec);
183 tdb_store(tdb, kbuf, dbuf, TDB_REPLACE);
187 tdb_unlockchain(tdb, kbuf);
188 return message_notify(pid);
191 tdb_unlockchain(tdb, kbuf);
197 /****************************************************************************
198 retrieve the next message for the current process
199 ****************************************************************************/
200 static BOOL message_recv(int *msg_type, pid_t *src, void **buf, size_t *len)
204 struct message_rec rec;
206 kbuf = message_key_pid(sys_getpid());
208 tdb_lockchain(tdb, kbuf);
210 dbuf = tdb_fetch(tdb, kbuf);
211 if (dbuf.dptr == NULL || dbuf.dsize == 0) goto failed;
213 memcpy(&rec, dbuf.dptr, sizeof(rec));
215 if (rec.msg_version != MESSAGE_VERSION) {
216 DEBUG(0,("message version %d received (expected %d)\n", rec.msg_version, MESSAGE_VERSION));
221 (*buf) = (void *)malloc(rec.len);
222 if (!(*buf)) goto failed;
224 memcpy(*buf, dbuf.dptr+sizeof(rec), rec.len);
230 *msg_type = rec.msg_type;
233 memmove(dbuf.dptr, dbuf.dptr+sizeof(rec)+rec.len, dbuf.dsize - (sizeof(rec)+rec.len));
234 dbuf.dsize -= sizeof(rec)+rec.len;
235 tdb_store(tdb, kbuf, dbuf, TDB_REPLACE);
238 tdb_unlockchain(tdb, kbuf);
242 tdb_unlockchain(tdb, kbuf);
247 /****************************************************************************
248 receive and dispatch any messages pending for this process
249 notice that all dispatch handlers for a particular msg_type get called,
250 so you can register multiple handlers for a message
251 ****************************************************************************/
252 void message_dispatch(void)
258 struct dispatch_fns *dfn;
260 if (!received_signal) return;
263 while (message_recv(&msg_type, &src, &buf, &len)) {
264 for (dfn = dispatch_fns; dfn; dfn = dfn->next) {
265 if (dfn->msg_type == msg_type) {
266 dfn->fn(msg_type, src, buf, len);
274 /****************************************************************************
275 register a dispatch function for a particular message type
276 ****************************************************************************/
277 void message_register(int msg_type,
278 void (*fn)(int msg_type, pid_t pid, void *buf, size_t len))
280 struct dispatch_fns *dfn;
282 dfn = (struct dispatch_fns *)malloc(sizeof(*dfn));
286 dfn->msg_type = msg_type;
289 DLIST_ADD(dispatch_fns, dfn);
292 /****************************************************************************
293 de-register the function for a particular message type
294 ****************************************************************************/
295 void message_deregister(int msg_type)
297 struct dispatch_fns *dfn, *next;
299 for (dfn = dispatch_fns; dfn; dfn = next) {
301 if (dfn->msg_type == msg_type) {
302 DLIST_REMOVE(dispatch_fns, dfn);
314 /****************************************************************************
315 send one of the messages for the broadcast
316 ****************************************************************************/
317 static int traverse_fn(TDB_CONTEXT *tdb, TDB_DATA kbuf, TDB_DATA dbuf, void *state)
319 struct connections_data crec;
321 memcpy(&crec, dbuf.dptr, sizeof(crec));
323 message_send_pid(crec.pid, msg_all.msg_type, msg_all.buf, msg_all.len);
327 /****************************************************************************
328 this is a useful function for sending messages to all smbd processes.
329 It isn't very efficient, but should be OK for the sorts of applications that
330 use it. When we need efficient broadcast we can add it.
331 ****************************************************************************/
332 BOOL message_send_all(int msg_type, void *buf, size_t len)
336 tdb = tdb_open(lock_path("connections.tdb"), 0, 0, O_RDONLY, 0);
338 DEBUG(2,("Failed to open connections database in message_send_all\n"));
342 msg_all.msg_type = msg_type;
346 tdb_traverse(tdb, traverse_fn, NULL);