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 << "\n"; 106 std::cout << "value of goodbyes: " << *goodbyes << "\n"; 107 } 108 else 109 { 110 ++fatalErrors_; 111 } 112 } 113 114 try 115 { 116 std::string value; 117 sdbusplus::unpackProperties(properties, propertyValueName, 118 value); 119 120 std::cerr << "Error: it should fail because of " 121 "not matched type\n"; 122 ++fatalErrors_; 123 } 124 catch (const sdbusplus::exception::UnpackPropertyError& error) 125 { 126 logExpectedException(error); 127 } 128 }); 129 } 130 131 void asyncGetAllProperties() 132 { 133 sdbusplus::asio::getAllProperties( 134 bus_, demoServiceName, demoObjectPath, demoInterfaceName, 135 [this](const boost::system::error_code ec, 136 const std::vector<std::pair< 137 std::string, 138 std::variant<std::monostate, std::string, uint32_t>>>& 139 properties) -> void { 140 if (ec) 141 { 142 logSystemErrorCode(ec); 143 return; 144 } 145 try 146 { 147 std::string greetings; 148 std::string goodbyes; 149 uint32_t value = 0u; 150 sdbusplus::unpackProperties(properties, propertyGrettingName, 151 greetings, propertyGoodbyesName, 152 goodbyes, 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(properties, "UnknownPropertyName", 167 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(properties, propertyGrettingName, 182 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 sdbusplus::asio::connection& bus_; 197 sdbusplus::asio::object_server& objServer_; 198 199 std::unique_ptr<sdbusplus::asio::dbus_interface> demo_; 200 std::string greetings_ = "Hello"; 201 std::string goodbyes_ = "Bye"; 202 203 uint32_t fatalErrors_ = 0u; 204 }; 205 206 int main(int, char**) 207 { 208 boost::asio::io_context ioc; 209 boost::asio::signal_set signals(ioc, SIGINT, SIGTERM); 210 211 signals.async_wait( 212 [&ioc](const boost::system::error_code&, const int&) { ioc.stop(); }); 213 214 auto bus = std::make_shared<sdbusplus::asio::connection>(ioc); 215 auto objServer = std::make_unique<sdbusplus::asio::object_server>(bus); 216 217 bus->request_name(demoServiceName.c_str()); 218 219 Application app(*bus, *objServer); 220 221 boost::asio::post(ioc, 222 [&app] { app.asyncGetAllPropertiesStringTypeOnly(); }); 223 boost::asio::post(ioc, [&app] { app.asyncGetAllProperties(); }); 224 225 ioc.run(); 226 227 std::cout << "Fatal errors count: " << app.fatalErrors() << "\n"; 228 229 return app.fatalErrors(); 230 } 231