summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStefan Metzmacher <metze@samba.org>2010-08-30 13:44:01 +0200
committerStefan Metzmacher <metze@samba.org>2010-09-03 17:00:18 +0200
commite26f0abe9183ac46fd8b749f7696f404414b780e (patch)
tree3e5a4df2e36aadd0577138ec18b822fc7bcc1a1c
parent328c7084f2356dfad5c482fac4cd783b8027ab6b (diff)
downloadsamba-e26f0abe9183ac46fd8b749f7696f404414b780e.tar.gz
samba-e26f0abe9183ac46fd8b749f7696f404414b780e.tar.bz2
samba-e26f0abe9183ac46fd8b749f7696f404414b780e.zip
s4:lib/messaging: add irpc dcerpc_binding_handle backend
metze
-rw-r--r--source4/lib/messaging/irpc.h9
-rw-r--r--source4/lib/messaging/messaging.c279
-rw-r--r--source4/lib/messaging/wscript_build2
3 files changed, 289 insertions, 1 deletions
diff --git a/source4/lib/messaging/irpc.h b/source4/lib/messaging/irpc.h
index 95cade12d5..158b9cb3ec 100644
--- a/source4/lib/messaging/irpc.h
+++ b/source4/lib/messaging/irpc.h
@@ -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);
diff --git a/source4/lib/messaging/messaging.c b/source4/lib/messaging/messaging.c
index 290210efaa..67b8401bf5 100644
--- a/source4/lib/messaging/messaging.c
+++ b/source4/lib/messaging/messaging.c
@@ -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;
+}
diff --git a/source4/lib/messaging/wscript_build b/source4/lib/messaging/wscript_build
index ae15406895..d775d6f7c6 100644
--- a/source4/lib/messaging/wscript_build
+++ b/source4/lib/messaging/wscript_build
@@ -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'
)