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);
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));
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 = sizeof(key);
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)
155 struct message_rec rec;
158 rec.msg_version = MESSAGE_VERSION;
159 rec.msg_type = msg_type;
161 rec.src = sys_getpid();
164 kbuf = message_key_pid(pid);
166 /* lock the record for the destination */
167 tdb_lockchain(tdb, kbuf);
169 dbuf = tdb_fetch(tdb, kbuf);
172 /* its a new record */
173 p = (void *)malloc(len + sizeof(rec));
176 memcpy(p, &rec, sizeof(rec));
177 if (len > 0) memcpy((void *)((char*)p+sizeof(rec)), buf, len);
180 dbuf.dsize = len + sizeof(rec);
181 tdb_store(tdb, kbuf, dbuf, TDB_REPLACE);
186 /* we're adding to an existing entry */
187 p = (void *)malloc(dbuf.dsize + len + sizeof(rec));
190 memcpy(p, dbuf.dptr, dbuf.dsize);
191 memcpy((void *)((char*)p+dbuf.dsize), &rec, sizeof(rec));
192 if (len > 0) memcpy((void *)((char*)p+dbuf.dsize+sizeof(rec)), buf, len);
196 dbuf.dsize += len + sizeof(rec);
197 tdb_store(tdb, kbuf, dbuf, TDB_REPLACE);
201 tdb_unlockchain(tdb, kbuf);
202 return message_notify(pid);
205 tdb_unlockchain(tdb, kbuf);
211 /****************************************************************************
212 retrieve the next message for the current process
213 ****************************************************************************/
214 static BOOL message_recv(int *msg_type, pid_t *src, void **buf, size_t *len)
218 struct message_rec rec;
220 kbuf = message_key_pid(sys_getpid());
222 tdb_lockchain(tdb, kbuf);
224 dbuf = tdb_fetch(tdb, kbuf);
225 if (dbuf.dptr == NULL || dbuf.dsize == 0) goto failed;
227 memcpy(&rec, dbuf.dptr, sizeof(rec));
229 if (rec.msg_version != MESSAGE_VERSION) {
230 DEBUG(0,("message version %d received (expected %d)\n", rec.msg_version, MESSAGE_VERSION));
235 (*buf) = (void *)malloc(rec.len);
236 if (!(*buf)) goto failed;
238 memcpy(*buf, dbuf.dptr+sizeof(rec), rec.len);
244 *msg_type = rec.msg_type;
247 memmove(dbuf.dptr, dbuf.dptr+sizeof(rec)+rec.len, dbuf.dsize - (sizeof(rec)+rec.len));
248 dbuf.dsize -= sizeof(rec)+rec.len;
249 tdb_store(tdb, kbuf, dbuf, TDB_REPLACE);
252 tdb_unlockchain(tdb, kbuf);
256 tdb_unlockchain(tdb, kbuf);
261 /****************************************************************************
262 receive and dispatch any messages pending for this process
263 notice that all dispatch handlers for a particular msg_type get called,
264 so you can register multiple handlers for a message
265 ****************************************************************************/
266 void message_dispatch(void)
272 struct dispatch_fns *dfn;
274 if (!received_signal) return;
277 while (message_recv(&msg_type, &src, &buf, &len)) {
278 for (dfn = dispatch_fns; dfn; dfn = dfn->next) {
279 if (dfn->msg_type == msg_type) {
280 dfn->fn(msg_type, src, buf, len);
288 /****************************************************************************
289 register a dispatch function for a particular message type
290 ****************************************************************************/
291 void message_register(int msg_type,
292 void (*fn)(int msg_type, pid_t pid, void *buf, size_t len))
294 struct dispatch_fns *dfn;
296 dfn = (struct dispatch_fns *)malloc(sizeof(*dfn));
300 dfn->msg_type = msg_type;
303 DLIST_ADD(dispatch_fns, dfn);
306 /****************************************************************************
307 de-register the function for a particular message type
308 ****************************************************************************/
309 void message_deregister(int msg_type)
311 struct dispatch_fns *dfn, *next;
313 for (dfn = dispatch_fns; dfn; dfn = next) {
315 if (dfn->msg_type == msg_type) {
316 DLIST_REMOVE(dispatch_fns, dfn);
328 /****************************************************************************
329 send one of the messages for the broadcast
330 ****************************************************************************/
331 static int traverse_fn(TDB_CONTEXT *the_tdb, TDB_DATA kbuf, TDB_DATA dbuf, void *state)
333 struct connections_data crec;
335 memcpy(&crec, dbuf.dptr, sizeof(crec));
337 if (crec.cnum == -1) return 0;
338 message_send_pid(crec.pid, msg_all.msg_type, msg_all.buf, msg_all.len);
342 /****************************************************************************
343 this is a useful function for sending messages to all smbd processes.
344 It isn't very efficient, but should be OK for the sorts of applications that
345 use it. When we need efficient broadcast we can add it.
346 ****************************************************************************/
347 BOOL message_send_all(int msg_type, void *buf, size_t len)
349 TDB_CONTEXT *the_tdb;
351 the_tdb = tdb_open(lock_path("connections.tdb"), 0, 0, O_RDONLY, 0);
353 DEBUG(2,("Failed to open connections database in message_send_all\n"));
357 msg_all.msg_type = msg_type;
361 tdb_traverse(the_tdb, traverse_fn, NULL);