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(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(p+dbuf.dsize, &rec, sizeof(rec));
178 if (len > 0) memcpy(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);