1 // Copyright 2014 The Chromium OS Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #ifndef LIBBRILLO_BRILLO_DBUS_DBUS_SIGNAL_HANDLER_H_
6 #define LIBBRILLO_BRILLO_DBUS_DBUS_SIGNAL_HANDLER_H_
7
8 #include <functional>
9 #include <string>
10 #include <utility>
11
12 #include <base/bind.h>
13 #include <brillo/dbus/dbus_param_reader.h>
14 #include <dbus/message.h>
15 #include <dbus/object_proxy.h>
16
17 namespace brillo {
18 namespace dbus_utils {
19
20 // brillo::dbus_utils::ConnectToSignal() is a helper function similar to
21 // dbus::ObjectProxy::ConnectToSignal() but the |signal_callback| is an actual
22 // C++ signal handler with expected signal parameters as native method args.
23 //
24 // brillo::dbus_utils::ConnectToSignal() actually registers a stub signal
25 // handler with D-Bus which has a standard signature that matches
26 // dbus::ObjectProxy::SignalCallback.
27 //
28 // When a D-Bus signal is emitted, the stub handler is invoked, which unpacks
29 // the expected parameters from dbus::Signal message and then calls
30 // |signal_callback| with unpacked arguments.
31 //
32 // If the signal message doesn't contain correct number or types of arguments,
33 // an error message is logged to the system log and the signal is ignored
34 // (|signal_callback| is not invoked).
35 template <typename... Args>
ConnectToSignal(::dbus::ObjectProxy * object_proxy,const std::string & interface_name,const std::string & signal_name,base::Callback<void (Args...)> signal_callback,::dbus::ObjectProxy::OnConnectedCallback on_connected_callback)36 void ConnectToSignal(
37 ::dbus::ObjectProxy* object_proxy,
38 const std::string& interface_name,
39 const std::string& signal_name,
40 base::Callback<void(Args...)> signal_callback,
41 ::dbus::ObjectProxy::OnConnectedCallback on_connected_callback) {
42 // DBusParamReader::Invoke() needs a functor object, not a base::Callback.
43 // Wrap the callback with lambda so we can redirect the call.
44 auto signal_callback_wrapper = [signal_callback](const Args&... args) {
45 if (!signal_callback.is_null()) {
46 signal_callback.Run(args...);
47 }
48 };
49
50 // Raw signal handler stub method. When called, unpacks the signal arguments
51 // from |signal| message buffer and redirects the call to
52 // |signal_callback_wrapper| which, in turn, would call the user-provided
53 // |signal_callback|.
54 auto dbus_signal_callback = [](std::function<void(const Args&...)> callback,
55 ::dbus::Signal* signal) {
56 ::dbus::MessageReader reader(signal);
57 DBusParamReader<false, Args...>::Invoke(callback, &reader, nullptr);
58 };
59
60 // Register our stub handler with D-Bus ObjectProxy.
61 object_proxy->ConnectToSignal(
62 interface_name, signal_name,
63 base::Bind(dbus_signal_callback, signal_callback_wrapper),
64 std::move(on_connected_callback));
65 }
66
67 } // namespace dbus_utils
68 } // namespace brillo
69
70 #endif // LIBBRILLO_BRILLO_DBUS_DBUS_SIGNAL_HANDLER_H_
71