// 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>, 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 LIBBRILLO_BRILLO_DBUS_DBUS_OBJECT_INTERNAL_IMPL_H_ #define LIBBRILLO_BRILLO_DBUS_DBUS_OBJECT_INTERNAL_IMPL_H_ #include #include #include #include #include #include #include #include #include #include #include namespace brillo { 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 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& handler) : handler_(handler) {} void HandleMethod(::dbus::MethodCall* method_call, ResponseSender sender) override { DBusMethodResponse 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::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 handler_; DISALLOW_COPY_AND_ASSIGN(SimpleDBusInterfaceMethodHandler); }; // Specialization of SimpleDBusInterfaceMethodHandlerInterface for // R=void (methods with no return values). template 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& 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::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 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 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& 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::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 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 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& 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::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 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, Args...) template 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, 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(new Response(method_call, sender)); handler_.Run(std::move(response), args...); }; ErrorPtr param_reader_error; ::dbus::MessageReader reader(method_call); if (!DBusParamReader::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, 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, dbus::Message*, // Args...); template 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, ::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(new Response(method_call, sender)); handler_.Run(std::move(response), method_call, args...); }; ErrorPtr param_reader_error; ::dbus::MessageReader reader(method_call); if (!DBusParamReader::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, ::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& 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 handler_; DISALLOW_COPY_AND_ASSIGN(RawDBusInterfaceMethodHandler); }; } // namespace dbus_utils } // namespace brillo #endif // LIBBRILLO_BRILLO_DBUS_DBUS_OBJECT_INTERNAL_IMPL_H_