1 #include <iostream> 2 #include <cassert> 3 #include <sdbusplus/message.hpp> 4 #include <sdbusplus/bus.hpp> 5 #include <unordered_map> 6 #include <set> 7 8 // Global to share the dbus type string between client and server. 9 static std::string verifyTypeString; 10 11 using verifyCallback_t = void (*)(sdbusplus::message::message&); 12 verifyCallback_t verifyCallback = nullptr; 13 14 static constexpr auto SERVICE = "sdbusplus.test.message.read"; 15 static constexpr auto INTERFACE = SERVICE; 16 static constexpr auto TEST_METHOD = "test"; 17 static constexpr auto QUIT_METHOD = "quit"; 18 19 // Open up the sdbus and claim SERVICE name. 20 auto serverInit() 21 { 22 auto b = sdbusplus::bus::new_default(); 23 b.request_name(SERVICE); 24 25 return std::move(b); 26 } 27 28 // Thread to run the dbus server. 29 void* server(void* b) 30 { 31 auto bus = sdbusplus::bus::bus(reinterpret_cast<sdbusplus::bus::busp_t>(b)); 32 33 while (1) 34 { 35 // Wait for messages. 36 auto m = bus.process(); 37 38 if (!m) 39 { 40 bus.wait(); 41 continue; 42 } 43 44 if (m.is_method_call(INTERFACE, TEST_METHOD)) 45 { 46 // Verify the message type matches what the test expects. 47 assert(verifyTypeString == m.get_signature()); 48 49 if (verifyCallback) 50 { 51 52 verifyCallback(m); 53 verifyCallback = nullptr; 54 } 55 else 56 { 57 std::cout << "Warning: No verification for " << verifyTypeString 58 << std::endl; 59 } 60 // Reply to client. 61 sd_bus_reply_method_return(m.release(), nullptr); 62 } 63 else if (m.is_method_call(INTERFACE, QUIT_METHOD)) 64 { 65 // Reply and exit. 66 sd_bus_reply_method_return(m.release(), nullptr); 67 break; 68 } 69 } 70 71 return nullptr; 72 } 73 74 auto newMethodCall__test(sdbusplus::bus::bus& b) 75 { 76 // Allocate a method-call message for INTERFACE,TEST_METHOD. 77 return b.new_method_call(SERVICE, "/", INTERFACE, TEST_METHOD); 78 } 79 80 void runTests() 81 { 82 using namespace std::literals; 83 84 auto b = sdbusplus::bus::new_default(); 85 86 // Test r-value int. 87 { 88 auto m = newMethodCall__test(b); 89 m.append(1); 90 verifyTypeString = "i"; 91 92 struct verify 93 { 94 static void op(sdbusplus::message::message& m) 95 { 96 int32_t i = 0; 97 m.read(i); 98 assert(i == 1); 99 } 100 }; 101 verifyCallback = &verify::op; 102 103 b.call_noreply(m); 104 } 105 // Test l-value int. 106 { 107 auto m = newMethodCall__test(b); 108 int a = 1; 109 m.append(a, a); 110 verifyTypeString = "ii"; 111 112 struct verify 113 { 114 static void op(sdbusplus::message::message& m) 115 { 116 int32_t a = 0, b = 0; 117 m.read(a, b); 118 assert(a == 1); 119 assert(b == 1); 120 } 121 }; 122 verifyCallback = &verify::op; 123 124 b.call_noreply(m); 125 } 126 127 // Test multiple ints. 128 { 129 auto m = newMethodCall__test(b); 130 m.append(1, 2, 3, 4, 5); 131 verifyTypeString = "iiiii"; 132 133 struct verify 134 { 135 static void op(sdbusplus::message::message& m) 136 { 137 int32_t a = 0, b = 0, c = 0, d = 0, e = 0; 138 m.read(a, b, c, d, e); 139 assert(a == 1); 140 assert(b == 2); 141 assert(c == 3); 142 assert(d == 4); 143 assert(e == 5); 144 } 145 }; 146 verifyCallback = &verify::op; 147 148 b.call_noreply(m); 149 } 150 151 // Test double and bool. 152 { 153 auto m = newMethodCall__test(b); 154 bool t = true; 155 bool f = false; 156 bool f2 = false; 157 m.append(t, true, f, std::move(f2), false, 1.1); 158 verifyTypeString = "bbbbbd"; 159 160 struct verify 161 { 162 static void op(sdbusplus::message::message& m) 163 { 164 bool t1, t2, f1, f2, f3; 165 double d; 166 m.read(t1, t2, f1, f2, f3, d); 167 assert(t1); 168 assert(t2); 169 assert(!f1); 170 assert(!f2); 171 assert(!f3); 172 assert(d == 1.1); 173 } 174 }; 175 verifyCallback = &verify::op; 176 177 b.call_noreply(m); 178 } 179 180 // Test r-value string. 181 { 182 auto m = newMethodCall__test(b); 183 m.append("asdf"s); 184 verifyTypeString = "s"; 185 186 struct verify 187 { 188 static void op(sdbusplus::message::message& m) 189 { 190 const char* s = nullptr; 191 m.read(s); 192 assert(0 == strcmp("asdf", s)); 193 } 194 }; 195 verifyCallback = &verify::op; 196 197 b.call_noreply(m); 198 } 199 200 // Test multiple strings, various forms. 201 { 202 auto m = newMethodCall__test(b); 203 auto str = "jkl;"s; 204 auto str2 = "JKL:"s; 205 m.append(1, "asdf", "ASDF"s, str, std::move(str2), 5); 206 verifyTypeString = "issssi"; 207 208 struct verify 209 { 210 static void op(sdbusplus::message::message& m) 211 { 212 int32_t a = 0, b = 0; 213 std::string s0, s1, s2, s3; 214 m.read(a, s0, s1, s2, s3, b); 215 assert(a == 1); 216 assert(b == 5); 217 assert(s0 == "asdf"s); 218 assert(s1 == "ASDF"s); 219 assert(s2 == "jkl;"s); 220 assert(s3 == "JKL:"); 221 } 222 }; 223 verifyCallback = &verify::op; 224 225 b.call_noreply(m); 226 } 227 228 // Test object_path and signature. 229 { 230 auto m = newMethodCall__test(b); 231 auto o = sdbusplus::message::object_path("/asdf"); 232 auto s = sdbusplus::message::signature("iii"); 233 m.append(1, o, s, 4); 234 verifyTypeString = "iogi"; 235 236 struct verify 237 { 238 static void op(sdbusplus::message::message& m) 239 { 240 int32_t a = 0, b = 0; 241 sdbusplus::message::object_path o; 242 sdbusplus::message::signature s; 243 m.read(a, o, s, b); 244 assert(a == 1); 245 assert(b == 4); 246 assert(std::string(o) == "/asdf"s); 247 assert(std::string(s) == "iii"s); 248 } 249 }; 250 verifyCallback = &verify::op; 251 252 b.call_noreply(m); 253 } 254 255 // Test vector. 256 { 257 auto m = newMethodCall__test(b); 258 std::vector<std::string> s{"1", "2", "3"}; 259 m.append(1, s, 2); 260 verifyTypeString = "iasi"; 261 262 struct verify 263 { 264 static void op(sdbusplus::message::message& m) 265 { 266 int32_t a = 0; 267 std::vector<std::string> s; 268 m.read(a, s); 269 assert(a == 1); 270 assert(s[0] == "1"); 271 assert(s[1] == "2"); 272 assert(s[2] == "3"); 273 decltype(s) s2 = {"1", "2", "3"}; 274 assert(s == s2); 275 } 276 }; 277 verifyCallback = &verify::op; 278 279 b.call_noreply(m); 280 } 281 282 // Test map. 283 { 284 auto m = newMethodCall__test(b); 285 std::map<std::string, int> s = {{"asdf", 3}, {"jkl;", 4}}; 286 m.append(1, s, 2); 287 verifyTypeString = "ia{si}i"; 288 289 struct verify 290 { 291 static void op(sdbusplus::message::message& m) 292 { 293 int32_t a = 0, b = 0; 294 std::map<std::string, int> s{}; 295 296 m.read(a, s, b); 297 assert(a == 1); 298 assert(s.size() == 2); 299 assert(s["asdf"] == 3); 300 assert(s["jkl;"] == 4); 301 assert(b == 2); 302 } 303 }; 304 verifyCallback = &verify::op; 305 306 b.call_noreply(m); 307 } 308 309 // Test unordered_map. 310 { 311 auto m = newMethodCall__test(b); 312 std::unordered_map<std::string, int> s = {{"asdf", 3}, {"jkl;", 4}}; 313 m.append(1, s, 2); 314 verifyTypeString = "ia{si}i"; 315 316 struct verify 317 { 318 static void op(sdbusplus::message::message& m) 319 { 320 int32_t a = 0, b = 0; 321 std::unordered_map<std::string, int> s{}; 322 323 m.read(a, s, b); 324 assert(a == 1); 325 assert(s.size() == 2); 326 assert(s["asdf"] == 3); 327 assert(s["jkl;"] == 4); 328 assert(b == 2); 329 } 330 }; 331 verifyCallback = &verify::op; 332 333 b.call_noreply(m); 334 } 335 336 // Test set. 337 { 338 auto m = newMethodCall__test(b); 339 std::set<std::string> s = {{"asdf"}, {"jkl;"}}; 340 m.append(1, s, 2); 341 verifyTypeString = "iasi"; 342 343 struct verify 344 { 345 static void op(sdbusplus::message::message& m) 346 { 347 int32_t a = 0, b = 0; 348 std::set<std::string> s{}; 349 350 m.read(a, s, b); 351 assert(a == 1); 352 assert(s.size() == 2); 353 assert(s.find("asdf") != s.end()); 354 assert(s.find("jkl;") != s.end()); 355 assert(b == 2); 356 } 357 }; 358 verifyCallback = &verify::op; 359 360 b.call_noreply(m); 361 } 362 363 // Test tuple. 364 { 365 auto m = newMethodCall__test(b); 366 std::tuple<int, double, std::string> a{3, 4.1, "asdf"}; 367 m.append(1, a, 2); 368 verifyTypeString = "i(ids)i"; 369 370 struct verify 371 { 372 static void op(sdbusplus::message::message& m) 373 { 374 int32_t a = 0, b = 0; 375 std::tuple<int, double, std::string> c{}; 376 377 m.read(a, c, b); 378 assert(a == 1); 379 assert(b == 2); 380 assert(c == std::make_tuple(3, 4.1, "asdf"s)); 381 } 382 }; 383 verifyCallback = &verify::op; 384 385 b.call_noreply(m); 386 } 387 388 // Test variant. 389 { 390 auto m = newMethodCall__test(b); 391 sdbusplus::message::variant<int, double> a1{3.1}, a2{4}; 392 m.append(1, a1, a2, 2); 393 verifyTypeString = "ivvi"; 394 395 struct verify 396 { 397 static void op(sdbusplus::message::message& m) 398 { 399 int32_t a, b; 400 sdbusplus::message::variant<int, double> a1{}, a2{}; 401 402 m.read(a, a1, a2, b); 403 assert(a == 1); 404 assert(a1 == 3.1); 405 assert(a2 == 4); 406 assert(b == 2); 407 } 408 }; 409 verifyCallback = &verify::op; 410 411 b.call_noreply(m); 412 } 413 414 // Test variant with missing/wrong type. 415 { 416 auto m = newMethodCall__test(b); 417 sdbusplus::message::variant<uint64_t, double> a1{3.1}, a2{uint64_t(4)}; 418 m.append(1, a1, a2, 2); 419 verifyTypeString = "ivvi"; 420 421 struct verify 422 { 423 static void op(sdbusplus::message::message& m) 424 { 425 int32_t a, b; 426 sdbusplus::message::variant<uint8_t, double> a1{}, a2{}; 427 428 m.read(a, a1, a2, b); 429 assert(a == 1); 430 assert(a1 == 3.1); 431 assert(a2 == uint8_t()); 432 assert(b == 2); 433 } 434 }; 435 verifyCallback = &verify::op; 436 437 b.call_noreply(m); 438 } 439 440 // Test map-variant. 441 { 442 auto m = newMethodCall__test(b); 443 std::map<std::string, sdbusplus::message::variant<int, double>> a1 = { 444 {"asdf", 3}, {"jkl;", 4.1}}; 445 m.append(1, a1, 2); 446 verifyTypeString = "ia{sv}i"; 447 448 struct verify 449 { 450 static void op(sdbusplus::message::message& m) 451 { 452 int32_t a = 0, b = 0; 453 std::map<std::string, sdbusplus::message::variant<int, double>> 454 a1{}; 455 456 m.read(a, a1, b); 457 assert(a == 1); 458 assert(a1["asdf"] == 3); 459 assert(a1["jkl;"] == 4.1); 460 assert(b == 2); 461 } 462 }; 463 verifyCallback = &verify::op; 464 465 b.call_noreply(m); 466 } 467 468 // Shutdown server. 469 { 470 auto m = b.new_method_call(SERVICE, "/", INTERFACE, QUIT_METHOD); 471 b.call_noreply(m); 472 } 473 } 474 475 int main() 476 { 477 478 // Initialize and start server thread. 479 pthread_t t; 480 { 481 auto b = serverInit(); 482 pthread_create(&t, NULL, server, b.release()); 483 } 484 485 runTests(); 486 487 // Wait for server thread to exit. 488 pthread_join(t, NULL); 489 490 return 0; 491 } 492