pidl:Samba3/ClientNDR: implement rpccli_ stubs on top of dcerpc_ stubs
[Samba/gebeck_regimport.git] / pidl / lib / Parse / Pidl / Samba3 / ClientNDR.pm
blob24f87b606375bd4273c5070eaec86cd63e74389f
1 ###################################################
2 # Samba3 client generator for IDL structures
3 # on top of Samba4 style NDR functions
4 # Copyright jelmer@samba.org 2005-2006
5 # Copyright gd@samba.org 2008
6 # released under the GNU GPL
8 package Parse::Pidl::Samba3::ClientNDR;
10 use Exporter;
11 @ISA = qw(Exporter);
12 @EXPORT_OK = qw(ParseFunction $res $res_hdr ParseOutputArgument);
14 use strict;
15 use Parse::Pidl qw(fatal warning error);
16 use Parse::Pidl::Util qw(has_property ParseExpr);
17 use Parse::Pidl::Typelist qw(mapTypeName);
18 use Parse::Pidl::Samba4 qw(DeclLong);
19 use Parse::Pidl::Samba4::Header qw(GenerateFunctionInEnv GenerateFunctionOutEnv);
21 use vars qw($VERSION);
22 $VERSION = '0.01';
24 sub indent($) { my ($self) = @_; $self->{tabs}.="\t"; }
25 sub deindent($) { my ($self) = @_; $self->{tabs} = substr($self->{tabs}, 1); }
26 sub pidl($$) { my ($self,$txt) = @_; $self->{res} .= $txt ? "$self->{tabs}$txt\n" : "\n"; }
27 sub pidl_hdr($$) { my ($self, $txt) = @_; $self->{res_hdr} .= "$txt\n"; }
28 sub fn_declare($$) { my ($self,$n) = @_; $self->pidl($n); $self->pidl_hdr("$n;"); }
30 sub genpad($)
32 my ($s) = @_;
33 my $nt = int((length($s)+1)/8);
34 my $lt = ($nt*8)-1;
35 my $ns = (length($s)-$lt);
36 return "\t"x($nt)." "x($ns);
39 sub new($)
41 my ($class) = shift;
42 my $self = { res => "", res_hdr => "", tabs => "" };
43 bless($self, $class);
46 sub ElementDirection($)
48 my ($e) = @_;
50 return "[in,out]" if (has_property($e, "in") and has_property($e, "out"));
51 return "[in]" if (has_property($e, "in"));
52 return "[out]" if (has_property($e, "out"));
53 return "[in,out]";
56 sub HeaderProperties($$)
58 my($props,$ignores) = @_;
59 my $ret = "";
61 foreach my $d (keys %{$props}) {
62 next if (grep(/^$d$/, @$ignores));
63 if($props->{$d} ne "1") {
64 $ret.= "$d($props->{$d}),";
65 } else {
66 $ret.="$d,";
70 if ($ret) {
71 return "[" . substr($ret, 0, -1) . "]";
75 sub ParseInvalidResponse($$)
77 my ($self, $type) = @_;
79 if ($type eq "sync") {
80 $self->pidl("return NT_STATUS_INVALID_NETWORK_RESPONSE;");
81 } elsif ($type eq "async") {
82 $self->pidl("tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);");
83 $self->pidl("return;");
84 } else {
85 die("ParseInvalidResponse($type)");
89 sub ParseOutputArgument($$$;$$$)
91 my ($self, $fn, $e, $r, $o, $invalid_response_type) = @_;
92 my $level = 0;
93 $r = "r." unless defined($r);
94 $o = "" unless defined($o);
95 $invalid_response_type = "sync" unless defined($invalid_response_type);
97 if ($e->{LEVELS}[0]->{TYPE} ne "POINTER" and $e->{LEVELS}[0]->{TYPE} ne "ARRAY") {
98 $self->pidl("return NT_STATUS_NOT_SUPPORTED;");
99 error($e->{ORIGINAL}, "[out] argument is not a pointer or array");
100 return;
103 if ($e->{LEVELS}[0]->{TYPE} eq "POINTER") {
104 $level = 1;
105 if ($e->{LEVELS}[0]->{POINTER_TYPE} ne "ref") {
106 $self->pidl("if ($o$e->{NAME} && ${r}out.$e->{NAME}) {");
107 $self->indent;
111 if ($e->{LEVELS}[$level]->{TYPE} eq "ARRAY") {
112 # This is a call to GenerateFunctionInEnv intentionally.
113 # Since the data is being copied into a user-provided data
114 # structure, the user should be able to know the size beforehand
115 # to allocate a structure of the right size.
116 my $in_env = GenerateFunctionInEnv($fn, $r);
117 my $out_env = GenerateFunctionOutEnv($fn, $r);
118 my $l = $e->{LEVELS}[$level];
119 unless (defined($l->{SIZE_IS})) {
120 $self->pidl('#error No size known for [out] array `$e->{NAME}');
121 error($e->{ORIGINAL}, "no size known for [out] array `$e->{NAME}'");
122 } else {
123 my $in_size_is = ParseExpr($l->{SIZE_IS}, $in_env, $e->{ORIGINAL});
124 my $out_size_is = ParseExpr($l->{SIZE_IS}, $out_env, $e->{ORIGINAL});
125 my $out_length_is = $out_size_is;
126 if (defined($l->{LENGTH_IS})) {
127 $out_length_is = ParseExpr($l->{LENGTH_IS}, $out_env, $e->{ORIGINAL});
129 if ($out_size_is ne $in_size_is) {
130 $self->pidl("if (($out_size_is) > ($in_size_is)) {");
131 $self->indent;
132 $self->ParseInvalidResponse($invalid_response_type);
133 $self->deindent;
134 $self->pidl("}");
136 if ($out_length_is ne $out_size_is) {
137 $self->pidl("if (($out_length_is) > ($out_size_is)) {");
138 $self->indent;
139 $self->ParseInvalidResponse($invalid_response_type);
140 $self->deindent;
141 $self->pidl("}");
143 if (has_property($e, "charset")) {
144 $self->pidl("memcpy(discard_const_p(uint8_t *, $o$e->{NAME}), ${r}out.$e->{NAME}, ($out_length_is) * sizeof(*$o$e->{NAME}));");
145 } else {
146 $self->pidl("memcpy($o$e->{NAME}, ${r}out.$e->{NAME}, ($out_length_is) * sizeof(*$o$e->{NAME}));");
149 } else {
150 $self->pidl("*$o$e->{NAME} = *${r}out.$e->{NAME};");
153 if ($e->{LEVELS}[0]->{TYPE} eq "POINTER") {
154 if ($e->{LEVELS}[0]->{POINTER_TYPE} ne "ref") {
155 $self->deindent;
156 $self->pidl("}");
161 sub ParseFunctionAsyncState($$$)
163 my ($self, $if, $fn) = @_;
165 my $state_str = "struct rpccli_$fn->{NAME}_state";
166 my $done_fn = "rpccli_$fn->{NAME}_done";
168 $self->pidl("$state_str {");
169 $self->indent;
170 $self->pidl("TALLOC_CTX *out_mem_ctx;");
171 if (defined($fn->{RETURN_TYPE})) {
172 $self->pidl(mapTypeName($fn->{RETURN_TYPE}). " result;");
174 $self->deindent;
175 $self->pidl("};");
176 $self->pidl("");
177 $self->pidl("static void $done_fn(struct tevent_req *subreq);");
178 $self->pidl("");
181 sub ParseFunctionAsyncSend($$$)
183 my ($self, $if, $fn) = @_;
185 my $fn_args = "";
186 my $uif = uc($if);
187 my $ufn = "NDR_".uc($fn->{NAME});
188 my $state_str = "struct rpccli_$fn->{NAME}_state";
189 my $done_fn = "rpccli_$fn->{NAME}_done";
190 my $out_mem_ctx = "rpccli_$fn->{NAME}_out_memory";
191 my $fn_str = "struct tevent_req *rpccli_$fn->{NAME}_send";
192 my $pad = genpad($fn_str);
194 $fn_args .= "TALLOC_CTX *mem_ctx";
195 $fn_args .= ",\n" . $pad . "struct tevent_context *ev";
196 $fn_args .= ",\n" . $pad . "struct rpc_pipe_client *cli";
198 foreach (@{$fn->{ELEMENTS}}) {
199 my $dir = ElementDirection($_);
200 my $prop = HeaderProperties($_->{PROPERTIES}, ["in", "out"]);
201 $fn_args .= ",\n" . $pad . DeclLong($_, "_") . " /* $dir $prop */";
204 $self->fn_declare("$fn_str($fn_args)");
205 $self->pidl("{");
206 $self->indent;
207 $self->pidl("struct tevent_req *req;");
208 $self->pidl("$state_str *state;");
209 $self->pidl("struct tevent_req *subreq;");
210 $self->pidl("");
211 $self->pidl("req = tevent_req_create(mem_ctx, &state,");
212 $self->pidl("\t\t\t$state_str);");
213 $self->pidl("if (req == NULL) {");
214 $self->indent;
215 $self->pidl("return NULL;");
216 $self->deindent;
217 $self->pidl("}");
218 $self->pidl("state->out_mem_ctx = NULL;");
219 $self->pidl("");
221 my $out_params = 0;
222 foreach (@{$fn->{ELEMENTS}}) {
223 if (grep(/out/, @{$_->{DIRECTION}})) {
224 $out_params++;
228 if ($out_params > 0) {
229 $self->pidl("state->out_mem_ctx = talloc_named_const(state, 0,");
230 $self->pidl("\t\t \"$out_mem_ctx\");");
231 $self->pidl("if (tevent_req_nomem(state->out_mem_ctx, req)) {");
232 $self->indent;
233 $self->pidl("return tevent_req_post(req, ev);");
234 $self->deindent;
235 $self->pidl("}");
236 $self->pidl("");
239 $fn_str = "subreq = dcerpc_$fn->{NAME}_send";
240 $pad = "\t" . genpad($fn_str);
241 $fn_args = "state,\n" . $pad . "ev,\n" . $pad . "cli->binding_handle";
242 foreach (@{$fn->{ELEMENTS}}) {
243 $fn_args .= ",\n" . $pad . "_". $_->{NAME};
246 $self->pidl("$fn_str($fn_args);");
247 $self->pidl("if (tevent_req_nomem(subreq, req)) {");
248 $self->indent;
249 $self->pidl("return tevent_req_post(req, ev);");
250 $self->deindent;
251 $self->pidl("}");
252 $self->pidl("tevent_req_set_callback(subreq, $done_fn, req);");
253 $self->pidl("return req;");
254 $self->deindent;
255 $self->pidl("}");
256 $self->pidl("");
259 sub ParseFunctionAsyncDone($$$)
261 my ($self, $if, $fn) = @_;
263 my $state_str = "struct rpccli_$fn->{NAME}_state";
264 my $done_fn = "rpccli_$fn->{NAME}_done";
266 $self->pidl("static void $done_fn(struct tevent_req *subreq)");
267 $self->pidl("{");
268 $self->indent;
269 $self->pidl("struct tevent_req *req = tevent_req_callback_data(");
270 $self->pidl("\tsubreq, struct tevent_req);");
271 $self->pidl("$state_str *state = tevent_req_data(");
272 $self->pidl("\treq, $state_str);");
273 $self->pidl("NTSTATUS status;");
274 $self->pidl("TALLOC_CTX *mem_ctx;");
275 $self->pidl("");
277 $self->pidl("if (state->out_mem_ctx) {");
278 $self->indent;
279 $self->pidl("mem_ctx = state->out_mem_ctx;");
280 $self->deindent;
281 $self->pidl("} else {");
282 $self->indent;
283 $self->pidl("mem_ctx = state;");
284 $self->deindent;
285 $self->pidl("}");
286 $self->pidl("");
288 my $fn_str = "status = dcerpc_$fn->{NAME}_recv";
289 my $pad = "\t" . genpad($fn_str);
290 my $fn_args = "subreq,\n" . $pad . "mem_ctx";
291 if (defined($fn->{RETURN_TYPE})) {
292 $fn_args .= ",\n" . $pad . "&state->result";
295 $self->pidl("$fn_str($fn_args);");
296 $self->pidl("TALLOC_FREE(subreq);");
297 $self->pidl("if (!NT_STATUS_IS_OK(status)) {");
298 $self->indent;
299 $self->pidl("tevent_req_nterror(req, status);");
300 $self->pidl("return;");
301 $self->deindent;
302 $self->pidl("}");
303 $self->pidl("");
305 $self->pidl("tevent_req_done(req);");
306 $self->deindent;
307 $self->pidl("}");
308 $self->pidl("");
311 sub ParseFunctionAsyncRecv($$$)
313 my ($self, $if, $fn) = @_;
315 my $fn_args = "";
316 my $state_str = "struct rpccli_$fn->{NAME}_state";
317 my $fn_str = "NTSTATUS rpccli_$fn->{NAME}_recv";
318 my $pad = genpad($fn_str);
320 $fn_args .= "struct tevent_req *req,\n" . $pad . "TALLOC_CTX *mem_ctx";
322 if (defined($fn->{RETURN_TYPE})) {
323 $fn_args .= ",\n" . $pad . "$fn->{RETURN_TYPE} *result";
326 $self->fn_declare("$fn_str($fn_args)");
327 $self->pidl("{");
328 $self->indent;
329 $self->pidl("$state_str *state = tevent_req_data(");
330 $self->pidl("\treq, $state_str);");
331 $self->pidl("NTSTATUS status;");
332 $self->pidl("");
333 $self->pidl("if (tevent_req_is_nterror(req, &status)) {");
334 $self->indent;
335 $self->pidl("tevent_req_received(req);");
336 $self->pidl("return status;");
337 $self->deindent;
338 $self->pidl("}");
339 $self->pidl("");
341 $self->pidl("/* Steal possbile out parameters to the callers context */");
342 $self->pidl("talloc_steal(mem_ctx, state->out_mem_ctx);");
343 $self->pidl("");
345 if (defined($fn->{RETURN_TYPE})) {
346 $self->pidl("/* Return result */");
347 $self->pidl("*result = state->result;");
348 $self->pidl("");
351 $self->pidl("tevent_req_received(req);");
352 $self->pidl("return NT_STATUS_OK;");
353 $self->deindent;
354 $self->pidl("}");
355 $self->pidl("");
358 sub ParseFunctionSync($$$)
360 my ($self, $if, $fn) = @_;
362 my $fn_args = "";
363 my $uif = uc($if);
364 my $ufn = "NDR_".uc($fn->{NAME});
365 my $fn_str = "NTSTATUS rpccli_$fn->{NAME}";
366 my $pad = genpad($fn_str);
368 $fn_args .= "struct rpc_pipe_client *cli,\n" . $pad . "TALLOC_CTX *mem_ctx";
370 foreach (@{$fn->{ELEMENTS}}) {
371 my $dir = ElementDirection($_);
372 my $prop = HeaderProperties($_->{PROPERTIES}, ["in", "out"]);
373 $fn_args .= ",\n" . $pad . DeclLong($_, "_") . " /* $dir $prop */";
376 if (defined($fn->{RETURN_TYPE}) && ($fn->{RETURN_TYPE} eq "WERROR")) {
377 $fn_args .= ",\n" . $pad . "WERROR *werror";
380 $self->fn_declare("$fn_str($fn_args)");
381 $self->pidl("{");
382 $self->indent;
383 if (defined($fn->{RETURN_TYPE})) {
384 $self->pidl(mapTypeName($fn->{RETURN_TYPE})." result;");
386 $self->pidl("NTSTATUS status;");
387 $self->pidl("");
389 $fn_str = "status = dcerpc_$fn->{NAME}";
390 $pad = "\t" . genpad($fn_str);
391 $fn_args = "cli->binding_handle,\n" . $pad . "mem_ctx";
392 foreach (@{$fn->{ELEMENTS}}) {
393 $fn_args .= ",\n" . $pad . "_". $_->{NAME};
395 if (defined($fn->{RETURN_TYPE})) {
396 $fn_args .= ",\n" . $pad . "&result";
399 $self->pidl("$fn_str($fn_args);");
400 $self->pidl("if (!NT_STATUS_IS_OK(status)) {");
401 $self->indent;
402 $self->pidl("return status;");
403 $self->deindent;
404 $self->pidl("}");
405 $self->pidl("");
407 $self->pidl("/* Return result */");
408 if (not $fn->{RETURN_TYPE}) {
409 $self->pidl("return NT_STATUS_OK;");
410 } elsif ($fn->{RETURN_TYPE} eq "NTSTATUS") {
411 $self->pidl("return result;");
412 } elsif ($fn->{RETURN_TYPE} eq "WERROR") {
413 $self->pidl("if (werror) {");
414 $self->indent;
415 $self->pidl("*werror = result;");
416 $self->deindent;
417 $self->pidl("}");
418 $self->pidl("");
419 $self->pidl("return werror_to_ntstatus(result);");
420 } else {
421 warning($fn->{ORIGINAL}, "Unable to convert $fn->{RETURN_TYPE} to NTSTATUS");
422 $self->pidl("return NT_STATUS_OK;");
425 $self->deindent;
426 $self->pidl("}");
427 $self->pidl("");
430 sub ParseFunction($$$)
432 my ($self, $if, $fn) = @_;
434 $self->ParseFunctionAsyncState($if, $fn);
435 $self->ParseFunctionAsyncSend($if, $fn);
436 $self->ParseFunctionAsyncDone($if, $fn);
437 $self->ParseFunctionAsyncRecv($if, $fn);
439 $self->ParseFunctionSync($if, $fn);
442 sub ParseInterface($$)
444 my ($self, $if) = @_;
446 my $uif = uc($if->{NAME});
448 $self->pidl_hdr("#ifndef __CLI_$uif\__");
449 $self->pidl_hdr("#define __CLI_$uif\__");
450 foreach my $fn (@{$if->{FUNCTIONS}}) {
451 next if has_property($fn, "noopnum");
452 next if has_property($fn, "todo");
453 $self->ParseFunction($if->{NAME}, $fn);
455 $self->pidl_hdr("#endif /* __CLI_$uif\__ */");
458 sub Parse($$$$)
460 my($self,$ndr,$header,$c_header) = @_;
462 $self->pidl("/*");
463 $self->pidl(" * Unix SMB/CIFS implementation.");
464 $self->pidl(" * client auto-generated by pidl. DO NOT MODIFY!");
465 $self->pidl(" */");
466 $self->pidl("");
467 $self->pidl("#include \"includes.h\"");
468 $self->pidl("#include \"$header\"");
469 $self->pidl_hdr("#include \"$c_header\"");
470 $self->pidl("");
472 foreach (@$ndr) {
473 $self->ParseInterface($_) if ($_->{TYPE} eq "INTERFACE");
476 return ($self->{res}, $self->{res_hdr});