1 #include <iostream> 2 #include <cassert> 3 #include <sdbusplus/message.hpp> 4 #include <sdbusplus/bus.hpp> 5 6 // Global to share the dbus type string between client and server. 7 static std::string verifyTypeString; 8 9 using verifyCallback_t = void(*)(sdbusplus::message::message&); 10 verifyCallback_t verifyCallback = nullptr; 11 12 static constexpr auto SERVICE = "sdbusplus.test"; 13 static constexpr auto INTERFACE = SERVICE; 14 static constexpr auto TEST_METHOD = "test"; 15 static constexpr auto QUIT_METHOD = "quit"; 16 17 // Open up the sdbus and claim SERVICE name. 18 auto serverInit() 19 { 20 auto b = sdbusplus::bus::new_default(); 21 b.request_name(SERVICE); 22 23 return std::move(b); 24 } 25 26 // Thread to run the dbus server. 27 void* server(void* b) 28 { 29 auto bus = sdbusplus::bus::bus(reinterpret_cast<sdbusplus::bus::busp_t>(b)); 30 31 while(1) 32 { 33 // Wait for messages. 34 auto m = bus.process(); 35 36 if(!m) 37 { 38 bus.wait(); 39 continue; 40 } 41 42 if (m.is_method_call(INTERFACE, TEST_METHOD)) 43 { 44 // Verify the message type matches what the test expects. 45 assert(verifyTypeString == m.get_signature()); 46 47 if (verifyCallback) 48 { 49 50 verifyCallback(m); 51 verifyCallback = nullptr; 52 } 53 else 54 { 55 std::cout << "Warning: No verification for " 56 << verifyTypeString << std::endl; 57 } 58 // Reply to client. 59 sd_bus_reply_method_return(m.release(), nullptr); 60 } 61 else if (m.is_method_call(INTERFACE, QUIT_METHOD)) 62 { 63 // Reply and exit. 64 sd_bus_reply_method_return(m.release(), nullptr); 65 break; 66 } 67 } 68 } 69 70 auto newMethodCall__test(sdbusplus::bus::bus& b) 71 { 72 // Allocate a method-call message for INTERFACE,TEST_METHOD. 73 return b.new_method_call(SERVICE, "/", INTERFACE, TEST_METHOD); 74 } 75 76 void runTests() 77 { 78 using namespace std::literals; 79 80 auto b = sdbusplus::bus::new_default(); 81 82 // Test r-value int. 83 { 84 auto m = newMethodCall__test(b); 85 m.append(1); 86 verifyTypeString = "i"; 87 88 struct verify 89 { 90 static void op(sdbusplus::message::message& m) 91 { 92 int32_t i = 0; 93 m.read(i); 94 assert(i == 1); 95 } 96 }; 97 verifyCallback = &verify::op; 98 99 b.call_noreply(m); 100 } 101 // Test l-value int. 102 { 103 auto m = newMethodCall__test(b); 104 int a = 1; 105 m.append(a, a); 106 verifyTypeString = "ii"; 107 108 struct verify 109 { 110 static void op(sdbusplus::message::message& m) 111 { 112 int32_t a = 0, b = 0; 113 m.read(a, b); 114 assert(a == 1); 115 assert(b == 1); 116 } 117 }; 118 verifyCallback = &verify::op; 119 120 b.call_noreply(m); 121 } 122 123 // Test multiple ints. 124 { 125 auto m = newMethodCall__test(b); 126 m.append(1, 2, 3, 4, 5); 127 verifyTypeString = "iiiii"; 128 129 struct verify 130 { 131 static void op(sdbusplus::message::message& m) 132 { 133 int32_t a = 0, b = 0, c = 0, d = 0, e = 0; 134 m.read(a,b,c,d,e); 135 assert(a == 1); 136 assert(b == 2); 137 assert(c == 3); 138 assert(d == 4); 139 assert(e == 5); 140 } 141 }; 142 verifyCallback = &verify::op; 143 144 b.call_noreply(m); 145 } 146 147 // Test r-value string. 148 { 149 auto m = newMethodCall__test(b); 150 m.append("asdf"s); 151 verifyTypeString = "s"; 152 153 struct verify 154 { 155 static void op(sdbusplus::message::message& m) 156 { 157 const char* s = nullptr; 158 m.read(s); 159 assert(0 == strcmp("asdf", s)); 160 } 161 }; 162 verifyCallback = &verify::op; 163 164 b.call_noreply(m); 165 } 166 167 // Test multiple strings, various forms. 168 { 169 auto m = newMethodCall__test(b); 170 auto str = "jkl;"s; 171 auto str2 = "JKL:"s; 172 m.append(1, "asdf", "ASDF"s, str, 173 std::move(str2), 5); 174 verifyTypeString = "issssi"; 175 176 struct verify 177 { 178 static void op(sdbusplus::message::message& m) 179 { 180 int32_t a = 0, b = 0; 181 std::string s0, s1, s2, s3; 182 m.read(a, s0, s1, s2, s3, b); 183 assert(a == 1); 184 assert(b == 5); 185 assert(s0 == "asdf"s); 186 assert(s1 == "ASDF"s); 187 assert(s2 == "jkl;"s); 188 assert(s3 == "JKL:"); 189 } 190 }; 191 verifyCallback = &verify::op; 192 193 b.call_noreply(m); 194 } 195 196 // Test vector. 197 { 198 auto m = newMethodCall__test(b); 199 std::vector<std::string> s{ "1", "2", "3"}; 200 m.append(1, s, 2); 201 verifyTypeString = "iasi"; 202 203 struct verify 204 { 205 static void op(sdbusplus::message::message& m) 206 { 207 int32_t a = 0; 208 std::vector<std::string> s; 209 m.read(a, s); 210 assert(a == 1); 211 assert(s[0] == "1"); 212 assert(s[1] == "2"); 213 assert(s[2] == "3"); 214 decltype(s) s2 = { "1" , "2" , "3" }; 215 assert(s == s2); 216 } 217 }; 218 verifyCallback = &verify::op; 219 220 b.call_noreply(m); 221 } 222 223 // Test map. 224 { 225 auto m = newMethodCall__test(b); 226 std::map<std::string, int> s = { { "asdf", 3 }, { "jkl;", 4 } }; 227 m.append(1, s, 2); 228 verifyTypeString = "ia{si}i"; 229 230 struct verify 231 { 232 static void op(sdbusplus::message::message& m) 233 { 234 int32_t a = 0, b = 0; 235 std::map<std::string, int> s{}; 236 237 m.read(a, s, b); 238 assert(a == 1); 239 assert(s.size() == 2); 240 assert(s["asdf"] == 3); 241 assert(s["jkl;"] == 4); 242 assert(b == 2); 243 } 244 }; 245 verifyCallback = &verify::op; 246 247 b.call_noreply(m); 248 } 249 250 // Test tuple. 251 { 252 auto m = newMethodCall__test(b); 253 std::tuple<int, double, std::string> a{ 3, 4.1, "asdf" }; 254 m.append(1, a, 2); 255 verifyTypeString = "i(ids)i"; 256 257 struct verify 258 { 259 static void op(sdbusplus::message::message& m) 260 { 261 int32_t a = 0, b = 0; 262 std::tuple<int, double, std::string> c{}; 263 264 m.read(a, c, b); 265 assert(a == 1); 266 assert(b == 2); 267 assert(c == std::make_tuple(3, 4.1, "asdf"s)); 268 } 269 }; 270 verifyCallback = &verify::op; 271 272 b.call_noreply(m); 273 } 274 275 // Test variant. 276 { 277 auto m = newMethodCall__test(b); 278 sdbusplus::message::variant<int, double> a1{3.1}, a2{4}; 279 m.append(1, a1, a2, 2); 280 verifyTypeString = "ivvi"; 281 282 struct verify 283 { 284 static void op(sdbusplus::message::message& m) 285 { 286 int32_t a, b; 287 sdbusplus::message::variant<int, double> a1{}, a2{}; 288 289 m.read(a, a1, a2, b); 290 assert(a == 1); 291 assert(a1 == 3.1); 292 assert(a2 == 4); 293 assert(b == 2); 294 } 295 }; 296 verifyCallback = &verify::op; 297 298 b.call_noreply(m); 299 } 300 301 // Test map-variant. 302 { 303 auto m = newMethodCall__test(b); 304 std::map<std::string, sdbusplus::message::variant<int, double>> a1 = 305 { { "asdf", 3 }, { "jkl;", 4.1 } }; 306 m.append(1, a1, 2); 307 verifyTypeString = "ia{sv}i"; 308 309 struct verify 310 { 311 static void op(sdbusplus::message::message& m) 312 { 313 int32_t a = 0, b = 0; 314 std::map<std::string, 315 sdbusplus::message::variant<int, double>> a1{}; 316 317 m.read(a, a1, b); 318 assert(a == 1); 319 assert(a1["asdf"] == 3); 320 assert(a1["jkl;"] == 4.1); 321 assert(b == 2); 322 } 323 }; 324 verifyCallback = &verify::op; 325 326 b.call_noreply(m); 327 } 328 329 330 // Shutdown server. 331 { 332 auto m = b.new_method_call(SERVICE, "/", INTERFACE, QUIT_METHOD); 333 b.call_noreply(m); 334 } 335 } 336 337 int main() 338 { 339 340 // Initialize and start server thread. 341 pthread_t t; 342 { 343 auto b = serverInit(); 344 pthread_create(&t, NULL, server, b.release()); 345 } 346 347 runTests(); 348 349 // Wait for server thread to exit. 350 pthread_join(t, NULL); 351 352 return 0; 353 } 354