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