| // Copyright 2014 The Chromium OS Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| // This file provides internal implementation details of dispatching D-Bus |
| // method calls to a D-Bus object methods by reading the expected parameter |
| // values from D-Bus message buffer then invoking a native C++ callback with |
| // those parameters passed in. If the callback returns a value, that value is |
| // sent back to the caller of D-Bus method via the response message. |
| |
| // This is achieved by redirecting the parsing of parameter values from D-Bus |
| // message buffer to DBusParamReader helper class. |
| // DBusParamReader de-serializes the parameter values from the D-Bus message |
| // and calls the provided native C++ callback with those arguments. |
| // However it expects the callback with a simple signature like this: |
| // void callback(Args...); |
| // The method handlers for DBusObject, on the other hand, have one of the |
| // following signatures: |
| // void handler(Args...); |
| // ReturnType handler(Args...); |
| // bool handler(ErrorPtr* error, Args...); |
| // void handler(std::unique_ptr<DBusMethodResponse<T1, T2,...>>, Args...); |
| // |
| // To make this all work, we craft a simple callback suitable for |
| // DBusParamReader using a lambda in DBusInvoker::Invoke() and redirect the call |
| // to the appropriate method handler using additional data captured by the |
| // lambda object. |
| |
| #ifndef LIBCHROMEOS_CHROMEOS_DBUS_DBUS_OBJECT_INTERNAL_IMPL_H_ |
| #define LIBCHROMEOS_CHROMEOS_DBUS_DBUS_OBJECT_INTERNAL_IMPL_H_ |
| |
| #include <memory> |
| #include <string> |
| #include <type_traits> |
| |
| #include <chromeos/dbus/data_serialization.h> |
| #include <chromeos/dbus/dbus_method_response.h> |
| #include <chromeos/dbus/dbus_param_reader.h> |
| #include <chromeos/dbus/dbus_param_writer.h> |
| #include <chromeos/dbus/utils.h> |
| #include <chromeos/errors/error.h> |
| #include <dbus/message.h> |
| |
| namespace chromeos { |
| namespace dbus_utils { |
| |
| // This is an abstract base class to allow dispatching a native C++ callback |
| // method when a corresponding D-Bus method is called. |
| class DBusInterfaceMethodHandlerInterface { |
| public: |
| virtual ~DBusInterfaceMethodHandlerInterface() = default; |
| |
| // Returns true if the method has been handled synchronously (whether or not |
| // a success or error response message had been sent). |
| virtual void HandleMethod(dbus::MethodCall* method_call, |
| ResponseSender sender) = 0; |
| }; |
| |
| // This is a special implementation of DBusInterfaceMethodHandlerInterface for |
| // extremely simple synchronous method handlers that cannot possibly fail |
| // (that is, they do not send an error response). |
| // The handler is expected to take an arbitrary number of arguments of type |
| // |Args...| which can contain both inputs (passed in by value or constant |
| // reference) and outputs (passed in as pointers)... |
| // It may also return a single value of type R (or could be a void function if |
| // no return value is to be sent to the caller). If the handler has a return |
| // value, then it cannot have any output parameters in its parameter list. |
| // The signature of the callback handler is expected to be: |
| // R(Args...) |
| template<typename R, typename... Args> |
| class SimpleDBusInterfaceMethodHandler |
| : public DBusInterfaceMethodHandlerInterface { |
| public: |
| // A constructor that takes a |handler| to be called when HandleMethod() |
| // virtual function is invoked. |
| explicit SimpleDBusInterfaceMethodHandler( |
| const base::Callback<R(Args...)>& handler) : handler_(handler) {} |
| |
| void HandleMethod(dbus::MethodCall* method_call, |
| ResponseSender sender) override { |
| DBusMethodResponse<R> method_response(method_call, sender); |
| auto invoke_callback = [this, &method_response](const Args&... args) { |
| method_response.Return(handler_.Run(args...)); |
| }; |
| |
| ErrorPtr param_reader_error; |
| dbus::MessageReader reader(method_call); |
| // The handler is expected a return value, don't allow output parameters. |
| if (!DBusParamReader<false, Args...>::Invoke( |
| invoke_callback, &reader, ¶m_reader_error)) { |
| // Error parsing method arguments. |
| method_response.ReplyWithError(param_reader_error.get()); |
| } |
| } |
| |
| private: |
| // C++ callback to be called when a DBus method is dispatched. |
| base::Callback<R(Args...)> handler_; |
| DISALLOW_COPY_AND_ASSIGN(SimpleDBusInterfaceMethodHandler); |
| }; |
| |
| // Specialization of SimpleDBusInterfaceMethodHandlerInterface for |
| // R=void (methods with no return values). |
| template<typename... Args> |
| class SimpleDBusInterfaceMethodHandler<void, Args...> |
| : public DBusInterfaceMethodHandlerInterface { |
| public: |
| // A constructor that takes a |handler| to be called when HandleMethod() |
| // virtual function is invoked. |
| explicit SimpleDBusInterfaceMethodHandler( |
| const base::Callback<void(Args...)>& handler) : handler_(handler) {} |
| |
| void HandleMethod(dbus::MethodCall* method_call, |
| ResponseSender sender) override { |
| DBusMethodResponseBase method_response(method_call, sender); |
| auto invoke_callback = [this, &method_response](const Args&... args) { |
| handler_.Run(args...); |
| auto response = method_response.CreateCustomResponse(); |
| dbus::MessageWriter writer(response.get()); |
| DBusParamWriter::AppendDBusOutParams(&writer, args...); |
| method_response.SendRawResponse(std::move(response)); |
| }; |
| |
| ErrorPtr param_reader_error; |
| dbus::MessageReader reader(method_call); |
| if (!DBusParamReader<true, Args...>::Invoke( |
| invoke_callback, &reader, ¶m_reader_error)) { |
| // Error parsing method arguments. |
| method_response.ReplyWithError(param_reader_error.get()); |
| } |
| } |
| |
| private: |
| // C++ callback to be called when a DBus method is dispatched. |
| base::Callback<void(Args...)> handler_; |
| DISALLOW_COPY_AND_ASSIGN(SimpleDBusInterfaceMethodHandler); |
| }; |
| |
| // An implementation of DBusInterfaceMethodHandlerInterface for simple |
| // synchronous method handlers that may fail and return an error response |
| // message. |
| // The handler is expected to take an arbitrary number of arguments of type |
| // |Args...| which can contain both inputs (passed in by value or constant |
| // reference) and outputs (passed in as pointers)... |
| // In case of an error, the handler must return false and set the error details |
| // into the |error| object provided. |
| // The signature of the callback handler is expected to be: |
| // bool(ErrorPtr*, Args...) |
| template<typename... Args> |
| class SimpleDBusInterfaceMethodHandlerWithError |
| : public DBusInterfaceMethodHandlerInterface { |
| public: |
| // A constructor that takes a |handler| to be called when HandleMethod() |
| // virtual function is invoked. |
| explicit SimpleDBusInterfaceMethodHandlerWithError( |
| const base::Callback<bool(ErrorPtr*, Args...)>& handler) |
| : handler_(handler) {} |
| |
| void HandleMethod(dbus::MethodCall* method_call, |
| ResponseSender sender) override { |
| DBusMethodResponseBase method_response(method_call, sender); |
| auto invoke_callback = [this, &method_response](const Args&... args) { |
| ErrorPtr error; |
| if (!handler_.Run(&error, args...)) { |
| method_response.ReplyWithError(error.get()); |
| } else { |
| auto response = method_response.CreateCustomResponse(); |
| dbus::MessageWriter writer(response.get()); |
| DBusParamWriter::AppendDBusOutParams(&writer, args...); |
| method_response.SendRawResponse(std::move(response)); |
| } |
| }; |
| |
| ErrorPtr param_reader_error; |
| dbus::MessageReader reader(method_call); |
| if (!DBusParamReader<true, Args...>::Invoke( |
| invoke_callback, &reader, ¶m_reader_error)) { |
| // Error parsing method arguments. |
| method_response.ReplyWithError(param_reader_error.get()); |
| } |
| } |
| |
| private: |
| // C++ callback to be called when a DBus method is dispatched. |
| base::Callback<bool(ErrorPtr*, Args...)> handler_; |
| DISALLOW_COPY_AND_ASSIGN(SimpleDBusInterfaceMethodHandlerWithError); |
| }; |
| |
| // An implementation of SimpleDBusInterfaceMethodHandlerWithErrorAndMessage |
| // which is almost identical to SimpleDBusInterfaceMethodHandlerWithError with |
| // the exception that the callback takes an additional parameter - raw D-Bus |
| // message used to invoke the method handler. |
| // The handler is expected to take an arbitrary number of arguments of type |
| // |Args...| which can contain both inputs (passed in by value or constant |
| // reference) and outputs (passed in as pointers)... |
| // In case of an error, the handler must return false and set the error details |
| // into the |error| object provided. |
| // The signature of the callback handler is expected to be: |
| // bool(ErrorPtr*, dbus::Message*, Args...) |
| template<typename... Args> |
| class SimpleDBusInterfaceMethodHandlerWithErrorAndMessage |
| : public DBusInterfaceMethodHandlerInterface { |
| public: |
| // A constructor that takes a |handler| to be called when HandleMethod() |
| // virtual function is invoked. |
| explicit SimpleDBusInterfaceMethodHandlerWithErrorAndMessage( |
| const base::Callback<bool(ErrorPtr*, dbus::Message*, Args...)>& handler) |
| : handler_(handler) {} |
| |
| void HandleMethod(dbus::MethodCall* method_call, |
| ResponseSender sender) override { |
| DBusMethodResponseBase method_response(method_call, sender); |
| auto invoke_callback = |
| [this, method_call, &method_response](const Args&... args) { |
| ErrorPtr error; |
| if (!handler_.Run(&error, method_call, args...)) { |
| method_response.ReplyWithError(error.get()); |
| } else { |
| auto response = method_response.CreateCustomResponse(); |
| dbus::MessageWriter writer(response.get()); |
| DBusParamWriter::AppendDBusOutParams(&writer, args...); |
| method_response.SendRawResponse(std::move(response)); |
| } |
| }; |
| |
| ErrorPtr param_reader_error; |
| dbus::MessageReader reader(method_call); |
| if (!DBusParamReader<true, Args...>::Invoke( |
| invoke_callback, &reader, ¶m_reader_error)) { |
| // Error parsing method arguments. |
| method_response.ReplyWithError(param_reader_error.get()); |
| } |
| } |
| |
| private: |
| // C++ callback to be called when a DBus method is dispatched. |
| base::Callback<bool(ErrorPtr*, dbus::Message*, Args...)> handler_; |
| DISALLOW_COPY_AND_ASSIGN(SimpleDBusInterfaceMethodHandlerWithErrorAndMessage); |
| }; |
| |
| // An implementation of DBusInterfaceMethodHandlerInterface for more generic |
| // (and possibly asynchronous) method handlers. The handler is expected |
| // to take an arbitrary number of input arguments of type |Args...| and send |
| // the method call response (including a possible error response) using |
| // the provided DBusMethodResponse object. |
| // The signature of the callback handler is expected to be: |
| // void(std::unique_ptr<DBusMethodResponse<RetTypes...>, Args...) |
| template<typename Response, typename... Args> |
| class DBusInterfaceMethodHandler : public DBusInterfaceMethodHandlerInterface { |
| public: |
| // A constructor that takes a |handler| to be called when HandleMethod() |
| // virtual function is invoked. |
| explicit DBusInterfaceMethodHandler( |
| const base::Callback<void(std::unique_ptr<Response>, Args...)>& handler) |
| : handler_(handler) {} |
| |
| // This method forwards the call to |handler_| after extracting the required |
| // arguments from the DBus message buffer specified in |method_call|. |
| // The output parameters of |handler_| (if any) are sent back to the called. |
| void HandleMethod(dbus::MethodCall* method_call, |
| ResponseSender sender) override { |
| auto invoke_callback = [this, method_call, &sender](const Args&... args) { |
| std::unique_ptr<Response> response(new Response(method_call, sender)); |
| handler_.Run(std::move(response), args...); |
| }; |
| |
| ErrorPtr param_reader_error; |
| dbus::MessageReader reader(method_call); |
| if (!DBusParamReader<false, Args...>::Invoke( |
| invoke_callback, &reader, ¶m_reader_error)) { |
| // Error parsing method arguments. |
| DBusMethodResponseBase method_response(method_call, sender); |
| method_response.ReplyWithError(param_reader_error.get()); |
| } |
| } |
| |
| private: |
| // C++ callback to be called when a D-Bus method is dispatched. |
| base::Callback<void(std::unique_ptr<Response>, Args...)> handler_; |
| |
| DISALLOW_COPY_AND_ASSIGN(DBusInterfaceMethodHandler); |
| }; |
| |
| // An implementation of DBusInterfaceMethodHandlerWithMessage which is almost |
| // identical to AddSimpleMethodHandlerWithError with the exception that the |
| // callback takes an additional parameter - raw D-Bus message. |
| // The handler is expected to take an arbitrary number of input arguments of |
| // type |Args...| and send the method call response (including a possible error |
| // response) using the provided DBusMethodResponse object. |
| // The signature of the callback handler is expected to be: |
| // void(std::unique_ptr<DBusMethodResponse<RetTypes...>, dbus::Message*, |
| // Args...); |
| template<typename Response, typename... Args> |
| class DBusInterfaceMethodHandlerWithMessage |
| : public DBusInterfaceMethodHandlerInterface { |
| public: |
| // A constructor that takes a |handler| to be called when HandleMethod() |
| // virtual function is invoked. |
| explicit DBusInterfaceMethodHandlerWithMessage( |
| const base::Callback<void(std::unique_ptr<Response>, dbus::Message*, |
| Args...)>& handler) |
| : handler_(handler) {} |
| |
| // This method forwards the call to |handler_| after extracting the required |
| // arguments from the DBus message buffer specified in |method_call|. |
| // The output parameters of |handler_| (if any) are sent back to the called. |
| void HandleMethod(dbus::MethodCall* method_call, |
| ResponseSender sender) override { |
| auto invoke_callback = [this, method_call, &sender](const Args&... args) { |
| std::unique_ptr<Response> response(new Response(method_call, sender)); |
| handler_.Run(std::move(response), method_call, args...); |
| }; |
| |
| ErrorPtr param_reader_error; |
| dbus::MessageReader reader(method_call); |
| if (!DBusParamReader<false, Args...>::Invoke( |
| invoke_callback, &reader, ¶m_reader_error)) { |
| // Error parsing method arguments. |
| DBusMethodResponseBase method_response(method_call, sender); |
| method_response.ReplyWithError(param_reader_error.get()); |
| } |
| } |
| |
| private: |
| // C++ callback to be called when a D-Bus method is dispatched. |
| base::Callback<void(std::unique_ptr<Response>, |
| dbus::Message*, Args...)> handler_; |
| |
| DISALLOW_COPY_AND_ASSIGN(DBusInterfaceMethodHandlerWithMessage); |
| }; |
| |
| // An implementation of DBusInterfaceMethodHandlerInterface that has custom |
| // processing of both input and output parameters. This class is used by |
| // DBusObject::AddRawMethodHandler and expects the callback to be of the |
| // following signature: |
| // void(dbus::MethodCall*, ResponseSender) |
| // It will be up to the callback to parse the input parameters from the |
| // message buffer and construct the D-Bus Response object. |
| class RawDBusInterfaceMethodHandler |
| : public DBusInterfaceMethodHandlerInterface { |
| public: |
| // A constructor that takes a |handler| to be called when HandleMethod() |
| // virtual function is invoked. |
| RawDBusInterfaceMethodHandler( |
| const base::Callback<void(dbus::MethodCall*, ResponseSender)>& handler) |
| : handler_(handler) {} |
| |
| void HandleMethod(dbus::MethodCall* method_call, |
| ResponseSender sender) override { |
| handler_.Run(method_call, sender); |
| } |
| |
| private: |
| // C++ callback to be called when a D-Bus method is dispatched. |
| base::Callback<void(dbus::MethodCall*, ResponseSender)> handler_; |
| |
| DISALLOW_COPY_AND_ASSIGN(RawDBusInterfaceMethodHandler); |
| }; |
| |
| } // namespace dbus_utils |
| } // namespace chromeos |
| |
| #endif // LIBCHROMEOS_CHROMEOS_DBUS_DBUS_OBJECT_INTERNAL_IMPL_H_ |