diff options
author | Jelmer Vernooij <jelmer@samba.org> | 2004-11-12 00:48:24 +0000 |
---|---|---|
committer | Gerald (Jerry) Carter <jerry@samba.org> | 2007-10-10 13:05:44 -0500 |
commit | 79c5d73a71c35f5b16232072a7b52033cb9364cb (patch) | |
tree | 62aec59516dd088a0b71b4f86119497b621acb16 /source4/build/pidl | |
parent | c8b894b670a2e854c5a6af598ab1f02b142b3406 (diff) | |
download | samba-79c5d73a71c35f5b16232072a7b52033cb9364cb.tar.gz samba-79c5d73a71c35f5b16232072a7b52033cb9364cb.tar.bz2 samba-79c5d73a71c35f5b16232072a7b52033cb9364cb.zip |
r3689: Large number of COM updates:
- Work on server side and local COM support (should work, just no
example classes yet)
- Use vtables so that local and remote calls can be used transparently
- Generate 'proxies and stubs' rather then heavily modified code in client.pm and server.pm. proxies (client side code) are generated in proxy.pm, stubs (server side dispatchers) are generated in stubs.pm
- Support registering classes and interfaces
- DCOM interfaces no longer have to be in the same IDL file as their
base interface, which will allow us to split up dcom.idl
(This used to be commit 7466947a23985f9bb15209b67880f7b94dc515c8)
Diffstat (limited to 'source4/build/pidl')
-rw-r--r-- | source4/build/pidl/README | 2 | ||||
-rw-r--r-- | source4/build/pidl/client.pm | 79 | ||||
-rw-r--r-- | source4/build/pidl/header.pm | 45 | ||||
-rw-r--r-- | source4/build/pidl/parser.pm | 9 | ||||
-rwxr-xr-x | source4/build/pidl/pidl.pl | 13 | ||||
-rw-r--r-- | source4/build/pidl/proxy.pm | 166 | ||||
-rw-r--r-- | source4/build/pidl/server.pm | 13 | ||||
-rw-r--r-- | source4/build/pidl/stub.pm | 221 |
8 files changed, 455 insertions, 93 deletions
diff --git a/source4/build/pidl/README b/source4/build/pidl/README index 17a214cd58..c6432a8c0e 100644 --- a/source4/build/pidl/README +++ b/source4/build/pidl/README @@ -21,6 +21,8 @@ parser.pm - Generates pull/push functions for parsing server.pm - Generates server side implementation in C template.pm - Generates stubs in C for server implementation validator.pm - Validates the parse tree +proxy.pm - Generates proxy object for DCOM (client-side) +stub.pm - Generates stub call handler for DCOM (server-side) Other files in this directory are: tables.pl - Generates a table of available interfaces from a list of IDL files diff --git a/source4/build/pidl/client.pm b/source4/build/pidl/client.pm index 549a5d0dd3..015ac05223 100644 --- a/source4/build/pidl/client.pm +++ b/source4/build/pidl/client.pm @@ -11,82 +11,33 @@ my($res); ##################################################################### # parse a function -sub ParseFunction($) +sub ParseFunction($$) { + my $interface = shift; my $fn = shift; my $name = $fn->{NAME}; my $uname = uc $name; - return if (util::has_property($fn, "local")); - - my $objarg; - if (util::has_property($fn, "object")) { - $objarg = "&d->objref->u_objref.u_standard.std.ipid"; - # FIXME: Support custom marshalling - - $res .= " -struct rpc_request *dcerpc_$name\_send(struct dcom_interface *d, TALLOC_CTX *mem_ctx, struct $name *r) -{ - struct dcerpc_pipe *p; - NTSTATUS status = dcom_get_pipe(d, &p); - - if (NT_STATUS_IS_ERR(status)) { - return NULL; - } - - ZERO_STRUCT(r->in.ORPCthis); - r->in.ORPCthis.version.MajorVersion = COM_MAJOR_VERSION; - r->in.ORPCthis.version.MinorVersion = COM_MINOR_VERSION; - -"; - } else { - $objarg = "NULL"; - $res .= " + $res .= " struct rpc_request *dcerpc_$name\_send(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx, struct $name *r) -{"; - } +{ - $res.=" if (p->flags & DCERPC_DEBUG_PRINT_IN) { NDR_PRINT_IN_DEBUG($name, r); } - return dcerpc_ndr_request_send(p, $objarg, DCERPC_$uname, mem_ctx, + return dcerpc_ndr_request_send(p, NULL, DCERPC_$uname, mem_ctx, (ndr_push_flags_fn_t) ndr_push_$name, (ndr_pull_flags_fn_t) ndr_pull_$name, r, sizeof(*r)); } -"; - - if (util::has_property($fn, "object")) { - $res .= -" -NTSTATUS dcerpc_$name(struct dcom_interface *d, TALLOC_CTX *mem_ctx, struct $name *r) -{ - struct dcerpc_pipe *p; - NTSTATUS status = dcom_get_pipe(d, &p); - struct rpc_request *req; - - if (NT_STATUS_IS_ERR(status)) { - return status; - } - - "; - $objarg = "d"; - } else { - $res .= -" NTSTATUS dcerpc_$name(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx, struct $name *r) { struct rpc_request *req; NTSTATUS status; - "; - $objarg = "p"; - } - - $res .= " - req = dcerpc_$name\_send($objarg, mem_ctx, r); + + req = dcerpc_$name\_send(p, mem_ctx, r); if (req == NULL) return NT_STATUS_NO_MEMORY; status = dcerpc_ndr_request_recv(req); @@ -112,22 +63,10 @@ sub ParseInterface($) { my($interface) = shift; my($data) = $interface->{DATA}; + $res = "/* Client functions generated by pidl */\n\n"; foreach my $d (@{$data}) { ($d->{TYPE} eq "FUNCTION") && - ParseFunction($d); - } -} - - -##################################################################### -# parse a parsed IDL structure back into an IDL file -sub Parse($) -{ - my($idl) = shift; - $res = "/* dcerpc client calls generated by pidl */\n\n"; - foreach my $x (@{$idl}) { - ($x->{TYPE} eq "INTERFACE") && - ParseInterface($x); + ParseFunction($interface, $d); } return $res; } diff --git a/source4/build/pidl/header.pm b/source4/build/pidl/header.pm index b981200781..188fdd4f72 100644 --- a/source4/build/pidl/header.pm +++ b/source4/build/pidl/header.pm @@ -298,22 +298,42 @@ sub HeaderFunction($) ##################################################################### # output prototypes for a IDL function -sub HeaderFnProto($) +sub HeaderFnProto($$) { + my $interface = shift; my $fn = shift; my $name = $fn->{NAME}; - my $firstarg = "dcerpc_pipe"; - if (util::has_property($fn, "object")) { - $firstarg = "dcom_interface"; - } - $res .= "void ndr_print_$name(struct ndr_print *, const char *, int, struct $name *);\n"; - $res .= "struct rpc_request *dcerpc_$name\_send(struct $firstarg *, TALLOC_CTX *, struct $name *);\n"; - $res .= "NTSTATUS dcerpc_$name(struct $firstarg *, TALLOC_CTX *, struct $name *);\n"; + + if (util::has_property($interface, "object")) { + $res .= "NTSTATUS dcom_$interface->{NAME}_$name (struct dcom_interface_p *, TALLOC_CTX *mem_ctx, struct $name *);\n"; + } else { + $res .= "NTSTATUS dcerpc_$name(struct dcerpc_pipe *, TALLOC_CTX *, struct $name *);\n"; + $res .= "struct rpc_request *dcerpc_$name\_send(struct dcerpc_pipe *, TALLOC_CTX *, struct $name *);\n"; + } $res .= "\n"; } + +##################################################################### +# generate vtable structure for DCOM interface +sub HeaderVTable($) +{ + my $interface = shift; + $res .= "struct dcom_$interface->{NAME}_vtable {\n"; + if (defined($interface->{BASE})) { + $res .= "\tstruct dcom_$interface->{BASE}\_vtable base;\n"; + } + + my $data = $interface->{DATA}; + foreach my $d (@{$data}) { + $res .= "\tNTSTATUS (*$d->{NAME}) (struct dcom_interface_p *, TALLOC_CTX *mem_ctx, struct $d->{NAME} *);\n" if ($d->{TYPE} eq "FUNCTION"); + } + $res .= "};\n\n"; +} + + ##################################################################### # parse the interface definitions sub HeaderInterface($) @@ -379,11 +399,14 @@ sub HeaderInterface($) HeaderTypedef($d); ($d->{TYPE} eq "TYPEDEF") && HeaderTypedefProto($d); - ($d->{TYPE} eq "FUNCTION") && + ($d->{TYPE} eq "FUNCTION") && HeaderFunction($d); - ($d->{TYPE} eq "FUNCTION") && - HeaderFnProto($d); + ($d->{TYPE} eq "FUNCTION") && + HeaderFnProto($interface, $d); } + + (util::has_property($interface, "object")) && + HeaderVTable($interface); $res .= "#endif /* _HEADER_NDR_$interface->{NAME} */\n"; } diff --git a/source4/build/pidl/parser.pm b/source4/build/pidl/parser.pm index fd95f91665..e55e5ecd9c 100644 --- a/source4/build/pidl/parser.pm +++ b/source4/build/pidl/parser.pm @@ -9,6 +9,7 @@ package IdlParser; use strict; use client; +use proxy; use needed; # the list of needed functions @@ -1594,11 +1595,15 @@ sub Parse($$) if ($x->{TYPE} eq "INTERFACE") { needed::BuildNeeded($x); ParseInterface($x); + + if (util::has_property($x, "object")) { + pidl IdlProxy::ParseInterface($x); + } else { + pidl IdlClient::ParseInterface($x); + } } } - pidl IdlClient::Parse($idl); - close(OUT); } diff --git a/source4/build/pidl/pidl.pl b/source4/build/pidl/pidl.pl index fcd189d8cd..bb7f1f8ed6 100755 --- a/source4/build/pidl/pidl.pl +++ b/source4/build/pidl/pidl.pl @@ -17,6 +17,7 @@ use idl; use dump; use header; use server; +use stub; use parser; use eparser; use validator; @@ -139,7 +140,17 @@ sub process_file($) if ($opt_server) { my($server) = util::ChangeExtension($output, "_s.c"); - util::FileSave($server, IdlServer::Parse($pidl)); + my $res = ""; + foreach my $x (@{$pidl}) { + next if ($x->{TYPE} ne "INTERFACE"); + + if (util::has_property($x, "object")) { + $res .= IdlStub::ParseInterface($x); + } else { + $res .= IdlServer::ParseInterface($x); + } + } + util::FileSave($server, $res); } if ($opt_parser) { diff --git a/source4/build/pidl/proxy.pm b/source4/build/pidl/proxy.pm new file mode 100644 index 0000000000..b6d9733419 --- /dev/null +++ b/source4/build/pidl/proxy.pm @@ -0,0 +1,166 @@ +################################################### +# DCOM proxy generator +# Copyright jelmer@samba.org 2003 +# released under the GNU GPL + +package IdlProxy; + +use strict; + +my($res); + +sub ParseVTable($$) +{ + my $interface = shift; + my $name = shift; + + # Generate the vtable + $res .="\tstruct dcom_$interface->{NAME}_vtable $name = {"; + + if (defined($interface->{BASE})) { + $res .= "\n\t\t{},"; + } + + my $data = $interface->{DATA}; + + foreach my $d (@{$data}) { + if ($d->{TYPE} eq "FUNCTION") { + $res .= "\n\t\tdcom_proxy_$interface->{NAME}_$d->{NAME}"; + $res .= ","; + } + } + + $res .= "\n\t};\n\n"; +} + +sub ParseRegFunc($) +{ + my $interface = shift; + + $res .= "NTSTATUS dcom_$interface->{NAME}_init(void) +{ + struct dcom_interface iface; +"; + + ParseVTable($interface, "proxy"); + + if (defined($interface->{BASE})) { + $res.= " + const void *base_vtable; + + GUID_from_string(DCERPC_" . (uc $interface->{BASE}) . "_UUID, &iface.base_iid); + + base_vtable = dcom_proxy_vtable_by_iid(&iface.base_iid); + if (base_vtable == NULL) { + return NT_STATUS_FOOBAR; + } + + proxy.base = *((const struct dcom_$interface->{BASE}_vtable *)base_vtable); + "; + } else { + $res .= "\tZERO_STRUCT(iface.base_iid);\n"; + } + + $res.= " + iface.num_methods = DCERPC_" . (uc $interface->{NAME}) . "_CALL_COUNT; + GUID_from_string(DCERPC_" . (uc $interface->{NAME}) . "_UUID, &iface.iid); + iface.proxy_vtable = talloc_memdup(NULL, &proxy, sizeof(struct dcom_$interface->{NAME}_vtable)); + + return register_backend(\"dcom_interface\", &iface); +}\n\n"; +} + +##################################################################### +# parse a function +sub ParseFunction($$) +{ + my $interface = shift; + my $fn = shift; + my $name = $fn->{NAME}; + my $uname = uc $name; + + if (util::has_property($fn, "local")) { + $res .= " +static NTSTATUS dcom_proxy_$interface->{NAME}_$name(struct dcom_interface_p *d, TALLOC_CTX *mem_ctx, struct $name *r) +{ + /* FIXME */ + return NT_STATUS_NOT_SUPPORTED; +}\n"; + } else { + $res .= " +static struct rpc_request *dcom_proxy_$interface->{NAME}_$name\_send(struct dcom_interface_p *d, TALLOC_CTX *mem_ctx, struct $name *r) +{ + struct dcerpc_pipe *p; + NTSTATUS status = dcom_get_pipe(d, &p); + + if (NT_STATUS_IS_ERR(status)) { + return NULL; + } + + ZERO_STRUCT(r->in.ORPCthis); + r->in.ORPCthis.version.MajorVersion = COM_MAJOR_VERSION; + r->in.ORPCthis.version.MinorVersion = COM_MINOR_VERSION; + + if (p->flags & DCERPC_DEBUG_PRINT_IN) { + NDR_PRINT_IN_DEBUG($name, r); + } + + return dcerpc_ndr_request_send(p, &d->ipid, DCERPC_$uname, mem_ctx, + (ndr_push_flags_fn_t) ndr_push_$name, + (ndr_pull_flags_fn_t) ndr_pull_$name, + r, sizeof(*r)); +} + +static NTSTATUS dcom_proxy_$interface->{NAME}_$name(struct dcom_interface_p *d, TALLOC_CTX *mem_ctx, struct $name *r) +{ + struct dcerpc_pipe *p; + NTSTATUS status = dcom_get_pipe(d, &p); + struct rpc_request *req; + + if (NT_STATUS_IS_ERR(status)) { + return status; + } + + req = dcom_proxy_$interface->{NAME}_$name\_send(d, mem_ctx, r); + if (req == NULL) return NT_STATUS_NO_MEMORY; + + status = dcerpc_ndr_request_recv(req); + + if (NT_STATUS_IS_OK(status) && (p->flags & DCERPC_DEBUG_PRINT_OUT)) { + NDR_PRINT_OUT_DEBUG($name, r); + } + "; + if ($fn->{RETURN_TYPE} eq "NTSTATUS") { + $res .= "\tif (NT_STATUS_IS_OK(status)) status = r->out.result;\n"; + } + $res .= + " + return status; +}"; + } + + $res .=" +NTSTATUS dcom_$interface->{NAME}_$name (struct dcom_interface_p *d, TALLOC_CTX *mem_ctx, struct $name *r) +{ + return ((const struct dcom_$interface->{NAME}_vtable *)d->vtable)->$name (d, mem_ctx, r); +} +"; +} + + +##################################################################### +# parse the interface definitions +sub ParseInterface($) +{ + my($interface) = shift; + my($data) = $interface->{DATA}; + $res = "/* DCOM stubs generated by pidl */\n\n"; + foreach my $d (@{$data}) { + ($d->{TYPE} eq "FUNCTION") && + ParseFunction($interface, $d); + } + + ParseRegFunc($interface); +} + +1; diff --git a/source4/build/pidl/server.pm b/source4/build/pidl/server.pm index 01c5adacb4..6a9ea157a9 100644 --- a/source4/build/pidl/server.pm +++ b/source4/build/pidl/server.pm @@ -203,19 +203,14 @@ NTSTATUS dcerpc_server_$name\_init(void) "; } - ##################################################################### # parse a parsed IDL structure back into an IDL file -sub Parse($) +sub ParseInterface($) { - my($idl) = shift; + my($interface) = shift; $res = "/* dcerpc server boilerplate generated by pidl */\n\n"; - foreach my $x (@{$idl}) { - if ($x->{TYPE} eq "INTERFACE") { - Boilerplate_Iface($x); - Boilerplate_Ep_Server($x); - } - } + Boilerplate_Iface($interface); + Boilerplate_Ep_Server($interface); return $res; } diff --git a/source4/build/pidl/stub.pm b/source4/build/pidl/stub.pm new file mode 100644 index 0000000000..1cfb3cb11e --- /dev/null +++ b/source4/build/pidl/stub.pm @@ -0,0 +1,221 @@ +################################################### +# stub boilerplate generator +# Copyright jelmer@samba.org 2004 +# Copyright tridge@samba.org 2003 +# released under the GNU GPL + +package IdlStub; + +use strict; + +my($res); + +sub pidl($) +{ + $res .= shift; +} + + +##################################################### +# generate the switch statement for function dispatch +sub gen_dispatch_switch($) +{ + my $data = shift; + + my $count = 0; + foreach my $d (@{$data}) { + next if ($d->{TYPE} ne "FUNCTION"); + + pidl "\tcase $count: {\n"; + pidl "\t\tstruct $d->{NAME} *r2 = r;\n"; + pidl "\t\tif (DEBUGLEVEL > 10) {\n"; + pidl "\t\t\tNDR_PRINT_FUNCTION_DEBUG($d->{NAME}, NDR_IN, r2);\n"; + pidl "\t\t}\n"; + if ($d->{RETURN_TYPE} && $d->{RETURN_TYPE} ne "void") { + pidl "\t\tr2->out.result = vtable->$d->{NAME}(iface, mem_ctx, r2);\n"; + } else { + pidl "\t\tvtable->$d->{NAME}(iface, mem_ctx, r2);\n"; + } + pidl "\t\tif (DEBUGLEVEL > 10 && dce_call->fault_code == 0) {\n"; + pidl "\t\t\tNDR_PRINT_FUNCTION_DEBUG($d->{NAME}, NDR_OUT | NDR_SET_VALUES, r2);\n"; + pidl "\t\t}\n"; + pidl "\t\tif (dce_call->fault_code != 0) {\n"; + pidl "\t\t\tDEBUG(2,(\"dcerpc_fault 0x%x in $d->{NAME}\\n\", dce_call->fault_code));\n"; + pidl "\t\t}\n"; + pidl "\t\tbreak;\n\t}\n"; + $count++; + } +} + + +##################################################################### +# produce boilerplate code for a interface +sub Boilerplate_Iface($) +{ + my($interface) = shift; + my($data) = $interface->{DATA}; + my $count = 0; + my $name = $interface->{NAME}; + my $uname = uc $name; + + foreach my $d (@{$data}) { + if ($d->{TYPE} eq "FUNCTION") { $count++; } + } + + if ($count == 0) { + return; + } + + pidl " +static NTSTATUS $name\__op_bind(struct dcesrv_call_state *dce_call, const struct dcesrv_interface *iface) +{ +#ifdef DCESRV_INTERFACE_$uname\_BIND + return DCESRV_INTERFACE_$uname\_BIND(dce_call,iface); +#else + return NT_STATUS_OK; +#endif +} + +static void $name\__op_unbind(struct dcesrv_connection *dce_conn, const struct dcesrv_interface *iface) +{ +#ifdef DCESRV_INTERFACE_$uname\_UNBIND + DCESRV_INTERFACE_$uname\_UNBIND(dce_conn,iface); +#else + return; +#endif +} + +static NTSTATUS $name\__op_dispatch(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, void *r) +{ + uint16 opnum = dce_call->pkt.u.request.opnum; + struct GUID ipid = dce_call->pkt.u.request.object.object; + struct dcom_interface_p *iface = dcoms_get_ifacep(&ipid); + struct dcom_$name\_vtable *vtable = if->vtable; + + dce_call->fault_code = 0; + + switch (opnum) { +"; + gen_dispatch_switch($data); + +pidl " + default: + dce_call->fault_code = DCERPC_FAULT_OP_RNG_ERROR; + break; + } + + if (dce_call->fault_code != 0) { + return NT_STATUS_NET_WRITE_FAULT; + } + return NT_STATUS_OK; +} + +static const struct dcesrv_interface $name\_interface = { + &dcerpc_table_$name, + $name\__op_bind, + $name\__op_unbind, + $name\__op_dispatch +}; + +"; +} + +##################################################################### +# produce boilerplate code for an endpoint server +sub Boilerplate_Ep_Server($) +{ + my($interface) = shift; + my($data) = $interface->{DATA}; + my $count = 0; + my $name = $interface->{NAME}; + my $uname = uc $name; + + foreach my $d (@{$data}) { + if ($d->{TYPE} eq "FUNCTION") { $count++; } + } + + if ($count == 0) { + return; + } + + pidl " +static NTSTATUS $name\__op_init_server(struct dcesrv_context *dce_ctx, const struct dcesrv_endpoint_server *ep_server) +{ + int i; + + for (i=0;i<$name\_interface.ndr->endpoints->count;i++) { + NTSTATUS ret; + const char *name = $name\_interface.ndr->endpoints->names[i]; + + ret = dcesrv_interface_register(dce_ctx, name, &$name\_interface, NULL); + if (!NT_STATUS_IS_OK(ret)) { + DEBUG(1,(\"$name\_op_init_server: failed to register endpoint \'%s\'\\n\",name)); + return ret; + } + } + + return NT_STATUS_OK; +} + +static BOOL $name\__op_interface_by_uuid(struct dcesrv_interface *iface, const char *uuid, uint32 if_version) +{ + if ($name\_interface.ndr->if_version == if_version && + strcmp($name\_interface.ndr->uuid, uuid)==0) { + memcpy(iface,&$name\_interface, sizeof(*iface)); + return True; + } + + return False; +} + +static BOOL $name\__op_interface_by_name(struct dcesrv_interface *iface, const char *name) +{ + if (strcmp($name\_interface.ndr->name, name)==0) { + memcpy(iface,&$name\_interface, sizeof(*iface)); + return True; + } + + return False; +} + +NTSTATUS dcerpc_server_$name\_init(void) +{ + NTSTATUS ret; + struct dcesrv_endpoint_server ep_server; + + /* fill in our name */ + ep_server.name = \"$name\"; + + /* fill in all the operations */ + ep_server.init_server = $name\__op_init_server; + + ep_server.interface_by_uuid = $name\__op_interface_by_uuid; + ep_server.interface_by_name = $name\__op_interface_by_name; + + /* register ourselves with the DCERPC subsystem. */ + ret = register_backend(\"dcerpc\", &ep_server); + + if (!NT_STATUS_IS_OK(ret)) { + DEBUG(0,(\"Failed to register \'$name\' endpoint server!\\n\")); + return ret; + } + + return ret; +} + +"; +} + +sub ParseInterface($) +{ + my($interface) = shift; + $res = "/* dcerpc server boilerplate generated by pidl */\n\n"; + + Boilerplate_Iface($interface); + Boilerplate_Ep_Server($interface); + + return $res; +} + +1; + |