28d5245af8d563d58ce7c126786e5706572a05b3
[kai/samba-autobuild/.git] / pidl / lib / Parse / Pidl / Samba3 / ClientNDR.pm
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
7
8 package Parse::Pidl::Samba3::ClientNDR;
9
10 use Exporter;
11 @ISA = qw(Exporter);
12 @EXPORT_OK = qw(ParseFunction $res $res_hdr);
13
14 use strict;
15 use Parse::Pidl qw(fatal warning error);
16 use Parse::Pidl::Util qw(has_property ParseExpr genpad);
17 use Parse::Pidl::NDR qw(ContainsPipe);
18 use Parse::Pidl::Typelist qw(mapTypeName);
19 use Parse::Pidl::Samba4 qw(DeclLong);
20 use Parse::Pidl::Samba4::Header qw(GenerateFunctionInEnv GenerateFunctionOutEnv);
21
22 use vars qw($VERSION);
23 $VERSION = '0.01';
24
25 sub indent($) { my ($self) = @_; $self->{tabs}.="\t"; }
26 sub deindent($) { my ($self) = @_; $self->{tabs} = substr($self->{tabs}, 1); }
27 sub pidl($$) { my ($self,$txt) = @_; $self->{res} .= $txt ? "$self->{tabs}$txt\n" : "\n"; }
28 sub pidl_hdr($$) { my ($self, $txt) = @_; $self->{res_hdr} .= "$txt\n"; } 
29 sub fn_declare($$) { my ($self,$n) = @_; $self->pidl($n); $self->pidl_hdr("$n;"); }
30
31 sub new($)
32 {
33         my ($class) = shift;
34         my $self = { res => "", res_hdr => "", tabs => "" };
35         bless($self, $class);
36 }
37
38 sub ElementDirection($)
39 {
40         my ($e) = @_;
41
42         return "[in,out]" if (has_property($e, "in") and has_property($e, "out"));
43         return "[in]" if (has_property($e, "in"));
44         return "[out]" if (has_property($e, "out"));
45         return "[in,out]";
46 }
47
48 sub HeaderProperties($$)
49 {
50         my($props,$ignores) = @_;
51         my $ret = "";
52
53         foreach my $d (sort(keys %{$props})) {
54                 next if (grep(/^$d$/, @$ignores));
55                 if($props->{$d} ne "1") {
56                         $ret.= "$d($props->{$d}),";
57                 } else {
58                         $ret.="$d,";
59                 }
60         }
61
62         if ($ret) {
63                 return "[" . substr($ret, 0, -1) . "]";
64         }
65 }
66
67 sub ParseInvalidResponse($$)
68 {
69         my ($self, $type) = @_;
70
71         if ($type eq "sync") {
72                 $self->pidl("return NT_STATUS_INVALID_NETWORK_RESPONSE;");
73         } elsif ($type eq "async") {
74                 $self->pidl("tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);");
75                 $self->pidl("return;");
76         } else {
77                 die("ParseInvalidResponse($type)");
78         }
79 }
80
81 sub ParseFunctionAsyncState($$$)
82 {
83         my ($self, $if, $fn) = @_;
84
85         my $state_str = "struct rpccli_$fn->{NAME}_state";
86         my $done_fn = "rpccli_$fn->{NAME}_done";
87
88         $self->pidl("$state_str {");
89         $self->indent;
90         $self->pidl("TALLOC_CTX *out_mem_ctx;");
91         if (defined($fn->{RETURN_TYPE})) {
92                 $self->pidl(mapTypeName($fn->{RETURN_TYPE}). " result;");
93         }
94         $self->deindent;
95         $self->pidl("};");
96         $self->pidl("");
97         $self->pidl("static void $done_fn(struct tevent_req *subreq);");
98         $self->pidl("");
99 }
100
101 sub ParseFunctionAsyncSend($$$)
102 {
103         my ($self, $if, $fn) = @_;
104
105         my $fn_args = "";
106         my $uif = uc($if);
107         my $ufn = "NDR_".uc($fn->{NAME});
108         my $state_str = "struct rpccli_$fn->{NAME}_state";
109         my $done_fn = "rpccli_$fn->{NAME}_done";
110         my $out_mem_ctx = "rpccli_$fn->{NAME}_out_memory";
111         my $fn_str = "struct tevent_req *rpccli_$fn->{NAME}_send";
112         my $pad = genpad($fn_str);
113
114         $fn_args .= "TALLOC_CTX *mem_ctx";
115         $fn_args .= ",\n" . $pad . "struct tevent_context *ev";
116         $fn_args .= ",\n" . $pad . "struct rpc_pipe_client *cli";
117
118         foreach (@{$fn->{ELEMENTS}}) {
119                 my $dir = ElementDirection($_);
120                 my $prop = HeaderProperties($_->{PROPERTIES}, ["in", "out"]);
121                 $fn_args .= ",\n" . $pad . DeclLong($_, "_") . " /* $dir $prop */";
122         }
123
124         $self->fn_declare("$fn_str($fn_args)");
125         $self->pidl("{");
126         $self->indent;
127         $self->pidl("struct tevent_req *req;");
128         $self->pidl("$state_str *state;");
129         $self->pidl("struct tevent_req *subreq;");
130         $self->pidl("");
131         $self->pidl("req = tevent_req_create(mem_ctx, &state,");
132         $self->pidl("\t\t\t$state_str);");
133         $self->pidl("if (req == NULL) {");
134         $self->indent;
135         $self->pidl("return NULL;");
136         $self->deindent;
137         $self->pidl("}");
138         $self->pidl("state->out_mem_ctx = NULL;");
139         $self->pidl("");
140
141         my $out_params = 0;
142         foreach (@{$fn->{ELEMENTS}}) {
143                 if (grep(/out/, @{$_->{DIRECTION}})) {
144                         $out_params++;
145                 }
146         }
147
148         if ($out_params > 0) {
149                 $self->pidl("state->out_mem_ctx = talloc_named_const(state, 0,");
150                 $self->pidl("\t\t     \"$out_mem_ctx\");");
151                 $self->pidl("if (tevent_req_nomem(state->out_mem_ctx, req)) {");
152                 $self->indent;
153                 $self->pidl("return tevent_req_post(req, ev);");
154                 $self->deindent;
155                 $self->pidl("}");
156                 $self->pidl("");
157         }
158
159         $fn_str = "subreq = dcerpc_$fn->{NAME}_send";
160         $pad = "\t" . genpad($fn_str);
161         $fn_args = "state,\n" . $pad . "ev,\n" . $pad . "cli->binding_handle";
162         foreach (@{$fn->{ELEMENTS}}) {
163                 $fn_args .= ",\n" . $pad . "_". $_->{NAME};
164         }
165
166         $self->pidl("$fn_str($fn_args);");
167         $self->pidl("if (tevent_req_nomem(subreq, req)) {");
168         $self->indent;
169         $self->pidl("return tevent_req_post(req, ev);");
170         $self->deindent;
171         $self->pidl("}");
172         $self->pidl("tevent_req_set_callback(subreq, $done_fn, req);");
173         $self->pidl("return req;");
174         $self->deindent;
175         $self->pidl("}");
176         $self->pidl("");
177 }
178
179 sub ParseFunctionAsyncDone($$$)
180 {
181         my ($self, $if, $fn) = @_;
182
183         my $state_str = "struct rpccli_$fn->{NAME}_state";
184         my $done_fn = "rpccli_$fn->{NAME}_done";
185
186         $self->pidl("static void $done_fn(struct tevent_req *subreq)");
187         $self->pidl("{");
188         $self->indent;
189         $self->pidl("struct tevent_req *req = tevent_req_callback_data(");
190         $self->pidl("\tsubreq, struct tevent_req);");
191         $self->pidl("$state_str *state = tevent_req_data(");
192         $self->pidl("\treq, $state_str);");
193         $self->pidl("NTSTATUS status;");
194         $self->pidl("TALLOC_CTX *mem_ctx;");
195         $self->pidl("");
196
197         $self->pidl("if (state->out_mem_ctx) {");
198         $self->indent;
199         $self->pidl("mem_ctx = state->out_mem_ctx;");
200         $self->deindent;
201         $self->pidl("} else {");
202         $self->indent;
203         $self->pidl("mem_ctx = state;");
204         $self->deindent;
205         $self->pidl("}");
206         $self->pidl("");
207
208         my $fn_str = "status = dcerpc_$fn->{NAME}_recv";
209         my $pad = "\t" . genpad($fn_str);
210         my $fn_args = "subreq,\n" . $pad . "mem_ctx";
211         if (defined($fn->{RETURN_TYPE})) {
212                 $fn_args .= ",\n" . $pad . "&state->result";
213         }
214
215         $self->pidl("$fn_str($fn_args);");
216         $self->pidl("TALLOC_FREE(subreq);");
217         $self->pidl("if (!NT_STATUS_IS_OK(status)) {");
218         $self->indent;
219         $self->pidl("tevent_req_nterror(req, status);");
220         $self->pidl("return;");
221         $self->deindent;
222         $self->pidl("}");
223         $self->pidl("");
224
225         $self->pidl("tevent_req_done(req);");
226         $self->deindent;
227         $self->pidl("}");
228         $self->pidl("");
229 }
230
231 sub ParseFunctionAsyncRecv($$$)
232 {
233         my ($self, $if, $fn) = @_;
234
235         my $fn_args = "";
236         my $state_str = "struct rpccli_$fn->{NAME}_state";
237         my $fn_str = "NTSTATUS rpccli_$fn->{NAME}_recv";
238         my $pad = genpad($fn_str);
239
240         $fn_args .= "struct tevent_req *req,\n" . $pad . "TALLOC_CTX *mem_ctx";
241
242         if (defined($fn->{RETURN_TYPE})) {
243                 $fn_args .= ",\n" . $pad . "$fn->{RETURN_TYPE} *result";
244         }
245
246         $self->fn_declare("$fn_str($fn_args)");
247         $self->pidl("{");
248         $self->indent;
249         $self->pidl("$state_str *state = tevent_req_data(");
250         $self->pidl("\treq, $state_str);");
251         $self->pidl("NTSTATUS status;");
252         $self->pidl("");
253         $self->pidl("if (tevent_req_is_nterror(req, &status)) {");
254         $self->indent;
255         $self->pidl("tevent_req_received(req);");
256         $self->pidl("return status;");
257         $self->deindent;
258         $self->pidl("}");
259         $self->pidl("");
260
261         $self->pidl("/* Steal possible out parameters to the callers context */");
262         $self->pidl("talloc_steal(mem_ctx, state->out_mem_ctx);");
263         $self->pidl("");
264
265         if (defined($fn->{RETURN_TYPE})) {
266                 $self->pidl("/* Return result */");
267                 $self->pidl("*result = state->result;");
268                 $self->pidl("");
269         }
270
271         $self->pidl("tevent_req_received(req);");
272         $self->pidl("return NT_STATUS_OK;");
273         $self->deindent;
274         $self->pidl("}");
275         $self->pidl("");
276 }
277
278 sub ParseFunctionSync($$$)
279 {
280         my ($self, $if, $fn) = @_;
281
282         my $fn_args = "";
283         my $uif = uc($if);
284         my $ufn = "NDR_".uc($fn->{NAME});
285         my $fn_str = "NTSTATUS rpccli_$fn->{NAME}";
286         my $pad = genpad($fn_str);
287
288         $fn_args .= "struct rpc_pipe_client *cli,\n" . $pad . "TALLOC_CTX *mem_ctx";
289
290         foreach (@{$fn->{ELEMENTS}}) {
291                 my $dir = ElementDirection($_);
292                 my $prop = HeaderProperties($_->{PROPERTIES}, ["in", "out"]);
293                 $fn_args .= ",\n" . $pad . DeclLong($_, "_") . " /* $dir $prop */";
294         }
295
296         if (defined($fn->{RETURN_TYPE}) && ($fn->{RETURN_TYPE} eq "WERROR")) {
297                 $fn_args .= ",\n" . $pad . "WERROR *werror";
298         }
299
300         $self->fn_declare("$fn_str($fn_args)");
301         $self->pidl("{");
302         $self->indent;
303         if (defined($fn->{RETURN_TYPE})) {
304                 $self->pidl(mapTypeName($fn->{RETURN_TYPE})." result;");
305         }
306         $self->pidl("NTSTATUS status;");
307         $self->pidl("");
308
309         $fn_str = "status = dcerpc_$fn->{NAME}";
310         $pad = "\t" . genpad($fn_str);
311         $fn_args = "cli->binding_handle,\n" . $pad . "mem_ctx";
312         foreach (@{$fn->{ELEMENTS}}) {
313                 $fn_args .= ",\n" . $pad . "_". $_->{NAME};
314         }
315         if (defined($fn->{RETURN_TYPE})) {
316                 $fn_args .= ",\n" . $pad . "&result";
317         }
318
319         $self->pidl("$fn_str($fn_args);");
320         $self->pidl("if (!NT_STATUS_IS_OK(status)) {");
321         $self->indent;
322         $self->pidl("return status;");
323         $self->deindent;
324         $self->pidl("}");
325         $self->pidl("");
326
327         $self->pidl("/* Return result */");
328         if (not $fn->{RETURN_TYPE}) {
329                 $self->pidl("return NT_STATUS_OK;");
330         } elsif ($fn->{RETURN_TYPE} eq "NTSTATUS") {
331                 $self->pidl("return result;");
332         } elsif ($fn->{RETURN_TYPE} eq "WERROR") {
333                 $self->pidl("if (werror) {");
334                 $self->indent;
335                 $self->pidl("*werror = result;");
336                 $self->deindent;
337                 $self->pidl("}");
338                 $self->pidl("");
339                 $self->pidl("return werror_to_ntstatus(result);");
340         } else {
341                 warning($fn->{ORIGINAL}, "Unable to convert $fn->{RETURN_TYPE} to NTSTATUS");
342                 $self->pidl("return NT_STATUS_OK;");
343         }
344
345         $self->deindent;
346         $self->pidl("}");
347         $self->pidl("");
348 }
349
350 sub ParseFunction($$$)
351 {
352         my ($self, $if, $fn) = @_;
353
354         $self->ParseFunctionAsyncState($if, $fn);
355         $self->ParseFunctionAsyncSend($if, $fn);
356         $self->ParseFunctionAsyncDone($if, $fn);
357         $self->ParseFunctionAsyncRecv($if, $fn);
358
359         $self->ParseFunctionSync($if, $fn);
360 }
361
362 sub ParseInterface($$)
363 {
364         my ($self, $if) = @_;
365
366         my $uif = uc($if->{NAME});
367
368         $self->pidl_hdr("#ifndef __CLI_$uif\__");
369         $self->pidl_hdr("#define __CLI_$uif\__");
370         foreach my $fn (@{$if->{FUNCTIONS}}) {
371                 next if has_property($fn, "noopnum");
372                 next if has_property($fn, "todo");
373
374                 my $skip = 0;
375                 foreach my $e (@{$fn->{ELEMENTS}}) {
376                         if (ContainsPipe($e, $e->{LEVELS}[0])) {
377                                 $skip = 1;
378                                 last;
379                         }
380                 }
381                 next if $skip;
382
383                 $self->ParseFunction($if->{NAME}, $fn);
384         }
385         $self->pidl_hdr("#endif /* __CLI_$uif\__ */");
386 }
387
388 sub Parse($$$$)
389 {
390         my($self,$ndr,$header,$c_header) = @_;
391
392         $self->pidl("/*");
393         $self->pidl(" * Unix SMB/CIFS implementation.");
394         $self->pidl(" * client auto-generated by pidl. DO NOT MODIFY!");
395         $self->pidl(" */");
396         $self->pidl("");
397         $self->pidl("#include \"includes.h\"");
398         $self->pidl("#include \"$header\"");
399         $self->pidl_hdr("#include \"$c_header\"");
400         $self->pidl("");
401         
402         foreach (@$ndr) {
403                 $self->ParseInterface($_) if ($_->{TYPE} eq "INTERFACE");
404         }
405
406         return ($self->{res}, $self->{res_hdr});
407 }
408
409 1;