From d60d8e57d83acfc94fa36c59fcfb9c6e03ee02b6 Mon Sep 17 00:00:00 2001 From: Jelmer Vernooij Date: Mon, 26 May 2008 03:07:18 +0200 Subject: Implement IRPC calls over the internal messaging bus. (This used to be commit 777dc3a2c7b5bf855344ba3ae8c8b564c48fc0c6) --- source4/lib/messaging/pyirpc.c | 189 +++++++++++++++++---------- source4/librpc/rpc/pyrpc.c | 4 +- source4/librpc/rpc/pyrpc.h | 2 +- source4/pidl/lib/Parse/Pidl/Samba4/Python.pm | 5 +- 4 files changed, 125 insertions(+), 75 deletions(-) (limited to 'source4') diff --git a/source4/lib/messaging/pyirpc.c b/source4/lib/messaging/pyirpc.c index 5ef940817c..41475daaff 100644 --- a/source4/lib/messaging/pyirpc.c +++ b/source4/lib/messaging/pyirpc.c @@ -22,11 +22,13 @@ #include "includes.h" #include #include "libcli/util/pyerrors.h" +#include "librpc/rpc/pyrpc.h" #include "lib/messaging/irpc.h" #include "lib/messaging/messaging.h" #include "lib/events/events.h" #include "cluster/cluster.h" #include "param/param.h" +#include "librpc/gen_ndr/py_irpc.h" PyAPI_DATA(PyTypeObject) messaging_Type; PyAPI_DATA(PyTypeObject) irpc_InterfaceType; @@ -360,69 +362,88 @@ PyObject *py_irpc_connect(PyTypeObject *self, PyObject *args, PyObject *kwargs) } } -static void py_irpc_dealloc(PyObject *self) +typedef struct { + PyObject_HEAD + struct irpc_request **reqs; + int count; + int current; + TALLOC_CTX *mem_ctx; + py_data_unpack_fn unpack_fn; +} irpc_ResultObject; + + +static PyObject *irpc_result_next(irpc_ResultObject *iterator) { - irpc_InterfaceObject *iface = (irpc_InterfaceObject *)self; - talloc_free(iface->mem_ctx); + NTSTATUS status; + + if (iterator->current >= iterator->count) { + PyErr_SetString(PyExc_StopIteration, "No more results"); + return NULL; + } + + status = irpc_call_recv(iterator->reqs[iterator->current]); + iterator->current++; + if (!NT_STATUS_IS_OK(status)) { + PyErr_SetNTSTATUS(status); + return NULL; + } + + return iterator->unpack_fn(iterator->reqs[iterator->current-1]->r); +} + +static PyObject *irpc_result_len(irpc_ResultObject *self) +{ + return PyLong_FromLong(self->count); +} + +static PyMethodDef irpc_result_methods[] = { + { "__len__", (PyCFunction)irpc_result_len, METH_NOARGS, + "Number of elements returned"}, + { NULL } +}; + +static void irpc_result_dealloc(PyObject *self) +{ + talloc_free(((irpc_ResultObject *)self)->mem_ctx); PyObject_Del(self); } -PyTypeObject irpc_InterfaceType = { +PyTypeObject irpc_ResultIteratorType = { PyObject_HEAD_INIT(NULL) 0, - .tp_name = "irpc.ClientConnection", - .tp_basicsize = sizeof(irpc_InterfaceObject), + .tp_name = "irpc.ResultIterator", + .tp_basicsize = sizeof(irpc_ResultObject), .tp_flags = Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE, - .tp_new = py_irpc_connect, - .tp_dealloc = py_irpc_dealloc, + .tp_iter = (iternextfunc)irpc_result_next, + .tp_methods = irpc_result_methods, + .tp_dealloc = irpc_result_dealloc, }; -#if 0 -/* - make an irpc call - called via the same interface as rpc -*/ -static int ejs_irpc_call(int eid, struct MprVar *io, - const struct ndr_interface_table *iface, int callnum, - ejs_pull_function_t ejs_pull, ejs_push_function_t ejs_push) +static PyObject *py_irpc_call(irpc_InterfaceObject *p, struct PyNdrRpcMethodDef *method_def, PyObject *args, PyObject *kwargs) { - NTSTATUS status; void *ptr; - struct ejs_rpc *ejs; - const struct ndr_interface_call *call; - struct ejs_irpc_connection *p; struct irpc_request **reqs; int i, count; - struct MprVar *results; - - p = (struct ejs_irpc_connection *)mprGetThisPtr(eid, "irpc"); - - ejs = talloc(mprMemCtx(), struct ejs_rpc); - if (ejs == NULL) { - status = NT_STATUS_NO_MEMORY; - goto done; - } - - call = &iface->calls[callnum]; - - ejs->eid = eid; - ejs->callname = call->name; + NTSTATUS status; + TALLOC_CTX *mem_ctx = talloc_new(NULL); + irpc_ResultObject *ret; /* allocate the C structure */ - ptr = talloc_zero_size(ejs, call->struct_size); + ptr = talloc_zero_size(mem_ctx, method_def->table->calls[method_def->opnum].struct_size); if (ptr == NULL) { status = NT_STATUS_NO_MEMORY; goto done; } /* convert the mpr object into a C structure */ - status = ejs_pull(ejs, io, ptr); - if (!NT_STATUS_IS_OK(status)) { - goto done; + if (!method_def->pack_in_data(args, kwargs, ptr)) { + talloc_free(mem_ctx); + return NULL; } for (count=0;p->dest_ids[count].id;count++) /* noop */ ; /* we need to make a call per server */ - reqs = talloc_array(ejs, struct irpc_request *, count); + reqs = talloc_array(mem_ctx, struct irpc_request *, count); if (reqs == NULL) { status = NT_STATUS_NO_MEMORY; goto done; @@ -431,50 +452,72 @@ static int ejs_irpc_call(int eid, struct MprVar *io, /* make the actual calls */ for (i=0;imsg_ctx, p->dest_ids[i], - iface, callnum, ptr, ptr); + method_def->table, method_def->opnum, ptr, ptr); if (reqs[i] == NULL) { status = NT_STATUS_NO_MEMORY; goto done; } talloc_steal(reqs, reqs[i]); } - - mprSetVar(io, "results", mprObject("results")); - results = mprGetProperty(io, "results", NULL); - /* and receive the results, placing them in io.results[i] */ - for (i=0;imem_ctx = mem_ctx; + ret->reqs = reqs; + ret->count = count; + ret->current = 0; + ret->unpack_fn = method_def->unpack_out_data; - status = irpc_call_recv(reqs[i]); - if (!NT_STATUS_IS_OK(status)) { - goto done; - } - status = ejs_push(ejs, io, ptr); - if (!NT_STATUS_IS_OK(status)) { - goto done; - } + return (PyObject *)ret; +done: + talloc_free(mem_ctx); + PyErr_SetNTSTATUS(status); + return NULL; +} - /* add to the results array */ - output = mprGetProperty(io, "output", NULL); - if (output) { - char idx[16]; - mprItoa(i, idx, sizeof(idx)); - mprSetProperty(results, idx, output); - mprDeleteProperty(io, "output"); - } - } - mprSetVar(results, "length", mprCreateIntegerVar(i)); +static PyObject *py_irpc_call_wrapper(PyObject *self, PyObject *args, void *wrapped, PyObject *kwargs) +{ + irpc_InterfaceObject *iface = (irpc_InterfaceObject *)self; + struct PyNdrRpcMethodDef *md = wrapped; -done: - talloc_free(ejs); - mpr_Return(eid, mprNTSTATUS(status)); - if (NT_STATUS_EQUAL(status, NT_STATUS_INTERNAL_ERROR)) { - return -1; + return py_irpc_call(iface, md, args, kwargs); +} + +static void py_irpc_dealloc(PyObject *self) +{ + irpc_InterfaceObject *iface = (irpc_InterfaceObject *)self; + talloc_free(iface->mem_ctx); + PyObject_Del(self); +} + +PyTypeObject irpc_InterfaceType = { + PyObject_HEAD_INIT(NULL) 0, + .tp_name = "irpc.ClientConnection", + .tp_basicsize = sizeof(irpc_InterfaceObject), + .tp_flags = Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE, + .tp_new = py_irpc_connect, + .tp_dealloc = py_irpc_dealloc, +}; + +static bool irpc_AddNdrRpcMethods(PyTypeObject *ifacetype, struct PyNdrRpcMethodDef *mds) +{ + int i; + for (i = 0; mds[i].name; i++) { + PyObject *ret; + struct wrapperbase *wb = calloc(sizeof(struct wrapperbase), 1); + + wb->name = discard_const_p(char, mds[i].name); + wb->flags = PyWrapperFlag_KEYWORDS; + wb->wrapper = (wrapperfunc)py_irpc_call_wrapper; + wb->doc = discard_const_p(char, mds[i].doc); + + ret = PyDescr_NewWrapper(ifacetype, wb, &mds[i]); + + PyDict_SetItemString(ifacetype->tp_dict, mds[i].name, + (PyObject *)ret); } - return 0; + + return true; } -#endif void initirpc(void) { @@ -486,6 +529,12 @@ void initirpc(void) if (PyType_Ready(&messaging_Type) < 0) return; + if (PyType_Ready(&irpc_ResultIteratorType) < 0) + return; + + if (!irpc_AddNdrRpcMethods(&irpc_InterfaceType, py_ndr_irpc_methods)) + return; + mod = Py_InitModule3("irpc", NULL, "Internal RPC"); if (mod == NULL) return; diff --git a/source4/librpc/rpc/pyrpc.c b/source4/librpc/rpc/pyrpc.c index fae3d727fa..d8344be511 100644 --- a/source4/librpc/rpc/pyrpc.c +++ b/source4/librpc/rpc/pyrpc.c @@ -71,7 +71,7 @@ static PyObject *py_dcerpc_call_wrapper(PyObject *self, PyObject *args, void *wr } -bool PyInterface_AddNdrRpcMethods(PyTypeObject *ifacetype, struct PyNdrRpcMethodDef *mds) +bool PyInterface_AddNdrRpcMethods(PyTypeObject *ifacetype, const struct PyNdrRpcMethodDef *mds) { int i; for (i = 0; mds[i].name; i++) { @@ -83,7 +83,7 @@ bool PyInterface_AddNdrRpcMethods(PyTypeObject *ifacetype, struct PyNdrRpcMethod wb->wrapper = (wrapperfunc)py_dcerpc_call_wrapper; wb->doc = discard_const_p(char, mds[i].doc); - ret = PyDescr_NewWrapper(ifacetype, wb, &mds[i]); + ret = PyDescr_NewWrapper(ifacetype, wb, discard_const_p(void, &mds[i])); PyDict_SetItemString(ifacetype->tp_dict, mds[i].name, (PyObject *)ret); diff --git a/source4/librpc/rpc/pyrpc.h b/source4/librpc/rpc/pyrpc.h index 0840030704..989aeecc7b 100644 --- a/source4/librpc/rpc/pyrpc.h +++ b/source4/librpc/rpc/pyrpc.h @@ -66,6 +66,6 @@ struct PyNdrRpcMethodDef { const struct ndr_interface_table *table; }; -bool PyInterface_AddNdrRpcMethods(PyTypeObject *object, struct PyNdrRpcMethodDef *mds); +bool PyInterface_AddNdrRpcMethods(PyTypeObject *object, const struct PyNdrRpcMethodDef *mds); #endif /* _PYRPC_H_ */ diff --git a/source4/pidl/lib/Parse/Pidl/Samba4/Python.pm b/source4/pidl/lib/Parse/Pidl/Samba4/Python.pm index 0832401d7d..055ee13b10 100644 --- a/source4/pidl/lib/Parse/Pidl/Samba4/Python.pm +++ b/source4/pidl/lib/Parse/Pidl/Samba4/Python.pm @@ -650,7 +650,8 @@ sub Interface($$$) push (@fns, [$infn, $outfn, "dcerpc_$d->{NAME}", $prettyname, $fndocstring, $d->{OPNUM}]); } - $self->pidl("static struct PyNdrRpcMethodDef interface_$interface->{NAME}\_methods[] = {"); + $self->pidl("const struct PyNdrRpcMethodDef py_ndr_$interface->{NAME}\_methods[] = {"); + $self->pidl_hdr("const struct PyNdrRpcMethodDef py_ndr_$interface->{NAME}\_methods[];"); $self->indent; foreach my $d (@fns) { my ($infn, $outfn, $callfn, $prettyname, $docstring, $opnum) = @$d; @@ -771,7 +772,7 @@ sub Interface($$$) $self->pidl(""); $self->register_module_typeobject($interface->{NAME}, "&$interface->{NAME}_InterfaceType"); - $self->register_module_readycode(["if (!PyInterface_AddNdrRpcMethods(&$interface->{NAME}_InterfaceType, interface_$interface->{NAME}_methods))", "\treturn;", ""]); + $self->register_module_readycode(["if (!PyInterface_AddNdrRpcMethods(&$interface->{NAME}_InterfaceType, py_ndr_$interface->{NAME}\_methods))", "\treturn;", ""]); } $self->pidl_hdr("\n"); -- cgit