1927171f88672fda187fac64e1a28bb84ac6877bcAlex Vakulenko// Copyright 2014 The Chromium OS Authors. All rights reserved.
2927171f88672fda187fac64e1a28bb84ac6877bcAlex Vakulenko// Use of this source code is governed by a BSD-style license that can be
3927171f88672fda187fac64e1a28bb84ac6877bcAlex Vakulenko// found in the LICENSE file.
4927171f88672fda187fac64e1a28bb84ac6877bcAlex Vakulenko
5fed60b0c640828b320f56293c8bebc43fd2b1da8Alex Vakulenko#ifndef LIBBRILLO_BRILLO_DBUS_DBUS_SIGNAL_HANDLER_H_
6fed60b0c640828b320f56293c8bebc43fd2b1da8Alex Vakulenko#define LIBBRILLO_BRILLO_DBUS_DBUS_SIGNAL_HANDLER_H_
7927171f88672fda187fac64e1a28bb84ac6877bcAlex Vakulenko
8927171f88672fda187fac64e1a28bb84ac6877bcAlex Vakulenko#include <string>
9927171f88672fda187fac64e1a28bb84ac6877bcAlex Vakulenko
109ed0cab99f18acb3570a35e9408f24355f6b8324Alex Vakulenko#include <brillo/bind_lambda.h>
119ed0cab99f18acb3570a35e9408f24355f6b8324Alex Vakulenko#include <brillo/dbus/dbus_param_reader.h>
12927171f88672fda187fac64e1a28bb84ac6877bcAlex Vakulenko#include <dbus/message.h>
13927171f88672fda187fac64e1a28bb84ac6877bcAlex Vakulenko#include <dbus/object_proxy.h>
14927171f88672fda187fac64e1a28bb84ac6877bcAlex Vakulenko
159ed0cab99f18acb3570a35e9408f24355f6b8324Alex Vakulenkonamespace brillo {
16927171f88672fda187fac64e1a28bb84ac6877bcAlex Vakulenkonamespace dbus_utils {
17927171f88672fda187fac64e1a28bb84ac6877bcAlex Vakulenko
189ed0cab99f18acb3570a35e9408f24355f6b8324Alex Vakulenko// brillo::dbus_utils::ConnectToSignal() is a helper function similar to
19927171f88672fda187fac64e1a28bb84ac6877bcAlex Vakulenko// dbus::ObjectProxy::ConnectToSignal() but the |signal_callback| is an actual
20927171f88672fda187fac64e1a28bb84ac6877bcAlex Vakulenko// C++ signal handler with expected signal parameters as native method args.
21927171f88672fda187fac64e1a28bb84ac6877bcAlex Vakulenko//
229ed0cab99f18acb3570a35e9408f24355f6b8324Alex Vakulenko// brillo::dbus_utils::ConnectToSignal() actually registers a stub signal
23927171f88672fda187fac64e1a28bb84ac6877bcAlex Vakulenko// handler with D-Bus which has a standard signature that matches
24927171f88672fda187fac64e1a28bb84ac6877bcAlex Vakulenko// dbus::ObjectProxy::SignalCallback.
25927171f88672fda187fac64e1a28bb84ac6877bcAlex Vakulenko//
26927171f88672fda187fac64e1a28bb84ac6877bcAlex Vakulenko// When a D-Bus signal is emitted, the stub handler is invoked, which unpacks
27927171f88672fda187fac64e1a28bb84ac6877bcAlex Vakulenko// the expected parameters from dbus::Signal message and then calls
28927171f88672fda187fac64e1a28bb84ac6877bcAlex Vakulenko// |signal_callback| with unpacked arguments.
29927171f88672fda187fac64e1a28bb84ac6877bcAlex Vakulenko//
30927171f88672fda187fac64e1a28bb84ac6877bcAlex Vakulenko// If the signal message doesn't contain correct number or types of arguments,
31927171f88672fda187fac64e1a28bb84ac6877bcAlex Vakulenko// an error message is logged to the system log and the signal is ignored
32927171f88672fda187fac64e1a28bb84ac6877bcAlex Vakulenko// (|signal_callback| is not invoked).
33927171f88672fda187fac64e1a28bb84ac6877bcAlex Vakulenkotemplate<typename... Args>
34927171f88672fda187fac64e1a28bb84ac6877bcAlex Vakulenkovoid ConnectToSignal(
35927171f88672fda187fac64e1a28bb84ac6877bcAlex Vakulenko    dbus::ObjectProxy* object_proxy,
36927171f88672fda187fac64e1a28bb84ac6877bcAlex Vakulenko    const std::string& interface_name,
37927171f88672fda187fac64e1a28bb84ac6877bcAlex Vakulenko    const std::string& signal_name,
38927171f88672fda187fac64e1a28bb84ac6877bcAlex Vakulenko    base::Callback<void(Args...)> signal_callback,
39927171f88672fda187fac64e1a28bb84ac6877bcAlex Vakulenko    dbus::ObjectProxy::OnConnectedCallback on_connected_callback) {
40927171f88672fda187fac64e1a28bb84ac6877bcAlex Vakulenko  // Raw signal handler stub method. When called, unpacks the signal arguments
41927171f88672fda187fac64e1a28bb84ac6877bcAlex Vakulenko  // from |signal| message buffer and redirects the call to
42927171f88672fda187fac64e1a28bb84ac6877bcAlex Vakulenko  // |signal_callback_wrapper| which, in turn, would call the user-provided
43927171f88672fda187fac64e1a28bb84ac6877bcAlex Vakulenko  // |signal_callback|.
44c7b0177da3ad8299c8c7650d1dc21768591bd362Luis Hector Chavez  auto dbus_signal_callback = [](
45c7b0177da3ad8299c8c7650d1dc21768591bd362Luis Hector Chavez      const base::Callback<void(Args...)>& signal_callback,
46c7b0177da3ad8299c8c7650d1dc21768591bd362Luis Hector Chavez      dbus::Signal* signal) {
47c7b0177da3ad8299c8c7650d1dc21768591bd362Luis Hector Chavez    // DBusParamReader::Invoke() needs a functor object, not a base::Callback.
48c7b0177da3ad8299c8c7650d1dc21768591bd362Luis Hector Chavez    // Wrap the callback with lambda so we can redirect the call.
49c7b0177da3ad8299c8c7650d1dc21768591bd362Luis Hector Chavez    auto signal_callback_wrapper = [signal_callback](const Args&... args) {
50c7b0177da3ad8299c8c7650d1dc21768591bd362Luis Hector Chavez      if (!signal_callback.is_null()) {
51c7b0177da3ad8299c8c7650d1dc21768591bd362Luis Hector Chavez        signal_callback.Run(args...);
52c7b0177da3ad8299c8c7650d1dc21768591bd362Luis Hector Chavez      }
53c7b0177da3ad8299c8c7650d1dc21768591bd362Luis Hector Chavez    };
54c7b0177da3ad8299c8c7650d1dc21768591bd362Luis Hector Chavez
55927171f88672fda187fac64e1a28bb84ac6877bcAlex Vakulenko    dbus::MessageReader reader(signal);
5605d29044d14a60775ed6c51c75a414eb0cb50347Alex Vakulenko    DBusParamReader<false, Args...>::Invoke(
5705d29044d14a60775ed6c51c75a414eb0cb50347Alex Vakulenko        signal_callback_wrapper, &reader, nullptr);
58927171f88672fda187fac64e1a28bb84ac6877bcAlex Vakulenko  };
59927171f88672fda187fac64e1a28bb84ac6877bcAlex Vakulenko
60927171f88672fda187fac64e1a28bb84ac6877bcAlex Vakulenko  // Register our stub handler with D-Bus ObjectProxy.
61927171f88672fda187fac64e1a28bb84ac6877bcAlex Vakulenko  object_proxy->ConnectToSignal(interface_name,
62927171f88672fda187fac64e1a28bb84ac6877bcAlex Vakulenko                                signal_name,
63c7b0177da3ad8299c8c7650d1dc21768591bd362Luis Hector Chavez                                base::Bind(dbus_signal_callback, signal_callback),
64927171f88672fda187fac64e1a28bb84ac6877bcAlex Vakulenko                                on_connected_callback);
65927171f88672fda187fac64e1a28bb84ac6877bcAlex Vakulenko}
66927171f88672fda187fac64e1a28bb84ac6877bcAlex Vakulenko
67927171f88672fda187fac64e1a28bb84ac6877bcAlex Vakulenko}  // namespace dbus_utils
689ed0cab99f18acb3570a35e9408f24355f6b8324Alex Vakulenko}  // namespace brillo
69927171f88672fda187fac64e1a28bb84ac6877bcAlex Vakulenko
70fed60b0c640828b320f56293c8bebc43fd2b1da8Alex Vakulenko#endif  // LIBBRILLO_BRILLO_DBUS_DBUS_SIGNAL_HANDLER_H_
71