Check sizes of data entries in connections.tdb before deciding they're crecs...
[sfrench/samba-autobuild/.git] / source / lib / messages.c
1 /* 
2    Unix SMB/Netbios implementation.
3    Version 3.0
4    Samba internal messaging functions
5    Copyright (C) Andrew Tridgell 2000
6    
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.
11    
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.
16    
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.
20 */
21
22 /* this module is used for internal messaging between Samba daemons. 
23
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
27    that process.
28
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
31    quick succession.
32
33 */
34
35 #include "includes.h"
36
37 /* the locking database handle */
38 static TDB_CONTEXT *tdb;
39 static int received_signal;
40
41 /* change the message version with any incompatible changes in the protocol */
42 #define MESSAGE_VERSION 1
43
44 struct message_rec {
45         int msg_version;
46         int msg_type;
47         pid_t dest;
48         pid_t src;
49         size_t len;
50 };
51
52 /* we have a linked list of dispatch handlers */
53 static struct dispatch_fns {
54         struct dispatch_fns *next, *prev;
55         int msg_type;
56         void (*fn)(int msg_type, pid_t pid, void *buf, size_t len);
57 } *dispatch_fns;
58
59 /****************************************************************************
60 notifications come in as signals
61 ****************************************************************************/
62 static void sig_usr1(void)
63 {
64         received_signal = 1;
65         sys_select_signal();
66 }
67
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)
72 {
73         DEBUG(1,("INFO: Received PING message from PID %u\n",(unsigned int)src));
74         message_send_pid(src, MSG_PONG, buf, len, True);
75 }
76 /****************************************************************************
77 return current debug level
78 ****************************************************************************/
79 void debuglevel_message(int msg_type, pid_t src, void *buf, size_t len)
80 {
81         DEBUG(1,("INFO: Received REQ_DEBUGLEVEL message from PID %u\n",(unsigned int)src));
82         message_send_pid(src, MSG_DEBUGLEVEL, DEBUGLEVEL_CLASS, sizeof(DEBUGLEVEL_CLASS), True);
83 }
84
85 /****************************************************************************
86  Initialise the messaging functions. 
87 ****************************************************************************/
88 BOOL message_init(void)
89 {
90         if (tdb) return True;
91
92         tdb = tdb_open(lock_path("messages.tdb"), 
93                        0, TDB_CLEAR_IF_FIRST, 
94                        O_RDWR|O_CREAT,0600);
95
96         if (!tdb) {
97                 DEBUG(0,("ERROR: Failed to initialise messages database\n"));
98                 return False;
99         }
100
101         CatchSignal(SIGUSR1, SIGNAL_CAST sig_usr1);
102
103         message_register(MSG_PING, ping_message);
104         message_register(MSG_REQ_DEBUGLEVEL, debuglevel_message);
105
106         return True;
107 }
108
109
110 /*******************************************************************
111  form a static tdb key from a pid
112 ******************************************************************/
113 static TDB_DATA message_key_pid(pid_t pid)
114 {
115         static char key[20];
116         TDB_DATA kbuf;
117
118         slprintf(key, sizeof(key)-1, "PID/%d", (int)pid);
119         
120         kbuf.dptr = (char *)key;
121         kbuf.dsize = strlen(key)+1;
122         return kbuf;
123 }
124
125
126 /****************************************************************************
127 notify a process that it has a message. If the process doesn't exist 
128 then delete its record in the database
129 ****************************************************************************/
130 static BOOL message_notify(pid_t pid)
131 {
132         if (kill(pid, SIGUSR1) == -1) {
133                 if (errno == ESRCH) {
134                         DEBUG(2,("pid %d doesn't exist - deleting messages record\n", (int)pid));
135                         tdb_delete(tdb, message_key_pid(pid));
136                 } else {
137                         DEBUG(2,("message to process %d failed - %s\n", (int)pid, strerror(errno)));
138                 }
139                 return False;
140         }
141         return True;
142 }
143
144 /****************************************************************************
145 send a message to a particular pid
146 ****************************************************************************/
147 BOOL message_send_pid(pid_t pid, int msg_type, void *buf, size_t len, BOOL duplicates_allowed)
148 {
149         TDB_DATA kbuf;
150         TDB_DATA dbuf;
151         struct message_rec rec;
152         void *p;
153
154         rec.msg_version = MESSAGE_VERSION;
155         rec.msg_type = msg_type;
156         rec.dest = pid;
157         rec.src = sys_getpid();
158         rec.len = len;
159
160         kbuf = message_key_pid(pid);
161
162         /* lock the record for the destination */
163         tdb_chainlock(tdb, kbuf);
164
165         dbuf = tdb_fetch(tdb, kbuf);
166
167         if (!dbuf.dptr) {
168                 /* its a new record */
169                 p = (void *)malloc(len + sizeof(rec));
170                 if (!p) goto failed;
171
172                 memcpy(p, &rec, sizeof(rec));
173                 if (len > 0) memcpy((void *)((char*)p+sizeof(rec)), buf, len);
174
175                 dbuf.dptr = p;
176                 dbuf.dsize = len + sizeof(rec);
177                 tdb_store(tdb, kbuf, dbuf, TDB_REPLACE);
178                 free(p);
179                 goto ok;
180         }
181
182         if (!duplicates_allowed) {
183                 char *ptr;
184                 struct message_rec prec;
185                 
186                 for(ptr = (char *)dbuf.dptr; ptr < dbuf.dptr + dbuf.dsize; ) {
187                         /*
188                          * First check if the message header matches, then, if it's a non-zero
189                          * sized message, check if the data matches. If so it's a duplicate and
190                          * we can discard it. JRA.
191                          */
192
193                         if (!memcmp(ptr, &rec, sizeof(rec))) {
194                                 if (!len || (len && !memcmp( ptr + sizeof(rec), (char *)buf, len))) {
195                                         DEBUG(10,("message_send_pid: discarding duplicate message.\n"));
196                                         free(dbuf.dptr);
197                                         tdb_chainunlock(tdb, kbuf);
198                                         return True;
199                                 }
200                         }
201                         memcpy(&prec, ptr, sizeof(prec));
202                         ptr += sizeof(rec) + prec.len;
203                 }
204         }
205
206         /* we're adding to an existing entry */
207         p = (void *)malloc(dbuf.dsize + len + sizeof(rec));
208         if (!p) goto failed;
209
210         memcpy(p, dbuf.dptr, dbuf.dsize);
211         memcpy((void *)((char*)p+dbuf.dsize), &rec, sizeof(rec));
212         if (len > 0) memcpy((void *)((char*)p+dbuf.dsize+sizeof(rec)), buf, len);
213
214         free(dbuf.dptr);
215         dbuf.dptr = p;
216         dbuf.dsize += len + sizeof(rec);
217         tdb_store(tdb, kbuf, dbuf, TDB_REPLACE);
218         free(dbuf.dptr);
219
220  ok:
221         tdb_chainunlock(tdb, kbuf);
222         errno = 0;                    /* paranoia */
223         return message_notify(pid);
224
225  failed:
226         tdb_chainunlock(tdb, kbuf);
227         errno = 0;                    /* paranoia */
228         return False;
229 }
230
231
232
233 /****************************************************************************
234 retrieve the next message for the current process
235 ****************************************************************************/
236 static BOOL message_recv(int *msg_type, pid_t *src, void **buf, size_t *len)
237 {
238         TDB_DATA kbuf;
239         TDB_DATA dbuf;
240         struct message_rec rec;
241
242         kbuf = message_key_pid(sys_getpid());
243
244         tdb_chainlock(tdb, kbuf);
245         
246         dbuf = tdb_fetch(tdb, kbuf);
247         if (dbuf.dptr == NULL || dbuf.dsize == 0) goto failed;
248
249         memcpy(&rec, dbuf.dptr, sizeof(rec));
250
251         if (rec.msg_version != MESSAGE_VERSION) {
252                 DEBUG(0,("message version %d received (expected %d)\n", rec.msg_version, MESSAGE_VERSION));
253                 goto failed;
254         }
255
256         if (rec.len > 0) {
257                 (*buf) = (void *)malloc(rec.len);
258                 if (!(*buf)) goto failed;
259
260                 memcpy(*buf, dbuf.dptr+sizeof(rec), rec.len);
261         } else {
262                 *buf = NULL;
263         }
264
265         *len = rec.len;
266         *msg_type = rec.msg_type;
267         *src = rec.src;
268
269         if (dbuf.dsize - (sizeof(rec)+rec.len) > 0)
270                 memmove(dbuf.dptr, dbuf.dptr+sizeof(rec)+rec.len, dbuf.dsize - (sizeof(rec)+rec.len));
271         dbuf.dsize -= sizeof(rec)+rec.len;
272
273         if (dbuf.dsize == 0)
274                 tdb_delete(tdb, kbuf);
275         else
276                 tdb_store(tdb, kbuf, dbuf, TDB_REPLACE);
277
278         free(dbuf.dptr);
279         tdb_chainunlock(tdb, kbuf);
280         return True;
281
282  failed:
283         tdb_chainunlock(tdb, kbuf);
284         return False;
285 }
286
287
288 /****************************************************************************
289 receive and dispatch any messages pending for this process
290 notice that all dispatch handlers for a particular msg_type get called,
291 so you can register multiple handlers for a message
292 ****************************************************************************/
293 void message_dispatch(void)
294 {
295         int msg_type;
296         pid_t src;
297         void *buf;
298         size_t len;
299         struct dispatch_fns *dfn;
300
301         if (!received_signal) return;
302         received_signal = 0;
303
304         while (message_recv(&msg_type, &src, &buf, &len)) {
305                 for (dfn = dispatch_fns; dfn; dfn = dfn->next) {
306                         if (dfn->msg_type == msg_type) {
307                                 dfn->fn(msg_type, src, buf, len);
308                         }
309                 }
310                 if (buf) free(buf);
311         }
312 }
313
314
315 /****************************************************************************
316 register a dispatch function for a particular message type
317 ****************************************************************************/
318 void message_register(int msg_type, 
319                       void (*fn)(int msg_type, pid_t pid, void *buf, size_t len))
320 {
321         struct dispatch_fns *dfn;
322
323         dfn = (struct dispatch_fns *)malloc(sizeof(*dfn));
324
325         ZERO_STRUCTP(dfn);
326
327         dfn->msg_type = msg_type;
328         dfn->fn = fn;
329
330         DLIST_ADD(dispatch_fns, dfn);
331 }
332
333 /****************************************************************************
334 de-register the function for a particular message type
335 ****************************************************************************/
336 void message_deregister(int msg_type)
337 {
338         struct dispatch_fns *dfn, *next;
339
340         for (dfn = dispatch_fns; dfn; dfn = next) {
341                 next = dfn->next;
342                 if (dfn->msg_type == msg_type) {
343                         DLIST_REMOVE(dispatch_fns, dfn);
344                         free(dfn);
345                 }
346         }       
347 }
348
349 struct msg_all {
350         int msg_type;
351         void *buf;
352         size_t len;
353         BOOL duplicates;
354 };
355
356 /****************************************************************************
357 send one of the messages for the broadcast
358 ****************************************************************************/
359 static int traverse_fn(TDB_CONTEXT *the_tdb, TDB_DATA kbuf, TDB_DATA dbuf, void *state)
360 {
361         struct connections_data crec;
362         struct msg_all *msg_all = (struct msg_all *)state;
363
364         if (dbuf.dsize != sizeof(crec))
365                 return 0;
366
367         memcpy(&crec, dbuf.dptr, sizeof(crec));
368
369         if (crec.cnum != -1)
370                 return 0;
371
372         /* if the msg send fails because the pid was not found (i.e. smbd died), 
373          * the msg has already been deleted from the messages.tdb.*/
374         if (!message_send_pid(crec.pid, msg_all->msg_type, msg_all->buf, msg_all->len,
375                                                         msg_all->duplicates)) {
376                 
377                 /* if the pid was not found delete the entry from connections.tdb */
378                 if (errno == ESRCH) {
379                         DEBUG(2,("pid %u doesn't exist - deleting connections %d [%s]\n",
380                                         (unsigned int)crec.pid, crec.cnum, crec.name));
381                         tdb_delete(the_tdb, kbuf);
382                 }
383         }
384         return 0;
385 }
386
387 /****************************************************************************
388 this is a useful function for sending messages to all smbd processes.
389 It isn't very efficient, but should be OK for the sorts of applications that 
390 use it. When we need efficient broadcast we can add it.
391 ****************************************************************************/
392 BOOL message_send_all(TDB_CONTEXT *conn_tdb, int msg_type, void *buf, size_t len, BOOL duplicates_allowed)
393 {
394         struct msg_all msg_all;
395
396         msg_all.msg_type = msg_type;
397         msg_all.buf = buf;
398         msg_all.len = len;
399         msg_all.duplicates = duplicates_allowed;
400
401         tdb_traverse(conn_tdb, traverse_fn, &msg_all);
402         return True;
403 }