9ef8004555a2972dd53d11baf69b3f6151dedeff
[samba.git] / source4 / build / pidl / stub.pm
1 ###################################################
2 # stub boilerplate generator
3 # Copyright jelmer@samba.org 2004
4 # Copyright tridge@samba.org 2003
5 # released under the GNU GPL
6
7 package IdlStub;
8
9 use strict;
10
11 my($res);
12
13 sub pidl($)
14 {
15         $res .= shift;
16 }
17
18
19 #####################################################
20 # generate the switch statement for function dispatch
21 sub gen_dispatch_switch($)
22 {
23         my $data = shift;
24
25         my $count = 0;
26         foreach my $d (@{$data}) {
27                 next if ($d->{TYPE} ne "FUNCTION");
28
29                 pidl "\tcase $count: {\n";
30                 if ($d->{RETURN_TYPE} && $d->{RETURN_TYPE} ne "void") {
31                         pidl "\t\tNTSTATUS result;\n";
32                 }
33                 pidl "\t\tstruct $d->{NAME} *r2 = r;\n";
34                 pidl "\t\tif (DEBUGLEVEL > 10) {\n";
35                 pidl "\t\t\tNDR_PRINT_FUNCTION_DEBUG($d->{NAME}, NDR_IN, r2);\n";
36                 pidl "\t\t}\n";
37                 if ($d->{RETURN_TYPE} && $d->{RETURN_TYPE} ne "void") {
38                         pidl "\t\tresult = vtable->$d->{NAME}(iface, mem_ctx, r2);\n";
39                 } else {
40                         pidl "\t\tvtable->$d->{NAME}(iface, mem_ctx, r2);\n";
41                 }
42                 pidl "\t\tif (DEBUGLEVEL > 10 && dce_call->fault_code == 0) {\n";
43                 pidl "\t\t\tNDR_PRINT_FUNCTION_DEBUG($d->{NAME}, NDR_OUT | NDR_SET_VALUES, r2);\n";
44                 pidl "\t\t}\n";
45                 pidl "\t\tif (dce_call->fault_code != 0) {\n";
46                 pidl "\t\t\tDEBUG(2,(\"dcerpc_fault 0x%x in $d->{NAME}\\n\", dce_call->fault_code));\n";
47                 pidl "\t\t}\n";
48                 pidl "\t\tbreak;\n\t}\n";
49                 $count++; 
50         }
51 }
52
53
54 #####################################################################
55 # produce boilerplate code for a interface
56 sub Boilerplate_Iface($)
57 {
58         my($interface) = shift;
59         my($data) = $interface->{DATA};
60         my $count = 0;
61         my $name = $interface->{NAME};
62         my $uname = uc $name;
63         my $uuid = util::make_str($interface->{PROPERTIES}->{uuid});
64         my $if_version = $interface->{PROPERTIES}->{version};
65
66         pidl "
67 static NTSTATUS $name\__op_bind(struct dcesrv_call_state *dce_call, const struct dcesrv_interface *iface)
68 {
69 #ifdef DCESRV_INTERFACE_$uname\_BIND
70         return DCESRV_INTERFACE_$uname\_BIND(dce_call,iface);
71 #else
72         return NT_STATUS_OK;
73 #endif
74 }
75
76 static void $name\__op_unbind(struct dcesrv_connection *dce_conn, const struct dcesrv_interface *iface)
77 {
78 #ifdef DCESRV_INTERFACE_$uname\_UNBIND
79         DCESRV_INTERFACE_$uname\_UNBIND(dce_conn,iface);
80 #else
81         return;
82 #endif
83 }
84
85 static NTSTATUS $name\__op_ndr_pull(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, struct ndr_pull *pull, void **r)
86 {
87         NTSTATUS status;
88         uint16 opnum = dce_call->pkt.u.request.opnum;
89
90         dce_call->fault_code = 0;
91
92         if (opnum >= dcerpc_table_$name.num_calls) {
93                 dce_call->fault_code = DCERPC_FAULT_OP_RNG_ERROR;
94                 return NT_STATUS_NET_WRITE_FAULT;
95         }
96
97         *r = talloc_size(mem_ctx, dcerpc_table_$name.calls[opnum].struct_size);
98         if (!*r) {
99                 return NT_STATUS_NO_MEMORY;
100         }
101
102         /* unravel the NDR for the packet */
103         status = dcerpc_table_$name.calls[opnum].ndr_pull(pull, NDR_IN, *r);
104         if (!NT_STATUS_IS_OK(status)) {
105                 dcerpc_log_packet(&dcerpc_table_$name, opnum, NDR_IN,
106                                   &dce_call->pkt.u.request.stub_and_verifier);
107                 dce_call->fault_code = DCERPC_FAULT_NDR;
108                 return NT_STATUS_NET_WRITE_FAULT;
109         }
110
111         return NT_STATUS_OK;
112 }
113
114 static NTSTATUS $name\__op_dispatch(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, void *r)
115 {
116         uint16 opnum = dce_call->pkt.u.request.opnum;
117         struct GUID ipid = dce_call->pkt.u.request.object.object;
118         struct dcom_interface_p *iface = dcom_get_local_iface_p(&ipid);
119         const struct dcom_$name\_vtable *vtable = iface->vtable;
120
121         dce_call->fault_code = 0;
122
123         switch (opnum) {
124 ";
125         gen_dispatch_switch($data);
126
127 pidl "
128         default:
129                 dce_call->fault_code = DCERPC_FAULT_OP_RNG_ERROR;
130                 break;
131         }
132
133         if (dce_call->fault_code != 0) {
134                 return NT_STATUS_NET_WRITE_FAULT;
135         }
136         return NT_STATUS_OK;
137 }
138
139 static NTSTATUS $name\__op_ndr_push(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, struct ndr_push *push, void *r)
140 {
141         NTSTATUS status;
142         uint16 opnum = dce_call->pkt.u.request.opnum;
143
144         status = dcerpc_table_$name.calls[opnum].ndr_push(push, NDR_OUT, r);
145         if (!NT_STATUS_IS_OK(status)) {
146                 dce_call->fault_code = DCERPC_FAULT_NDR;
147                 return NT_STATUS_NET_WRITE_FAULT;
148         }
149
150         return NT_STATUS_OK;
151 }
152
153 static const struct dcesrv_interface $name\_interface = {
154         \"$name\",
155         $uuid,
156         $if_version,
157         $name\__op_bind,
158         $name\__op_unbind,
159         $name\__op_ndr_pull,
160         $name\__op_dispatch,
161         $name\__op_ndr_push
162 };
163
164 ";
165 }
166
167 #####################################################################
168 # produce boilerplate code for an endpoint server
169 sub Boilerplate_Ep_Server($)
170 {
171         my($interface) = shift;
172         my $name = $interface->{NAME};
173         my $uname = uc $name;
174
175         pidl "
176 static NTSTATUS $name\__op_init_server(struct dcesrv_context *dce_ctx, const struct dcesrv_endpoint_server *ep_server)
177 {
178         int i;
179
180         for (i=0;i<dcerpc_table_$name.endpoints->count;i++) {
181                 NTSTATUS ret;
182                 const char *name = dcerpc_table_$name.endpoints->names[i];
183
184                 ret = dcesrv_interface_register(dce_ctx, name, &$name\_interface, NULL);
185                 if (!NT_STATUS_IS_OK(ret)) {
186                         DEBUG(1,(\"$name\_op_init_server: failed to register endpoint \'%s\'\\n\",name));
187                         return ret;
188                 }
189         }
190
191         return NT_STATUS_OK;
192 }
193
194 static BOOL $name\__op_interface_by_uuid(struct dcesrv_interface *iface, const char *uuid, uint32 if_version)
195 {
196         if (dcerpc_table_$name.if_version == if_version &&
197                 strcmp(dcerpc_table_$name.uuid, uuid)==0) {
198                 memcpy(iface,&dcerpc_table_$name, sizeof(*iface));
199                 return True;
200         }
201
202         return False;
203 }
204
205 static BOOL $name\__op_interface_by_name(struct dcesrv_interface *iface, const char *name)
206 {
207         if (strcmp(dcerpc_table_$name.name, name)==0) {
208                 memcpy(iface,&dcerpc_table_$name, sizeof(*iface));
209                 return True;
210         }
211
212         return False;   
213 }
214         
215 NTSTATUS dcerpc_server_$name\_init(void)
216 {
217         NTSTATUS ret;
218         struct dcesrv_endpoint_server ep_server;
219
220         /* fill in our name */
221         ep_server.name = \"$name\";
222
223         /* fill in all the operations */
224         ep_server.init_server = $name\__op_init_server;
225
226         ep_server.interface_by_uuid = $name\__op_interface_by_uuid;
227         ep_server.interface_by_name = $name\__op_interface_by_name;
228
229         /* register ourselves with the DCERPC subsystem. */
230         ret = dcerpc_register_ep_server(&ep_server);
231
232         if (!NT_STATUS_IS_OK(ret)) {
233                 DEBUG(0,(\"Failed to register \'$name\' endpoint server!\\n\"));
234                 return ret;
235         }
236
237         return ret;
238 }
239
240 ";
241 }
242
243 sub ParseInterface($)
244 {
245         my($interface) = shift;
246                 my($data) = $interface->{DATA};
247         my $count = 0;
248
249         $res = "";
250
251         if (!defined $interface->{PROPERTIES}->{uuid}) {
252                 return $res;
253         }
254
255         if (!defined $interface->{PROPERTIES}->{version}) {
256                 $interface->{PROPERTIES}->{version} = "0.0";
257         }
258
259         foreach my $d (@{$data}) {
260                 if ($d->{TYPE} eq "FUNCTION") { $count++; }
261         }
262
263         if ($count == 0) {
264                 return $res;
265         }
266
267         $res = "/* dcom interface stub generated by pidl */\n\n";
268         Boilerplate_Iface($interface);
269         Boilerplate_Ep_Server($interface);
270
271         return $res;
272 }
273
274 1;