s4:lib/messaging: add irpc dcerpc_binding_handle backend
authorStefan Metzmacher <metze@samba.org>
Mon, 30 Aug 2010 11:44:01 +0000 (13:44 +0200)
committerStefan Metzmacher <metze@samba.org>
Fri, 3 Sep 2010 15:00:18 +0000 (17:00 +0200)
metze

source4/lib/messaging/irpc.h
source4/lib/messaging/messaging.c
source4/lib/messaging/wscript_build

index 95cade12d58a12e9753c787bc3acdde5f6f0697d..158b9cb3ec5149b1430aa5317c372bf14a8d467b 100644 (file)
@@ -79,6 +79,10 @@ struct irpc_request {
                void (*fn)(struct irpc_request *);
                void *private_data;
        } async;
+       struct {
+               void (*handler)(struct irpc_request *irpc, struct irpc_message *m);
+               void *private_data;
+       } incoming;
 };
 
 NTSTATUS irpc_register(struct messaging_context *msg_ctx, 
@@ -94,6 +98,11 @@ NTSTATUS irpc_call(struct messaging_context *msg_ctx,
                   const struct ndr_interface_table *table, 
                   int callnum, void *r, TALLOC_CTX *ctx);
 
+struct dcerpc_binding_handle *irpc_binding_handle(TALLOC_CTX *mem_ctx,
+                                       struct messaging_context *msg_ctx,
+                                       struct server_id server_id,
+                                       const struct ndr_interface_table *table);
+
 NTSTATUS irpc_add_name(struct messaging_context *msg_ctx, const char *name);
 struct server_id *irpc_servers_byname(struct messaging_context *msg_ctx, TALLOC_CTX *mem_ctx, const char *name);
 void irpc_remove_name(struct messaging_context *msg_ctx, const char *name);
index 290210efaa514eb90a85d2a485fb7feb73b85c7c..67b8401bf570cc6a39ce4d3130b0cd3b617e69c2 100644 (file)
@@ -33,6 +33,7 @@
 #include "../tdb/include/tdb.h"
 #include "../lib/util/util_tdb.h"
 #include "cluster/cluster.h"
+#include "../lib/util/tevent_ntstatus.h"
 
 /* change the message version with any incompatible changes in the protocol */
 #define MESSAGING_VERSION 1
@@ -683,6 +684,11 @@ static void irpc_handler_reply(struct messaging_context *msg_ctx, struct irpc_me
        irpc = (struct irpc_request *)idr_find(msg_ctx->idr, m->header.callid);
        if (irpc == NULL) return;
 
+       if (irpc->incoming.handler) {
+               irpc->incoming.handler(irpc, m);
+               return;
+       }
+
        /* parse the reply data */
        ndr_err = irpc->table->calls[irpc->callnum].ndr_pull(m->ndr, NDR_OUT, irpc->r);
        if (NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
@@ -889,6 +895,8 @@ struct irpc_request *irpc_call_send(struct messaging_context *msg_ctx,
        irpc->async.fn = NULL;
        irpc->mem_ctx  = ctx;
        irpc->reject_free = false;
+       irpc->incoming.handler = NULL;
+       irpc->incoming.private_data = NULL;
 
        talloc_set_destructor(irpc, irpc_destructor);
 
@@ -1122,3 +1130,274 @@ struct server_id messaging_get_server_id(struct messaging_context *msg_ctx)
 {
        return msg_ctx->server_id;
 }
+
+struct irpc_bh_state {
+       struct messaging_context *msg_ctx;
+       struct server_id server_id;
+       const struct ndr_interface_table *table;
+};
+
+static bool irpc_bh_is_connected(struct dcerpc_binding_handle *h)
+{
+       struct irpc_bh_state *hs = dcerpc_binding_handle_data(h,
+                                  struct irpc_bh_state);
+
+       if (!hs->msg_ctx) {
+               return false;
+       }
+
+       return true;
+}
+
+struct irpc_bh_raw_call_state {
+       struct irpc_request *irpc;
+       uint32_t opnum;
+       DATA_BLOB in_data;
+       DATA_BLOB in_packet;
+       DATA_BLOB out_data;
+};
+
+static void irpc_bh_raw_call_incoming_handler(struct irpc_request *irpc,
+                                             struct irpc_message *m);
+
+static struct tevent_req *irpc_bh_raw_call_send(TALLOC_CTX *mem_ctx,
+                                               struct tevent_context *ev,
+                                               struct dcerpc_binding_handle *h,
+                                               const struct GUID *object,
+                                               uint32_t opnum,
+                                               uint32_t in_flags,
+                                               const uint8_t *in_data,
+                                               size_t in_length)
+{
+       struct irpc_bh_state *hs =
+               dcerpc_binding_handle_data(h,
+               struct irpc_bh_state);
+       struct tevent_req *req;
+       struct irpc_bh_raw_call_state *state;
+       bool ok;
+       struct irpc_header header;
+       struct ndr_push *ndr;
+       NTSTATUS status;
+       enum ndr_err_code ndr_err;
+
+       req = tevent_req_create(mem_ctx, &state,
+                               struct irpc_bh_raw_call_state);
+       if (req == NULL) {
+               return NULL;
+       }
+       state->opnum = opnum;
+       state->in_data.data = discard_const_p(uint8_t, in_data);
+       state->in_data.length = in_length;
+
+       ok = irpc_bh_is_connected(h);
+       if (!ok) {
+               tevent_req_nterror(req, NT_STATUS_INVALID_CONNECTION);
+               return tevent_req_post(req, ev);
+       }
+
+       state->irpc = talloc_zero(state, struct irpc_request);
+       if (tevent_req_nomem(state->irpc, req)) {
+               return tevent_req_post(req, ev);
+       }
+
+       state->irpc->msg_ctx  = hs->msg_ctx;
+       state->irpc->table    = hs->table;
+       state->irpc->callnum  = state->opnum;
+       state->irpc->callid   = idr_get_new(hs->msg_ctx->idr,
+                                           state->irpc, UINT16_MAX);
+       if (state->irpc->callid == -1) {
+               tevent_req_nterror(req, NT_STATUS_INSUFFICIENT_RESOURCES);
+               return tevent_req_post(req, ev);
+       }
+       state->irpc->r        = NULL;
+       state->irpc->done     = false;
+       state->irpc->async.fn = NULL;
+       state->irpc->mem_ctx  = state;
+       state->irpc->reject_free = false;
+       state->irpc->incoming.handler = irpc_bh_raw_call_incoming_handler;
+       state->irpc->incoming.private_data = req;
+
+       talloc_set_destructor(state->irpc, irpc_destructor);
+
+       /* setup the header */
+       header.uuid = hs->table->syntax_id.uuid;
+
+       header.if_version = hs->table->syntax_id.if_version;
+       header.callid     = state->irpc->callid;
+       header.callnum    = state->opnum;
+       header.flags      = 0;
+       header.status     = NT_STATUS_OK;
+
+       /* construct the irpc packet */
+       ndr = ndr_push_init_ctx(state->irpc);
+       if (tevent_req_nomem(ndr, req)) {
+               return tevent_req_post(req, ev);
+       }
+
+       ndr_err = ndr_push_irpc_header(ndr, NDR_SCALARS|NDR_BUFFERS, &header);
+       status = ndr_map_error2ntstatus(ndr_err);
+       if (!NT_STATUS_IS_OK(status)) {
+               tevent_req_nterror(req, status);
+               return tevent_req_post(req, ev);
+       }
+
+       ndr_err = ndr_push_bytes(ndr, in_data, in_length);
+       status = ndr_map_error2ntstatus(ndr_err);
+       if (!NT_STATUS_IS_OK(status)) {
+               tevent_req_nterror(req, status);
+               return tevent_req_post(req, ev);
+       }
+
+       /* and send it */
+       state->in_packet = ndr_push_blob(ndr);
+       status = messaging_send(hs->msg_ctx, hs->server_id,
+                               MSG_IRPC, &state->in_packet);
+       if (!NT_STATUS_IS_OK(status)) {
+               tevent_req_nterror(req, status);
+               return tevent_req_post(req, ev);
+       }
+
+       tevent_req_set_endtime(req, ev, timeval_current_ofs(IRPC_CALL_TIMEOUT, 0));
+
+       return req;
+}
+
+static void irpc_bh_raw_call_incoming_handler(struct irpc_request *irpc,
+                                             struct irpc_message *m)
+{
+       struct tevent_req *req =
+               talloc_get_type_abort(irpc->incoming.private_data,
+               struct tevent_req);
+       struct irpc_bh_raw_call_state *state =
+               tevent_req_data(req,
+               struct irpc_bh_raw_call_state);
+
+       talloc_steal(state, m);
+
+       if (!NT_STATUS_IS_OK(m->header.status)) {
+               tevent_req_nterror(req, m->header.status);
+               return;
+       }
+
+       state->out_data = data_blob_talloc(state,
+               m->ndr->data + m->ndr->offset,
+               m->ndr->data_size - m->ndr->offset);
+       if ((m->ndr->data_size - m->ndr->offset) > 0 && !state->out_data.data) {
+               tevent_req_nomem(NULL, req);
+               return;
+       }
+
+       tevent_req_done(req);
+}
+
+static NTSTATUS irpc_bh_raw_call_recv(struct tevent_req *req,
+                                       TALLOC_CTX *mem_ctx,
+                                       uint8_t **out_data,
+                                       size_t *out_length,
+                                       uint32_t *out_flags)
+{
+       struct irpc_bh_raw_call_state *state =
+               tevent_req_data(req,
+               struct irpc_bh_raw_call_state);
+       NTSTATUS status;
+
+       if (tevent_req_is_nterror(req, &status)) {
+               tevent_req_received(req);
+               return status;
+       }
+
+       *out_data = talloc_move(mem_ctx, &state->out_data.data);
+       *out_length = state->out_data.length;
+       *out_flags = 0;
+       tevent_req_received(req);
+       return NT_STATUS_OK;
+}
+
+struct irpc_bh_disconnect_state {
+       uint8_t _dummy;
+};
+
+static struct tevent_req *irpc_bh_disconnect_send(TALLOC_CTX *mem_ctx,
+                                               struct tevent_context *ev,
+                                               struct dcerpc_binding_handle *h)
+{
+       struct irpc_bh_state *hs = dcerpc_binding_handle_data(h,
+                                    struct irpc_bh_state);
+       struct tevent_req *req;
+       struct irpc_bh_disconnect_state *state;
+       bool ok;
+
+       req = tevent_req_create(mem_ctx, &state,
+                               struct irpc_bh_disconnect_state);
+       if (req == NULL) {
+               return NULL;
+       }
+
+       ok = irpc_bh_is_connected(h);
+       if (!ok) {
+               tevent_req_nterror(req, NT_STATUS_INVALID_CONNECTION);
+               return tevent_req_post(req, ev);
+       }
+
+       hs->msg_ctx = NULL;
+
+       tevent_req_done(req);
+       return tevent_req_post(req, ev);
+}
+
+static NTSTATUS irpc_bh_disconnect_recv(struct tevent_req *req)
+{
+       NTSTATUS status;
+
+       if (tevent_req_is_nterror(req, &status)) {
+               tevent_req_received(req);
+               return status;
+       }
+
+       tevent_req_received(req);
+       return NT_STATUS_OK;
+}
+
+static bool irpc_bh_ref_alloc(struct dcerpc_binding_handle *h)
+{
+       return true;
+}
+
+static const struct dcerpc_binding_handle_ops irpc_bh_ops = {
+       .name                   = "wbint",
+       .is_connected           = irpc_bh_is_connected,
+       .raw_call_send          = irpc_bh_raw_call_send,
+       .raw_call_recv          = irpc_bh_raw_call_recv,
+       .disconnect_send        = irpc_bh_disconnect_send,
+       .disconnect_recv        = irpc_bh_disconnect_recv,
+
+       .ref_alloc              = irpc_bh_ref_alloc,
+};
+
+/* initialise a irpc binding handle */
+struct dcerpc_binding_handle *irpc_binding_handle(TALLOC_CTX *mem_ctx,
+                                       struct messaging_context *msg_ctx,
+                                       struct server_id server_id,
+                                       const struct ndr_interface_table *table)
+{
+       struct dcerpc_binding_handle *h;
+       struct irpc_bh_state *hs;
+
+       h = dcerpc_binding_handle_create(mem_ctx,
+                                        &irpc_bh_ops,
+                                        NULL,
+                                        table,
+                                        &hs,
+                                        struct irpc_bh_state,
+                                        __location__);
+       if (h == NULL) {
+               return NULL;
+       }
+       hs->msg_ctx = msg_ctx;
+       hs->server_id = server_id;
+       hs->table = table;
+
+       dcerpc_binding_handle_set_sync_ev(h, msg_ctx->event.ev);
+
+       return h;
+}
index ae15406895985cc901487246ff647faef0fa63c9..d775d6f7c6af5203414bbcb4b126e72663940be8 100644 (file)
@@ -3,7 +3,7 @@
 
 bld.SAMBA_SUBSYSTEM('MESSAGING',
        source='messaging.c',
-       public_deps='LIBSAMBA-UTIL TDB_WRAP NDR_IRPC UNIX_PRIVS UTIL_TDB CLUSTER LIBNDR samba_socket'
+       public_deps='LIBSAMBA-UTIL TDB_WRAP NDR_IRPC UNIX_PRIVS UTIL_TDB CLUSTER LIBNDR samba_socket dcerpc'
        )