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/util/unix_privs.h"
31 #include "librpc/rpc/dcerpc.h"
32 #include "cluster/cluster.h"
33 #include "../lib/util/tevent_ntstatus.h"
34 #include "lib/param/param.h"
35 #include "lib/util/server_id_db.h"
38 /* change the message version with any incompatible changes in the protocol */
39 #define IMESSAGING_VERSION 1
45 struct imessaging_context
*msg_ctx
;
48 void (*handler
)(struct irpc_request
*irpc
, struct irpc_message
*m
);
53 struct imessaging_context
{
54 struct server_id server_id
;
55 struct socket_context
*sock
;
56 const char *base_path
;
58 struct dispatch_fn
**dispatch
;
60 struct idr_context
*dispatch_tree
;
61 struct imessaging_rec
*pending
;
62 struct imessaging_rec
*retry_queue
;
63 struct irpc_list
*irpc
;
64 struct idr_context
*idr
;
65 struct server_id_db
*names
;
66 struct timeval start_time
;
67 struct tevent_timer
*retry_te
;
69 struct tevent_fd
*fde
;
73 /* we have a linked list of dispatch handlers for each msg_type that
74 this messaging server can deal with */
76 struct dispatch_fn
*next
, *prev
;
82 /* an individual message */
83 struct imessaging_rec
{
84 struct imessaging_rec
*next
, *prev
;
85 struct imessaging_context
*msg
;
88 struct imessaging_header
{
91 struct server_id from
;
101 static void irpc_handler(struct imessaging_context
*, void *,
102 uint32_t, struct server_id
, DATA_BLOB
*);
106 A useful function for testing the message system.
108 static void ping_message(struct imessaging_context
*msg
, void *private_data
,
109 uint32_t msg_type
, struct server_id src
, DATA_BLOB
*data
)
111 struct server_id_buf idbuf
;
112 DEBUG(1,("INFO: Received PING message from server %s [%.*s]\n",
113 server_id_str_buf(src
, &idbuf
), (int)data
->length
,
114 data
->data
?(const char *)data
->data
:""));
115 imessaging_send(msg
, src
, MSG_PONG
, data
);
119 return uptime of messaging server via irpc
121 static NTSTATUS
irpc_uptime(struct irpc_message
*msg
,
122 struct irpc_uptime
*r
)
124 struct imessaging_context
*ctx
= talloc_get_type(msg
->private_data
, struct imessaging_context
);
125 *r
->out
.start_time
= timeval_to_nttime(&ctx
->start_time
);
130 return the path to a messaging socket
132 static char *imessaging_path(struct imessaging_context
*msg
, struct server_id server_id
)
134 struct server_id_buf buf
;
136 return talloc_asprintf(msg
, "%s/msg.%s", msg
->base_path
,
137 server_id_str_buf(server_id
, &buf
));
141 dispatch a fully received message
143 note that this deliberately can match more than one message handler
144 per message. That allows a single messasging context to register
145 (for example) a debug handler for more than one piece of code
147 static void imessaging_dispatch(struct imessaging_context
*msg
, struct imessaging_rec
*rec
)
149 struct dispatch_fn
*d
, *next
;
151 /* temporary IDs use an idtree, the rest use a array of pointers */
152 if (rec
->header
->msg_type
>= MSG_TMP_BASE
) {
153 d
= (struct dispatch_fn
*)idr_find(msg
->dispatch_tree
,
154 rec
->header
->msg_type
);
155 } else if (rec
->header
->msg_type
< msg
->num_types
) {
156 d
= msg
->dispatch
[rec
->header
->msg_type
];
161 for (; d
; d
= next
) {
164 data
.data
= rec
->packet
.data
+ sizeof(*rec
->header
);
165 data
.length
= rec
->header
->length
;
166 d
->fn(msg
, d
->private_data
, d
->msg_type
, rec
->header
->from
, &data
);
168 rec
->header
->length
= 0;
172 handler for messages that arrive from other nodes in the cluster
174 static void cluster_message_handler(struct imessaging_context
*msg
, DATA_BLOB packet
)
176 struct imessaging_rec
*rec
;
178 rec
= talloc(msg
, struct imessaging_rec
);
180 smb_panic("Unable to allocate imessaging_rec");
184 rec
->path
= msg
->path
;
185 rec
->header
= (struct imessaging_header
*)packet
.data
;
186 rec
->packet
= packet
;
189 if (packet
.length
!= sizeof(*rec
->header
) + rec
->header
->length
) {
190 DEBUG(0,("messaging: bad message header size %d should be %d\n",
191 rec
->header
->length
, (int)(packet
.length
- sizeof(*rec
->header
))));
196 imessaging_dispatch(msg
, rec
);
203 try to send the message
205 static NTSTATUS
try_send(struct imessaging_rec
*rec
)
207 struct imessaging_context
*msg
= rec
->msg
;
211 struct socket_address
*path
;
213 /* rec->path is the path of the *other* socket, where we want
215 path
= socket_address_from_strings(msg
, msg
->sock
->backend_name
,
218 return NT_STATUS_NO_MEMORY
;
221 /* we send with privileges so messages work from any context */
222 priv
= root_privileges();
223 status
= socket_sendto(msg
->sock
, &rec
->packet
, &nsent
, path
);
231 retry backed off messages
233 static void msg_retry_timer(struct tevent_context
*ev
, struct tevent_timer
*te
,
234 struct timeval t
, void *private_data
)
236 struct imessaging_context
*msg
= talloc_get_type(private_data
,
237 struct imessaging_context
);
238 msg
->retry_te
= NULL
;
240 /* put the messages back on the main queue */
241 while (msg
->retry_queue
) {
242 struct imessaging_rec
*rec
= msg
->retry_queue
;
243 DLIST_REMOVE(msg
->retry_queue
, rec
);
244 DLIST_ADD_END(msg
->pending
, rec
, struct imessaging_rec
*);
247 TEVENT_FD_WRITEABLE(msg
->event
.fde
);
251 handle a socket write event
253 static void imessaging_send_handler(struct imessaging_context
*msg
, struct tevent_context
*ev
)
255 while (msg
->pending
) {
256 struct imessaging_rec
*rec
= msg
->pending
;
258 status
= try_send(rec
);
259 if (NT_STATUS_EQUAL(status
, STATUS_MORE_ENTRIES
)) {
261 if (rec
->retries
> 3) {
262 /* we're getting continuous write errors -
263 backoff this record */
264 DLIST_REMOVE(msg
->pending
, rec
);
265 DLIST_ADD_END(msg
->retry_queue
, rec
,
266 struct imessaging_rec
*);
267 if (msg
->retry_te
== NULL
) {
269 tevent_add_timer(ev
, msg
,
270 timeval_current_ofs(1, 0),
271 msg_retry_timer
, msg
);
277 if (!NT_STATUS_IS_OK(status
)) {
278 TALLOC_CTX
*tmp_ctx
= talloc_new(msg
);
279 DEBUG(1,("messaging: Lost message from %s to %s of type %u - %s\n",
280 server_id_str(tmp_ctx
, &rec
->header
->from
),
281 server_id_str(tmp_ctx
, &rec
->header
->to
),
282 rec
->header
->msg_type
,
284 talloc_free(tmp_ctx
);
286 DLIST_REMOVE(msg
->pending
, rec
);
289 if (msg
->pending
== NULL
) {
290 TEVENT_FD_NOT_WRITEABLE(msg
->event
.fde
);
295 handle a new incoming packet
297 static void imessaging_recv_handler(struct imessaging_context
*msg
, struct tevent_context
*ev
)
299 struct imessaging_rec
*rec
;
304 /* see how many bytes are in the next packet */
305 status
= socket_pending(msg
->sock
, &msize
);
306 if (!NT_STATUS_IS_OK(status
)) {
307 DEBUG(0,("socket_pending failed in messaging - %s\n",
312 packet
= data_blob_talloc(msg
, NULL
, msize
);
313 if (packet
.data
== NULL
) {
314 /* assume this is temporary and retry */
318 status
= socket_recv(msg
->sock
, packet
.data
, msize
, &msize
);
319 if (!NT_STATUS_IS_OK(status
)) {
320 data_blob_free(&packet
);
324 if (msize
< sizeof(*rec
->header
)) {
325 DEBUG(0,("messaging: bad message of size %d\n", (int)msize
));
326 data_blob_free(&packet
);
330 rec
= talloc(msg
, struct imessaging_rec
);
332 smb_panic("Unable to allocate imessaging_rec");
335 talloc_steal(rec
, packet
.data
);
337 rec
->path
= msg
->path
;
338 rec
->header
= (struct imessaging_header
*)packet
.data
;
339 rec
->packet
= packet
;
342 if (msize
!= sizeof(*rec
->header
) + rec
->header
->length
) {
343 DEBUG(0,("messaging: bad message header size %d should be %d\n",
344 rec
->header
->length
, (int)(msize
- sizeof(*rec
->header
))));
349 imessaging_dispatch(msg
, rec
);
355 handle a socket event
357 static void imessaging_handler(struct tevent_context
*ev
, struct tevent_fd
*fde
,
358 uint16_t flags
, void *private_data
)
360 struct imessaging_context
*msg
= talloc_get_type(private_data
,
361 struct imessaging_context
);
362 if (flags
& TEVENT_FD_WRITE
) {
363 imessaging_send_handler(msg
, ev
);
365 if (flags
& TEVENT_FD_READ
) {
366 imessaging_recv_handler(msg
, ev
);
372 Register a dispatch function for a particular message type.
374 NTSTATUS
imessaging_register(struct imessaging_context
*msg
, void *private_data
,
375 uint32_t msg_type
, msg_callback_t fn
)
377 struct dispatch_fn
*d
;
379 /* possibly expand dispatch array */
380 if (msg_type
>= msg
->num_types
) {
381 struct dispatch_fn
**dp
;
383 dp
= talloc_realloc(msg
, msg
->dispatch
, struct dispatch_fn
*, msg_type
+1);
384 NT_STATUS_HAVE_NO_MEMORY(dp
);
386 for (i
=msg
->num_types
;i
<=msg_type
;i
++) {
387 msg
->dispatch
[i
] = NULL
;
389 msg
->num_types
= msg_type
+1;
392 d
= talloc_zero(msg
->dispatch
, struct dispatch_fn
);
393 NT_STATUS_HAVE_NO_MEMORY(d
);
394 d
->msg_type
= msg_type
;
395 d
->private_data
= private_data
;
398 DLIST_ADD(msg
->dispatch
[msg_type
], d
);
404 register a temporary message handler. The msg_type is allocated
407 NTSTATUS
imessaging_register_tmp(struct imessaging_context
*msg
, void *private_data
,
408 msg_callback_t fn
, uint32_t *msg_type
)
410 struct dispatch_fn
*d
;
413 d
= talloc_zero(msg
->dispatch
, struct dispatch_fn
);
414 NT_STATUS_HAVE_NO_MEMORY(d
);
415 d
->private_data
= private_data
;
418 id
= idr_get_new_above(msg
->dispatch_tree
, d
, MSG_TMP_BASE
, UINT16_MAX
);
421 return NT_STATUS_TOO_MANY_CONTEXT_IDS
;
424 d
->msg_type
= (uint32_t)id
;
425 (*msg_type
) = d
->msg_type
;
431 De-register the function for a particular message type.
433 void imessaging_deregister(struct imessaging_context
*msg
, uint32_t msg_type
, void *private_data
)
435 struct dispatch_fn
*d
, *next
;
437 if (msg_type
>= msg
->num_types
) {
438 d
= (struct dispatch_fn
*)idr_find(msg
->dispatch_tree
,
441 idr_remove(msg
->dispatch_tree
, msg_type
);
446 for (d
= msg
->dispatch
[msg_type
]; d
; d
= next
) {
448 if (d
->private_data
== private_data
) {
449 DLIST_REMOVE(msg
->dispatch
[msg_type
], d
);
456 Send a message to a particular server
458 NTSTATUS
imessaging_send(struct imessaging_context
*msg
, struct server_id server
,
459 uint32_t msg_type
, const DATA_BLOB
*data
)
461 struct imessaging_rec
*rec
;
463 size_t dlength
= data
?data
->length
:0;
465 rec
= talloc(msg
, struct imessaging_rec
);
467 return NT_STATUS_NO_MEMORY
;
470 rec
->packet
= data_blob_talloc(rec
, NULL
, sizeof(*rec
->header
) + dlength
);
471 if (rec
->packet
.data
== NULL
) {
473 return NT_STATUS_NO_MEMORY
;
478 rec
->header
= (struct imessaging_header
*)rec
->packet
.data
;
480 ZERO_STRUCTP(rec
->header
);
481 rec
->header
->version
= IMESSAGING_VERSION
;
482 rec
->header
->msg_type
= msg_type
;
483 rec
->header
->from
= msg
->server_id
;
484 rec
->header
->to
= server
;
485 rec
->header
->length
= dlength
;
487 memcpy(rec
->packet
.data
+ sizeof(*rec
->header
),
488 data
->data
, dlength
);
491 if (!cluster_node_equal(&msg
->server_id
, &server
)) {
492 /* the destination is on another node - dispatch via
494 status
= cluster_message_send(server
, &rec
->packet
);
499 rec
->path
= imessaging_path(msg
, server
);
500 talloc_steal(rec
, rec
->path
);
502 if (msg
->pending
!= NULL
) {
503 status
= STATUS_MORE_ENTRIES
;
505 status
= try_send(rec
);
508 if (NT_STATUS_EQUAL(status
, STATUS_MORE_ENTRIES
)) {
509 if (msg
->pending
== NULL
) {
510 TEVENT_FD_WRITEABLE(msg
->event
.fde
);
512 DLIST_ADD_END(msg
->pending
, rec
, struct imessaging_rec
*);
522 Send a message to a particular server, with the message containing a single pointer
524 NTSTATUS
imessaging_send_ptr(struct imessaging_context
*msg
, struct server_id server
,
525 uint32_t msg_type
, void *ptr
)
529 blob
.data
= (uint8_t *)&ptr
;
530 blob
.length
= sizeof(void *);
532 return imessaging_send(msg
, server
, msg_type
, &blob
);
537 remove our messaging socket and database entry
539 int imessaging_cleanup(struct imessaging_context
*msg
)
545 DEBUG(5,("imessaging: cleaning up %s\n", msg
->path
));
551 create the listening socket and setup the dispatcher
553 use auto_remove=true when you want a destructor to remove the
554 associated messaging socket and database entry on talloc free. Don't
555 use this in processes that may fork and a child may talloc free this
558 struct imessaging_context
*imessaging_init(TALLOC_CTX
*mem_ctx
,
559 struct loadparm_context
*lp_ctx
,
560 struct server_id server_id
,
561 struct tevent_context
*ev
,
564 struct imessaging_context
*msg
;
566 struct socket_address
*path
;
573 msg
= talloc_zero(mem_ctx
, struct imessaging_context
);
578 /* setup a handler for messages from other cluster nodes, if appropriate */
579 status
= cluster_message_init(msg
, server_id
, cluster_message_handler
);
580 if (!NT_STATUS_IS_OK(status
)) {
584 /* create the messaging directory if needed */
586 msg
->base_path
= lpcfg_imessaging_path(msg
, lp_ctx
);
587 if (msg
->base_path
== NULL
) {
591 ok
= directory_create_or_exist_strict(msg
->base_path
, geteuid(), 0700);
596 msg
->path
= imessaging_path(msg
, server_id
);
597 if (msg
->path
== NULL
) {
601 msg
->server_id
= server_id
;
602 msg
->idr
= idr_init(msg
);
603 if (msg
->idr
== NULL
) {
607 msg
->dispatch_tree
= idr_init(msg
);
608 if (msg
->dispatch_tree
== NULL
) {
612 msg
->start_time
= timeval_current();
614 msg
->names
= server_id_db_init(
615 msg
, server_id
, msg
->base_path
, 0,
616 TDB_INCOMPATIBLE_HASH
|TDB_CLEAR_IF_FIRST
|
617 lpcfg_tdb_flags(lp_ctx
, 0));
618 if (msg
->names
== NULL
) {
622 status
= socket_create("unix", SOCKET_TYPE_DGRAM
, &msg
->sock
, 0);
623 if (!NT_STATUS_IS_OK(status
)) {
627 /* by stealing here we ensure that the socket is cleaned up (and even
629 talloc_steal(msg
, msg
->sock
);
631 path
= socket_address_from_strings(msg
, msg
->sock
->backend_name
,
637 status
= socket_listen(msg
->sock
, path
, 50, 0);
638 if (!NT_STATUS_IS_OK(status
)) {
639 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);
646 msg
->event
.fde
= tevent_add_fd(ev
, msg
, socket_get_fd(msg
->sock
),
647 TEVENT_FD_READ
, imessaging_handler
, msg
);
648 tevent_fd_set_auto_close(msg
->event
.fde
);
651 talloc_set_destructor(msg
, imessaging_cleanup
);
654 imessaging_register(msg
, NULL
, MSG_PING
, ping_message
);
655 imessaging_register(msg
, NULL
, MSG_IRPC
, irpc_handler
);
656 IRPC_REGISTER(msg
, irpc
, IRPC_UPTIME
, irpc_uptime
, msg
);
665 A hack, for the short term until we get 'client only' messaging in place
667 struct imessaging_context
*imessaging_client_init(TALLOC_CTX
*mem_ctx
,
668 struct loadparm_context
*lp_ctx
,
669 struct tevent_context
*ev
)
674 id
.task_id
= generate_random();
675 id
.vnn
= NONCLUSTER_VNN
;
677 /* This is because we are not in the s3 serverid database */
678 id
.unique_id
= SERVERID_UNIQUE_ID_NOT_TO_VERIFY
;
680 return imessaging_init(mem_ctx
, lp_ctx
, id
, ev
, true);
683 a list of registered irpc server functions
686 struct irpc_list
*next
, *prev
;
688 const struct ndr_interface_table
*table
;
696 register a irpc server function
698 NTSTATUS
irpc_register(struct imessaging_context
*msg_ctx
,
699 const struct ndr_interface_table
*table
,
700 int callnum
, irpc_function_t fn
, void *private_data
)
702 struct irpc_list
*irpc
;
704 /* override an existing handler, if any */
705 for (irpc
=msg_ctx
->irpc
; irpc
; irpc
=irpc
->next
) {
706 if (irpc
->table
== table
&& irpc
->callnum
== callnum
) {
711 irpc
= talloc(msg_ctx
, struct irpc_list
);
712 NT_STATUS_HAVE_NO_MEMORY(irpc
);
713 DLIST_ADD(msg_ctx
->irpc
, irpc
);
717 irpc
->callnum
= callnum
;
719 irpc
->private_data
= private_data
;
720 irpc
->uuid
= irpc
->table
->syntax_id
.uuid
;
727 handle an incoming irpc reply message
729 static void irpc_handler_reply(struct imessaging_context
*msg_ctx
, struct irpc_message
*m
)
731 struct irpc_request
*irpc
;
733 irpc
= (struct irpc_request
*)idr_find(msg_ctx
->idr
, m
->header
.callid
);
734 if (irpc
== NULL
) return;
736 irpc
->incoming
.handler(irpc
, m
);
742 NTSTATUS
irpc_send_reply(struct irpc_message
*m
, NTSTATUS status
)
744 struct ndr_push
*push
;
746 enum ndr_err_code ndr_err
;
748 m
->header
.status
= status
;
750 /* setup the reply */
751 push
= ndr_push_init_ctx(m
->ndr
);
753 status
= NT_STATUS_NO_MEMORY
;
757 m
->header
.flags
|= IRPC_FLAG_REPLY
;
758 m
->header
.creds
.token
= NULL
;
760 /* construct the packet */
761 ndr_err
= ndr_push_irpc_header(push
, NDR_SCALARS
|NDR_BUFFERS
, &m
->header
);
762 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
763 status
= ndr_map_error2ntstatus(ndr_err
);
767 ndr_err
= m
->irpc
->table
->calls
[m
->irpc
->callnum
].ndr_push(push
, NDR_OUT
, m
->data
);
768 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
769 status
= ndr_map_error2ntstatus(ndr_err
);
773 /* send the reply message */
774 packet
= ndr_push_blob(push
);
775 status
= imessaging_send(m
->msg_ctx
, m
->from
, MSG_IRPC
, &packet
);
776 if (!NT_STATUS_IS_OK(status
)) goto failed
;
784 handle an incoming irpc request message
786 static void irpc_handler_request(struct imessaging_context
*msg_ctx
,
787 struct irpc_message
*m
)
791 enum ndr_err_code ndr_err
;
793 for (i
=msg_ctx
->irpc
; i
; i
=i
->next
) {
794 if (GUID_equal(&i
->uuid
, &m
->header
.uuid
) &&
795 i
->table
->syntax_id
.if_version
== m
->header
.if_version
&&
796 i
->callnum
== m
->header
.callnum
) {
802 /* no registered handler for this message */
807 /* allocate space for the structure */
808 r
= talloc_zero_size(m
->ndr
, i
->table
->calls
[m
->header
.callnum
].struct_size
);
809 if (r
== NULL
) goto failed
;
811 m
->ndr
->flags
|= LIBNDR_FLAG_REF_ALLOC
;
813 /* parse the request data */
814 ndr_err
= i
->table
->calls
[i
->callnum
].ndr_pull(m
->ndr
, NDR_IN
, r
);
815 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) goto failed
;
818 m
->private_data
= i
->private_data
;
819 m
->defer_reply
= false;
821 m
->msg_ctx
= msg_ctx
;
825 m
->header
.status
= i
->fn(m
, r
);
828 /* the server function won't ever be replying to this request */
833 if (m
->defer_reply
) {
834 /* the server function has asked to defer the reply to later */
835 talloc_steal(msg_ctx
, m
);
839 irpc_send_reply(m
, m
->header
.status
);
847 handle an incoming irpc message
849 static void irpc_handler(struct imessaging_context
*msg_ctx
, void *private_data
,
850 uint32_t msg_type
, struct server_id src
, DATA_BLOB
*packet
)
852 struct irpc_message
*m
;
853 enum ndr_err_code ndr_err
;
855 m
= talloc(msg_ctx
, struct irpc_message
);
856 if (m
== NULL
) goto failed
;
860 m
->ndr
= ndr_pull_init_blob(packet
, m
);
861 if (m
->ndr
== NULL
) goto failed
;
863 m
->ndr
->flags
|= LIBNDR_FLAG_REF_ALLOC
;
865 ndr_err
= ndr_pull_irpc_header(m
->ndr
, NDR_BUFFERS
|NDR_SCALARS
, &m
->header
);
866 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) goto failed
;
868 if (m
->header
.flags
& IRPC_FLAG_REPLY
) {
869 irpc_handler_reply(msg_ctx
, m
);
871 irpc_handler_request(msg_ctx
, m
);
881 destroy a irpc request
883 static int irpc_destructor(struct irpc_request
*irpc
)
885 if (irpc
->callid
!= -1) {
886 idr_remove(irpc
->msg_ctx
->idr
, irpc
->callid
);
894 add a string name that this irpc server can be called on
896 NTSTATUS
irpc_add_name(struct imessaging_context
*msg_ctx
, const char *name
)
900 ret
= server_id_db_add(msg_ctx
->names
, name
);
902 return map_nt_error_from_unix_common(ret
);
908 return a list of server ids for a server name
910 NTSTATUS
irpc_servers_byname(struct imessaging_context
*msg_ctx
,
911 TALLOC_CTX
*mem_ctx
, const char *name
,
912 unsigned *num_servers
,
913 struct server_id
**servers
)
917 ret
= server_id_db_lookup(msg_ctx
->names
, name
, mem_ctx
,
918 num_servers
, servers
);
920 return map_nt_error_from_unix_common(ret
);
925 static int all_servers_func(const char *name
, unsigned num_servers
,
926 const struct server_id
*servers
,
929 struct irpc_name_records
*name_records
= talloc_get_type(
930 private_data
, struct irpc_name_records
);
931 struct irpc_name_record
*name_record
;
935 = talloc_realloc(name_records
, name_records
->names
,
936 struct irpc_name_record
*, name_records
->num_records
+1);
937 if (!name_records
->names
) {
941 name_records
->names
[name_records
->num_records
] = name_record
942 = talloc(name_records
->names
,
943 struct irpc_name_record
);
948 name_records
->num_records
++;
950 name_record
->name
= talloc_strdup(name_record
, name
);
951 if (!name_record
->name
) {
955 name_record
->count
= num_servers
;
956 name_record
->ids
= talloc_array(name_record
, struct server_id
,
958 if (name_record
->ids
== NULL
) {
961 for (i
=0;i
<name_record
->count
;i
++) {
962 name_record
->ids
[i
] = servers
[i
];
968 return a list of server ids for a server name
970 struct irpc_name_records
*irpc_all_servers(struct imessaging_context
*msg_ctx
,
974 struct irpc_name_records
*name_records
= talloc_zero(mem_ctx
, struct irpc_name_records
);
975 if (name_records
== NULL
) {
979 ret
= server_id_db_traverse_read(msg_ctx
->names
, all_servers_func
,
982 TALLOC_FREE(name_records
);
990 remove a name from a messaging context
992 void irpc_remove_name(struct imessaging_context
*msg_ctx
, const char *name
)
994 server_id_db_remove(msg_ctx
->names
, name
);
997 struct server_id
imessaging_get_server_id(struct imessaging_context
*msg_ctx
)
999 return msg_ctx
->server_id
;
1002 struct irpc_bh_state
{
1003 struct imessaging_context
*msg_ctx
;
1004 struct server_id server_id
;
1005 const struct ndr_interface_table
*table
;
1007 struct security_token
*token
;
1010 static bool irpc_bh_is_connected(struct dcerpc_binding_handle
*h
)
1012 struct irpc_bh_state
*hs
= dcerpc_binding_handle_data(h
,
1013 struct irpc_bh_state
);
1022 static uint32_t irpc_bh_set_timeout(struct dcerpc_binding_handle
*h
,
1025 struct irpc_bh_state
*hs
= dcerpc_binding_handle_data(h
,
1026 struct irpc_bh_state
);
1027 uint32_t old
= hs
->timeout
;
1029 hs
->timeout
= timeout
;
1034 struct irpc_bh_raw_call_state
{
1035 struct irpc_request
*irpc
;
1038 DATA_BLOB in_packet
;
1042 static void irpc_bh_raw_call_incoming_handler(struct irpc_request
*irpc
,
1043 struct irpc_message
*m
);
1045 static struct tevent_req
*irpc_bh_raw_call_send(TALLOC_CTX
*mem_ctx
,
1046 struct tevent_context
*ev
,
1047 struct dcerpc_binding_handle
*h
,
1048 const struct GUID
*object
,
1051 const uint8_t *in_data
,
1054 struct irpc_bh_state
*hs
=
1055 dcerpc_binding_handle_data(h
,
1056 struct irpc_bh_state
);
1057 struct tevent_req
*req
;
1058 struct irpc_bh_raw_call_state
*state
;
1060 struct irpc_header header
;
1061 struct ndr_push
*ndr
;
1063 enum ndr_err_code ndr_err
;
1065 req
= tevent_req_create(mem_ctx
, &state
,
1066 struct irpc_bh_raw_call_state
);
1070 state
->opnum
= opnum
;
1071 state
->in_data
.data
= discard_const_p(uint8_t, in_data
);
1072 state
->in_data
.length
= in_length
;
1074 ok
= irpc_bh_is_connected(h
);
1076 tevent_req_nterror(req
, NT_STATUS_CONNECTION_DISCONNECTED
);
1077 return tevent_req_post(req
, ev
);
1080 state
->irpc
= talloc_zero(state
, struct irpc_request
);
1081 if (tevent_req_nomem(state
->irpc
, req
)) {
1082 return tevent_req_post(req
, ev
);
1085 state
->irpc
->msg_ctx
= hs
->msg_ctx
;
1086 state
->irpc
->callid
= idr_get_new(hs
->msg_ctx
->idr
,
1087 state
->irpc
, UINT16_MAX
);
1088 if (state
->irpc
->callid
== -1) {
1089 tevent_req_nterror(req
, NT_STATUS_INSUFFICIENT_RESOURCES
);
1090 return tevent_req_post(req
, ev
);
1092 state
->irpc
->incoming
.handler
= irpc_bh_raw_call_incoming_handler
;
1093 state
->irpc
->incoming
.private_data
= req
;
1095 talloc_set_destructor(state
->irpc
, irpc_destructor
);
1097 /* setup the header */
1098 header
.uuid
= hs
->table
->syntax_id
.uuid
;
1100 header
.if_version
= hs
->table
->syntax_id
.if_version
;
1101 header
.callid
= state
->irpc
->callid
;
1102 header
.callnum
= state
->opnum
;
1104 header
.status
= NT_STATUS_OK
;
1105 header
.creds
.token
= hs
->token
;
1107 /* construct the irpc packet */
1108 ndr
= ndr_push_init_ctx(state
->irpc
);
1109 if (tevent_req_nomem(ndr
, req
)) {
1110 return tevent_req_post(req
, ev
);
1113 ndr_err
= ndr_push_irpc_header(ndr
, NDR_SCALARS
|NDR_BUFFERS
, &header
);
1114 status
= ndr_map_error2ntstatus(ndr_err
);
1115 if (!NT_STATUS_IS_OK(status
)) {
1116 tevent_req_nterror(req
, status
);
1117 return tevent_req_post(req
, ev
);
1120 ndr_err
= ndr_push_bytes(ndr
, in_data
, in_length
);
1121 status
= ndr_map_error2ntstatus(ndr_err
);
1122 if (!NT_STATUS_IS_OK(status
)) {
1123 tevent_req_nterror(req
, status
);
1124 return tevent_req_post(req
, ev
);
1128 state
->in_packet
= ndr_push_blob(ndr
);
1129 status
= imessaging_send(hs
->msg_ctx
, hs
->server_id
,
1130 MSG_IRPC
, &state
->in_packet
);
1131 if (!NT_STATUS_IS_OK(status
)) {
1132 tevent_req_nterror(req
, status
);
1133 return tevent_req_post(req
, ev
);
1136 if (hs
->timeout
!= IRPC_CALL_TIMEOUT_INF
) {
1137 /* set timeout-callback in case caller wants that */
1138 ok
= tevent_req_set_endtime(req
, ev
, timeval_current_ofs(hs
->timeout
, 0));
1140 return tevent_req_post(req
, ev
);
1147 static void irpc_bh_raw_call_incoming_handler(struct irpc_request
*irpc
,
1148 struct irpc_message
*m
)
1150 struct tevent_req
*req
=
1151 talloc_get_type_abort(irpc
->incoming
.private_data
,
1153 struct irpc_bh_raw_call_state
*state
=
1154 tevent_req_data(req
,
1155 struct irpc_bh_raw_call_state
);
1157 talloc_steal(state
, m
);
1159 if (!NT_STATUS_IS_OK(m
->header
.status
)) {
1160 tevent_req_nterror(req
, m
->header
.status
);
1164 state
->out_data
= data_blob_talloc(state
,
1165 m
->ndr
->data
+ m
->ndr
->offset
,
1166 m
->ndr
->data_size
- m
->ndr
->offset
);
1167 if ((m
->ndr
->data_size
- m
->ndr
->offset
) > 0 && !state
->out_data
.data
) {
1168 tevent_req_oom(req
);
1172 tevent_req_done(req
);
1175 static NTSTATUS
irpc_bh_raw_call_recv(struct tevent_req
*req
,
1176 TALLOC_CTX
*mem_ctx
,
1179 uint32_t *out_flags
)
1181 struct irpc_bh_raw_call_state
*state
=
1182 tevent_req_data(req
,
1183 struct irpc_bh_raw_call_state
);
1186 if (tevent_req_is_nterror(req
, &status
)) {
1187 tevent_req_received(req
);
1191 *out_data
= talloc_move(mem_ctx
, &state
->out_data
.data
);
1192 *out_length
= state
->out_data
.length
;
1194 tevent_req_received(req
);
1195 return NT_STATUS_OK
;
1198 struct irpc_bh_disconnect_state
{
1202 static struct tevent_req
*irpc_bh_disconnect_send(TALLOC_CTX
*mem_ctx
,
1203 struct tevent_context
*ev
,
1204 struct dcerpc_binding_handle
*h
)
1206 struct irpc_bh_state
*hs
= dcerpc_binding_handle_data(h
,
1207 struct irpc_bh_state
);
1208 struct tevent_req
*req
;
1209 struct irpc_bh_disconnect_state
*state
;
1212 req
= tevent_req_create(mem_ctx
, &state
,
1213 struct irpc_bh_disconnect_state
);
1218 ok
= irpc_bh_is_connected(h
);
1220 tevent_req_nterror(req
, NT_STATUS_CONNECTION_DISCONNECTED
);
1221 return tevent_req_post(req
, ev
);
1226 tevent_req_done(req
);
1227 return tevent_req_post(req
, ev
);
1230 static NTSTATUS
irpc_bh_disconnect_recv(struct tevent_req
*req
)
1234 if (tevent_req_is_nterror(req
, &status
)) {
1235 tevent_req_received(req
);
1239 tevent_req_received(req
);
1240 return NT_STATUS_OK
;
1243 static bool irpc_bh_ref_alloc(struct dcerpc_binding_handle
*h
)
1248 static const struct dcerpc_binding_handle_ops irpc_bh_ops
= {
1250 .is_connected
= irpc_bh_is_connected
,
1251 .set_timeout
= irpc_bh_set_timeout
,
1252 .raw_call_send
= irpc_bh_raw_call_send
,
1253 .raw_call_recv
= irpc_bh_raw_call_recv
,
1254 .disconnect_send
= irpc_bh_disconnect_send
,
1255 .disconnect_recv
= irpc_bh_disconnect_recv
,
1257 .ref_alloc
= irpc_bh_ref_alloc
,
1260 /* initialise a irpc binding handle */
1261 struct dcerpc_binding_handle
*irpc_binding_handle(TALLOC_CTX
*mem_ctx
,
1262 struct imessaging_context
*msg_ctx
,
1263 struct server_id server_id
,
1264 const struct ndr_interface_table
*table
)
1266 struct dcerpc_binding_handle
*h
;
1267 struct irpc_bh_state
*hs
;
1269 h
= dcerpc_binding_handle_create(mem_ctx
,
1274 struct irpc_bh_state
,
1279 hs
->msg_ctx
= msg_ctx
;
1280 hs
->server_id
= server_id
;
1282 hs
->timeout
= IRPC_CALL_TIMEOUT
;
1287 struct dcerpc_binding_handle
*irpc_binding_handle_by_name(TALLOC_CTX
*mem_ctx
,
1288 struct imessaging_context
*msg_ctx
,
1289 const char *dest_task
,
1290 const struct ndr_interface_table
*table
)
1292 struct dcerpc_binding_handle
*h
;
1294 struct server_id
*sids
;
1295 struct server_id sid
;
1298 /* find the server task */
1300 status
= irpc_servers_byname(msg_ctx
, mem_ctx
, dest_task
,
1302 if (!NT_STATUS_IS_OK(status
)) {
1303 errno
= EADDRNOTAVAIL
;
1309 h
= irpc_binding_handle(mem_ctx
, msg_ctx
,
1318 void irpc_binding_handle_add_security_token(struct dcerpc_binding_handle
*h
,
1319 struct security_token
*token
)
1321 struct irpc_bh_state
*hs
=
1322 dcerpc_binding_handle_data(h
,
1323 struct irpc_bh_state
);