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;
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_chainlock(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 if (!duplicates_allowed) {
188 struct message_rec prec;
190 for(ptr = (char *)dbuf.dptr; ptr < dbuf.dptr + dbuf.dsize; ) {
192 * First check if the message header matches, then, if it's a non-zero
193 * sized message, check if the data matches. If so it's a duplicate and
194 * we can discard it. JRA.
197 if (!memcmp(ptr, &rec, sizeof(rec))) {
198 if (!len || (len && !memcmp( ptr + sizeof(rec), (char *)buf, len))) {
199 DEBUG(10,("message_send_pid: discarding duplicate message.\n"));
201 tdb_chainunlock(tdb, kbuf);
205 memcpy(&prec, ptr, sizeof(prec));
206 ptr += sizeof(rec) + prec.len;
210 /* we're adding to an existing entry */
211 p = (void *)malloc(dbuf.dsize + len + sizeof(rec));
214 memcpy(p, dbuf.dptr, dbuf.dsize);
215 memcpy((void *)((char*)p+dbuf.dsize), &rec, sizeof(rec));
216 if (len > 0) memcpy((void *)((char*)p+dbuf.dsize+sizeof(rec)), buf, len);
220 dbuf.dsize += len + sizeof(rec);
221 tdb_store(tdb, kbuf, dbuf, TDB_REPLACE);
225 tdb_chainunlock(tdb, kbuf);
226 return message_notify(pid);
229 tdb_chainunlock(tdb, kbuf);
235 /****************************************************************************
236 retrieve the next message for the current process
237 ****************************************************************************/
238 static BOOL message_recv(int *msg_type, pid_t *src, void **buf, size_t *len)
242 struct message_rec rec;
244 kbuf = message_key_pid(sys_getpid());
246 tdb_chainlock(tdb, kbuf);
248 dbuf = tdb_fetch(tdb, kbuf);
249 if (dbuf.dptr == NULL || dbuf.dsize == 0) goto failed;
251 memcpy(&rec, dbuf.dptr, sizeof(rec));
253 if (rec.msg_version != MESSAGE_VERSION) {
254 DEBUG(0,("message version %d received (expected %d)\n", rec.msg_version, MESSAGE_VERSION));
259 (*buf) = (void *)malloc(rec.len);
260 if (!(*buf)) goto failed;
262 memcpy(*buf, dbuf.dptr+sizeof(rec), rec.len);
268 *msg_type = rec.msg_type;
271 if (dbuf.dsize - (sizeof(rec)+rec.len) > 0)
272 memmove(dbuf.dptr, dbuf.dptr+sizeof(rec)+rec.len, dbuf.dsize - (sizeof(rec)+rec.len));
273 dbuf.dsize -= sizeof(rec)+rec.len;
276 tdb_delete(tdb, kbuf);
278 tdb_store(tdb, kbuf, dbuf, TDB_REPLACE);
281 tdb_chainunlock(tdb, kbuf);
285 tdb_chainunlock(tdb, kbuf);
290 /****************************************************************************
291 receive and dispatch any messages pending for this process
292 notice that all dispatch handlers for a particular msg_type get called,
293 so you can register multiple handlers for a message
294 ****************************************************************************/
295 void message_dispatch(void)
301 struct dispatch_fns *dfn;
303 if (!received_signal) return;
306 while (message_recv(&msg_type, &src, &buf, &len)) {
307 for (dfn = dispatch_fns; dfn; dfn = dfn->next) {
308 if (dfn->msg_type == msg_type) {
309 dfn->fn(msg_type, src, buf, len);
317 /****************************************************************************
318 register a dispatch function for a particular message type
319 ****************************************************************************/
320 void message_register(int msg_type,
321 void (*fn)(int msg_type, pid_t pid, void *buf, size_t len))
323 struct dispatch_fns *dfn;
325 dfn = (struct dispatch_fns *)malloc(sizeof(*dfn));
329 dfn->msg_type = msg_type;
332 DLIST_ADD(dispatch_fns, dfn);
335 /****************************************************************************
336 de-register the function for a particular message type
337 ****************************************************************************/
338 void message_deregister(int msg_type)
340 struct dispatch_fns *dfn, *next;
342 for (dfn = dispatch_fns; dfn; dfn = next) {
344 if (dfn->msg_type == msg_type) {
345 DLIST_REMOVE(dispatch_fns, dfn);
358 /****************************************************************************
359 send one of the messages for the broadcast
360 ****************************************************************************/
361 static int traverse_fn(TDB_CONTEXT *the_tdb, TDB_DATA kbuf, TDB_DATA dbuf, void *state)
363 struct connections_data crec;
365 memcpy(&crec, dbuf.dptr, sizeof(crec));
367 if (crec.cnum != -1) return 0;
368 message_send_pid(crec.pid, msg_all.msg_type, msg_all.buf, msg_all.len, msg_all.duplicates);
372 /****************************************************************************
373 this is a useful function for sending messages to all smbd processes.
374 It isn't very efficient, but should be OK for the sorts of applications that
375 use it. When we need efficient broadcast we can add it.
376 ****************************************************************************/
377 BOOL message_send_all(TDB_CONTEXT *conn_tdb, int msg_type, void *buf, size_t len, BOOL duplicates_allowed)
379 msg_all.msg_type = msg_type;
382 msg_all.duplicates = duplicates_allowed;
384 tdb_traverse(conn_tdb, traverse_fn, NULL);