Home | History | Annotate | Download | only in dbus
      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.
     76   explicit SimpleDBusInterfaceMethodHandler(
     77       const base::Callback<R(Args...)>& handler) : handler_(handler) {}
     78 
     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.
    110   explicit SimpleDBusInterfaceMethodHandler(
    111       const base::Callback<void(Args...)>& handler) : handler_(handler) {}
    112 
    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.
    155   explicit SimpleDBusInterfaceMethodHandlerWithError(
    156       const base::Callback<bool(ErrorPtr*, Args...)>& handler)
    157       : handler_(handler) {}
    158 
    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.
    206   explicit SimpleDBusInterfaceMethodHandlerWithErrorAndMessage(
    207       const base::Callback<bool(ErrorPtr*, dbus::Message*, Args...)>& handler)
    208       : handler_(handler) {}
    209 
    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.
    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.
    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.
    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.
    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.
    344   explicit RawDBusInterfaceMethodHandler(
    345       const base::Callback<void(dbus::MethodCall*, ResponseSender)>& handler)
    346       : handler_(handler) {}
    347 
    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