1 #include <boost/asio/io_context.hpp>
2 #include <boost/asio/signal_set.hpp>
3 #include <sdbusplus/asio/connection.hpp>
4 #include <sdbusplus/asio/object_server.hpp>
5 #include <sdbusplus/asio/property.hpp>
6 #include <sdbusplus/bus.hpp>
7 #include <sdbusplus/unpack_properties.hpp>
8 
9 #include <iostream>
10 
11 const std::string demoServiceName = "demo.service";
12 const std::string demoObjectPath = "/xyz/demo";
13 const std::string demoInterfaceName = "xyz.demo";
14 const std::string propertyGrettingName = "Greetings";
15 const std::string propertyGoodbyesName = "Goodbyes";
16 const std::string propertyValueName = "Value";
17 
18 class Application
19 {
20   public:
21     Application(sdbusplus::asio::connection& bus,
22                 sdbusplus::asio::object_server& objServer) :
23         bus_(bus),
24         objServer_(objServer)
25     {
26         demo_ = objServer_.add_unique_interface(demoObjectPath,
27                                                 demoInterfaceName);
28 
29         demo_->register_property_r<std::string>(
30             propertyGrettingName, sdbusplus::vtable::property_::const_,
31             [this](const auto&) { return greetings_; });
32 
33         demo_->register_property_rw<std::string>(
34             propertyGoodbyesName, sdbusplus::vtable::property_::emits_change,
35             [this](const auto& newPropertyValue, const auto&) {
36                 goodbyes_ = newPropertyValue;
37                 return true;
38             },
39             [this](const auto&) { return goodbyes_; });
40 
41         demo_->register_property_r<uint32_t>(
42             propertyValueName, sdbusplus::vtable::property_::const_,
43             [](const auto& value) -> uint32_t { return value; });
44 
45         demo_->initialize();
46     }
47 
48     uint32_t fatalErrors() const
49     {
50         return fatalErrors_;
51     }
52 
53     auto logSystemErrorCode(boost::system::error_code ec)
54     {
55         std::cerr << "Error: " << ec << "\n";
56         ++fatalErrors_;
57     }
58 
59     void logException(const std::exception& e)
60     {
61         std::cerr << "Error: " << e.what() << "\n";
62         ++fatalErrors_;
63     }
64 
65     void logUnpackError(const sdbusplus::UnpackErrorReason reason,
66                         const std::string& property)
67     {
68         std::cerr << "UnpackError: " << static_cast<int>(reason) << ", "
69                   << property << "\n";
70         ++fatalErrors_;
71     }
72 
73     void logExpectedException(
74         const sdbusplus::exception::UnpackPropertyError& error)
75     {
76         std::cout << "As expected " << error.what() << "\n";
77     }
78 
79     void asyncGetAllPropertiesStringTypeOnly()
80     {
81         sdbusplus::asio::getAllProperties(
82             bus_, demoServiceName, demoObjectPath, demoInterfaceName,
83             [this](const boost::system::error_code ec,
84                    const std::vector<std::pair<
85                        std::string, std::variant<std::monostate, std::string>>>&
86                        properties) -> void {
87                 if (ec)
88                 {
89                     logSystemErrorCode(ec);
90                     return;
91                 }
92                 {
93                     const std::string* greetings = nullptr;
94                     const std::string* goodbyes = nullptr;
95                     const bool success = sdbusplus::unpackPropertiesNoThrow(
96                         [this](const sdbusplus::UnpackErrorReason reason,
97                                const std::string& property) {
98                             logUnpackError(reason, property);
99                         },
100                         properties, propertyGrettingName, greetings,
101                         propertyGoodbyesName, goodbyes);
102 
103                     if (success)
104                     {
105                         std::cout << "value of greetings: " << *greetings
106                                   << "\n";
107                         std::cout << "value of goodbyes: " << *goodbyes << "\n";
108                     }
109                     else
110                     {
111                         ++fatalErrors_;
112                     }
113                 }
114 
115                 try
116                 {
117                     std::string value;
118                     sdbusplus::unpackProperties(properties, propertyValueName,
119                                                 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_, demoServiceName, demoObjectPath, demoInterfaceName,
136             [this](const boost::system::error_code ec,
137                    const 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,
152                                                 propertyGrettingName, greetings,
153                                                 propertyGoodbyesName, goodbyes,
154                                                 propertyValueName, value);
155 
156                     std::cout << "value of greetings: " << greetings << "\n";
157                     std::cout << "value of goodbyes: " << goodbyes << "\n";
158                     std::cout << "value of value: " << value << "\n";
159                 }
160                 catch (const sdbusplus::exception::UnpackPropertyError& error)
161                 {
162                     logException(error);
163                 }
164 
165                 try
166                 {
167                     std::string unknownProperty;
168                     sdbusplus::unpackProperties(
169                         properties, "UnknownPropertyName", unknownProperty);
170 
171                     std::cerr << "Error: it should fail because of "
172                                  "missing property\n";
173                     ++fatalErrors_;
174                 }
175                 catch (const sdbusplus::exception::UnpackPropertyError& error)
176                 {
177                     logExpectedException(error);
178                 }
179 
180                 try
181                 {
182                     uint32_t notMatchingType;
183                     sdbusplus::unpackProperties(
184                         properties, propertyGrettingName, notMatchingType);
185 
186                     std::cerr << "Error: it should fail because of "
187                                  "not matched type\n";
188                     ++fatalErrors_;
189                 }
190                 catch (const sdbusplus::exception::UnpackPropertyError& error)
191                 {
192                     logExpectedException(error);
193                 }
194             });
195     }
196 
197   private:
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(demoServiceName.c_str());
220 
221     Application app(*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