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