source: trunk/samba/source/lib/messages.c @ 26

Last change on this file since 26 was 26, checked in by Paul Smedley, 14 years ago

Updated source to 3.0.25rc1

File size: 22.3 KB
Line 
1/*
2   Unix SMB/CIFS implementation.
3   Samba internal messaging functions
4   Copyright (C) Andrew Tridgell 2000
5   Copyright (C) 2001 by Martin Pool
6   Copyright (C) 2002 by Jeremy Allison
7   
8   This program is free software; you can redistribute it and/or modify
9   it under the terms of the GNU General Public License as published by
10   the Free Software Foundation; either version 2 of the License, or
11   (at your option) any later version.
12   
13   This program is distributed in the hope that it will be useful,
14   but WITHOUT ANY WARRANTY; without even the implied warranty of
15   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16   GNU General Public License for more details.
17   
18   You should have received a copy of the GNU General Public License
19   along with this program; if not, write to the Free Software
20   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21*/
22
23/**
24  @defgroup messages Internal messaging framework
25  @{
26  @file messages.c
27 
28  @brief  Module for internal messaging between Samba daemons.
29
30   The idea is that if a part of Samba wants to do communication with
31   another Samba process then it will do a message_register() of a
32   dispatch function, and use message_send_pid() to send messages to
33   that process.
34
35   The dispatch function is given the pid of the sender, and it can
36   use that to reply by message_send_pid().  See ping_message() for a
37   simple example.
38
39   @caution Dispatch functions must be able to cope with incoming
40   messages on an *odd* byte boundary.
41
42   This system doesn't have any inherent size limitations but is not
43   very efficient for large messages or when messages are sent in very
44   quick succession.
45
46*/
47
48#include "includes.h"
49
50/* the locking database handle */
51static TDB_CONTEXT *tdb;
52static int received_signal;
53
54/* change the message version with any incompatible changes in the protocol */
55#define MESSAGE_VERSION 1
56
57struct message_rec {
58        int msg_version;
59        int msg_type;
60        struct process_id dest;
61        struct process_id src;
62        size_t len;
63};
64
65/* we have a linked list of dispatch handlers */
66static struct dispatch_fns {
67        struct dispatch_fns *next, *prev;
68        int msg_type;
69        void (*fn)(int msg_type, struct process_id pid, void *buf, size_t len,
70                   void *private_data);
71        void *private_data;
72} *dispatch_fns;
73
74/****************************************************************************
75 Free global objects.
76****************************************************************************/
77
78void gfree_messages(void)
79{
80        struct dispatch_fns *dfn, *next;
81
82        /* delete the dispatch_fns list */
83        dfn = dispatch_fns;
84        while( dfn ) {
85                next = dfn->next;
86                DLIST_REMOVE(dispatch_fns, dfn);
87                SAFE_FREE(dfn);
88                dfn = next;
89        }
90}
91
92/****************************************************************************
93 Notifications come in as signals.
94****************************************************************************/
95
96static void sig_usr1(void)
97{
98        received_signal = 1;
99        sys_select_signal(SIGUSR1);
100}
101
102/****************************************************************************
103 A useful function for testing the message system.
104****************************************************************************/
105
106static void ping_message(int msg_type, struct process_id src,
107                         void *buf, size_t len, void *private_data)
108{
109        const char *msg = buf ? (const char *)buf : "none";
110
111        DEBUG(1,("INFO: Received PING message from PID %s [%s]\n",
112                 procid_str_static(&src), msg));
113        message_send_pid(src, MSG_PONG, buf, len, True);
114}
115
116/****************************************************************************
117 Initialise the messaging functions.
118****************************************************************************/
119
120BOOL message_init(void)
121{
122        sec_init();
123
124        if (tdb)
125                return True;
126
127        tdb = tdb_open_log(lock_path("messages.tdb"), 
128                       0, TDB_CLEAR_IF_FIRST|TDB_DEFAULT, 
129                       O_RDWR|O_CREAT,0600);
130        if (!tdb) {
131                DEBUG(0,("ERROR: Failed to initialise messages database\n"));
132                return False;
133        }
134
135        /* Activate the per-hashchain freelist */
136        tdb_set_max_dead(tdb, 5);
137
138        CatchSignal(SIGUSR1, SIGNAL_CAST sig_usr1);
139
140        message_register(MSG_PING, ping_message, NULL);
141
142        /* Register some debugging related messages */
143
144        register_msg_pool_usage();
145        register_dmalloc_msgs();
146
147        return True;
148}
149
150/*******************************************************************
151 Form a static tdb key from a pid.
152******************************************************************/
153
154static TDB_DATA message_key_pid(struct process_id pid)
155{
156        static char key[20];
157        TDB_DATA kbuf;
158
159        slprintf(key, sizeof(key)-1, "PID/%s", procid_str_static(&pid));
160       
161        kbuf.dptr = (char *)key;
162        kbuf.dsize = strlen(key)+1;
163        return kbuf;
164}
165
166/****************************************************************************
167 Notify a process that it has a message. If the process doesn't exist
168 then delete its record in the database.
169****************************************************************************/
170
171static NTSTATUS message_notify(struct process_id procid)
172{
173        pid_t pid = procid.pid;
174        int ret;
175        uid_t euid = geteuid();
176
177        /*
178         * Doing kill with a non-positive pid causes messages to be
179         * sent to places we don't want.
180         */
181
182        SMB_ASSERT(pid > 0);
183
184        if (euid != 0) {
185                /* If we're not root become so to send the message. */
186                save_re_uid();
187                set_effective_uid(0);
188        }
189
190        ret = kill(pid, SIGUSR1);
191
192        if (euid != 0) {
193                /* Go back to who we were. */
194                int saved_errno = errno;
195                restore_re_uid_fromroot();
196                errno = saved_errno;
197        }
198
199        if (ret == -1) {
200                if (errno == ESRCH) {
201                        DEBUG(2,("pid %d doesn't exist - deleting messages record\n",
202                                 (int)pid));
203                        tdb_delete(tdb, message_key_pid(procid));
204
205                        /*
206                         * INVALID_HANDLE is the closest I can think of -- vl
207                         */
208                        return NT_STATUS_INVALID_HANDLE;
209                }
210
211                DEBUG(2,("message to process %d failed - %s\n", (int)pid,
212                         strerror(errno)));
213
214                /*
215                 * No call to map_nt_error_from_unix -- don't want to link in
216                 * errormap.o into lots of utils.
217                 */
218
219                if (errno == EINVAL) return NT_STATUS_INVALID_PARAMETER;
220                if (errno == EPERM)  return NT_STATUS_ACCESS_DENIED;
221                return NT_STATUS_UNSUCCESSFUL;
222        }
223
224        return NT_STATUS_OK;
225}
226
227/****************************************************************************
228 Send a message to a particular pid.
229****************************************************************************/
230
231static NTSTATUS message_send_pid_internal(struct process_id pid, int msg_type,
232                                          const void *buf, size_t len,
233                                          BOOL duplicates_allowed,
234                                          unsigned int timeout)
235{
236        TDB_DATA kbuf;
237        TDB_DATA dbuf;
238        TDB_DATA old_dbuf;
239        struct message_rec rec;
240        char *ptr;
241        struct message_rec prec;
242
243        /* NULL pointer means implicit length zero. */
244        if (!buf) {
245                SMB_ASSERT(len == 0);
246        }
247
248        /*
249         * Doing kill with a non-positive pid causes messages to be
250         * sent to places we don't want.
251         */
252
253        SMB_ASSERT(procid_to_pid(&pid) > 0);
254
255        rec.msg_version = MESSAGE_VERSION;
256        rec.msg_type = msg_type;
257        rec.dest = pid;
258        rec.src = procid_self();
259        rec.len = buf ? len : 0;
260
261        kbuf = message_key_pid(pid);
262
263        dbuf.dptr = (char *)SMB_MALLOC(len + sizeof(rec));
264        if (!dbuf.dptr) {
265                return NT_STATUS_NO_MEMORY;
266        }
267
268        memcpy(dbuf.dptr, &rec, sizeof(rec));
269        if (len > 0 && buf)
270                memcpy((void *)((char*)dbuf.dptr+sizeof(rec)), buf, len);
271
272        dbuf.dsize = len + sizeof(rec);
273
274        if (duplicates_allowed) {
275
276                /* If duplicates are allowed we can just append the message and return. */
277
278                /* lock the record for the destination */
279                if (timeout) {
280                        if (tdb_chainlock_with_timeout(tdb, kbuf, timeout) == -1) {
281                                DEBUG(0,("message_send_pid_internal: failed to get "
282                                         "chainlock with timeout %ul.\n", timeout));
283                                return NT_STATUS_IO_TIMEOUT;
284                        }
285                } else {
286                        if (tdb_chainlock(tdb, kbuf) == -1) {
287                                DEBUG(0,("message_send_pid_internal: failed to get "
288                                         "chainlock.\n"));
289                                return NT_STATUS_LOCK_NOT_GRANTED;
290                        }
291                }       
292                tdb_append(tdb, kbuf, dbuf);
293                tdb_chainunlock(tdb, kbuf);
294
295                SAFE_FREE(dbuf.dptr);
296                errno = 0;                    /* paranoia */
297                return message_notify(pid);
298        }
299
300        /* lock the record for the destination */
301        if (timeout) {
302                if (tdb_chainlock_with_timeout(tdb, kbuf, timeout) == -1) {
303                        DEBUG(0,("message_send_pid_internal: failed to get chainlock "
304                                 "with timeout %ul.\n", timeout));
305                        return NT_STATUS_IO_TIMEOUT;
306                }
307        } else {
308                if (tdb_chainlock(tdb, kbuf) == -1) {
309                        DEBUG(0,("message_send_pid_internal: failed to get "
310                                 "chainlock.\n"));
311                        return NT_STATUS_LOCK_NOT_GRANTED;
312                }
313        }       
314
315        old_dbuf = tdb_fetch(tdb, kbuf);
316
317        if (!old_dbuf.dptr) {
318                /* its a new record */
319
320                tdb_store(tdb, kbuf, dbuf, TDB_REPLACE);
321                tdb_chainunlock(tdb, kbuf);
322
323                SAFE_FREE(dbuf.dptr);
324                errno = 0;                    /* paranoia */
325                return message_notify(pid);
326        }
327
328        /* Not a new record. Check for duplicates. */
329
330        for(ptr = (char *)old_dbuf.dptr; ptr < old_dbuf.dptr + old_dbuf.dsize; ) {
331                /*
332                 * First check if the message header matches, then, if it's a non-zero
333                 * sized message, check if the data matches. If so it's a duplicate and
334                 * we can discard it. JRA.
335                 */
336
337                if (!memcmp(ptr, &rec, sizeof(rec))) {
338                        if (!len || (len && !memcmp( ptr + sizeof(rec), buf, len))) {
339                                tdb_chainunlock(tdb, kbuf);
340                                DEBUG(10,("message_send_pid_internal: discarding "
341                                          "duplicate message.\n"));
342                                SAFE_FREE(dbuf.dptr);
343                                SAFE_FREE(old_dbuf.dptr);
344                                return NT_STATUS_OK;
345                        }
346                }
347                memcpy(&prec, ptr, sizeof(prec));
348                ptr += sizeof(rec) + prec.len;
349        }
350
351        /* we're adding to an existing entry */
352
353        tdb_append(tdb, kbuf, dbuf);
354        tdb_chainunlock(tdb, kbuf);
355
356        SAFE_FREE(old_dbuf.dptr);
357        SAFE_FREE(dbuf.dptr);
358
359        errno = 0;                    /* paranoia */
360        return message_notify(pid);
361}
362
363/****************************************************************************
364 Send a message to a particular pid - no timeout.
365****************************************************************************/
366
367NTSTATUS message_send_pid(struct process_id pid, int msg_type, const void *buf,
368                          size_t len, BOOL duplicates_allowed)
369{
370        return message_send_pid_internal(pid, msg_type, buf, len,
371                                         duplicates_allowed, 0);
372}
373
374/****************************************************************************
375 Send a message to a particular pid, with timeout in seconds.
376****************************************************************************/
377
378NTSTATUS message_send_pid_with_timeout(struct process_id pid, int msg_type,
379                                       const void *buf, size_t len,
380                                       BOOL duplicates_allowed, unsigned int timeout)
381{
382        return message_send_pid_internal(pid, msg_type, buf, len, duplicates_allowed,
383                                         timeout);
384}
385
386/****************************************************************************
387 Count the messages pending for a particular pid. Expensive....
388****************************************************************************/
389
390unsigned int messages_pending_for_pid(struct process_id pid)
391{
392        TDB_DATA kbuf;
393        TDB_DATA dbuf;
394        char *buf;
395        unsigned int message_count = 0;
396
397        kbuf = message_key_pid(pid);
398
399        dbuf = tdb_fetch(tdb, kbuf);
400        if (dbuf.dptr == NULL || dbuf.dsize == 0) {
401                SAFE_FREE(dbuf.dptr);
402                return 0;
403        }
404
405        for (buf = dbuf.dptr; dbuf.dsize > sizeof(struct message_rec);) {
406                struct message_rec rec;
407                memcpy(&rec, buf, sizeof(rec));
408                buf += (sizeof(rec) + rec.len);
409                dbuf.dsize -= (sizeof(rec) + rec.len);
410                message_count++;
411        }
412
413        SAFE_FREE(dbuf.dptr);
414        return message_count;
415}
416
417/****************************************************************************
418 Retrieve all messages for the current process.
419****************************************************************************/
420
421static BOOL retrieve_all_messages(char **msgs_buf, size_t *total_len)
422{
423        TDB_DATA kbuf;
424        TDB_DATA dbuf;
425        TDB_DATA null_dbuf;
426
427        ZERO_STRUCT(null_dbuf);
428
429        *msgs_buf = NULL;
430        *total_len = 0;
431
432        kbuf = message_key_pid(pid_to_procid(sys_getpid()));
433
434        if (tdb_chainlock(tdb, kbuf) == -1)
435                return False;
436
437        dbuf = tdb_fetch(tdb, kbuf);
438        /*
439         * Replace with an empty record to keep the allocated
440         * space in the tdb.
441         */
442        tdb_store(tdb, kbuf, null_dbuf, TDB_REPLACE);
443        tdb_chainunlock(tdb, kbuf);
444
445        if (dbuf.dptr == NULL || dbuf.dsize == 0) {
446                SAFE_FREE(dbuf.dptr);
447                return False;
448        }
449
450        *msgs_buf = dbuf.dptr;
451        *total_len = dbuf.dsize;
452
453        return True;
454}
455
456/****************************************************************************
457 Parse out the next message for the current process.
458****************************************************************************/
459
460static BOOL message_recv(char *msgs_buf, size_t total_len, int *msg_type,
461                         struct process_id *src, char **buf, size_t *len)
462{
463        struct message_rec rec;
464        char *ret_buf = *buf;
465
466        *buf = NULL;
467        *len = 0;
468
469        if (total_len - (ret_buf - msgs_buf) < sizeof(rec))
470                return False;
471
472        memcpy(&rec, ret_buf, sizeof(rec));
473        ret_buf += sizeof(rec);
474
475        if (rec.msg_version != MESSAGE_VERSION) {
476                DEBUG(0,("message version %d received (expected %d)\n", rec.msg_version, MESSAGE_VERSION));
477                return False;
478        }
479
480        if (rec.len > 0) {
481                if (total_len - (ret_buf - msgs_buf) < rec.len)
482                        return False;
483        }
484
485        *len = rec.len;
486        *msg_type = rec.msg_type;
487        *src = rec.src;
488        *buf = ret_buf;
489
490        return True;
491}
492
493/****************************************************************************
494 Receive and dispatch any messages pending for this process.
495 JRA changed Dec 13 2006. Only one message handler now permitted per type.
496 *NOTE*: Dispatch functions must be able to cope with incoming
497 messages on an *odd* byte boundary.
498****************************************************************************/
499
500void message_dispatch(void)
501{
502        int msg_type;
503        struct process_id src;
504        char *buf;
505        char *msgs_buf;
506        size_t len, total_len;
507        int n_handled;
508
509        if (!received_signal)
510                return;
511
512        DEBUG(10,("message_dispatch: received_signal = %d\n", received_signal));
513
514        received_signal = 0;
515
516        if (!retrieve_all_messages(&msgs_buf, &total_len))
517                return;
518
519        for (buf = msgs_buf; message_recv(msgs_buf, total_len, &msg_type, &src, &buf, &len); buf += len) {
520                struct dispatch_fns *dfn;
521
522                DEBUG(10,("message_dispatch: received msg_type=%d "
523                          "src_pid=%u\n", msg_type,
524                          (unsigned int) procid_to_pid(&src)));
525
526                n_handled = 0;
527                for (dfn = dispatch_fns; dfn; dfn = dfn->next) {
528                        if (dfn->msg_type == msg_type) {
529                                DEBUG(10,("message_dispatch: processing message of type %d.\n", msg_type));
530                                dfn->fn(msg_type, src,
531                                        len ? (void *)buf : NULL, len,
532                                        dfn->private_data);
533                                n_handled++;
534                                break;
535                        }
536                }
537                if (!n_handled) {
538                        DEBUG(5,("message_dispatch: warning: no handler registed for "
539                                 "msg_type %d in pid %u\n",
540                                 msg_type, (unsigned int)sys_getpid()));
541                }
542        }
543        SAFE_FREE(msgs_buf);
544}
545
546/****************************************************************************
547 Register/replace a dispatch function for a particular message type.
548 JRA changed Dec 13 2006. Only one message handler now permitted per type.
549 *NOTE*: Dispatch functions must be able to cope with incoming
550 messages on an *odd* byte boundary.
551****************************************************************************/
552
553void message_register(int msg_type, 
554                      void (*fn)(int msg_type, struct process_id pid,
555                                 void *buf, size_t len,
556                                 void *private_data),
557                      void *private_data)
558{
559        struct dispatch_fns *dfn;
560
561        for (dfn = dispatch_fns; dfn; dfn = dfn->next) {
562                if (dfn->msg_type == msg_type) {
563                        dfn->fn = fn;
564                        return;
565                }
566        }
567
568        dfn = SMB_MALLOC_P(struct dispatch_fns);
569
570        if (dfn != NULL) {
571
572                ZERO_STRUCTPN(dfn);
573
574                dfn->msg_type = msg_type;
575                dfn->fn = fn;
576                dfn->private_data = private_data;
577
578                DLIST_ADD(dispatch_fns, dfn);
579        }
580        else {
581       
582                DEBUG(0,("message_register: Not enough memory. malloc failed!\n"));
583        }
584}
585
586/****************************************************************************
587 De-register the function for a particular message type.
588****************************************************************************/
589
590void message_deregister(int msg_type)
591{
592        struct dispatch_fns *dfn, *next;
593
594        for (dfn = dispatch_fns; dfn; dfn = next) {
595                next = dfn->next;
596                if (dfn->msg_type == msg_type) {
597                        DLIST_REMOVE(dispatch_fns, dfn);
598                        SAFE_FREE(dfn);
599                        return;
600                }
601        }       
602}
603
604struct msg_all {
605        int msg_type;
606        uint32 msg_flag;
607        const void *buf;
608        size_t len;
609        BOOL duplicates;
610        int n_sent;
611};
612
613/****************************************************************************
614 Send one of the messages for the broadcast.
615****************************************************************************/
616
617static int traverse_fn(TDB_CONTEXT *the_tdb, TDB_DATA kbuf, TDB_DATA dbuf, void *state)
618{
619        struct connections_data crec;
620        struct msg_all *msg_all = (struct msg_all *)state;
621        NTSTATUS status;
622
623        if (dbuf.dsize != sizeof(crec))
624                return 0;
625
626        memcpy(&crec, dbuf.dptr, sizeof(crec));
627
628        if (crec.cnum != -1)
629                return 0;
630
631        /* Don't send if the receiver hasn't registered an interest. */
632
633        if(!(crec.bcast_msg_flags & msg_all->msg_flag))
634                return 0;
635
636        /* If the msg send fails because the pid was not found (i.e. smbd died),
637         * the msg has already been deleted from the messages.tdb.*/
638
639        status = message_send_pid(crec.pid, msg_all->msg_type,
640                                  msg_all->buf, msg_all->len,
641                                  msg_all->duplicates);
642
643        if (NT_STATUS_EQUAL(status, NT_STATUS_INVALID_HANDLE)) {
644               
645                /* If the pid was not found delete the entry from connections.tdb */
646
647                DEBUG(2,("pid %s doesn't exist - deleting connections %d [%s]\n",
648                         procid_str_static(&crec.pid), crec.cnum, crec.name));
649                tdb_delete(the_tdb, kbuf);
650        }
651        msg_all->n_sent++;
652        return 0;
653}
654
655/**
656 * Send a message to all smbd processes.
657 *
658 * It isn't very efficient, but should be OK for the sorts of
659 * applications that use it. When we need efficient broadcast we can add
660 * it.
661 *
662 * @param n_sent Set to the number of messages sent.  This should be
663 * equal to the number of processes, but be careful for races.
664 *
665 * @retval True for success.
666 **/
667BOOL message_send_all(TDB_CONTEXT *conn_tdb, int msg_type,
668                      const void *buf, size_t len,
669                      BOOL duplicates_allowed,
670                      int *n_sent)
671{
672        struct msg_all msg_all;
673
674        msg_all.msg_type = msg_type;
675        if (msg_type < 1000)
676                msg_all.msg_flag = FLAG_MSG_GENERAL;
677        else if (msg_type > 1000 && msg_type < 2000)
678                msg_all.msg_flag = FLAG_MSG_NMBD;
679        else if (msg_type > 2000 && msg_type < 2100)
680                msg_all.msg_flag = FLAG_MSG_PRINT_NOTIFY;
681        else if (msg_type > 2100 && msg_type < 3000)
682                msg_all.msg_flag = FLAG_MSG_PRINT_GENERAL;
683        else if (msg_type > 3000 && msg_type < 4000)
684                msg_all.msg_flag = FLAG_MSG_SMBD;
685        else
686                return False;
687
688        msg_all.buf = buf;
689        msg_all.len = len;
690        msg_all.duplicates = duplicates_allowed;
691        msg_all.n_sent = 0;
692
693        tdb_traverse(conn_tdb, traverse_fn, &msg_all);
694        if (n_sent)
695                *n_sent = msg_all.n_sent;
696        return True;
697}
698
699/*
700 * Block and unblock receiving of messages. Allows removal of race conditions
701 * when doing a fork and changing message disposition.
702 */
703
704void message_block(void)
705{
706        BlockSignals(True, SIGUSR1);
707}
708
709void message_unblock(void)
710{
711        BlockSignals(False, SIGUSR1);
712}
713
714/*
715 * Samba4 API wrapper around the Samba3 implementation. Yes, I know, we could
716 * import the whole Samba4 thing, but I want notify.c from Samba4 in first.
717 */
718
719struct messaging_callback {
720        struct messaging_callback *prev, *next;
721        uint32 msg_type;
722        void (*fn)(struct messaging_context *msg, void *private_data, 
723                   uint32_t msg_type, 
724                   struct server_id server_id, DATA_BLOB *data);
725        void *private_data;
726};
727
728struct messaging_context {
729        struct server_id id;
730        struct messaging_callback *callbacks;
731};
732
733static int messaging_context_destructor(struct messaging_context *ctx)
734{
735        struct messaging_callback *cb;
736
737        for (cb = ctx->callbacks; cb; cb = cb->next) {
738                /*
739                 * We unconditionally remove all instances of our callback
740                 * from the tdb basis.
741                 */
742                message_deregister(cb->msg_type);
743        }
744        return 0;
745}
746
747struct messaging_context *messaging_init(TALLOC_CTX *mem_ctx, 
748                                         struct server_id server_id, 
749                                         struct event_context *ev)
750{
751        struct messaging_context *ctx;
752
753        if (!(ctx = TALLOC_ZERO_P(mem_ctx, struct messaging_context))) {
754                return NULL;
755        }
756
757        ctx->id = server_id;
758        talloc_set_destructor(ctx, messaging_context_destructor);
759        return ctx;
760}
761
762static void messaging_callback(int msg_type, struct process_id pid,
763                               void *buf, size_t len, void *private_data)
764{
765        struct messaging_context *ctx = talloc_get_type_abort(
766                private_data, struct messaging_context);
767        struct messaging_callback *cb, *next;
768
769        for (cb = ctx->callbacks; cb; cb = next) {
770                /*
771                 * Allow a callback to remove itself
772                 */
773                next = cb->next;
774
775                if (msg_type == cb->msg_type) {
776                        DATA_BLOB blob;
777                        struct server_id id;
778
779                        blob.data = (uint8 *)buf;
780                        blob.length = len;
781                        id.id = pid;
782
783                        cb->fn(ctx, cb->private_data, msg_type, id, &blob);
784                }
785        }
786}
787
788/*
789 * Register a dispatch function for a particular message type. Allow multiple
790 * registrants
791*/
792NTSTATUS messaging_register(struct messaging_context *ctx, void *private_data,
793                            uint32_t msg_type,
794                            void (*fn)(struct messaging_context *msg,
795                                       void *private_data, 
796                                       uint32_t msg_type, 
797                                       struct server_id server_id,
798                                       DATA_BLOB *data))
799{
800        struct messaging_callback *cb;
801
802        if (!(cb = talloc(ctx, struct messaging_callback))) {
803                return NT_STATUS_NO_MEMORY;
804        }
805
806        cb->msg_type = msg_type;
807        cb->fn = fn;
808        cb->private_data = private_data;
809
810        DLIST_ADD(ctx->callbacks, cb);
811        message_register(msg_type, messaging_callback, ctx);
812        return NT_STATUS_OK;
813}
814
815/*
816  De-register the function for a particular message type.
817*/
818void messaging_deregister(struct messaging_context *ctx, uint32_t msg_type,
819                          void *private_data)
820{
821        struct messaging_callback *cb, *next;
822
823        for (cb = ctx->callbacks; cb; cb = next) {
824                next = cb->next;
825                if ((cb->msg_type == msg_type)
826                    && (cb->private_data == private_data)) {
827                        DLIST_REMOVE(ctx->callbacks, cb);
828                        TALLOC_FREE(cb);
829                }
830        }
831}
832
833/*
834  Send a message to a particular server
835*/
836NTSTATUS messaging_send(struct messaging_context *msg,
837                        struct server_id server, 
838                        uint32_t msg_type, DATA_BLOB *data)
839{
840        return message_send_pid_internal(server.id, msg_type, data->data,
841                                         data->length, True, 0);
842}
843
844/** @} **/
Note: See TracBrowser for help on using the repository browser.