2 Unix SMB/CIFS implementation.
4 Samba internal messaging functions
6 Copyright (C) Andrew Tridgell 2004
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 3 of the License, or
11 (at your option) any later version.
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.
18 You should have received a copy of the GNU General Public License
19 along with this program. If not, see <http://www.gnu.org/licenses/>.
23 #include "lib/events/events.h"
24 #include "system/filesys.h"
25 #include "messaging/messaging.h"
26 #include "../lib/util/dlinklist.h"
27 #include "lib/socket/socket.h"
28 #include "librpc/gen_ndr/ndr_irpc.h"
29 #include "lib/messaging/irpc.h"
30 #include "lib/tdb_wrap/tdb_wrap.h"
31 #include "../lib/util/unix_privs.h"
32 #include "librpc/rpc/dcerpc.h"
33 #include "../lib/tdb_compat/tdb_compat.h"
34 #include "../lib/util/util_tdb.h"
35 #include "cluster/cluster.h"
36 #include "../lib/util/tevent_ntstatus.h"
37 #include "lib/param/param.h"
39 /* change the message version with any incompatible changes in the protocol */
40 #define IMESSAGING_VERSION 1
46 struct imessaging_context
*msg_ctx
;
49 void (*handler
)(struct irpc_request
*irpc
, struct irpc_message
*m
);
54 struct imessaging_context
{
55 struct server_id server_id
;
56 struct socket_context
*sock
;
57 const char *base_path
;
59 struct loadparm_context
*lp_ctx
;
60 struct dispatch_fn
**dispatch
;
62 struct idr_context
*dispatch_tree
;
63 struct imessaging_rec
*pending
;
64 struct imessaging_rec
*retry_queue
;
65 struct irpc_list
*irpc
;
66 struct idr_context
*idr
;
68 struct timeval start_time
;
69 struct tevent_timer
*retry_te
;
71 struct tevent_context
*ev
;
72 struct tevent_fd
*fde
;
76 /* we have a linked list of dispatch handlers for each msg_type that
77 this messaging server can deal with */
79 struct dispatch_fn
*next
, *prev
;
85 /* an individual message */
86 struct imessaging_rec
{
87 struct imessaging_rec
*next
, *prev
;
88 struct imessaging_context
*msg
;
91 struct imessaging_header
{
94 struct server_id from
;
104 static void irpc_handler(struct imessaging_context
*, void *,
105 uint32_t, struct server_id
, DATA_BLOB
*);
109 A useful function for testing the message system.
111 static void ping_message(struct imessaging_context
*msg
, void *private_data
,
112 uint32_t msg_type
, struct server_id src
, DATA_BLOB
*data
)
114 char *task_id
= server_id_str(NULL
, &src
);
115 DEBUG(1,("INFO: Received PING message from server %s [%.*s]\n",
116 task_id
, (int)data
->length
,
117 data
->data
?(const char *)data
->data
:""));
118 talloc_free(task_id
);
119 imessaging_send(msg
, src
, MSG_PONG
, data
);
123 return uptime of messaging server via irpc
125 static NTSTATUS
irpc_uptime(struct irpc_message
*msg
,
126 struct irpc_uptime
*r
)
128 struct imessaging_context
*ctx
= talloc_get_type(msg
->private_data
, struct imessaging_context
);
129 *r
->out
.start_time
= timeval_to_nttime(&ctx
->start_time
);
134 return the path to a messaging socket
136 static char *imessaging_path(struct imessaging_context
*msg
, struct server_id server_id
)
138 TALLOC_CTX
*tmp_ctx
= talloc_new(msg
);
139 const char *id
= server_id_str(tmp_ctx
, &server_id
);
144 s
= talloc_asprintf(msg
, "%s/msg.%s", msg
->base_path
, id
);
145 talloc_steal(s
, tmp_ctx
);
150 dispatch a fully received message
152 note that this deliberately can match more than one message handler
153 per message. That allows a single messasging context to register
154 (for example) a debug handler for more than one piece of code
156 static void imessaging_dispatch(struct imessaging_context
*msg
, struct imessaging_rec
*rec
)
158 struct dispatch_fn
*d
, *next
;
160 /* temporary IDs use an idtree, the rest use a array of pointers */
161 if (rec
->header
->msg_type
>= MSG_TMP_BASE
) {
162 d
= (struct dispatch_fn
*)idr_find(msg
->dispatch_tree
,
163 rec
->header
->msg_type
);
164 } else if (rec
->header
->msg_type
< msg
->num_types
) {
165 d
= msg
->dispatch
[rec
->header
->msg_type
];
170 for (; d
; d
= next
) {
173 data
.data
= rec
->packet
.data
+ sizeof(*rec
->header
);
174 data
.length
= rec
->header
->length
;
175 d
->fn(msg
, d
->private_data
, d
->msg_type
, rec
->header
->from
, &data
);
177 rec
->header
->length
= 0;
181 handler for messages that arrive from other nodes in the cluster
183 static void cluster_message_handler(struct imessaging_context
*msg
, DATA_BLOB packet
)
185 struct imessaging_rec
*rec
;
187 rec
= talloc(msg
, struct imessaging_rec
);
189 smb_panic("Unable to allocate imessaging_rec");
193 rec
->path
= msg
->path
;
194 rec
->header
= (struct imessaging_header
*)packet
.data
;
195 rec
->packet
= packet
;
198 if (packet
.length
!= sizeof(*rec
->header
) + rec
->header
->length
) {
199 DEBUG(0,("messaging: bad message header size %d should be %d\n",
200 rec
->header
->length
, (int)(packet
.length
- sizeof(*rec
->header
))));
205 imessaging_dispatch(msg
, rec
);
212 try to send the message
214 static NTSTATUS
try_send(struct imessaging_rec
*rec
)
216 struct imessaging_context
*msg
= rec
->msg
;
220 struct socket_address
*path
;
222 /* rec->path is the path of the *other* socket, where we want
224 path
= socket_address_from_strings(msg
, msg
->sock
->backend_name
,
227 return NT_STATUS_NO_MEMORY
;
230 /* we send with privileges so messages work from any context */
231 priv
= root_privileges();
232 status
= socket_sendto(msg
->sock
, &rec
->packet
, &nsent
, path
);
240 retry backed off messages
242 static void msg_retry_timer(struct tevent_context
*ev
, struct tevent_timer
*te
,
243 struct timeval t
, void *private_data
)
245 struct imessaging_context
*msg
= talloc_get_type(private_data
,
246 struct imessaging_context
);
247 msg
->retry_te
= NULL
;
249 /* put the messages back on the main queue */
250 while (msg
->retry_queue
) {
251 struct imessaging_rec
*rec
= msg
->retry_queue
;
252 DLIST_REMOVE(msg
->retry_queue
, rec
);
253 DLIST_ADD_END(msg
->pending
, rec
, struct imessaging_rec
*);
256 TEVENT_FD_WRITEABLE(msg
->event
.fde
);
260 handle a socket write event
262 static void imessaging_send_handler(struct imessaging_context
*msg
)
264 while (msg
->pending
) {
265 struct imessaging_rec
*rec
= msg
->pending
;
267 status
= try_send(rec
);
268 if (NT_STATUS_EQUAL(status
, STATUS_MORE_ENTRIES
)) {
270 if (rec
->retries
> 3) {
271 /* we're getting continuous write errors -
272 backoff this record */
273 DLIST_REMOVE(msg
->pending
, rec
);
274 DLIST_ADD_END(msg
->retry_queue
, rec
,
275 struct imessaging_rec
*);
276 if (msg
->retry_te
== NULL
) {
278 tevent_add_timer(msg
->event
.ev
, msg
,
279 timeval_current_ofs(1, 0),
280 msg_retry_timer
, msg
);
286 if (!NT_STATUS_IS_OK(status
)) {
287 TALLOC_CTX
*tmp_ctx
= talloc_new(msg
);
288 DEBUG(1,("messaging: Lost message from %s to %s of type %u - %s\n",
289 server_id_str(tmp_ctx
, &rec
->header
->from
),
290 server_id_str(tmp_ctx
, &rec
->header
->to
),
291 rec
->header
->msg_type
,
293 talloc_free(tmp_ctx
);
295 DLIST_REMOVE(msg
->pending
, rec
);
298 if (msg
->pending
== NULL
) {
299 TEVENT_FD_NOT_WRITEABLE(msg
->event
.fde
);
304 handle a new incoming packet
306 static void imessaging_recv_handler(struct imessaging_context
*msg
)
308 struct imessaging_rec
*rec
;
313 /* see how many bytes are in the next packet */
314 status
= socket_pending(msg
->sock
, &msize
);
315 if (!NT_STATUS_IS_OK(status
)) {
316 DEBUG(0,("socket_pending failed in messaging - %s\n",
321 packet
= data_blob_talloc(msg
, NULL
, msize
);
322 if (packet
.data
== NULL
) {
323 /* assume this is temporary and retry */
327 status
= socket_recv(msg
->sock
, packet
.data
, msize
, &msize
);
328 if (!NT_STATUS_IS_OK(status
)) {
329 data_blob_free(&packet
);
333 if (msize
< sizeof(*rec
->header
)) {
334 DEBUG(0,("messaging: bad message of size %d\n", (int)msize
));
335 data_blob_free(&packet
);
339 rec
= talloc(msg
, struct imessaging_rec
);
341 smb_panic("Unable to allocate imessaging_rec");
344 talloc_steal(rec
, packet
.data
);
346 rec
->path
= msg
->path
;
347 rec
->header
= (struct imessaging_header
*)packet
.data
;
348 rec
->packet
= packet
;
351 if (msize
!= sizeof(*rec
->header
) + rec
->header
->length
) {
352 DEBUG(0,("messaging: bad message header size %d should be %d\n",
353 rec
->header
->length
, (int)(msize
- sizeof(*rec
->header
))));
358 imessaging_dispatch(msg
, rec
);
364 handle a socket event
366 static void imessaging_handler(struct tevent_context
*ev
, struct tevent_fd
*fde
,
367 uint16_t flags
, void *private_data
)
369 struct imessaging_context
*msg
= talloc_get_type(private_data
,
370 struct imessaging_context
);
371 if (flags
& TEVENT_FD_WRITE
) {
372 imessaging_send_handler(msg
);
374 if (flags
& TEVENT_FD_READ
) {
375 imessaging_recv_handler(msg
);
381 Register a dispatch function for a particular message type.
383 NTSTATUS
imessaging_register(struct imessaging_context
*msg
, void *private_data
,
384 uint32_t msg_type
, msg_callback_t fn
)
386 struct dispatch_fn
*d
;
388 /* possibly expand dispatch array */
389 if (msg_type
>= msg
->num_types
) {
390 struct dispatch_fn
**dp
;
392 dp
= talloc_realloc(msg
, msg
->dispatch
, struct dispatch_fn
*, msg_type
+1);
393 NT_STATUS_HAVE_NO_MEMORY(dp
);
395 for (i
=msg
->num_types
;i
<=msg_type
;i
++) {
396 msg
->dispatch
[i
] = NULL
;
398 msg
->num_types
= msg_type
+1;
401 d
= talloc_zero(msg
->dispatch
, struct dispatch_fn
);
402 NT_STATUS_HAVE_NO_MEMORY(d
);
403 d
->msg_type
= msg_type
;
404 d
->private_data
= private_data
;
407 DLIST_ADD(msg
->dispatch
[msg_type
], d
);
413 register a temporary message handler. The msg_type is allocated
416 NTSTATUS
imessaging_register_tmp(struct imessaging_context
*msg
, void *private_data
,
417 msg_callback_t fn
, uint32_t *msg_type
)
419 struct dispatch_fn
*d
;
422 d
= talloc_zero(msg
->dispatch
, struct dispatch_fn
);
423 NT_STATUS_HAVE_NO_MEMORY(d
);
424 d
->private_data
= private_data
;
427 id
= idr_get_new_above(msg
->dispatch_tree
, d
, MSG_TMP_BASE
, UINT16_MAX
);
430 return NT_STATUS_TOO_MANY_CONTEXT_IDS
;
433 d
->msg_type
= (uint32_t)id
;
434 (*msg_type
) = d
->msg_type
;
440 De-register the function for a particular message type.
442 void imessaging_deregister(struct imessaging_context
*msg
, uint32_t msg_type
, void *private_data
)
444 struct dispatch_fn
*d
, *next
;
446 if (msg_type
>= msg
->num_types
) {
447 d
= (struct dispatch_fn
*)idr_find(msg
->dispatch_tree
,
450 idr_remove(msg
->dispatch_tree
, msg_type
);
455 for (d
= msg
->dispatch
[msg_type
]; d
; d
= next
) {
457 if (d
->private_data
== private_data
) {
458 DLIST_REMOVE(msg
->dispatch
[msg_type
], d
);
465 Send a message to a particular server
467 NTSTATUS
imessaging_send(struct imessaging_context
*msg
, struct server_id server
,
468 uint32_t msg_type
, const DATA_BLOB
*data
)
470 struct imessaging_rec
*rec
;
472 size_t dlength
= data
?data
->length
:0;
474 rec
= talloc(msg
, struct imessaging_rec
);
476 return NT_STATUS_NO_MEMORY
;
479 rec
->packet
= data_blob_talloc(rec
, NULL
, sizeof(*rec
->header
) + dlength
);
480 if (rec
->packet
.data
== NULL
) {
482 return NT_STATUS_NO_MEMORY
;
487 rec
->header
= (struct imessaging_header
*)rec
->packet
.data
;
489 ZERO_STRUCTP(rec
->header
);
490 rec
->header
->version
= IMESSAGING_VERSION
;
491 rec
->header
->msg_type
= msg_type
;
492 rec
->header
->from
= msg
->server_id
;
493 rec
->header
->to
= server
;
494 rec
->header
->length
= dlength
;
496 memcpy(rec
->packet
.data
+ sizeof(*rec
->header
),
497 data
->data
, dlength
);
500 if (!cluster_node_equal(&msg
->server_id
, &server
)) {
501 /* the destination is on another node - dispatch via
503 status
= cluster_message_send(server
, &rec
->packet
);
508 rec
->path
= imessaging_path(msg
, server
);
509 talloc_steal(rec
, rec
->path
);
511 if (msg
->pending
!= NULL
) {
512 status
= STATUS_MORE_ENTRIES
;
514 status
= try_send(rec
);
517 if (NT_STATUS_EQUAL(status
, STATUS_MORE_ENTRIES
)) {
518 if (msg
->pending
== NULL
) {
519 TEVENT_FD_WRITEABLE(msg
->event
.fde
);
521 DLIST_ADD_END(msg
->pending
, rec
, struct imessaging_rec
*);
531 Send a message to a particular server, with the message containing a single pointer
533 NTSTATUS
imessaging_send_ptr(struct imessaging_context
*msg
, struct server_id server
,
534 uint32_t msg_type
, void *ptr
)
538 blob
.data
= (uint8_t *)&ptr
;
539 blob
.length
= sizeof(void *);
541 return imessaging_send(msg
, server
, msg_type
, &blob
);
546 remove our messaging socket and database entry
548 int imessaging_cleanup(struct imessaging_context
*msg
)
554 DEBUG(5,("imessaging: cleaning up %s\n", msg
->path
));
556 while (msg
->names
&& msg
->names
[0]) {
557 irpc_remove_name(msg
, msg
->names
[0]);
563 create the listening socket and setup the dispatcher
565 use temporary=true when you want a destructor to remove the
566 associated messaging socket and database entry on talloc free. Don't
567 use this in processes that may fork and a child may talloc free this
570 struct imessaging_context
*imessaging_init(TALLOC_CTX
*mem_ctx
,
571 struct loadparm_context
*lp_ctx
,
572 struct server_id server_id
,
573 struct tevent_context
*ev
,
576 struct imessaging_context
*msg
;
578 struct socket_address
*path
;
585 msg
= talloc_zero(mem_ctx
, struct imessaging_context
);
590 /* setup a handler for messages from other cluster nodes, if appropriate */
591 status
= cluster_message_init(msg
, server_id
, cluster_message_handler
);
592 if (!NT_STATUS_IS_OK(status
)) {
597 /* create the messaging directory if needed */
599 msg
->lp_ctx
= talloc_reference(msg
, lp_ctx
);
605 msg
->base_path
= lpcfg_imessaging_path(msg
, lp_ctx
);
607 ok
= directory_create_or_exist_strict(msg
->base_path
, geteuid(), 0700);
613 msg
->path
= imessaging_path(msg
, server_id
);
614 msg
->server_id
= server_id
;
615 msg
->idr
= idr_init(msg
);
616 msg
->dispatch_tree
= idr_init(msg
);
617 msg
->start_time
= timeval_current();
619 status
= socket_create("unix", SOCKET_TYPE_DGRAM
, &msg
->sock
, 0);
620 if (!NT_STATUS_IS_OK(status
)) {
625 /* by stealing here we ensure that the socket is cleaned up (and even
627 talloc_steal(msg
, msg
->sock
);
629 path
= socket_address_from_strings(msg
, msg
->sock
->backend_name
,
636 status
= socket_listen(msg
->sock
, path
, 50, 0);
637 if (!NT_STATUS_IS_OK(status
)) {
638 DEBUG(0,("Unable to setup messaging listener for '%s':%s\n", msg
->path
, nt_errstr(status
)));
643 /* it needs to be non blocking for sends */
644 set_blocking(socket_get_fd(msg
->sock
), false);
647 msg
->event
.fde
= tevent_add_fd(ev
, msg
, socket_get_fd(msg
->sock
),
648 TEVENT_FD_READ
, imessaging_handler
, msg
);
649 tevent_fd_set_auto_close(msg
->event
.fde
);
652 talloc_set_destructor(msg
, imessaging_cleanup
);
655 imessaging_register(msg
, NULL
, MSG_PING
, ping_message
);
656 imessaging_register(msg
, NULL
, MSG_IRPC
, irpc_handler
);
657 IRPC_REGISTER(msg
, irpc
, IRPC_UPTIME
, irpc_uptime
, msg
);
663 A hack, for the short term until we get 'client only' messaging in place
665 struct imessaging_context
*imessaging_client_init(TALLOC_CTX
*mem_ctx
,
666 struct loadparm_context
*lp_ctx
,
667 struct tevent_context
*ev
)
672 id
.task_id
= generate_random();
673 id
.vnn
= NONCLUSTER_VNN
;
675 /* This is because we are not in the s3 serverid database */
676 id
.unique_id
= SERVERID_UNIQUE_ID_NOT_TO_VERIFY
;
678 return imessaging_init(mem_ctx
, lp_ctx
, id
, ev
, true);
681 a list of registered irpc server functions
684 struct irpc_list
*next
, *prev
;
686 const struct ndr_interface_table
*table
;
694 register a irpc server function
696 NTSTATUS
irpc_register(struct imessaging_context
*msg_ctx
,
697 const struct ndr_interface_table
*table
,
698 int callnum
, irpc_function_t fn
, void *private_data
)
700 struct irpc_list
*irpc
;
702 /* override an existing handler, if any */
703 for (irpc
=msg_ctx
->irpc
; irpc
; irpc
=irpc
->next
) {
704 if (irpc
->table
== table
&& irpc
->callnum
== callnum
) {
709 irpc
= talloc(msg_ctx
, struct irpc_list
);
710 NT_STATUS_HAVE_NO_MEMORY(irpc
);
711 DLIST_ADD(msg_ctx
->irpc
, irpc
);
715 irpc
->callnum
= callnum
;
717 irpc
->private_data
= private_data
;
718 irpc
->uuid
= irpc
->table
->syntax_id
.uuid
;
725 handle an incoming irpc reply message
727 static void irpc_handler_reply(struct imessaging_context
*msg_ctx
, struct irpc_message
*m
)
729 struct irpc_request
*irpc
;
731 irpc
= (struct irpc_request
*)idr_find(msg_ctx
->idr
, m
->header
.callid
);
732 if (irpc
== NULL
) return;
734 irpc
->incoming
.handler(irpc
, m
);
740 NTSTATUS
irpc_send_reply(struct irpc_message
*m
, NTSTATUS status
)
742 struct ndr_push
*push
;
744 enum ndr_err_code ndr_err
;
746 m
->header
.status
= status
;
748 /* setup the reply */
749 push
= ndr_push_init_ctx(m
->ndr
);
751 status
= NT_STATUS_NO_MEMORY
;
755 m
->header
.flags
|= IRPC_FLAG_REPLY
;
756 m
->header
.creds
.token
= NULL
;
758 /* construct the packet */
759 ndr_err
= ndr_push_irpc_header(push
, NDR_SCALARS
|NDR_BUFFERS
, &m
->header
);
760 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
761 status
= ndr_map_error2ntstatus(ndr_err
);
765 ndr_err
= m
->irpc
->table
->calls
[m
->irpc
->callnum
].ndr_push(push
, NDR_OUT
, m
->data
);
766 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
767 status
= ndr_map_error2ntstatus(ndr_err
);
771 /* send the reply message */
772 packet
= ndr_push_blob(push
);
773 status
= imessaging_send(m
->msg_ctx
, m
->from
, MSG_IRPC
, &packet
);
774 if (!NT_STATUS_IS_OK(status
)) goto failed
;
782 handle an incoming irpc request message
784 static void irpc_handler_request(struct imessaging_context
*msg_ctx
,
785 struct irpc_message
*m
)
789 enum ndr_err_code ndr_err
;
791 for (i
=msg_ctx
->irpc
; i
; i
=i
->next
) {
792 if (GUID_equal(&i
->uuid
, &m
->header
.uuid
) &&
793 i
->table
->syntax_id
.if_version
== m
->header
.if_version
&&
794 i
->callnum
== m
->header
.callnum
) {
800 /* no registered handler for this message */
805 /* allocate space for the structure */
806 r
= talloc_zero_size(m
->ndr
, i
->table
->calls
[m
->header
.callnum
].struct_size
);
807 if (r
== NULL
) goto failed
;
809 m
->ndr
->flags
|= LIBNDR_FLAG_REF_ALLOC
;
811 /* parse the request data */
812 ndr_err
= i
->table
->calls
[i
->callnum
].ndr_pull(m
->ndr
, NDR_IN
, r
);
813 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) goto failed
;
816 m
->private_data
= i
->private_data
;
817 m
->defer_reply
= false;
819 m
->msg_ctx
= msg_ctx
;
822 m
->ev
= msg_ctx
->event
.ev
;
824 m
->header
.status
= i
->fn(m
, r
);
827 /* the server function won't ever be replying to this request */
832 if (m
->defer_reply
) {
833 /* the server function has asked to defer the reply to later */
834 talloc_steal(msg_ctx
, m
);
838 irpc_send_reply(m
, m
->header
.status
);
846 handle an incoming irpc message
848 static void irpc_handler(struct imessaging_context
*msg_ctx
, void *private_data
,
849 uint32_t msg_type
, struct server_id src
, DATA_BLOB
*packet
)
851 struct irpc_message
*m
;
852 enum ndr_err_code ndr_err
;
854 m
= talloc(msg_ctx
, struct irpc_message
);
855 if (m
== NULL
) goto failed
;
859 m
->ndr
= ndr_pull_init_blob(packet
, m
);
860 if (m
->ndr
== NULL
) goto failed
;
862 m
->ndr
->flags
|= LIBNDR_FLAG_REF_ALLOC
;
864 ndr_err
= ndr_pull_irpc_header(m
->ndr
, NDR_BUFFERS
|NDR_SCALARS
, &m
->header
);
865 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) goto failed
;
867 if (m
->header
.flags
& IRPC_FLAG_REPLY
) {
868 irpc_handler_reply(msg_ctx
, m
);
870 irpc_handler_request(msg_ctx
, m
);
880 destroy a irpc request
882 static int irpc_destructor(struct irpc_request
*irpc
)
884 if (irpc
->callid
!= -1) {
885 idr_remove(irpc
->msg_ctx
->idr
, irpc
->callid
);
893 open the naming database
895 static struct tdb_wrap
*irpc_namedb_open(struct imessaging_context
*msg_ctx
)
898 char *path
= talloc_asprintf(msg_ctx
, "%s/names.tdb", msg_ctx
->base_path
);
902 t
= tdb_wrap_open(msg_ctx
, path
, 0, 0, O_RDWR
|O_CREAT
, 0660, msg_ctx
->lp_ctx
);
909 add a string name that this irpc server can be called on
911 NTSTATUS
irpc_add_name(struct imessaging_context
*msg_ctx
, const char *name
)
916 NTSTATUS status
= NT_STATUS_OK
;
918 t
= irpc_namedb_open(msg_ctx
);
919 NT_STATUS_HAVE_NO_MEMORY(t
);
921 if (tdb_lock_bystring(t
->tdb
, name
) != 0) {
923 return NT_STATUS_LOCK_NOT_GRANTED
;
925 rec
= tdb_fetch_bystring(t
->tdb
, name
);
926 count
= rec
.dsize
/ sizeof(struct server_id
);
927 rec
.dptr
= (unsigned char *)realloc_p(rec
.dptr
, struct server_id
, count
+1);
928 rec
.dsize
+= sizeof(struct server_id
);
929 if (rec
.dptr
== NULL
) {
930 tdb_unlock_bystring(t
->tdb
, name
);
932 return NT_STATUS_NO_MEMORY
;
934 ((struct server_id
*)rec
.dptr
)[count
] = msg_ctx
->server_id
;
935 if (tdb_store_bystring(t
->tdb
, name
, rec
, 0) != 0) {
936 status
= NT_STATUS_INTERNAL_ERROR
;
939 tdb_unlock_bystring(t
->tdb
, name
);
942 msg_ctx
->names
= str_list_add(msg_ctx
->names
, name
);
943 talloc_steal(msg_ctx
, msg_ctx
->names
);
949 return a list of server ids for a server name
951 struct server_id
*irpc_servers_byname(struct imessaging_context
*msg_ctx
,
958 struct server_id
*ret
;
960 t
= irpc_namedb_open(msg_ctx
);
965 if (tdb_lock_bystring(t
->tdb
, name
) != 0) {
969 rec
= tdb_fetch_bystring(t
->tdb
, name
);
970 if (rec
.dptr
== NULL
) {
971 tdb_unlock_bystring(t
->tdb
, name
);
975 count
= rec
.dsize
/ sizeof(struct server_id
);
976 ret
= talloc_array(mem_ctx
, struct server_id
, count
+1);
978 tdb_unlock_bystring(t
->tdb
, name
);
982 for (i
=0;i
<count
;i
++) {
983 ret
[i
] = ((struct server_id
*)rec
.dptr
)[i
];
985 server_id_set_disconnected(&ret
[i
]);
987 tdb_unlock_bystring(t
->tdb
, name
);
993 static int all_servers_func(struct tdb_context
*tdb
, TDB_DATA key
, TDB_DATA data
, void *state
)
995 struct irpc_name_records
*name_records
= talloc_get_type(state
, struct irpc_name_records
);
996 struct irpc_name_record
*name_record
;
1000 = talloc_realloc(name_records
, name_records
->names
,
1001 struct irpc_name_record
*, name_records
->num_records
+1);
1002 if (!name_records
->names
) {
1006 name_records
->names
[name_records
->num_records
] = name_record
1007 = talloc(name_records
->names
,
1008 struct irpc_name_record
);
1013 name_records
->num_records
++;
1016 = talloc_strndup(name_record
,
1017 (const char *)key
.dptr
, key
.dsize
);
1018 if (!name_record
->name
) {
1022 name_record
->count
= data
.dsize
/ sizeof(struct server_id
);
1023 name_record
->ids
= talloc_array(name_record
,
1025 name_record
->count
);
1026 if (name_record
->ids
== NULL
) {
1029 for (i
=0;i
<name_record
->count
;i
++) {
1030 name_record
->ids
[i
] = ((struct server_id
*)data
.dptr
)[i
];
1036 return a list of server ids for a server name
1038 struct irpc_name_records
*irpc_all_servers(struct imessaging_context
*msg_ctx
,
1039 TALLOC_CTX
*mem_ctx
)
1043 struct irpc_name_records
*name_records
= talloc_zero(mem_ctx
, struct irpc_name_records
);
1044 if (name_records
== NULL
) {
1048 t
= irpc_namedb_open(msg_ctx
);
1053 ret
= tdb_traverse_read(t
->tdb
, all_servers_func
, name_records
);
1061 return name_records
;
1065 remove a name from a messaging context
1067 void irpc_remove_name(struct imessaging_context
*msg_ctx
, const char *name
)
1072 struct server_id
*ids
;
1074 str_list_remove(msg_ctx
->names
, name
);
1076 t
= irpc_namedb_open(msg_ctx
);
1081 if (tdb_lock_bystring(t
->tdb
, name
) != 0) {
1085 rec
= tdb_fetch_bystring(t
->tdb
, name
);
1086 if (rec
.dptr
== NULL
) {
1087 tdb_unlock_bystring(t
->tdb
, name
);
1091 count
= rec
.dsize
/ sizeof(struct server_id
);
1094 tdb_unlock_bystring(t
->tdb
, name
);
1098 ids
= (struct server_id
*)rec
.dptr
;
1099 for (i
=0;i
<count
;i
++) {
1100 if (cluster_id_equal(&ids
[i
], &msg_ctx
->server_id
)) {
1102 memmove(ids
+i
, ids
+i
+1,
1103 sizeof(struct server_id
) * (count
-(i
+1)));
1105 rec
.dsize
-= sizeof(struct server_id
);
1109 tdb_store_bystring(t
->tdb
, name
, rec
, 0);
1111 tdb_unlock_bystring(t
->tdb
, name
);
1115 struct server_id
imessaging_get_server_id(struct imessaging_context
*msg_ctx
)
1117 return msg_ctx
->server_id
;
1120 struct irpc_bh_state
{
1121 struct imessaging_context
*msg_ctx
;
1122 struct server_id server_id
;
1123 const struct ndr_interface_table
*table
;
1125 struct security_token
*token
;
1128 static bool irpc_bh_is_connected(struct dcerpc_binding_handle
*h
)
1130 struct irpc_bh_state
*hs
= dcerpc_binding_handle_data(h
,
1131 struct irpc_bh_state
);
1140 static uint32_t irpc_bh_set_timeout(struct dcerpc_binding_handle
*h
,
1143 struct irpc_bh_state
*hs
= dcerpc_binding_handle_data(h
,
1144 struct irpc_bh_state
);
1145 uint32_t old
= hs
->timeout
;
1147 hs
->timeout
= timeout
;
1152 struct irpc_bh_raw_call_state
{
1153 struct irpc_request
*irpc
;
1156 DATA_BLOB in_packet
;
1160 static void irpc_bh_raw_call_incoming_handler(struct irpc_request
*irpc
,
1161 struct irpc_message
*m
);
1163 static struct tevent_req
*irpc_bh_raw_call_send(TALLOC_CTX
*mem_ctx
,
1164 struct tevent_context
*ev
,
1165 struct dcerpc_binding_handle
*h
,
1166 const struct GUID
*object
,
1169 const uint8_t *in_data
,
1172 struct irpc_bh_state
*hs
=
1173 dcerpc_binding_handle_data(h
,
1174 struct irpc_bh_state
);
1175 struct tevent_req
*req
;
1176 struct irpc_bh_raw_call_state
*state
;
1178 struct irpc_header header
;
1179 struct ndr_push
*ndr
;
1181 enum ndr_err_code ndr_err
;
1183 req
= tevent_req_create(mem_ctx
, &state
,
1184 struct irpc_bh_raw_call_state
);
1188 state
->opnum
= opnum
;
1189 state
->in_data
.data
= discard_const_p(uint8_t, in_data
);
1190 state
->in_data
.length
= in_length
;
1192 ok
= irpc_bh_is_connected(h
);
1194 tevent_req_nterror(req
, NT_STATUS_CONNECTION_DISCONNECTED
);
1195 return tevent_req_post(req
, ev
);
1198 state
->irpc
= talloc_zero(state
, struct irpc_request
);
1199 if (tevent_req_nomem(state
->irpc
, req
)) {
1200 return tevent_req_post(req
, ev
);
1203 state
->irpc
->msg_ctx
= hs
->msg_ctx
;
1204 state
->irpc
->callid
= idr_get_new(hs
->msg_ctx
->idr
,
1205 state
->irpc
, UINT16_MAX
);
1206 if (state
->irpc
->callid
== -1) {
1207 tevent_req_nterror(req
, NT_STATUS_INSUFFICIENT_RESOURCES
);
1208 return tevent_req_post(req
, ev
);
1210 state
->irpc
->incoming
.handler
= irpc_bh_raw_call_incoming_handler
;
1211 state
->irpc
->incoming
.private_data
= req
;
1213 talloc_set_destructor(state
->irpc
, irpc_destructor
);
1215 /* setup the header */
1216 header
.uuid
= hs
->table
->syntax_id
.uuid
;
1218 header
.if_version
= hs
->table
->syntax_id
.if_version
;
1219 header
.callid
= state
->irpc
->callid
;
1220 header
.callnum
= state
->opnum
;
1222 header
.status
= NT_STATUS_OK
;
1223 header
.creds
.token
= hs
->token
;
1225 /* construct the irpc packet */
1226 ndr
= ndr_push_init_ctx(state
->irpc
);
1227 if (tevent_req_nomem(ndr
, req
)) {
1228 return tevent_req_post(req
, ev
);
1231 ndr_err
= ndr_push_irpc_header(ndr
, NDR_SCALARS
|NDR_BUFFERS
, &header
);
1232 status
= ndr_map_error2ntstatus(ndr_err
);
1233 if (!NT_STATUS_IS_OK(status
)) {
1234 tevent_req_nterror(req
, status
);
1235 return tevent_req_post(req
, ev
);
1238 ndr_err
= ndr_push_bytes(ndr
, in_data
, in_length
);
1239 status
= ndr_map_error2ntstatus(ndr_err
);
1240 if (!NT_STATUS_IS_OK(status
)) {
1241 tevent_req_nterror(req
, status
);
1242 return tevent_req_post(req
, ev
);
1246 state
->in_packet
= ndr_push_blob(ndr
);
1247 status
= imessaging_send(hs
->msg_ctx
, hs
->server_id
,
1248 MSG_IRPC
, &state
->in_packet
);
1249 if (!NT_STATUS_IS_OK(status
)) {
1250 tevent_req_nterror(req
, status
);
1251 return tevent_req_post(req
, ev
);
1254 if (hs
->timeout
!= IRPC_CALL_TIMEOUT_INF
) {
1255 /* set timeout-callback in case caller wants that */
1256 ok
= tevent_req_set_endtime(req
, ev
, timeval_current_ofs(hs
->timeout
, 0));
1258 return tevent_req_post(req
, ev
);
1265 static void irpc_bh_raw_call_incoming_handler(struct irpc_request
*irpc
,
1266 struct irpc_message
*m
)
1268 struct tevent_req
*req
=
1269 talloc_get_type_abort(irpc
->incoming
.private_data
,
1271 struct irpc_bh_raw_call_state
*state
=
1272 tevent_req_data(req
,
1273 struct irpc_bh_raw_call_state
);
1275 talloc_steal(state
, m
);
1277 if (!NT_STATUS_IS_OK(m
->header
.status
)) {
1278 tevent_req_nterror(req
, m
->header
.status
);
1282 state
->out_data
= data_blob_talloc(state
,
1283 m
->ndr
->data
+ m
->ndr
->offset
,
1284 m
->ndr
->data_size
- m
->ndr
->offset
);
1285 if ((m
->ndr
->data_size
- m
->ndr
->offset
) > 0 && !state
->out_data
.data
) {
1286 tevent_req_oom(req
);
1290 tevent_req_done(req
);
1293 static NTSTATUS
irpc_bh_raw_call_recv(struct tevent_req
*req
,
1294 TALLOC_CTX
*mem_ctx
,
1297 uint32_t *out_flags
)
1299 struct irpc_bh_raw_call_state
*state
=
1300 tevent_req_data(req
,
1301 struct irpc_bh_raw_call_state
);
1304 if (tevent_req_is_nterror(req
, &status
)) {
1305 tevent_req_received(req
);
1309 *out_data
= talloc_move(mem_ctx
, &state
->out_data
.data
);
1310 *out_length
= state
->out_data
.length
;
1312 tevent_req_received(req
);
1313 return NT_STATUS_OK
;
1316 struct irpc_bh_disconnect_state
{
1320 static struct tevent_req
*irpc_bh_disconnect_send(TALLOC_CTX
*mem_ctx
,
1321 struct tevent_context
*ev
,
1322 struct dcerpc_binding_handle
*h
)
1324 struct irpc_bh_state
*hs
= dcerpc_binding_handle_data(h
,
1325 struct irpc_bh_state
);
1326 struct tevent_req
*req
;
1327 struct irpc_bh_disconnect_state
*state
;
1330 req
= tevent_req_create(mem_ctx
, &state
,
1331 struct irpc_bh_disconnect_state
);
1336 ok
= irpc_bh_is_connected(h
);
1338 tevent_req_nterror(req
, NT_STATUS_CONNECTION_DISCONNECTED
);
1339 return tevent_req_post(req
, ev
);
1344 tevent_req_done(req
);
1345 return tevent_req_post(req
, ev
);
1348 static NTSTATUS
irpc_bh_disconnect_recv(struct tevent_req
*req
)
1352 if (tevent_req_is_nterror(req
, &status
)) {
1353 tevent_req_received(req
);
1357 tevent_req_received(req
);
1358 return NT_STATUS_OK
;
1361 static bool irpc_bh_ref_alloc(struct dcerpc_binding_handle
*h
)
1366 static const struct dcerpc_binding_handle_ops irpc_bh_ops
= {
1368 .is_connected
= irpc_bh_is_connected
,
1369 .set_timeout
= irpc_bh_set_timeout
,
1370 .raw_call_send
= irpc_bh_raw_call_send
,
1371 .raw_call_recv
= irpc_bh_raw_call_recv
,
1372 .disconnect_send
= irpc_bh_disconnect_send
,
1373 .disconnect_recv
= irpc_bh_disconnect_recv
,
1375 .ref_alloc
= irpc_bh_ref_alloc
,
1378 /* initialise a irpc binding handle */
1379 struct dcerpc_binding_handle
*irpc_binding_handle(TALLOC_CTX
*mem_ctx
,
1380 struct imessaging_context
*msg_ctx
,
1381 struct server_id server_id
,
1382 const struct ndr_interface_table
*table
)
1384 struct dcerpc_binding_handle
*h
;
1385 struct irpc_bh_state
*hs
;
1387 h
= dcerpc_binding_handle_create(mem_ctx
,
1392 struct irpc_bh_state
,
1397 hs
->msg_ctx
= msg_ctx
;
1398 hs
->server_id
= server_id
;
1400 hs
->timeout
= IRPC_CALL_TIMEOUT
;
1402 dcerpc_binding_handle_set_sync_ev(h
, msg_ctx
->event
.ev
);
1407 struct dcerpc_binding_handle
*irpc_binding_handle_by_name(TALLOC_CTX
*mem_ctx
,
1408 struct imessaging_context
*msg_ctx
,
1409 const char *dest_task
,
1410 const struct ndr_interface_table
*table
)
1412 struct dcerpc_binding_handle
*h
;
1413 struct server_id
*sids
;
1414 struct server_id sid
;
1416 /* find the server task */
1417 sids
= irpc_servers_byname(msg_ctx
, mem_ctx
, dest_task
);
1419 errno
= EADDRNOTAVAIL
;
1422 if (server_id_is_disconnected(&sids
[0])) {
1424 errno
= EADDRNOTAVAIL
;
1430 h
= irpc_binding_handle(mem_ctx
, msg_ctx
,
1439 void irpc_binding_handle_add_security_token(struct dcerpc_binding_handle
*h
,
1440 struct security_token
*token
)
1442 struct irpc_bh_state
*hs
=
1443 dcerpc_binding_handle_data(h
,
1444 struct irpc_bh_state
);