1 #include <boost/asio.hpp>
2 #include <sdbusplus/asio/connection.hpp>
3 #include <sdbusplus/asio/object_server.hpp>
4 #include <sdbusplus/asio/property.hpp>
5 #include <sdbusplus/bus.hpp>
6 #include <sdbusplus/unpack_properties.hpp>
7 
8 #include <iostream>
9 
10 namespace xyz
11 {
12 namespace demo
13 {
14 
15 const std::string path = "/xyz/demo";
16 const std::string name = "xyz.demo";
17 const std::string interface = "xyz.demo.interface";
18 
19 } // namespace demo
20 } // namespace xyz
21 
22 namespace name
23 {
24 
25 const std::string greetings = "Greetings";
26 const std::string goodbyes = "Goodbyes";
27 const std::string value = "Value";
28 
29 } // namespace name
30 
31 class Application
32 {
33   public:
34     Application(boost::asio::io_context& ioc, sdbusplus::asio::connection& bus,
35                 sdbusplus::asio::object_server& objServer) :
36         ioc_(ioc),
37         bus_(bus), objServer_(objServer)
38     {
39         demo_ = objServer_.add_interface(xyz::demo::path, xyz::demo::interface);
40 
41         demo_->register_property_r(name::greetings, std::string(),
42                                    sdbusplus::vtable::property_::const_,
43                                    [this](const auto&) { return greetings_; });
44 
45         demo_->register_property_rw(
46             name::goodbyes, std::string(),
47             sdbusplus::vtable::property_::emits_change,
48             [this](const auto& newPropertyValue, const auto&) {
49                 goodbyes_ = newPropertyValue;
50                 return 1;
51             },
52             [this](const auto&) { return goodbyes_; });
53 
54         demo_->register_property_r(
55             name::value, uint32_t{42}, sdbusplus::vtable::property_::const_,
56             [](const auto& value) -> uint32_t { return value; });
57 
58         demo_->initialize();
59     }
60 
61     ~Application()
62     {
63         objServer_.remove_interface(demo_);
64     }
65 
66     uint32_t fatalErrors() const
67     {
68         return fatalErrors_;
69     }
70 
71     auto logSystemErrorCode()
72     {
73         return [this](boost::system::error_code ec) {
74             std::cerr << "Error: " << ec << "\n";
75             ++fatalErrors_;
76         };
77     }
78 
79     void logException(const std::exception& e)
80     {
81         std::cerr << "Error: " << e.what() << "\n";
82         ++fatalErrors_;
83     }
84 
85     void logExpectedException(
86         const sdbusplus::exception::UnpackPropertyError& error)
87     {
88         std::cout << "As expected " << error.what() << " => "
89                   << error.propertyName << " is missing because "
90                   << error.reason << "\n";
91     }
92 
93     void asyncGetAllPropertiesStringTypeOnly()
94     {
95         sdbusplus::asio::getAllProperties(
96             bus_, xyz::demo::name, xyz::demo::path, xyz::demo::interface,
97             logSystemErrorCode(),
98             [this](std::vector<std::pair<
99                        std::string, std::variant<std::monostate, std::string>>>&
100                        properties) {
101                 try
102                 {
103                     std::string greetings;
104                     std::string goodbyes;
105                     sdbusplus::unpackProperties(properties, name::greetings,
106                                                 greetings, name::goodbyes,
107                                                 goodbyes);
108 
109                     std::cout << "value of greetings: " << greetings << "\n";
110                     std::cout << "value of goodbyes: " << goodbyes << "\n";
111                 }
112                 catch (const sdbusplus::exception::UnpackPropertyError& error)
113                 {
114                     logException(error);
115                 }
116 
117                 try
118                 {
119                     std::string value;
120                     sdbusplus::unpackProperties(properties, name::value, value);
121 
122                     std::cerr << "Error: it should fail because of "
123                                  "not matched type\n";
124                     ++fatalErrors_;
125                 }
126                 catch (const sdbusplus::exception::UnpackPropertyError& error)
127                 {
128                     logExpectedException(error);
129                 }
130             });
131     }
132 
133     void asyncGetAllProperties()
134     {
135         sdbusplus::asio::getAllProperties(
136             bus_, xyz::demo::name, xyz::demo::path, xyz::demo::interface,
137             logSystemErrorCode(),
138             [this](
139                 std::vector<std::pair<std::string,
140                                       std::variant<std::monostate, std::string,
141                                                    uint32_t>>>& properties) {
142                 try
143                 {
144                     std::string greetings;
145                     std::string goodbyes;
146                     uint32_t value = 0u;
147                     sdbusplus::unpackProperties(properties, name::greetings,
148                                                 greetings, name::goodbyes,
149                                                 goodbyes, name::value, value);
150 
151                     std::cout << "value of greetings: " << greetings << "\n";
152                     std::cout << "value of goodbyes: " << goodbyes << "\n";
153                     std::cout << "value of value: " << value << "\n";
154                 }
155                 catch (const sdbusplus::exception::UnpackPropertyError& error)
156                 {
157                     logException(error);
158                 }
159 
160                 try
161                 {
162                     std::string unknownProperty;
163                     sdbusplus::unpackProperties(
164                         properties, "UnknownPropertyName", unknownProperty);
165 
166                     std::cerr << "Error: it should fail because of "
167                                  "missing property\n";
168                     ++fatalErrors_;
169                 }
170                 catch (const sdbusplus::exception::UnpackPropertyError& error)
171                 {
172                     logExpectedException(error);
173                 }
174 
175                 try
176                 {
177                     uint32_t notMatchingType;
178                     sdbusplus::unpackProperties(properties, name::greetings,
179                                                 notMatchingType);
180 
181                     std::cerr << "Error: it should fail because of "
182                                  "not matched type\n";
183                     ++fatalErrors_;
184                 }
185                 catch (const sdbusplus::exception::UnpackPropertyError& error)
186                 {
187                     logExpectedException(error);
188                 }
189             });
190     }
191 
192   private:
193     boost::asio::io_context& ioc_;
194     sdbusplus::asio::connection& bus_;
195     sdbusplus::asio::object_server& objServer_;
196 
197     std::shared_ptr<sdbusplus::asio::dbus_interface> demo_;
198     std::string greetings_ = "Hello";
199     std::string goodbyes_ = "Bye";
200 
201     uint32_t fatalErrors_ = 0u;
202 };
203 
204 int main(int, char**)
205 {
206     boost::asio::io_context ioc;
207     boost::asio::signal_set signals(ioc, SIGINT, SIGTERM);
208 
209     signals.async_wait(
210         [&ioc](const boost::system::error_code&, const int&) { ioc.stop(); });
211 
212     auto bus = std::make_shared<sdbusplus::asio::connection>(ioc);
213     auto objServer = std::make_unique<sdbusplus::asio::object_server>(bus);
214 
215     bus->request_name(xyz::demo::name.c_str());
216 
217     Application app(ioc, *bus, *objServer);
218 
219     boost::asio::post(ioc,
220                       [&app] { app.asyncGetAllPropertiesStringTypeOnly(); });
221     boost::asio::post(ioc, [&app] { app.asyncGetAllProperties(); });
222 
223     ioc.run();
224 
225     std::cout << "Fatal errors count: " << app.fatalErrors() << "\n";
226 
227     return app.fatalErrors();
228 }
229