You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
365 lines
15 KiB
365 lines
15 KiB
// 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 LIBBRILLO_BRILLO_DBUS_DBUS_OBJECT_INTERNAL_IMPL_H_
|
|
#define LIBBRILLO_BRILLO_DBUS_DBUS_OBJECT_INTERNAL_IMPL_H_
|
|
|
|
#include <memory>
|
|
#include <string>
|
|
#include <type_traits>
|
|
#include <utility>
|
|
|
|
#include <brillo/dbus/data_serialization.h>
|
|
#include <brillo/dbus/dbus_method_response.h>
|
|
#include <brillo/dbus/dbus_param_reader.h>
|
|
#include <brillo/dbus/dbus_param_writer.h>
|
|
#include <brillo/dbus/utils.h>
|
|
#include <brillo/errors/error.h>
|
|
#include <dbus/message.h>
|
|
|
|
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<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 brillo
|
|
|
|
#endif // LIBBRILLO_BRILLO_DBUS_DBUS_OBJECT_INTERNAL_IMPL_H_
|