diff --git a/source4/lib/messaging/pyirpc.c b/source4/lib/messaging/pyirpc.c index 5ef940817c4..41475daaffa 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,6 +362,126 @@ PyObject *py_irpc_connect(PyTypeObject *self, PyObject *args, PyObject *kwargs) } } +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) +{ + 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_ResultIteratorType = { + PyObject_HEAD_INIT(NULL) 0, + .tp_name = "irpc.ResultIterator", + .tp_basicsize = sizeof(irpc_ResultObject), + .tp_flags = Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE, + .tp_iter = (iternextfunc)irpc_result_next, + .tp_methods = irpc_result_methods, + .tp_dealloc = irpc_result_dealloc, +}; + +static PyObject *py_irpc_call(irpc_InterfaceObject *p, struct PyNdrRpcMethodDef *method_def, PyObject *args, PyObject *kwargs) +{ + void *ptr; + struct irpc_request **reqs; + int i, count; + NTSTATUS status; + TALLOC_CTX *mem_ctx = talloc_new(NULL); + irpc_ResultObject *ret; + + /* allocate the C structure */ + 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 */ + 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(mem_ctx, struct irpc_request *, count); + if (reqs == NULL) { + status = NT_STATUS_NO_MEMORY; + goto done; + } + + /* make the actual calls */ + for (i=0;imsg_ctx, p->dest_ids[i], + method_def->table, method_def->opnum, ptr, ptr); + if (reqs[i] == NULL) { + status = NT_STATUS_NO_MEMORY; + goto done; + } + talloc_steal(reqs, reqs[i]); + } + + ret = PyObject_New(irpc_ResultObject, &irpc_ResultIteratorType); + ret->mem_ctx = mem_ctx; + ret->reqs = reqs; + ret->count = count; + ret->current = 0; + ret->unpack_fn = method_def->unpack_out_data; + + return (PyObject *)ret; +done: + talloc_free(mem_ctx); + PyErr_SetNTSTATUS(status); + return NULL; +} + +static PyObject *py_irpc_call_wrapper(PyObject *self, PyObject *args, void *wrapped, PyObject *kwargs) +{ + irpc_InterfaceObject *iface = (irpc_InterfaceObject *)self; + struct PyNdrRpcMethodDef *md = wrapped; + + return py_irpc_call(iface, md, args, kwargs); +} + static void py_irpc_dealloc(PyObject *self) { irpc_InterfaceObject *iface = (irpc_InterfaceObject *)self; @@ -376,105 +498,26 @@ PyTypeObject irpc_InterfaceType = { .tp_dealloc = py_irpc_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 bool irpc_AddNdrRpcMethods(PyTypeObject *ifacetype, struct PyNdrRpcMethodDef *mds) { - 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; + int i; + for (i = 0; mds[i].name; i++) { + PyObject *ret; + struct wrapperbase *wb = calloc(sizeof(struct wrapperbase), 1); - p = (struct ejs_irpc_connection *)mprGetThisPtr(eid, "irpc"); + 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]); - ejs = talloc(mprMemCtx(), struct ejs_rpc); - if (ejs == NULL) { - status = NT_STATUS_NO_MEMORY; - goto done; + PyDict_SetItemString(ifacetype->tp_dict, mds[i].name, + (PyObject *)ret); } - call = &iface->calls[callnum]; - - ejs->eid = eid; - ejs->callname = call->name; - - /* allocate the C structure */ - ptr = talloc_zero_size(ejs, call->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; - } - - 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); - if (reqs == NULL) { - status = NT_STATUS_NO_MEMORY; - goto done; - } - - /* make the actual calls */ - for (i=0;imsg_ctx, p->dest_ids[i], - iface, callnum, 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;iwrapper = (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 0840030704c..989aeecc7b9 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 0832401d7d3..055ee13b108 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");