1 // Copyright 2014 The Chromium OS 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 // This file provides internal implementation details of dispatching D-Bus
6 // method calls to a D-Bus object methods by reading the expected parameter
7 // values from D-Bus message buffer then invoking a native C++ callback with
8 // those parameters passed in. If the callback returns a value, that value is
9 // sent back to the caller of D-Bus method via the response message.
10 
11 // This is achieved by redirecting the parsing of parameter values from D-Bus
12 // message buffer to DBusParamReader helper class.
13 // DBusParamReader de-serializes the parameter values from the D-Bus message
14 // and calls the provided native C++ callback with those arguments.
15 // However it expects the callback with a simple signature like this:
16 //    void callback(Args...);
17 // The method handlers for DBusObject, on the other hand, have one of the
18 // following signatures:
19 //    void handler(Args...);
20 //    ReturnType handler(Args...);
21 //    bool handler(ErrorPtr* error, Args...);
22 //    void handler(std::unique_ptr<DBusMethodResponse<T1, T2,...>>, Args...);
23 //
24 // To make this all work, we craft a simple callback suitable for
25 // DBusParamReader using a lambda in DBusInvoker::Invoke() and redirect the call
26 // to the appropriate method handler using additional data captured by the
27 // lambda object.
28 
29 #ifndef LIBBRILLO_BRILLO_DBUS_DBUS_OBJECT_INTERNAL_IMPL_H_
30 #define LIBBRILLO_BRILLO_DBUS_DBUS_OBJECT_INTERNAL_IMPL_H_
31 
32 #include <memory>
33 #include <string>
34 #include <type_traits>
35 
36 #include <brillo/dbus/data_serialization.h>
37 #include <brillo/dbus/dbus_method_response.h>
38 #include <brillo/dbus/dbus_param_reader.h>
39 #include <brillo/dbus/dbus_param_writer.h>
40 #include <brillo/dbus/utils.h>
41 #include <brillo/errors/error.h>
42 #include <dbus/message.h>
43 
44 namespace brillo {
45 namespace dbus_utils {
46 
47 // This is an abstract base class to allow dispatching a native C++ callback
48 // method when a corresponding D-Bus method is called.
49 class DBusInterfaceMethodHandlerInterface {
50  public:
51   virtual ~DBusInterfaceMethodHandlerInterface() = default;
52 
53   // Returns true if the method has been handled synchronously (whether or not
54   // a success or error response message had been sent).
55   virtual void HandleMethod(dbus::MethodCall* method_call,
56                             ResponseSender sender) = 0;
57 };
58 
59 // This is a special implementation of DBusInterfaceMethodHandlerInterface for
60 // extremely simple synchronous method handlers that cannot possibly fail
61 // (that is, they do not send an error response).
62 // The handler is expected to take an arbitrary number of arguments of type
63 // |Args...| which can contain both inputs (passed in by value or constant
64 // reference) and outputs (passed in as pointers)...
65 // It may also return a single value of type R (or could be a void function if
66 // no return value is to be sent to the caller). If the handler has a return
67 // value, then it cannot have any output parameters in its parameter list.
68 // The signature of the callback handler is expected to be:
69 //    R(Args...)
70 template<typename R, typename... Args>
71 class SimpleDBusInterfaceMethodHandler
72     : public DBusInterfaceMethodHandlerInterface {
73  public:
74   // A constructor that takes a |handler| to be called when HandleMethod()
75   // virtual function is invoked.
SimpleDBusInterfaceMethodHandler(const base::Callback<R (Args...)> & handler)76   explicit SimpleDBusInterfaceMethodHandler(
77       const base::Callback<R(Args...)>& handler) : handler_(handler) {}
78 
HandleMethod(dbus::MethodCall * method_call,ResponseSender sender)79   void HandleMethod(dbus::MethodCall* method_call,
80                     ResponseSender sender) override {
81     DBusMethodResponse<R> method_response(method_call, sender);
82     auto invoke_callback = [this, &method_response](const Args&... args) {
83       method_response.Return(handler_.Run(args...));
84     };
85 
86     ErrorPtr param_reader_error;
87     dbus::MessageReader reader(method_call);
88     // The handler is expected a return value, don't allow output parameters.
89     if (!DBusParamReader<false, Args...>::Invoke(
90             invoke_callback, &reader, &param_reader_error)) {
91       // Error parsing method arguments.
92       method_response.ReplyWithError(param_reader_error.get());
93     }
94   }
95 
96  private:
97   // C++ callback to be called when a DBus method is dispatched.
98   base::Callback<R(Args...)> handler_;
99   DISALLOW_COPY_AND_ASSIGN(SimpleDBusInterfaceMethodHandler);
100 };
101 
102 // Specialization of SimpleDBusInterfaceMethodHandlerInterface for
103 // R=void (methods with no return values).
104 template<typename... Args>
105 class SimpleDBusInterfaceMethodHandler<void, Args...>
106     : public DBusInterfaceMethodHandlerInterface {
107  public:
108   // A constructor that takes a |handler| to be called when HandleMethod()
109   // virtual function is invoked.
SimpleDBusInterfaceMethodHandler(const base::Callback<void (Args...)> & handler)110   explicit SimpleDBusInterfaceMethodHandler(
111       const base::Callback<void(Args...)>& handler) : handler_(handler) {}
112 
HandleMethod(dbus::MethodCall * method_call,ResponseSender sender)113   void HandleMethod(dbus::MethodCall* method_call,
114                     ResponseSender sender) override {
115     DBusMethodResponseBase method_response(method_call, sender);
116     auto invoke_callback = [this, &method_response](const Args&... args) {
117       handler_.Run(args...);
118       auto response = method_response.CreateCustomResponse();
119       dbus::MessageWriter writer(response.get());
120       DBusParamWriter::AppendDBusOutParams(&writer, args...);
121       method_response.SendRawResponse(std::move(response));
122     };
123 
124     ErrorPtr param_reader_error;
125     dbus::MessageReader reader(method_call);
126     if (!DBusParamReader<true, Args...>::Invoke(
127             invoke_callback, &reader, &param_reader_error)) {
128       // Error parsing method arguments.
129       method_response.ReplyWithError(param_reader_error.get());
130     }
131   }
132 
133  private:
134   // C++ callback to be called when a DBus method is dispatched.
135   base::Callback<void(Args...)> handler_;
136   DISALLOW_COPY_AND_ASSIGN(SimpleDBusInterfaceMethodHandler);
137 };
138 
139 // An implementation of DBusInterfaceMethodHandlerInterface for simple
140 // synchronous method handlers that may fail and return an error response
141 // message.
142 // The handler is expected to take an arbitrary number of arguments of type
143 // |Args...| which can contain both inputs (passed in by value or constant
144 // reference) and outputs (passed in as pointers)...
145 // In case of an error, the handler must return false and set the error details
146 // into the |error| object provided.
147 // The signature of the callback handler is expected to be:
148 //    bool(ErrorPtr*, Args...)
149 template<typename... Args>
150 class SimpleDBusInterfaceMethodHandlerWithError
151     : public DBusInterfaceMethodHandlerInterface {
152  public:
153   // A constructor that takes a |handler| to be called when HandleMethod()
154   // virtual function is invoked.
SimpleDBusInterfaceMethodHandlerWithError(const base::Callback<bool (ErrorPtr *,Args...)> & handler)155   explicit SimpleDBusInterfaceMethodHandlerWithError(
156       const base::Callback<bool(ErrorPtr*, Args...)>& handler)
157       : handler_(handler) {}
158 
HandleMethod(dbus::MethodCall * method_call,ResponseSender sender)159   void HandleMethod(dbus::MethodCall* method_call,
160                     ResponseSender sender) override {
161     DBusMethodResponseBase method_response(method_call, sender);
162     auto invoke_callback = [this, &method_response](const Args&... args) {
163       ErrorPtr error;
164       if (!handler_.Run(&error, args...)) {
165         method_response.ReplyWithError(error.get());
166       } else {
167         auto response = method_response.CreateCustomResponse();
168         dbus::MessageWriter writer(response.get());
169         DBusParamWriter::AppendDBusOutParams(&writer, args...);
170         method_response.SendRawResponse(std::move(response));
171       }
172     };
173 
174     ErrorPtr param_reader_error;
175     dbus::MessageReader reader(method_call);
176     if (!DBusParamReader<true, Args...>::Invoke(
177             invoke_callback, &reader, &param_reader_error)) {
178       // Error parsing method arguments.
179       method_response.ReplyWithError(param_reader_error.get());
180     }
181   }
182 
183  private:
184   // C++ callback to be called when a DBus method is dispatched.
185   base::Callback<bool(ErrorPtr*, Args...)> handler_;
186   DISALLOW_COPY_AND_ASSIGN(SimpleDBusInterfaceMethodHandlerWithError);
187 };
188 
189 // An implementation of SimpleDBusInterfaceMethodHandlerWithErrorAndMessage
190 // which is almost identical to SimpleDBusInterfaceMethodHandlerWithError with
191 // the exception that the callback takes an additional parameter - raw D-Bus
192 // message used to invoke the method handler.
193 // The handler is expected to take an arbitrary number of arguments of type
194 // |Args...| which can contain both inputs (passed in by value or constant
195 // reference) and outputs (passed in as pointers)...
196 // In case of an error, the handler must return false and set the error details
197 // into the |error| object provided.
198 // The signature of the callback handler is expected to be:
199 //    bool(ErrorPtr*, dbus::Message*, Args...)
200 template<typename... Args>
201 class SimpleDBusInterfaceMethodHandlerWithErrorAndMessage
202     : public DBusInterfaceMethodHandlerInterface {
203  public:
204   // A constructor that takes a |handler| to be called when HandleMethod()
205   // virtual function is invoked.
SimpleDBusInterfaceMethodHandlerWithErrorAndMessage(const base::Callback<bool (ErrorPtr *,dbus::Message *,Args...)> & handler)206   explicit SimpleDBusInterfaceMethodHandlerWithErrorAndMessage(
207       const base::Callback<bool(ErrorPtr*, dbus::Message*, Args...)>& handler)
208       : handler_(handler) {}
209 
HandleMethod(dbus::MethodCall * method_call,ResponseSender sender)210   void HandleMethod(dbus::MethodCall* method_call,
211                     ResponseSender sender) override {
212     DBusMethodResponseBase method_response(method_call, sender);
213     auto invoke_callback =
214         [this, method_call, &method_response](const Args&... args) {
215       ErrorPtr error;
216       if (!handler_.Run(&error, method_call, args...)) {
217         method_response.ReplyWithError(error.get());
218       } else {
219         auto response = method_response.CreateCustomResponse();
220         dbus::MessageWriter writer(response.get());
221         DBusParamWriter::AppendDBusOutParams(&writer, args...);
222         method_response.SendRawResponse(std::move(response));
223       }
224     };
225 
226     ErrorPtr param_reader_error;
227     dbus::MessageReader reader(method_call);
228     if (!DBusParamReader<true, Args...>::Invoke(
229             invoke_callback, &reader, &param_reader_error)) {
230       // Error parsing method arguments.
231       method_response.ReplyWithError(param_reader_error.get());
232     }
233   }
234 
235  private:
236   // C++ callback to be called when a DBus method is dispatched.
237   base::Callback<bool(ErrorPtr*, dbus::Message*, Args...)> handler_;
238   DISALLOW_COPY_AND_ASSIGN(SimpleDBusInterfaceMethodHandlerWithErrorAndMessage);
239 };
240 
241 // An implementation of DBusInterfaceMethodHandlerInterface for more generic
242 // (and possibly asynchronous) method handlers. The handler is expected
243 // to take an arbitrary number of input arguments of type |Args...| and send
244 // the method call response (including a possible error response) using
245 // the provided DBusMethodResponse object.
246 // The signature of the callback handler is expected to be:
247 //    void(std::unique_ptr<DBusMethodResponse<RetTypes...>, Args...)
248 template<typename Response, typename... Args>
249 class DBusInterfaceMethodHandler : public DBusInterfaceMethodHandlerInterface {
250  public:
251   // A constructor that takes a |handler| to be called when HandleMethod()
252   // virtual function is invoked.
DBusInterfaceMethodHandler(const base::Callback<void (std::unique_ptr<Response>,Args...)> & handler)253   explicit DBusInterfaceMethodHandler(
254       const base::Callback<void(std::unique_ptr<Response>, Args...)>& handler)
255       : handler_(handler) {}
256 
257   // This method forwards the call to |handler_| after extracting the required
258   // arguments from the DBus message buffer specified in |method_call|.
259   // The output parameters of |handler_| (if any) are sent back to the called.
HandleMethod(dbus::MethodCall * method_call,ResponseSender sender)260   void HandleMethod(dbus::MethodCall* method_call,
261                     ResponseSender sender) override {
262     auto invoke_callback = [this, method_call, &sender](const Args&... args) {
263       std::unique_ptr<Response> response(new Response(method_call, sender));
264       handler_.Run(std::move(response), args...);
265     };
266 
267     ErrorPtr param_reader_error;
268     dbus::MessageReader reader(method_call);
269     if (!DBusParamReader<false, Args...>::Invoke(
270             invoke_callback, &reader, &param_reader_error)) {
271       // Error parsing method arguments.
272       DBusMethodResponseBase method_response(method_call, sender);
273       method_response.ReplyWithError(param_reader_error.get());
274     }
275   }
276 
277  private:
278   // C++ callback to be called when a D-Bus method is dispatched.
279   base::Callback<void(std::unique_ptr<Response>, Args...)> handler_;
280 
281   DISALLOW_COPY_AND_ASSIGN(DBusInterfaceMethodHandler);
282 };
283 
284 // An implementation of DBusInterfaceMethodHandlerWithMessage which is almost
285 // identical to AddSimpleMethodHandlerWithError with the exception that the
286 // callback takes an additional parameter - raw D-Bus message.
287 // The handler is expected to take an arbitrary number of input arguments of
288 // type |Args...| and send the method call response (including a possible error
289 // response) using the provided DBusMethodResponse object.
290 // The signature of the callback handler is expected to be:
291 //    void(std::unique_ptr<DBusMethodResponse<RetTypes...>, dbus::Message*,
292 //         Args...);
293 template<typename Response, typename... Args>
294 class DBusInterfaceMethodHandlerWithMessage
295     : public DBusInterfaceMethodHandlerInterface {
296  public:
297   // A constructor that takes a |handler| to be called when HandleMethod()
298   // virtual function is invoked.
DBusInterfaceMethodHandlerWithMessage(const base::Callback<void (std::unique_ptr<Response>,dbus::Message *,Args...)> & handler)299   explicit DBusInterfaceMethodHandlerWithMessage(
300       const base::Callback<void(std::unique_ptr<Response>, dbus::Message*,
301                                 Args...)>& handler)
302       : handler_(handler) {}
303 
304   // This method forwards the call to |handler_| after extracting the required
305   // arguments from the DBus message buffer specified in |method_call|.
306   // The output parameters of |handler_| (if any) are sent back to the called.
HandleMethod(dbus::MethodCall * method_call,ResponseSender sender)307   void HandleMethod(dbus::MethodCall* method_call,
308                     ResponseSender sender) override {
309     auto invoke_callback = [this, method_call, &sender](const Args&... args) {
310       std::unique_ptr<Response> response(new Response(method_call, sender));
311       handler_.Run(std::move(response), method_call, args...);
312     };
313 
314     ErrorPtr param_reader_error;
315     dbus::MessageReader reader(method_call);
316     if (!DBusParamReader<false, Args...>::Invoke(
317             invoke_callback, &reader, &param_reader_error)) {
318       // Error parsing method arguments.
319       DBusMethodResponseBase method_response(method_call, sender);
320       method_response.ReplyWithError(param_reader_error.get());
321     }
322   }
323 
324  private:
325   // C++ callback to be called when a D-Bus method is dispatched.
326   base::Callback<void(std::unique_ptr<Response>,
327                       dbus::Message*, Args...)> handler_;
328 
329   DISALLOW_COPY_AND_ASSIGN(DBusInterfaceMethodHandlerWithMessage);
330 };
331 
332 // An implementation of DBusInterfaceMethodHandlerInterface that has custom
333 // processing of both input and output parameters. This class is used by
334 // DBusObject::AddRawMethodHandler and expects the callback to be of the
335 // following signature:
336 //    void(dbus::MethodCall*, ResponseSender)
337 // It will be up to the callback to parse the input parameters from the
338 // message buffer and construct the D-Bus Response object.
339 class RawDBusInterfaceMethodHandler
340     : public DBusInterfaceMethodHandlerInterface {
341  public:
342   // A constructor that takes a |handler| to be called when HandleMethod()
343   // virtual function is invoked.
RawDBusInterfaceMethodHandler(const base::Callback<void (dbus::MethodCall *,ResponseSender)> & handler)344   RawDBusInterfaceMethodHandler(
345       const base::Callback<void(dbus::MethodCall*, ResponseSender)>& handler)
346       : handler_(handler) {}
347 
HandleMethod(dbus::MethodCall * method_call,ResponseSender sender)348   void HandleMethod(dbus::MethodCall* method_call,
349                     ResponseSender sender) override {
350     handler_.Run(method_call, sender);
351   }
352 
353  private:
354   // C++ callback to be called when a D-Bus method is dispatched.
355   base::Callback<void(dbus::MethodCall*, ResponseSender)> handler_;
356 
357   DISALLOW_COPY_AND_ASSIGN(RawDBusInterfaceMethodHandler);
358 };
359 
360 }  // namespace dbus_utils
361 }  // namespace brillo
362 
363 #endif  // LIBBRILLO_BRILLO_DBUS_DBUS_OBJECT_INTERNAL_IMPL_H_
364