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