aboutsummaryrefslogtreecommitdiffstats
path: root/brillo/dbus/dbus_param_reader.h
diff options
context:
space:
mode:
Diffstat (limited to 'brillo/dbus/dbus_param_reader.h')
-rw-r--r--brillo/dbus/dbus_param_reader.h165
1 files changed, 165 insertions, 0 deletions
diff --git a/brillo/dbus/dbus_param_reader.h b/brillo/dbus/dbus_param_reader.h
new file mode 100644
index 0000000..f72f93c
--- /dev/null
+++ b/brillo/dbus/dbus_param_reader.h
@@ -0,0 +1,165 @@
+// 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 generic method to parse function call arguments from
+// D-Bus message buffer and subsequently invokes a provided native C++ callback
+// with the parameter values passed as the callback arguments.
+
+// This functionality is achieved by parsing method arguments one by one,
+// left to right from the C++ callback's type signature, and moving the parsed
+// arguments to the back to the next call to DBusInvoke::Invoke's arguments as
+// const refs. Each iteration has one fewer template specialization arguments,
+// until there is only the return type remaining and we fall through to either
+// the void or the non-void final specialization.
+
+#ifndef LIBCHROMEOS_BRILLO_DBUS_DBUS_PARAM_READER_H_
+#define LIBCHROMEOS_BRILLO_DBUS_DBUS_PARAM_READER_H_
+
+#include <type_traits>
+
+#include <brillo/dbus/data_serialization.h>
+#include <brillo/dbus/utils.h>
+#include <brillo/errors/error.h>
+#include <brillo/errors/error_codes.h>
+#include <dbus/message.h>
+
+namespace brillo {
+namespace dbus_utils {
+
+// A generic DBusParamReader stub class which allows us to specialize on
+// a variable list of expected function parameters later on.
+// This struct in itself is not used. But its concrete template specializations
+// defined below are.
+// |allow_out_params| controls whether DBusParamReader allows the parameter
+// list to contain OUT parameters (pointers).
+template<bool allow_out_params, typename...>
+struct DBusParamReader;
+
+// A generic specialization of DBusParamReader to handle variable function
+// parameters. This specialization pops one parameter off the D-Bus message
+// buffer and calls other specializations of DBusParamReader with fewer
+// parameters to pop the remaining parameters.
+// CurrentParam - the type of the current method parameter we are processing.
+// RestOfParams - the types of remaining parameters to be processed.
+template<bool allow_out_params, typename CurrentParam, typename... RestOfParams>
+struct DBusParamReader<allow_out_params, CurrentParam, RestOfParams...> {
+ // DBusParamReader::Invoke() is a member function that actually extracts the
+ // current parameter from the message buffer.
+ // handler - the C++ callback functor to be called when all the
+ // parameters are processed.
+ // method_call - D-Bus method call object we are processing.
+ // reader - D-Bus message reader to pop the current argument value from.
+ // args... - the callback parameters processed so far.
+ template<typename CallbackType, typename... Args>
+ static bool Invoke(const CallbackType& handler,
+ dbus::MessageReader* reader,
+ ErrorPtr* error,
+ const Args&... args) {
+ return InvokeHelper<CurrentParam, CallbackType, Args...>(
+ handler, reader, error, static_cast<const Args&>(args)...);
+ }
+
+ //
+ // There are two specializations of this function:
+ // 1. For the case where ParamType is a value type (D-Bus IN parameter).
+ // 2. For the case where ParamType is a pointer (D-Bus OUT parameter).
+ // In the second case, the parameter is not popped off the message reader,
+ // since we do not expect the client to provide any data for it.
+ // However after the final handler is called, the values for the OUT
+ // parameters should be sent back in the method call response message.
+
+ // Overload 1: ParamType is not a pointer.
+ template<typename ParamType, typename CallbackType, typename... Args>
+ static typename std::enable_if<!std::is_pointer<ParamType>::value, bool>::type
+ InvokeHelper(const CallbackType& handler,
+ dbus::MessageReader* reader,
+ ErrorPtr* error,
+ const Args&... args) {
+ if (!reader->HasMoreData()) {
+ Error::AddTo(error, FROM_HERE, errors::dbus::kDomain,
+ DBUS_ERROR_INVALID_ARGS,
+ "Too few parameters in a method call");
+ return false;
+ }
+ // ParamType could be a reference type (e.g. 'const std::string&').
+ // Here we need a value type so we can create an object of this type and
+ // pop the value off the message buffer into. Using std::decay<> to get
+ // the value type. If ParamType is already a value type, ParamValueType will
+ // be the same as ParamType.
+ using ParamValueType = typename std::decay<ParamType>::type;
+ // The variable to hold the value of the current parameter we reading from
+ // the message buffer.
+ ParamValueType current_param;
+ if (!DBusType<ParamValueType>::Read(reader, &current_param)) {
+ Error::AddTo(error, FROM_HERE, errors::dbus::kDomain,
+ DBUS_ERROR_INVALID_ARGS,
+ "Method parameter type mismatch");
+ return false;
+ }
+ // Call DBusParamReader::Invoke() to process the rest of parameters.
+ // Note that this is not a recursive call because it is calling a different
+ // method of a different class. We exclude the current parameter type
+ // (ParamType) from DBusParamReader<> template parameter list and forward
+ // all the parameters to the arguments of Invoke() and append the current
+ // parameter to the end of the parameter list. We pass it as a const
+ // reference to allow to use move-only types such as std::unique_ptr<> and
+ // to eliminate unnecessarily copying data.
+ return DBusParamReader<allow_out_params, RestOfParams...>::Invoke(
+ handler, reader, error,
+ static_cast<const Args&>(args)...,
+ static_cast<const ParamValueType&>(current_param));
+ }
+
+ // Overload 2: ParamType is a pointer.
+ template<typename ParamType, typename CallbackType, typename... Args>
+ static typename std::enable_if<allow_out_params &&
+ std::is_pointer<ParamType>::value, bool>::type
+ InvokeHelper(const CallbackType& handler,
+ dbus::MessageReader* reader,
+ ErrorPtr* error,
+ const Args&... args) {
+ // ParamType is a pointer. This is expected to be an output parameter.
+ // Create storage for it and the handler will provide a value for it.
+ using ParamValueType = typename std::remove_pointer<ParamType>::type;
+ // The variable to hold the value of the current parameter we are passing
+ // to the handler.
+ ParamValueType current_param{}; // Default-initialize the value.
+ // Call DBusParamReader::Invoke() to process the rest of parameters.
+ // Note that this is not a recursive call because it is calling a different
+ // method of a different class. We exclude the current parameter type
+ // (ParamType) from DBusParamReader<> template parameter list and forward
+ // all the parameters to the arguments of Invoke() and append the current
+ // parameter to the end of the parameter list.
+ return DBusParamReader<allow_out_params, RestOfParams...>::Invoke(
+ handler, reader, error,
+ static_cast<const Args&>(args)...,
+ &current_param);
+ }
+}; // struct DBusParamReader<ParamType, RestOfParams...>
+
+// The final specialization of DBusParamReader<> used when no more parameters
+// are expected in the message buffer. Actually dispatches the call to the
+// handler with all the accumulated arguments.
+template<bool allow_out_params>
+struct DBusParamReader<allow_out_params> {
+ template<typename CallbackType, typename... Args>
+ static bool Invoke(const CallbackType& handler,
+ dbus::MessageReader* reader,
+ ErrorPtr* error,
+ const Args&... args) {
+ if (reader->HasMoreData()) {
+ Error::AddTo(error, FROM_HERE, errors::dbus::kDomain,
+ DBUS_ERROR_INVALID_ARGS,
+ "Too many parameters in a method call");
+ return false;
+ }
+ handler(args...);
+ return true;
+ }
+}; // struct DBusParamReader<>
+
+} // namespace dbus_utils
+} // namespace brillo
+
+#endif // LIBCHROMEOS_BRILLO_DBUS_DBUS_PARAM_READER_H_