pidl: Use NDR_ZERO_STRUCT(P) macros
[kai/samba-autobuild/.git] / pidl / lib / Parse / Pidl / Samba3 / ServerNDR.pm
1 ###################################################
2 # Samba3 server generator for IDL structures
3 # on top of Samba4 style NDR functions
4 # Copyright jelmer@samba.org 2005-2006
5 # released under the GNU GPL
6
7 package Parse::Pidl::Samba3::ServerNDR;
8
9 use Exporter;
10 @ISA = qw(Exporter);
11 @EXPORT_OK = qw(DeclLevel);
12
13 use strict;
14 use Parse::Pidl qw(warning error fatal);
15 use Parse::Pidl::Typelist qw(mapTypeName scalar_is_reference);
16 use Parse::Pidl::Util qw(ParseExpr has_property is_constant);
17 use Parse::Pidl::NDR qw(GetNextLevel ContainsPipe);
18 use Parse::Pidl::Samba4 qw(ElementStars DeclLong);
19 use Parse::Pidl::Samba4::Header qw(GenerateFunctionOutEnv);
20
21 use vars qw($VERSION);
22 $VERSION = '0.01';
23
24 my $res;
25 my $res_hdr;
26 my $tabs = "";
27 sub pidl_reset() { $res=""; $res_hdr="", $tabs=""; }
28 sub pidl_return() { my $s = $res; my $h = $res_hdr; pidl_reset(); return ($s, $h) }
29 sub indent() { $tabs.="\t"; }
30 sub deindent() { $tabs = substr($tabs, 1); }
31 sub pidl($) { my ($txt) = @_; $res .= $txt?$tabs.(shift)."\n":"\n"; }
32 sub pidl_hdr($) { $res_hdr .= (shift)."\n"; }
33 sub fn_declare($) { my ($n) = @_; pidl $n; pidl_hdr "$n;"; }
34
35 sub DeclLevel($$)
36 {
37         my ($e, $l) = @_;
38         my $res = "";
39
40         if (has_property($e, "charset")) {
41                 $res .= "const char";
42         } else {
43                 $res .= mapTypeName($e->{TYPE});
44         }
45
46         my $stars = ElementStars($e, $l);
47
48         $res .= " ".$stars unless ($stars eq "");
49
50         return $res;
51 }
52
53 sub AllocOutVar($$$$$$$)
54 {
55         my ($e, $mem_ctx, $name, $env, $check, $cleanup, $return) = @_;
56
57         my $l = $e->{LEVELS}[0];
58
59         # we skip pointer to arrays
60         if ($l->{TYPE} eq "POINTER") {
61                 my $nl = GetNextLevel($e, $l);
62                 $l = $nl if ($nl->{TYPE} eq "ARRAY");
63         } elsif
64
65         # we don't support multi-dimentional arrays yet
66         ($l->{TYPE} eq "ARRAY") {
67                 my $nl = GetNextLevel($e, $l);
68                 if ($nl->{TYPE} eq "ARRAY") {
69                         fatal($e->{ORIGINAL},"multi-dimentional [out] arrays are not supported!");
70                 }
71         } else {
72                 # neither pointer nor array, no need to alloc something.
73                 return;
74         }
75
76         if ($l->{TYPE} eq "ARRAY") {
77                 unless(defined($l->{SIZE_IS})) {
78                         error($e->{ORIGINAL}, "No size known for array `$e->{NAME}'");
79                         pidl "#error No size known for array `$e->{NAME}'";
80                 } else {
81                         my $size = ParseExpr($l->{SIZE_IS}, $env, $e);
82                         pidl "$name = talloc_zero_array($mem_ctx, " . DeclLevel($e, 1) . ", $size);";
83                 }
84         } else {
85                 pidl "$name = talloc_zero($mem_ctx, " . DeclLevel($e, 1) . ");";
86         }
87
88         pidl "if (" . $check->($name) . ") {";
89         indent;
90         pidl $cleanup->($name) if defined($cleanup);
91         pidl $return->($name) if defined($return);
92         deindent;
93         pidl "}";
94         pidl "";
95 }
96
97 sub CallWithStruct($$$$$$)
98 {
99         my ($pipes_struct, $mem_ctx, $fn, $check, $cleanup, $return) = @_;
100         my $env = GenerateFunctionOutEnv($fn);
101         my $hasout = 0;
102         foreach (@{$fn->{ELEMENTS}}) {
103                 if (grep(/out/, @{$_->{DIRECTION}})) { $hasout = 1; }
104         }
105
106         pidl "NDR_ZERO_STRUCT(r->out);" if ($hasout);
107
108         foreach (@{$fn->{ELEMENTS}}) {
109                 my @dir = @{$_->{DIRECTION}};
110                 if (grep(/in/, @dir) and grep(/out/, @dir)) {
111                         pidl "r->out.$_->{NAME} = r->in.$_->{NAME};";
112                 }
113         }
114
115         foreach (@{$fn->{ELEMENTS}}) {
116                 next if ContainsPipe($_, $_->{LEVELS}[0]);
117                 my @dir = @{$_->{DIRECTION}};
118                 if (grep(/in/, @dir) and grep(/out/, @dir)) {
119                         # noop
120                 } elsif (grep(/out/, @dir) and not
121                                  has_property($_, "represent_as")) {
122                         AllocOutVar($_, $mem_ctx, "r->out.$_->{NAME}", $env,
123                                     $check, $cleanup, $return);
124                 }
125         }
126
127         my $proto = "_$fn->{NAME}(struct pipes_struct *p, struct $fn->{NAME} *r)";
128         my $ret = "_$fn->{NAME}($pipes_struct, r)";
129
130         if ($fn->{RETURN_TYPE}) {
131                 $ret = "r->out.result = $ret";
132                 $proto = mapTypeName($fn->{RETURN_TYPE})." $proto";
133         } else {
134                 $proto = "void $proto";
135         }
136
137         pidl_hdr "$proto;";
138         pidl "$ret;";
139 }
140
141 sub ParseFunction($$)
142 {
143         my ($if,$fn) = @_;
144
145         my $op = "NDR_".uc($fn->{NAME});
146
147         pidl "static bool api_$fn->{NAME}(struct pipes_struct *p)";
148         pidl "{";
149         indent;
150         pidl "const struct ndr_interface_call *call;";
151         pidl "struct ndr_pull *pull;";
152         pidl "struct ndr_push *push;";
153         pidl "enum ndr_err_code ndr_err;";
154         pidl "struct $fn->{NAME} *r;";
155         pidl "";
156         pidl "call = &ndr_table_$if->{NAME}.calls[$op];";
157         pidl "";
158         pidl "r = talloc(talloc_tos(), struct $fn->{NAME});";
159         pidl "if (r == NULL) {";
160         pidl "\treturn false;";
161         pidl "}";
162         pidl "";
163         pidl "pull = ndr_pull_init_blob(&p->in_data.data, r);";
164         pidl "if (pull == NULL) {";
165         pidl "\ttalloc_free(r);";
166         pidl "\treturn false;";
167         pidl "}";
168         pidl "";
169         pidl "pull->flags |= LIBNDR_FLAG_REF_ALLOC;";
170         pidl "if (p->endian) {";
171         pidl "\tpull->flags |= LIBNDR_FLAG_BIGENDIAN;";
172         pidl "}";
173         pidl "ndr_err = call->ndr_pull(pull, NDR_IN, r);";
174         pidl "if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {";
175         pidl "\ttalloc_free(r);";
176         pidl "\treturn false;";
177         pidl "}";
178         pidl "";
179         pidl "if (DEBUGLEVEL >= 10) {";
180         pidl "\tNDR_PRINT_FUNCTION_DEBUG($fn->{NAME}, NDR_IN, r);";
181         pidl "}";
182         pidl "";
183
184         CallWithStruct("p", "r", $fn,
185                 sub ($) {
186                         my ($name) = @_;
187                         return "${name} == NULL";
188                 },
189                 sub ($) {
190                         my ($name) = @_;
191                         return "talloc_free(r);";
192                 },
193                 sub ($) {
194                         my ($name) = @_;
195                         return "return false;";
196                 }
197         );
198
199         pidl "";
200         pidl "if (p->fault_state) {";
201         pidl "\ttalloc_free(r);";
202         pidl "\t/* Return true here, srv_pipe_hnd.c will take care */";
203         pidl "\treturn true;";
204         pidl "}";
205         pidl "";
206         pidl "if (DEBUGLEVEL >= 10) {";
207         pidl "\tNDR_PRINT_FUNCTION_DEBUG($fn->{NAME}, NDR_OUT | NDR_SET_VALUES, r);";
208         pidl "}";
209         pidl "";
210         pidl "push = ndr_push_init_ctx(r);";
211         pidl "if (push == NULL) {";
212         pidl "\ttalloc_free(r);";
213         pidl "\treturn false;";
214         pidl "}";
215         pidl "";
216         pidl "/*";
217         pidl " * carry over the pointer count to the reply in case we are";
218         pidl " * using full pointer. See NDR specification for full pointers";
219         pidl " */";
220         pidl "push->ptr_count = pull->ptr_count;";
221         pidl "";
222         pidl "ndr_err = call->ndr_push(push, NDR_OUT, r);";
223         pidl "if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {";
224         pidl "\ttalloc_free(r);";
225         pidl "\treturn false;";
226         pidl "}";
227         pidl "";
228         pidl "p->out_data.rdata = ndr_push_blob(push);";
229         pidl "talloc_steal(p->mem_ctx, p->out_data.rdata.data);";
230         pidl "";
231         pidl "talloc_free(r);";
232         pidl "";
233         pidl "return true;";
234         deindent;
235         pidl "}";
236         pidl "";
237 }
238
239 sub ParseInterface($)
240 {
241         my $if = shift;
242
243         my $uif = uc($if->{NAME});
244
245         pidl_hdr "#ifndef __SRV_$uif\__";
246         pidl_hdr "#define __SRV_$uif\__";
247
248         foreach (@{$if->{FUNCTIONS}}) {
249                 next if ($_->{PROPERTIES}{noopnum});
250                 ParseFunction($if, $_);
251         }
252
253         pidl "";
254         pidl "/* Tables */";
255         pidl "static const struct api_struct api_$if->{NAME}_cmds[] = ";
256         pidl "{";
257         indent;
258
259         foreach (@{$if->{FUNCTIONS}}) {
260                 next if ($_->{PROPERTIES}{noopnum});
261                 pidl "{\"" . uc($_->{NAME}) . "\", NDR_" . uc($_->{NAME}) . ", api_$_->{NAME}},";
262         }
263
264         deindent;
265         pidl "};";
266
267         pidl "";
268
269         pidl_hdr "const struct api_struct *$if->{NAME}_get_pipe_fns(int *n_fns);";
270         pidl "const struct api_struct *$if->{NAME}_get_pipe_fns(int *n_fns)";
271         pidl "{";
272         indent;
273         pidl "*n_fns = sizeof(api_$if->{NAME}_cmds) / sizeof(struct api_struct);";
274         pidl "return api_$if->{NAME}_cmds;";
275         deindent;
276         pidl "}";
277         pidl "";
278
279         if (not has_property($if, "no_srv_register")) {
280             pidl_hdr "struct rpc_srv_callbacks;";
281             pidl_hdr "NTSTATUS rpc_$if->{NAME}_init(const struct rpc_srv_callbacks *rpc_srv_cb);";
282             pidl "NTSTATUS rpc_$if->{NAME}_init(const struct rpc_srv_callbacks *rpc_srv_cb)";
283             pidl "{";
284             pidl "\treturn rpc_srv_register(SMB_RPC_INTERFACE_VERSION, \"$if->{NAME}\", \"$if->{NAME}\", \&ndr_table_$if->{NAME}, api_$if->{NAME}_cmds, sizeof(api_$if->{NAME}_cmds) / sizeof(struct api_struct), rpc_srv_cb);";
285             pidl "}";
286
287             pidl "";
288
289             pidl_hdr "NTSTATUS rpc_$if->{NAME}_shutdown(void);";
290             pidl "NTSTATUS rpc_$if->{NAME}_shutdown(void)";
291             pidl "{";
292             pidl "\treturn rpc_srv_unregister(\&ndr_table_$if->{NAME});";
293             pidl "}";
294         }
295         pidl_hdr "#endif /* __SRV_$uif\__ */";
296 }
297
298 sub Parse($$$)
299 {
300         my($ndr,$header,$ndr_header) = @_;
301
302         pidl_reset();
303
304         pidl "/*";
305         pidl " * Unix SMB/CIFS implementation.";
306         pidl " * server auto-generated by pidl. DO NOT MODIFY!";
307         pidl " */";
308         pidl "";
309         pidl "#include \"includes.h\"";
310         pidl "#include \"ntdomain.h\"";
311         pidl "#include \"$header\"";
312         pidl_hdr "#include \"$ndr_header\"";
313         pidl "";
314
315         foreach (@$ndr) {
316                 ParseInterface($_) if ($_->{TYPE} eq "INTERFACE");
317         }
318
319         return pidl_return();
320 }
321
322 1;