1// Copyright 2019 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "{{module.path}}-mojolpm.h"
6
7#include <functional>
8
9#include "base/no_destructor.h"
10#include "base/task/post_task.h"
11
12{% for extra_traits_header in all_extra_traits_headers %}
13#include "{{extra_traits_header}}"
14{%- endfor %}
15
16{%- import "mojolpm_macros.tmpl" as util %}
17{%- import "mojolpm_from_proto_macros.tmpl" as from_proto %}
18{%- import "mojolpm_to_proto_macros.tmpl" as to_proto %}
19{%- import "mojolpm_traits_specialization_macros.tmpl" as traits_specialization %}
20
21namespace mojo {
22{%- for struct in structs %}
23{{- traits_specialization.define_struct(struct) }}
24{%- endfor %}
25
26{%- for union in unions %}
27{{ traits_specialization.define_union(union) }}
28{%- endfor %}
29} // namespace mojo
30
31namespace mojolpm {
32{%- for enum in all_enums %}
33{{- from_proto.define_enum(enum) }}
34{{- to_proto.define_enum(enum) }}
35{%- endfor %}
36
37{%- for struct in structs %}
38{%-   set proto_type = "::mojolpm" ~ (struct|get_qualified_name_for_kind(flatten_nested_kind=True)) %}
39{%-   set struct_type = proto_type ~ "_ProtoStruct" %}
40{%-   for field in struct.fields %}
41{%-       set name = field.name|camel_to_under %}
42{%-       set kind = field.kind %}
43{%-       if kind|is_array_kind or kind|is_map_kind %}
44{{- from_proto.define(struct_type, kind, name) }}
45{{- to_proto.define(struct_type, kind, name) }}
46{%-       endif %}
47{%-   endfor %}
48{{- from_proto.define_struct(struct) }}
49{{- to_proto.define_struct(struct) }}
50{%- endfor %}
51
52{%- for union in unions %}
53{%-   set proto_type = "::mojolpm" ~ (union|get_qualified_name_for_kind(flatten_nested_kind=True)) %}
54{%-   set union_type = proto_type ~ "_ProtoUnion" %}
55{%-     for field in union.fields %}
56{%-       set name = field.name|camel_to_under %}
57{%-       set kind = field.kind %}
58{%-       if kind|is_array_kind or kind|is_map_kind %}
59{{- from_proto.define(union_type, kind, name)}}
60{{- to_proto.define(union_type, kind, name)}}
61{%-       endif %}
62{%-     endfor %}
63{{- from_proto.define_union(union) }}
64{{- to_proto.define_union(union) }}
65{%- endfor %}
66
67{%- for interface in interfaces %}
68{%-   set mojom_type = interface|get_qualified_name_for_kind(flatten_nested_kind=True) %}
69{%-   set proto_type = "::mojolpm" ~ (interface|get_qualified_name_for_kind(flatten_nested_kind=True)) %}
70class {{interface.name}}Impl : public {{mojom_type}} {
71 public:
72  {{interface.name}}Impl() {
73  }
74
75{%-   for method in interface.methods -%}{{"\n"}}
76  void {{method.name}}({{ "\n" }}
77{%-     for param in method.parameters -%}
78{%-       set name = param.name|camel_to_under -%}
79{%-       set kind = param.kind -%}
80{%-       set param_mojom_type = kind|cpp_wrapper_param_type(add_same_module_namespaces=true) -%}
81{{ ",\n" if not loop.first }}      {{param_mojom_type}} {{name}}
82{%-     endfor -%}
83{%-     if method.response_parameters != None -%}
84{{ ",\n" if method.parameters }}    {{mojom_type}}::{{method.name}}Callback callback
85{%-     endif -%}
86) override {
87{%-     for param in method.parameters -%}
88{%-       set name = param.name|camel_to_under -%}
89{%-       set kind = param.kind -%}
90{{ util.add_instance(kind, name, False)|indent(2, True) }}
91{%-     endfor %}
92    mojolpmdbg("{{interface.name}}Impl.{{method.name}}\n");
93{%-       if method.response_parameters != None %}
94    mojolpm::GetContext()->AddInstance<{{mojom_type}}::{{method.name}}Callback>(std::move(callback));
95{%-       endif %}
96  }
97{%-   endfor %}
98};
99
100bool FromProto(uint32_t input,
101               ::mojo::PendingRemote<{{mojom_type}}>& output) {
102  bool result = false;
103  ::mojo::Remote<{{mojom_type}}>* output_ptr = nullptr;
104
105  if (input) {
106    output_ptr = mojolpm::GetContext()->GetInstance<::mojo::Remote<{{mojom_type}}>>(input);
107    if (output_ptr) {
108      // TODO(markbrand): look for a cleaner way to handle this check.
109      if (!output_ptr->is_bound() || (output_ptr->internal_state()
110          && output_ptr->internal_state()->has_pending_callbacks())) {
111        // not safe to Unbind, so fail instead.
112        output_ptr = nullptr;
113      } else {
114        output = output_ptr->Unbind();
115        result = true;
116      }
117    }
118  } else {
119    auto impl = std::make_unique<{{interface.name}}Impl>();
120    auto receiver_ptr =
121      std::make_unique<::mojo::Receiver<{{mojom_type}}>>(
122        impl.get(), output.InitWithNewPipeAndPassReceiver());
123    mojolpm::GetContext()->AddInstance(std::move(impl));
124    mojolpm::GetContext()->AddInstance(std::move(receiver_ptr));
125    result = true;
126  }
127
128  return result;
129}
130
131bool ToProto(::mojo::PendingRemote<{{mojom_type}}>&& input,
132             uint32_t& output) {
133  ::mojo::Remote<{{mojom_type}}> remote(std::move(input));
134  int next_id = NextId<{{mojom_type}}>();
135  output = mojolpm::GetContext()->AddInstance(next_id, std::move(remote));
136  return true;
137}
138
139bool FromProto(uint32_t input,
140               ::mojo::PendingReceiver<{{mojom_type}}>& output) {
141  ::mojo::Remote<{{mojom_type}}> remote = ::mojo::Remote<{{mojom_type}}>();
142  output = remote.BindNewPipeAndPassReceiver();
143  mojolpm::GetContext()->AddInstance(input, std::move(remote));
144  return true;
145}
146
147bool ToProto(::mojo::PendingReceiver<{{mojom_type}}>&& input,
148             uint32_t& output) {
149  // This should only get called from callbacks into the fuzzer, ie from one of
150  // the XxxImpls or from a return callback. Since that is the case, we want to
151  // bind the receiver and store it.
152
153  auto impl = std::make_unique<{{interface.name}}Impl>();
154  auto receiver_ptr = std::make_unique<::mojo::Receiver<{{mojom_type}}>>(
155    impl.get(), std::move(input));
156  mojolpm::GetContext()->AddInstance(std::move(impl));
157  output = mojolpm::GetContext()->AddInstance(std::move(receiver_ptr));
158  return true;
159}
160
161bool FromProto(uint32_t input,
162               ::mojo::PendingAssociatedRemote<{{mojom_type}}>& output) {
163  mojolpmdbg("PendingAssociatedRemote {{interface.name}}\n");
164  bool result = false;
165  ::mojo::AssociatedRemote<{{mojom_type}}>* output_ptr;
166
167  if (input) {
168    output_ptr = mojolpm::GetContext()->GetInstance<::mojo::AssociatedRemote<{{mojom_type}}>>(input);
169    if (output_ptr) {
170      // TODO(markbrand): look for a cleaner way to handle this check.
171      if (!output_ptr->is_bound() || (output_ptr->internal_state()
172          && output_ptr->internal_state()->has_pending_callbacks())) {
173        // not safe to Unbind, so fail instead.
174        output_ptr = nullptr;
175      } else {
176        output = output_ptr->Unbind();
177        result = true;
178      }
179    }
180  } else {
181    auto impl = std::make_unique<{{interface.name}}Impl>();
182    auto receiver_ptr =
183      std::make_unique<::mojo::AssociatedReceiver<{{mojom_type}}>>(
184        impl.get(), output.InitWithNewEndpointAndPassReceiver());
185    mojolpm::GetContext()->AddInstance(std::move(impl));
186    mojolpm::GetContext()->AddInstance(std::move(receiver_ptr));
187    result = true;
188  }
189
190  return result;
191}
192
193bool ToProto(::mojo::PendingAssociatedRemote<{{mojom_type}}>&& input,
194             uint32_t& output) {
195  ::mojo::AssociatedRemote<{{mojom_type}}> remote(std::move(input));
196  int next_id = NextId<{{mojom_type}}>();
197  output = mojolpm::GetContext()->AddInstance(next_id, std::move(remote));
198  return true;
199}
200
201bool FromProto(uint32_t input,
202               ::mojo::PendingAssociatedReceiver<{{mojom_type}}>& output) {
203  ::mojo::AssociatedRemote<{{mojom_type}}> remote = ::mojo::AssociatedRemote<{{mojom_type}}>();
204  output = remote.BindNewEndpointAndPassReceiver();
205  mojolpm::GetContext()->AddInstance(input, std::move(remote));
206  return true;
207}
208
209bool ToProto(::mojo::PendingAssociatedReceiver<{{mojom_type}}>&& input,
210             uint32_t& output) {
211  // This should only get called from callbacks into the fuzzer, ie from one of
212  // the XxxImpls or from a return callback. Since that is the case, we want to
213  // bind the receiver and store it.
214
215  auto impl = std::make_unique<{{interface.name}}Impl>();
216  auto receiver_ptr = std::make_unique<::mojo::AssociatedReceiver<{{mojom_type}}>>(
217    impl.get(), std::move(input));
218  mojolpm::GetContext()->AddInstance(std::move(impl));
219  output = mojolpm::GetContext()->AddInstance(std::move(receiver_ptr));
220  return true;
221}{{"\n"-}}
222
223{%-   for method in interface.methods %}
224{%-     set method_type = proto_type ~ "::" ~ interface.name ~ "_" ~ method.name %}
225{%-     for param in method.parameters %}
226{%-       set name = param.name|camel_to_under %}
227{%-       set kind = param.kind %}
228{%-       if kind|is_array_kind or kind|is_map_kind -%}
229{{ from_proto.define(method_type, kind, name) }}
230{{ to_proto.define(method_type, kind, name) }}
231{%-       endif %}
232{%-     endfor %}
233{%-   endfor %}
234{%-   for method in interface.methods %}
235{%-     if method.response_parameters != None %}
236{%-       set method_type = proto_type ~ "::" ~ interface.name ~ "_" ~ method.name ~ "Response" %}
237{%-       for param in method.response_parameters %}
238{%-         set name = param.name %}
239{%-         set kind = param.kind %}
240{%-         if kind|is_array_kind or kind|is_map_kind -%}
241{{- from_proto.define(method_type, kind, name)}}
242{{- to_proto.define(method_type, kind, name)}}
243{%-         endif %}
244{%-       endfor %}
245{%-     endif %}
246{%-   endfor %}
247{%- endfor %}
248
249{%- for interface in interfaces %}
250{%-   set mojom_type = interface|get_qualified_name_for_kind(flatten_nested_kind=True) %}
251{%-   set proto_type = "::mojolpm" ~ (interface|get_qualified_name_for_kind(flatten_nested_kind=True)) %}
252{%-   if interface.methods %}
253bool HandleRemoteAction(const {{proto_type}}::RemoteAction& input) {
254  bool result = true;
255
256  switch (input.method_case()) {
257{%-     for method in interface.methods %}
258    case {{proto_type}}::RemoteAction::k{{("m_" ~ method.name)|under_to_camel(digits_split=True)}}: {
259      result = HandleRemoteCall(input.id(), input.{{("m" ~ method.name)|camel_to_under}}());
260    } break;
261{%-     endfor %}
262    case {{proto_type}}::RemoteAction::kReset: {
263      mojolpm::GetContext()->GetAndRemoveInstance<::mojo::Remote<{{mojom_type}}>>(input.id());
264    } break;
265
266    default: {
267      result = false;
268    }
269  }
270
271  return result;
272}
273
274bool HandleAssociatedRemoteAction(const {{proto_type}}::AssociatedRemoteAction& input) {
275  bool result = true;
276
277  switch (input.method_case()) {
278{%-     for method in interface.methods %}
279    case {{proto_type}}::AssociatedRemoteAction::k{{("m_" ~ method.name)|under_to_camel(digits_split=True)}}: {
280      result = HandleAssociatedRemoteCall(input.id(), input.{{("m" ~ method.name)|camel_to_under}}());
281    } break;
282{%-     endfor %}
283    case {{proto_type}}::AssociatedRemoteAction::kReset: {
284      mojolpm::GetContext()->GetAndRemoveInstance<::mojo::AssociatedRemote<{{mojom_type}}>>(input.id());
285    } break;
286
287    default: {
288      result = false;
289    }
290  }
291
292  return result;
293}
294
295bool HandleReceiverAction(
296    const {{proto_type}}::ReceiverAction& input) {
297  bool result = true;
298  switch (input.response_case()) {
299{%-     for method in interface.methods %}
300    case {{proto_type}}::ReceiverAction::k{{("m_" ~ method.name ~ "_response")|under_to_camel(digits_split=True)}}: {
301      result = HandleResponse(input.id(), input.{{("m" ~ method.name ~ "_response")|camel_to_under}}());
302    } break;
303{%-     endfor %}
304
305    default: {
306      result = false;
307    }
308  }
309
310  return result;
311}{{"\n"-}}
312{%-     for method in interface.methods %}
313{%-       if method.response_parameters != None %}
314static void {{interface.name}}_{{method.name}}Callback(
315{%-         for param in method.response_parameters %}
316{%-           set name = param.name|camel_to_under %}
317{%-           set kind = param.kind %}
318{%-           set param_mojom_type = kind|cpp_wrapper_param_type(add_same_module_namespaces=true) %}{{ ',' if not loop.first }}
319  {{param_mojom_type}} param_{{name}}
320{%-         endfor -%}
321) {
322{%-         for param in method.response_parameters %}
323{%-           set name = param.name|camel_to_under %}
324{%-           set kind = param.kind %}
325{{ util.add_instance(kind, 'param_' ~ name, False) }}
326{%-         endfor %}
327  mojolpmdbg("{{interface.name}}.{{method.name}}Callback\n");
328}{{"\n"-}}
329{%-       endif %}
330template <typename T>
331bool HandleCall(uint32_t instance_id,
332                      const {{proto_type}}::{{interface.name}}_{{method.name}}& input) {
333  T* instance =
334    mojolpm::GetContext()->GetInstance<T>(instance_id);
335  if (!instance || !instance->is_bound() || !instance->is_connected()) {
336    return false;
337  }
338
339  mojolpm::GetContext()->StartDeserialization();
340
341  bool mojolpm_result = true;
342{%-       for param in method.parameters %}
343{%-         set name = param.name|camel_to_under %}
344{%-         set kind = param.kind %}
345{%-         set param_mojom_type = kind|cpp_wrapper_type(add_same_module_namespaces=true) %}
346{%-         set param_maybe_mojom_type = kind|cpp_wrapper_type(add_same_module_namespaces=true, ignore_nullable=True) %}
347  {{param_mojom_type}} local_{{name}};
348{%-         if kind|is_nullable_kind %}
349  {{param_maybe_mojom_type}} local_maybe_{{name}};
350{%-         endif %}
351{%-       endfor %}
352
353{%-       for param in method.parameters -%}
354{%-         set name = param.name|camel_to_under %}
355{%-         set kind = param.kind %}
356{%-         if not kind|is_nullable_kind %}
357  mojolpm_result &= FromProto(input.m_{{name}}(), local_{{name}});
358{%-         else %}
359  if (FromProto(input.m_{{name}}(), local_maybe_{{name}})) {
360    local_{{name}} = std::move(local_maybe_{{name}});
361  }
362{%-         endif %}
363{%-       endfor %}
364  if (mojolpm_result) {
365    (*instance)->{{method.name}}(
366{%-       for param in method.parameters -%}
367{%-         set name = param.name|camel_to_under %}
368{%-         set kind = param.kind %}
369      std::move(local_{{name}}){{ ',' if not loop.last }}
370{%-       endfor -%}
371{%-       if method.response_parameters != None -%}
372{{ ',' if method.parameters }}
373      base::BindOnce(&{{interface.name}}_{{method.name}}Callback));
374{%-       else -%}
375);
376{%-       endif -%}
377    mojolpm::GetContext()->EndDeserialization(Context::Rollback::kNoRollback);
378  } else {
379    mojolpm::GetContext()->EndDeserialization(Context::Rollback::kRollback);
380    mojolpmdbg("call failed\n");
381  }
382
383  return mojolpm_result;
384}
385
386bool HandleRemoteCall(
387    uint32_t instance_id, const {{proto_type}}::{{interface.name}}_{{method.name}}& input) {
388  mojolpmdbg("HandleRemoteCall({{interface.name}}::{{method.name}})\n");
389  return HandleCall<::mojo::Remote<{{mojom_type}}>>(instance_id, input);
390}
391
392bool HandleAssociatedRemoteCall(
393    uint32_t instance_id, const {{proto_type}}::{{interface.name}}_{{method.name}}& input) {
394  mojolpmdbg("HandleAssociatedRemoteCall({{interface.name}}::{{method.name}})\n");
395  return HandleCall<::mojo::AssociatedRemote<{{mojom_type}}>>(instance_id, input);
396}
397
398bool HandleResponse(
399    uint32_t callback_id, const {{proto_type}}::{{interface.name}}_{{method.name}}Response& input) {
400  mojolpmdbg("HandleResponse({{interface.name}}::{{method.name}})\n");
401{%-       if method.response_parameters == None %}
402  return true;
403{%-     else %}
404  auto mojolpm_callback = mojolpm::GetContext()->GetAndRemoveInstance<
405    {{mojom_type}}::{{method.name}}Callback>(callback_id);
406
407  if (!mojolpm_callback) {
408    return true;
409  }
410
411  mojolpm::GetContext()->StartDeserialization();
412
413  bool mojolpm_result = true;
414{%-         for param in method.response_parameters %}
415{%-           set name = param.name|camel_to_under %}
416{%-           set kind = param.kind %}
417{%-           set param_mojom_type = kind|cpp_wrapper_type(add_same_module_namespaces=true) %}
418{%-           set param_maybe_mojom_type = kind|cpp_wrapper_type(add_same_module_namespaces=true, ignore_nullable=True) %}
419  {{param_mojom_type}} local_{{name}};
420{%-           if kind|is_nullable_kind %}
421  {{param_maybe_mojom_type}} local_maybe_{{name}};
422{%-           endif %}
423{%-         endfor %}
424
425{%-         for param in method.response_parameters -%}
426{%-           set name = param.name|camel_to_under %}
427{%-           set kind = param.kind %}
428{%-           if not kind|is_nullable_kind %}
429  mojolpm_result &= FromProto(input.m_{{name}}(), local_{{name}});
430  mojolpmdbg("{{name}} %i\n", mojolpm_result);
431{%-           else %}
432  if (FromProto(input.m_{{name}}(), local_maybe_{{name}})) {
433    local_{{name}} = std::move(local_maybe_{{name}});
434  }
435{%-           endif %}
436{%-         endfor %}
437  if (mojolpm_result) {
438    std::move(*mojolpm_callback).Run(
439{%-         for param in method.response_parameters -%}
440{%-           set name = param.name|camel_to_under %}
441{%-           set kind = param.kind %}
442{%-           if kind|is_interface_kind or kind|is_associated_kind %}
443      {{kind|cpp_wrapper_param_type(add_same_module_namespaces=true)}}(std::move(local_{{name}})){{ ',' if not loop.last }}
444{%-           else %}
445      std::move(local_{{name}}){{ ',' if not loop.last }}
446{%-           endif %}
447{%-         endfor -%}
448);
449    mojolpm::GetContext()->EndDeserialization(Context::Rollback::kNoRollback);
450  } else {
451    mojolpm::GetContext()->EndDeserialization(Context::Rollback::kRollback);
452    mojolpm::GetContext()->AddInstance<
453      {{mojom_type}}::{{method.name}}Callback>(callback_id, std::move(*mojolpm_callback));
454  }
455
456  return mojolpm_result;
457{%-       endif %}
458}{{"\n"-}}
459{%-     endfor %}
460{%-   endif %}
461{%- endfor -%}
462}  // namespace mojolpm
463