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