r14735: Use dcerpc_syntax_id rather then seperate GUID + if_version everywhere
[gd/samba-autobuild/.git] / source4 / lib / messaging / messaging.c
1 /* 
2    Unix SMB/CIFS implementation.
3
4    Samba internal messaging functions
5
6    Copyright (C) Andrew Tridgell 2004
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 #include "includes.h"
24 #include "lib/events/events.h"
25 #include "system/filesys.h"
26 #include "messaging/messaging.h"
27 #include "dlinklist.h"
28 #include "lib/socket/socket.h"
29 #include "librpc/gen_ndr/ndr_irpc.h"
30 #include "lib/messaging/irpc.h"
31 #include "db_wrap.h"
32 #include "lib/tdb/include/tdbutil.h"
33 #include "lib/util/unix_privs.h"
34 #include "librpc/rpc/dcerpc.h"
35
36 /* change the message version with any incompatible changes in the protocol */
37 #define MESSAGING_VERSION 1
38
39 struct messaging_context {
40         uint32_t server_id;
41         struct socket_context *sock;
42         const char *base_path;
43         const char *path;
44         struct dispatch_fn *dispatch;
45         struct messaging_rec *pending;
46         struct irpc_list *irpc;
47         struct idr_context *idr;
48         const char **names;
49         struct timeval start_time;
50
51         struct {
52                 struct event_context *ev;
53                 struct fd_event *fde;
54         } event;
55 };
56
57 /* we have a linked list of dispatch handlers that this messaging
58    server can deal with */
59 struct dispatch_fn {
60         struct dispatch_fn *next, *prev;
61         uint32_t msg_type;
62         void *private;
63         void (*fn)(struct messaging_context *msg, void *private, 
64                    uint32_t msg_type, uint32_t server_id, DATA_BLOB *data);
65 };
66
67 /* an individual message */
68 struct messaging_rec {
69         struct messaging_rec *next, *prev;
70         struct messaging_context *msg;
71         const char *path;
72
73         struct messaging_header {
74                 uint32_t version;
75                 uint32_t msg_type;
76                 uint32_t from;
77                 uint32_t to;
78                 uint32_t length;
79         } *header;
80
81         DATA_BLOB packet;
82 };
83
84
85 static void irpc_handler(struct messaging_context *, void *, 
86                          uint32_t, uint32_t, DATA_BLOB *);
87
88
89 /*
90  A useful function for testing the message system.
91 */
92 static void ping_message(struct messaging_context *msg, void *private, 
93                          uint32_t msg_type, uint32_t src, DATA_BLOB *data)
94 {
95         DEBUG(1,("INFO: Received PING message from server %u [%.*s]\n",
96                  (uint_t)src, (int)data->length, 
97                  data->data?(const char *)data->data:""));
98         messaging_send(msg, src, MSG_PONG, data);
99 }
100
101 /*
102   return uptime of messaging server via irpc
103 */
104 static NTSTATUS irpc_uptime(struct irpc_message *msg, 
105                             struct irpc_uptime *r)
106 {
107         struct messaging_context *ctx = talloc_get_type(msg->private, struct messaging_context);
108         *r->out.start_time = timeval_to_nttime(&ctx->start_time);
109         return NT_STATUS_OK;
110 }
111
112 /* 
113    return the path to a messaging socket
114 */
115 static char *messaging_path(struct messaging_context *msg, uint32_t server_id)
116 {
117         return talloc_asprintf(msg, "%s/msg.%u", msg->base_path, (unsigned)server_id);
118 }
119
120 /*
121   dispatch a fully received message
122
123   note that this deliberately can match more than one message handler
124   per message. That allows a single messasging context to register
125   (for example) a debug handler for more than one piece of code
126 */
127 static void messaging_dispatch(struct messaging_context *msg, struct messaging_rec *rec)
128 {
129         struct dispatch_fn *d, *next;
130         for (d=msg->dispatch;d;d=next) {
131                 next = d->next;
132                 if (d->msg_type == rec->header->msg_type) {
133                         DATA_BLOB data;
134                         data.data = rec->packet.data + sizeof(*rec->header);
135                         data.length = rec->header->length;
136                         d->fn(msg, d->private, d->msg_type, rec->header->from, &data);
137                 }
138         }
139         rec->header->length = 0;
140 }
141
142
143 /*
144   try to send the message
145 */
146 static NTSTATUS try_send(struct messaging_rec *rec)
147 {
148         struct messaging_context *msg = rec->msg;
149         size_t nsent;
150         void *priv;
151         NTSTATUS status;
152         struct socket_address *path;
153
154         /* rec->path is the path of the *other* socket, where we want
155          * this to end up */
156         path = socket_address_from_strings(msg, msg->sock->backend_name, 
157                                            rec->path, 0);
158         if (!path) {
159                 return NT_STATUS_NO_MEMORY;
160         }
161
162         /* we send with privileges so messages work from any context */
163         priv = root_privileges();
164         status = socket_sendto(msg->sock, &rec->packet, &nsent, 0, path);
165         talloc_free(path);
166         talloc_free(priv);
167
168         return status;
169 }
170
171 /*
172   handle a socket write event
173 */
174 static void messaging_send_handler(struct messaging_context *msg)
175 {
176         while (msg->pending) {
177                 struct messaging_rec *rec = msg->pending;
178                 NTSTATUS status;
179                 status = try_send(rec);
180                 if (NT_STATUS_EQUAL(status, STATUS_MORE_ENTRIES)) {
181                         break;
182                 }
183                 if (!NT_STATUS_IS_OK(status)) {
184                         DEBUG(1,("messaging: Lost message from %u to %u of type %u - %s\n", 
185                                  rec->header->from, rec->header->to, rec->header->msg_type, 
186                                  nt_errstr(status)));
187                 }
188                 DLIST_REMOVE(msg->pending, rec);
189                 talloc_free(rec);
190         }
191         if (msg->pending == NULL) {
192                 EVENT_FD_NOT_WRITEABLE(msg->event.fde);
193         }
194 }
195
196 /*
197   handle a new incoming packet
198 */
199 static void messaging_recv_handler(struct messaging_context *msg)
200 {
201         struct messaging_rec *rec;
202         NTSTATUS status;
203         DATA_BLOB packet;
204         size_t msize;
205
206         /* see how many bytes are in the next packet */
207         status = socket_pending(msg->sock, &msize);
208         if (!NT_STATUS_IS_OK(status)) {
209                 DEBUG(0,("socket_pending failed in messaging - %s\n", 
210                          nt_errstr(status)));
211                 return;
212         }
213         
214         packet = data_blob_talloc(msg, NULL, msize);
215         if (packet.data == NULL) {
216                 /* assume this is temporary and retry */
217                 return;
218         }
219             
220         status = socket_recv(msg->sock, packet.data, msize, &msize, 0);
221         if (!NT_STATUS_IS_OK(status)) {
222                 data_blob_free(&packet);
223                 return;
224         }
225
226         if (msize < sizeof(*rec->header)) {
227                 DEBUG(0,("messaging: bad message of size %d\n", (int)msize));
228                 data_blob_free(&packet);
229                 return;
230         }
231
232         rec = talloc(msg, struct messaging_rec);
233         if (rec == NULL) {
234                 smb_panic("Unable to allocate messaging_rec");
235         }
236
237         talloc_steal(rec, packet.data);
238         rec->msg           = msg;
239         rec->path          = msg->path;
240         rec->header        = (struct messaging_header *)packet.data;
241         rec->packet        = packet;
242
243         if (msize != sizeof(*rec->header) + rec->header->length) {
244                 DEBUG(0,("messaging: bad message header size %d should be %d\n", 
245                          rec->header->length, (int)(msize - sizeof(*rec->header))));
246                 talloc_free(rec);
247                 return;
248         }
249
250         messaging_dispatch(msg, rec);
251         talloc_free(rec);
252 }
253
254
255 /*
256   handle a socket event
257 */
258 static void messaging_handler(struct event_context *ev, struct fd_event *fde, 
259                               uint16_t flags, void *private)
260 {
261         struct messaging_context *msg = talloc_get_type(private, 
262                                                         struct messaging_context);
263         if (flags & EVENT_FD_WRITE) {
264                 messaging_send_handler(msg);
265         }
266         if (flags & EVENT_FD_READ) {
267                 messaging_recv_handler(msg);
268         }
269 }
270
271
272 /*
273   Register a dispatch function for a particular message type.
274 */
275 void messaging_register(struct messaging_context *msg, void *private,
276                         uint32_t msg_type, 
277                         void (*fn)(struct messaging_context *, void *, uint32_t, uint32_t, DATA_BLOB *))
278 {
279         struct dispatch_fn *d;
280
281         d = talloc(msg, struct dispatch_fn);
282         d->msg_type = msg_type;
283         d->private = private;
284         d->fn = fn;
285         DLIST_ADD(msg->dispatch, d);
286 }
287
288 /*
289   De-register the function for a particular message type.
290 */
291 void messaging_deregister(struct messaging_context *msg, uint32_t msg_type, void *private)
292 {
293         struct dispatch_fn *d, *next;
294
295         for (d = msg->dispatch; d; d = next) {
296                 next = d->next;
297                 if (d->msg_type == msg_type && 
298                     d->private == private) {
299                         DLIST_REMOVE(msg->dispatch, d);
300                         talloc_free(d);
301                 }
302         }       
303 }
304
305
306 /*
307   Send a message to a particular server
308 */
309 NTSTATUS messaging_send(struct messaging_context *msg, uint32_t server, 
310                         uint32_t msg_type, DATA_BLOB *data)
311 {
312         struct messaging_rec *rec;
313         NTSTATUS status;
314         size_t dlength = data?data->length:0;
315
316         rec = talloc(msg, struct messaging_rec);
317         if (rec == NULL) {
318                 return NT_STATUS_NO_MEMORY;
319         }
320
321         rec->packet = data_blob_talloc(rec, NULL, sizeof(*rec->header) + dlength);
322         if (rec->packet.data == NULL) {
323                 talloc_free(rec);
324                 return NT_STATUS_NO_MEMORY;
325         }
326
327         rec->msg              = msg;
328         rec->header           = (struct messaging_header *)rec->packet.data;
329         rec->header->version  = MESSAGING_VERSION;
330         rec->header->msg_type = msg_type;
331         rec->header->from     = msg->server_id;
332         rec->header->to       = server;
333         rec->header->length   = dlength;
334         if (dlength != 0) {
335                 memcpy(rec->packet.data + sizeof(*rec->header), 
336                        data->data, dlength);
337         }
338
339         rec->path = messaging_path(msg, server);
340         talloc_steal(rec, rec->path);
341
342         if (msg->pending != NULL) {
343                 status = STATUS_MORE_ENTRIES;
344         } else {
345                 status = try_send(rec);
346         }
347
348         if (NT_STATUS_EQUAL(status, STATUS_MORE_ENTRIES)) {
349                 if (msg->pending == NULL) {
350                         EVENT_FD_WRITEABLE(msg->event.fde);
351                 }
352                 DLIST_ADD_END(msg->pending, rec, struct messaging_rec *);
353                 return NT_STATUS_OK;
354         }
355
356         talloc_free(rec);
357
358         return status;
359 }
360
361 /*
362   Send a message to a particular server, with the message containing a single pointer
363 */
364 NTSTATUS messaging_send_ptr(struct messaging_context *msg, uint32_t server, 
365                             uint32_t msg_type, void *ptr)
366 {
367         DATA_BLOB blob;
368
369         blob.data = (void *)&ptr;
370         blob.length = sizeof(void *);
371
372         return messaging_send(msg, server, msg_type, &blob);
373 }
374
375
376 /*
377   destroy the messaging context
378 */
379 static int messaging_destructor(void *ptr)
380 {
381         struct messaging_context *msg = ptr;
382         unlink(msg->path);
383         while (msg->names && msg->names[0]) {
384                 irpc_remove_name(msg, msg->names[0]);
385         }
386         return 0;
387 }
388
389 /*
390   create the listening socket and setup the dispatcher
391 */
392 struct messaging_context *messaging_init(TALLOC_CTX *mem_ctx, uint32_t server_id, 
393                                          struct event_context *ev)
394 {
395         struct messaging_context *msg;
396         NTSTATUS status;
397         struct socket_address *path;
398         char *dir;
399
400         msg = talloc(mem_ctx, struct messaging_context);
401         if (msg == NULL) {
402                 return NULL;
403         }
404
405         if (ev == NULL) {
406                 ev = event_context_init(msg);
407         }
408
409         /* create the messaging directory if needed */
410         dir = smbd_tmp_path(msg, "messaging");
411         mkdir(dir, 0700);
412         talloc_free(dir);
413
414         msg->base_path  = smbd_tmp_path(msg, "messaging");
415         msg->path       = messaging_path(msg, server_id);
416         msg->server_id  = server_id;
417         msg->dispatch   = NULL;
418         msg->pending    = NULL;
419         msg->idr        = idr_init(msg);
420         msg->irpc       = NULL;
421         msg->names      = NULL;
422         msg->start_time = timeval_current();
423
424         status = socket_create("unix", SOCKET_TYPE_DGRAM, &msg->sock, 0);
425         if (!NT_STATUS_IS_OK(status)) {
426                 talloc_free(msg);
427                 return NULL;
428         }
429
430         /* by stealing here we ensure that the socket is cleaned up (and even 
431            deleted) on exit */
432         talloc_steal(msg, msg->sock);
433
434         path = socket_address_from_strings(msg, msg->sock->backend_name, 
435                                            msg->path, 0);
436         if (!path) {
437                 talloc_free(msg);
438                 return NULL;
439         }
440
441         status = socket_listen(msg->sock, path, 50, 0);
442         if (!NT_STATUS_IS_OK(status)) {
443                 DEBUG(0,("Unable to setup messaging listener for '%s':%s\n", msg->path, nt_errstr(status)));
444                 talloc_free(msg);
445                 return NULL;
446         }
447
448         /* it needs to be non blocking for sends */
449         set_blocking(socket_get_fd(msg->sock), False);
450
451         msg->event.ev   = talloc_reference(msg, ev);
452         msg->event.fde  = event_add_fd(ev, msg, socket_get_fd(msg->sock), 
453                                        EVENT_FD_READ, messaging_handler, msg);
454
455         talloc_set_destructor(msg, messaging_destructor);
456         
457         messaging_register(msg, NULL, MSG_PING, ping_message);
458         messaging_register(msg, NULL, MSG_IRPC, irpc_handler);
459         IRPC_REGISTER(msg, irpc, IRPC_UPTIME, irpc_uptime, msg);
460
461         return msg;
462 }
463
464 /* 
465    A hack, for the short term until we get 'client only' messaging in place 
466 */
467 struct messaging_context *messaging_client_init(TALLOC_CTX *mem_ctx, 
468                                                 struct event_context *ev)
469 {
470         return messaging_init(mem_ctx, random() % 0x10000000, ev);
471 }
472 /*
473   a list of registered irpc server functions
474 */
475 struct irpc_list {
476         struct irpc_list *next, *prev;
477         struct GUID uuid;
478         const struct dcerpc_interface_table *table;
479         int callnum;
480         irpc_function_t fn;
481         void *private;
482 };
483
484
485 /*
486   register a irpc server function
487 */
488 NTSTATUS irpc_register(struct messaging_context *msg_ctx, 
489                        const struct dcerpc_interface_table *table, 
490                        int callnum, irpc_function_t fn, void *private)
491 {
492         struct irpc_list *irpc;
493
494         /* override an existing handler, if any */
495         for (irpc=msg_ctx->irpc; irpc; irpc=irpc->next) {
496                 if (irpc->table == table && irpc->callnum == callnum) {
497                         break;
498                 }
499         }
500         if (irpc == NULL) {
501                 irpc = talloc(msg_ctx, struct irpc_list);
502                 NT_STATUS_HAVE_NO_MEMORY(irpc);
503                 DLIST_ADD(msg_ctx->irpc, irpc);
504         }
505
506         irpc->table   = table;
507         irpc->callnum = callnum;
508         irpc->fn      = fn;
509         irpc->private = private;
510         irpc->uuid = irpc->table->syntax_id.uuid;
511
512         return NT_STATUS_OK;
513 }
514
515
516 /*
517   handle an incoming irpc reply message
518 */
519 static void irpc_handler_reply(struct messaging_context *msg_ctx, struct irpc_message *m)
520 {
521         struct irpc_request *irpc;
522
523         irpc = idr_find(msg_ctx->idr, m->header.callid);
524         if (irpc == NULL) return;
525
526         /* parse the reply data */
527         irpc->status = irpc->table->calls[irpc->callnum].ndr_pull(m->ndr, NDR_OUT, irpc->r);
528         if (NT_STATUS_IS_OK(irpc->status)) {
529                 irpc->status = m->header.status;
530                 talloc_steal(irpc->mem_ctx, m);
531         } else {
532                 talloc_steal(irpc, m);
533         }
534         irpc->done = True;
535         if (irpc->async.fn) {
536                 irpc->async.fn(irpc);
537         }
538 }
539
540 /*
541   send a irpc reply
542 */
543 NTSTATUS irpc_send_reply(struct irpc_message *m, NTSTATUS status)
544 {
545         struct ndr_push *push;
546         DATA_BLOB packet;
547
548         m->header.status = status;
549
550         /* setup the reply */
551         push = ndr_push_init_ctx(m->ndr);
552         if (push == NULL) {
553                 status = NT_STATUS_NO_MEMORY;
554                 goto failed;
555         }
556
557         m->header.flags |= IRPC_FLAG_REPLY;
558
559         /* construct the packet */
560         status = ndr_push_irpc_header(push, NDR_SCALARS|NDR_BUFFERS, &m->header);
561         if (!NT_STATUS_IS_OK(status)) goto failed;
562
563         status = m->irpc->table->calls[m->irpc->callnum].ndr_push(push, NDR_OUT, m->data);
564         if (!NT_STATUS_IS_OK(status)) goto failed;
565
566         /* send the reply message */
567         packet = ndr_push_blob(push);
568         status = messaging_send(m->msg_ctx, m->from, MSG_IRPC, &packet);
569         if (!NT_STATUS_IS_OK(status)) goto failed;
570
571 failed:
572         talloc_free(m);
573         return status;
574 }
575
576 /*
577   handle an incoming irpc request message
578 */
579 static void irpc_handler_request(struct messaging_context *msg_ctx, 
580                                  struct irpc_message *m)
581 {
582         struct irpc_list *i;
583         void *r;
584         NTSTATUS status;
585
586         for (i=msg_ctx->irpc; i; i=i->next) {
587                 if (GUID_equal(&i->uuid, &m->header.uuid) &&
588                     i->table->syntax_id.if_version == m->header.if_version &&
589                     i->callnum == m->header.callnum) {
590                         break;
591                 }
592         }
593
594         if (i == NULL) {
595                 /* no registered handler for this message */
596                 talloc_free(m);
597                 return;
598         }
599
600         /* allocate space for the structure */
601         r = talloc_zero_size(m->ndr, i->table->calls[m->header.callnum].struct_size);
602         if (r == NULL) goto failed;
603
604         /* parse the request data */
605         status = i->table->calls[i->callnum].ndr_pull(m->ndr, NDR_IN, r);
606         if (!NT_STATUS_IS_OK(status)) goto failed;
607
608         /* make the call */
609         m->private     = i->private;
610         m->defer_reply = False;
611         m->msg_ctx     = msg_ctx;
612         m->irpc        = i;
613         m->data        = r;
614         m->ev          = msg_ctx->event.ev;
615
616         m->header.status = i->fn(m, r);
617
618         if (m->defer_reply) {
619                 /* the server function has asked to defer the reply to later */
620                 talloc_steal(msg_ctx, m);
621                 return;
622         }
623
624         irpc_send_reply(m, m->header.status);
625         return;
626
627 failed:
628         talloc_free(m);
629 }
630
631 /*
632   handle an incoming irpc message
633 */
634 static void irpc_handler(struct messaging_context *msg_ctx, void *private, 
635                          uint32_t msg_type, uint32_t src, DATA_BLOB *packet)
636 {
637         struct irpc_message *m;
638         NTSTATUS status;
639
640         m = talloc(msg_ctx, struct irpc_message);
641         if (m == NULL) goto failed;
642
643         m->from = src;
644
645         m->ndr = ndr_pull_init_blob(packet, m);
646         if (m->ndr == NULL) goto failed;
647
648         m->ndr->flags |= LIBNDR_FLAG_REF_ALLOC;
649
650         status = ndr_pull_irpc_header(m->ndr, NDR_BUFFERS|NDR_SCALARS, &m->header);
651         if (!NT_STATUS_IS_OK(status)) goto failed;
652
653         if (m->header.flags & IRPC_FLAG_REPLY) {
654                 irpc_handler_reply(msg_ctx, m);
655         } else {
656                 irpc_handler_request(msg_ctx, m);
657         }
658         return;
659
660 failed:
661         talloc_free(m);
662 }
663
664
665 /*
666   destroy a irpc request
667 */
668 static int irpc_destructor(void *ptr)
669 {
670         struct irpc_request *irpc = talloc_get_type(ptr, struct irpc_request);
671         idr_remove(irpc->msg_ctx->idr, irpc->callid);
672         return 0;
673 }
674
675 /*
676   timeout a irpc request
677 */
678 static void irpc_timeout(struct event_context *ev, struct timed_event *te, 
679                          struct timeval t, void *private)
680 {
681         struct irpc_request *irpc = talloc_get_type(private, struct irpc_request);
682         irpc->status = NT_STATUS_IO_TIMEOUT;
683         irpc->done = True;
684         if (irpc->async.fn) {
685                 irpc->async.fn(irpc);
686         }
687 }
688
689
690 /*
691   make a irpc call - async send
692 */
693 struct irpc_request *irpc_call_send(struct messaging_context *msg_ctx, 
694                                     uint32_t server_id, 
695                                     const struct dcerpc_interface_table *table, 
696                                     int callnum, void *r, TALLOC_CTX *ctx)
697 {
698         struct irpc_header header;
699         struct ndr_push *ndr;
700         NTSTATUS status;
701         DATA_BLOB packet;
702         struct irpc_request *irpc;
703
704         irpc = talloc(msg_ctx, struct irpc_request);
705         if (irpc == NULL) goto failed;
706
707         irpc->msg_ctx  = msg_ctx;
708         irpc->table    = table;
709         irpc->callnum  = callnum;
710         irpc->callid   = idr_get_new(msg_ctx->idr, irpc, UINT16_MAX);
711         if (irpc->callid == -1) goto failed;
712         irpc->r        = r;
713         irpc->done     = False;
714         irpc->async.fn = NULL;
715         irpc->mem_ctx  = ctx;
716
717         talloc_set_destructor(irpc, irpc_destructor);
718
719         /* setup the header */
720         header.uuid = table->syntax_id.uuid;
721
722         header.if_version = table->syntax_id.if_version;
723         header.callid     = irpc->callid;
724         header.callnum    = callnum;
725         header.flags      = 0;
726         header.status     = NT_STATUS_OK;
727
728         /* construct the irpc packet */
729         ndr = ndr_push_init_ctx(irpc);
730         if (ndr == NULL) goto failed;
731
732         status = ndr_push_irpc_header(ndr, NDR_SCALARS|NDR_BUFFERS, &header);
733         if (!NT_STATUS_IS_OK(status)) goto failed;
734
735         status = table->calls[callnum].ndr_push(ndr, NDR_IN, r);
736         if (!NT_STATUS_IS_OK(status)) goto failed;
737
738         /* and send it */
739         packet = ndr_push_blob(ndr);
740         status = messaging_send(msg_ctx, server_id, MSG_IRPC, &packet);
741         if (!NT_STATUS_IS_OK(status)) goto failed;
742
743         event_add_timed(msg_ctx->event.ev, irpc, 
744                         timeval_current_ofs(IRPC_CALL_TIMEOUT, 0), 
745                         irpc_timeout, irpc);
746
747         talloc_free(ndr);
748         return irpc;
749
750 failed:
751         talloc_free(irpc);
752         return NULL;
753 }
754
755 /*
756   wait for a irpc reply
757 */
758 NTSTATUS irpc_call_recv(struct irpc_request *irpc)
759 {
760         NTSTATUS status;
761
762         NT_STATUS_HAVE_NO_MEMORY(irpc);
763
764         while (!irpc->done) {
765                 if (event_loop_once(irpc->msg_ctx->event.ev) != 0) {
766                         return NT_STATUS_CONNECTION_DISCONNECTED;
767                 }
768         }
769         status = irpc->status;
770         talloc_free(irpc);
771         return status;
772 }
773
774 /*
775   perform a synchronous irpc request
776 */
777 NTSTATUS irpc_call(struct messaging_context *msg_ctx, 
778                    uint32_t server_id, 
779                    const struct dcerpc_interface_table *table, 
780                    int callnum, void *r,
781                    TALLOC_CTX *mem_ctx)
782 {
783         struct irpc_request *irpc = irpc_call_send(msg_ctx, server_id, 
784                                                    table, callnum, r, mem_ctx);
785         return irpc_call_recv(irpc);
786 }
787
788 /*
789   open the naming database
790 */
791 static struct tdb_wrap *irpc_namedb_open(struct messaging_context *msg_ctx)
792 {
793         struct tdb_wrap *t;
794         char *path = talloc_asprintf(msg_ctx, "%s/names.tdb", msg_ctx->base_path);
795         if (path == NULL) {
796                 return NULL;
797         }
798         t = tdb_wrap_open(msg_ctx, path, 0, 0, O_RDWR|O_CREAT, 0660);
799         talloc_free(path);
800         return t;
801 }
802         
803
804 /*
805   add a string name that this irpc server can be called on
806 */
807 NTSTATUS irpc_add_name(struct messaging_context *msg_ctx, const char *name)
808 {
809         struct tdb_wrap *t;
810         TDB_DATA rec;
811         int count;
812         NTSTATUS status = NT_STATUS_OK;
813
814         t = irpc_namedb_open(msg_ctx);
815         NT_STATUS_HAVE_NO_MEMORY(t);
816
817         if (tdb_lock_bystring(t->tdb, name) != 0) {
818                 talloc_free(t);
819                 return NT_STATUS_LOCK_NOT_GRANTED;
820         }
821         rec = tdb_fetch_bystring(t->tdb, name);
822         count = rec.dsize / sizeof(uint32_t);
823         rec.dptr = (unsigned char *)realloc_p(rec.dptr, uint32_t, count+1);
824         rec.dsize += sizeof(uint32_t);
825         if (rec.dptr == NULL) {
826                 tdb_unlock_bystring(t->tdb, name);
827                 talloc_free(t);
828                 return NT_STATUS_NO_MEMORY;
829         }
830         ((uint32_t *)rec.dptr)[count] = msg_ctx->server_id;
831         if (tdb_store_bystring(t->tdb, name, rec, 0) != 0) {
832                 status = NT_STATUS_INTERNAL_ERROR;
833         }
834         free(rec.dptr);
835         tdb_unlock_bystring(t->tdb, name);
836         talloc_free(t);
837
838         msg_ctx->names = str_list_add(msg_ctx->names, name);
839         talloc_steal(msg_ctx, msg_ctx->names);
840
841         return status;
842 }
843
844 /*
845   return a list of server ids for a server name
846 */
847 uint32_t *irpc_servers_byname(struct messaging_context *msg_ctx, const char *name)
848 {
849         struct tdb_wrap *t;
850         TDB_DATA rec;
851         int count, i;
852         uint32_t *ret;
853
854         t = irpc_namedb_open(msg_ctx);
855         if (t == NULL) {
856                 return NULL;
857         }
858
859         if (tdb_lock_bystring(t->tdb, name) != 0) {
860                 talloc_free(t);
861                 return NULL;
862         }
863         rec = tdb_fetch_bystring(t->tdb, name);
864         if (rec.dptr == NULL) {
865                 tdb_unlock_bystring(t->tdb, name);
866                 talloc_free(t);
867                 return NULL;
868         }
869         count = rec.dsize / sizeof(uint32_t);
870         ret = talloc_array(msg_ctx, uint32_t, count+1);
871         if (ret == NULL) {
872                 tdb_unlock_bystring(t->tdb, name);
873                 talloc_free(t);
874                 return NULL;
875         }
876         for (i=0;i<count;i++) {
877                 ret[i] = ((uint32_t *)rec.dptr)[i];
878         }
879         ret[i] = 0;
880         free(rec.dptr);
881         tdb_unlock_bystring(t->tdb, name);
882         talloc_free(t);
883
884         return ret;
885 }
886
887 /*
888   remove a name from a messaging context
889 */
890 void irpc_remove_name(struct messaging_context *msg_ctx, const char *name)
891 {
892         struct tdb_wrap *t;
893         TDB_DATA rec;
894         int count, i;
895         uint32_t *ids;
896
897         str_list_remove(msg_ctx->names, name);
898
899         t = irpc_namedb_open(msg_ctx);
900         if (t == NULL) {
901                 return;
902         }
903
904         if (tdb_lock_bystring(t->tdb, name) != 0) {
905                 talloc_free(t);
906                 return;
907         }
908         rec = tdb_fetch_bystring(t->tdb, name);
909         count = rec.dsize / sizeof(uint32_t);
910         if (count == 0) {
911                 tdb_unlock_bystring(t->tdb, name);
912                 talloc_free(t);
913                 return;
914         }
915         ids = (uint32_t *)rec.dptr;
916         for (i=0;i<count;i++) {
917                 if (ids[i] == msg_ctx->server_id) {
918                         if (i < count-1) {
919                                 memmove(ids+i, ids+i+1, count-(i+1));
920                         }
921                         rec.dsize -= sizeof(uint32_t);
922                         break;
923                 }
924         }
925         tdb_store_bystring(t->tdb, name, rec, 0);
926         free(rec.dptr);
927         tdb_unlock_bystring(t->tdb, name);
928         talloc_free(t);
929 }