1 #pragma once
2 
3 #include "data_types.hpp"
4 
5 #include <phosphor-logging/log.hpp>
6 #include <sdbusplus/bus.hpp>
7 #include <sdbusplus/bus/match.hpp>
8 #include <sdbusplus/exception.hpp>
9 #include <sdbusplus/message.hpp>
10 
11 #include <string>
12 
13 struct Loop;
14 
15 namespace phosphor
16 {
17 namespace dbus
18 {
19 namespace monitoring
20 {
21 
22 using namespace phosphor::logging;
23 
24 /** @class SDBusPlus
25  *  @brief DBus access delegate implementation for sdbusplus.
26  */
27 class SDBusPlus
28 {
29   private:
30     static auto& getWatches()
31     {
32         static std::vector<sdbusplus::bus::match::match> watches;
33         return watches;
34     }
35 
36   public:
37     static auto& getBus()
38     {
39         static auto bus = sdbusplus::bus::new_default();
40         return bus;
41     }
42 
43     /** @brief Invoke a method; ignore reply. */
44     template <typename... Args>
45     static void callMethodNoReply(const std::string& busName,
46                                   const std::string& path,
47                                   const std::string& interface,
48                                   const std::string& method, Args&&... args)
49     {
50         auto reqMsg = getBus().new_method_call(
51             busName.c_str(), path.c_str(), interface.c_str(), method.c_str());
52         reqMsg.append(std::forward<Args>(args)...);
53         getBus().call_noreply(reqMsg);
54 
55         // TODO: openbmc/openbmc#1719
56         // invoke these methods async, with a callback
57         // handler that checks for errors and logs.
58     }
59 
60     /** @brief Invoke a method. */
61     template <typename... Args>
62     static auto callMethod(const std::string& busName, const std::string& path,
63                            const std::string& interface,
64                            const std::string& method, Args&&... args)
65     {
66         auto reqMsg = getBus().new_method_call(
67             busName.c_str(), path.c_str(), interface.c_str(), method.c_str());
68         reqMsg.append(std::forward<Args>(args)...);
69         return getBus().call(reqMsg);
70     }
71 
72     /** @brief Invoke a method and read the response. */
73     template <typename Ret, typename... Args>
74     static auto callMethodAndRead(const std::string& busName,
75                                   const std::string& path,
76                                   const std::string& interface,
77                                   const std::string& method, Args&&... args)
78     {
79         Ret resp;
80         sdbusplus::message::message respMsg = callMethod<Args...>(
81             busName, path, interface, method, std::forward<Args>(args)...);
82         try
83         {
84             respMsg.read(resp);
85         }
86         catch (const sdbusplus::exception::exception& e)
87         {
88             // Empty responses are expected sometimes, and the calling
89             // code is set up to handle it.
90         }
91         return resp;
92     }
93 
94     /** @brief Register a DBus signal callback. */
95     static auto
96         addMatch(const std::string& match,
97                  const sdbusplus::bus::match::match::callback_t& callback)
98     {
99         getWatches().emplace_back(getBus(), match, callback);
100     }
101 
102     /** @brief Look up the bus name for a path and interface */
103     static auto getBusName(const std::string& path,
104                            const std::string& interface)
105     {
106         std::vector<std::string> interfaces{interface};
107         std::string name;
108 
109         try
110         {
111             auto object = callMethodAndRead<GetObject>(
112                 MAPPER_BUSNAME, MAPPER_PATH, MAPPER_INTERFACE, "GetObject",
113                 path, interfaces);
114 
115             if (!object.empty())
116             {
117                 name = object.begin()->first;
118             }
119         }
120         catch (const sdbusplus::exception::exception& e)
121         {
122             // Empty responses are expected sometimes, and the calling
123             // code is set up to handle it.
124         }
125         return name;
126     }
127 
128     friend Loop;
129 };
130 
131 } // namespace monitoring
132 } // namespace dbus
133 } // namespace phosphor
134