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 (*)(sd_bus_message*); 12 verifyCallback_t verifyCallback = nullptr; 13 14 static constexpr auto SERVICE = "sdbusplus.test.message.append"; 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().release(); 37 38 if (m == nullptr) 39 { 40 bus.wait(); 41 continue; 42 } 43 44 if (sd_bus_message_is_method_call(m, INTERFACE, TEST_METHOD)) 45 { 46 // Verify the message type matches what the test expects. 47 assert(verifyTypeString == sd_bus_message_get_signature(m, true)); 48 if (verifyCallback) 49 { 50 verifyCallback(m); 51 verifyCallback = nullptr; 52 } 53 else 54 { 55 std::cout << "Warning: No verification for " << verifyTypeString 56 << std::endl; 57 } 58 // Reply to client. 59 sd_bus_reply_method_return(m, nullptr); 60 } 61 else if (sd_bus_message_is_method_call(m, INTERFACE, QUIT_METHOD)) 62 { 63 // Reply and exit. 64 sd_bus_reply_method_return(m, nullptr); 65 break; 66 } 67 } 68 69 return nullptr; 70 } 71 72 auto newMethodCall__test(sdbusplus::bus::bus& b) 73 { 74 // Allocate a method-call message for INTERFACE,TEST_METHOD. 75 return b.new_method_call(SERVICE, "/", INTERFACE, TEST_METHOD); 76 } 77 78 void runTests() 79 { 80 using namespace std::literals; 81 82 auto b = sdbusplus::bus::new_default(); 83 84 // Test r-value int. 85 { 86 auto m = newMethodCall__test(b); 87 m.append(1); 88 verifyTypeString = "i"; 89 90 struct verify 91 { 92 static void op(sd_bus_message* m) 93 { 94 int32_t i = 0; 95 sd_bus_message_read_basic(m, 'i', &i); 96 assert(i == 1); 97 } 98 }; 99 verifyCallback = &verify::op; 100 101 b.call_noreply(m); 102 } 103 // Test l-value int. 104 { 105 auto m = newMethodCall__test(b); 106 int a = 1; 107 m.append(a, a); 108 verifyTypeString = "ii"; 109 110 struct verify 111 { 112 static void op(sd_bus_message* m) 113 { 114 int32_t a = 0, b = 0; 115 sd_bus_message_read(m, "ii", &a, &b); 116 assert(a == 1); 117 assert(b == 1); 118 } 119 }; 120 verifyCallback = &verify::op; 121 122 b.call_noreply(m); 123 } 124 125 // Test multiple ints. 126 { 127 auto m = newMethodCall__test(b); 128 m.append(1, 2, 3, 4, 5); 129 verifyTypeString = "iiiii"; 130 131 struct verify 132 { 133 static void op(sd_bus_message* m) 134 { 135 int32_t a = 0, b = 0, c = 0, d = 0, e = 0; 136 sd_bus_message_read(m, "iiiii", &a, &b, &c, &d, &e); 137 assert(a == 1); 138 assert(b == 2); 139 assert(c == 3); 140 assert(d == 4); 141 assert(e == 5); 142 } 143 }; 144 verifyCallback = &verify::op; 145 146 b.call_noreply(m); 147 } 148 149 // Test double and bool. 150 { 151 auto m = newMethodCall__test(b); 152 bool t = true; 153 bool f = false; 154 bool f2 = false; 155 m.append(t, true, f, std::move(f2), false, 1.1); 156 verifyTypeString = "bbbbbd"; 157 158 struct verify 159 { 160 static void op(sd_bus_message* m) 161 { 162 bool t1, t2, f1, f2, f3; 163 double d; 164 sd_bus_message_read(m, "bbbbbd", &t1, &t2, &f1, &f2, &f3, &d); 165 assert(t1); 166 assert(t2); 167 assert(!f1); 168 assert(!f2); 169 assert(!f3); 170 assert(d == 1.1); 171 } 172 }; 173 verifyCallback = &verify::op; 174 175 b.call_noreply(m); 176 } 177 178 // Test r-value string. 179 { 180 auto m = newMethodCall__test(b); 181 m.append("asdf"s); 182 verifyTypeString = "s"; 183 184 struct verify 185 { 186 static void op(sd_bus_message* m) 187 { 188 const char* s = nullptr; 189 sd_bus_message_read_basic(m, 's', &s); 190 assert(0 == strcmp("asdf", s)); 191 } 192 }; 193 verifyCallback = &verify::op; 194 195 b.call_noreply(m); 196 } 197 198 // Test const string owned by const struct. openbmc/openbmc#1025 199 { 200 struct 201 { 202 const char* foo; 203 204 void insert(sdbusplus::message::message& m) 205 { 206 m.append(foo); 207 } 208 } s; 209 210 auto m = newMethodCall__test(b); 211 s.foo = "1234"; 212 s.insert(m); 213 214 verifyTypeString = "s"; 215 216 struct verify 217 { 218 static void op(sd_bus_message* m) 219 { 220 const char* s = nullptr; 221 sd_bus_message_read_basic(m, 's', &s); 222 assert(0 == strcmp("1234", s)); 223 } 224 }; 225 verifyCallback = &verify::op; 226 227 b.call_noreply(m); 228 } 229 230 // Test multiple strings, various forms. 231 { 232 auto m = newMethodCall__test(b); 233 auto str = "jkl;"s; 234 auto str2 = "JKL:"s; 235 const char* str3 = "1234"; 236 const char* const str4 = "5678"; 237 const auto str5 = "!@#$"; 238 m.append(1, "asdf", "ASDF"s, str, std::move(str2), str3, str4, str5, 5); 239 verifyTypeString = "isssssssi"; 240 241 struct verify 242 { 243 static void op(sd_bus_message* m) 244 { 245 int32_t a = 0, b = 0; 246 const char *s0 = nullptr, *s1 = nullptr, *s2 = nullptr, 247 *s3 = nullptr, *s4 = nullptr, *s5 = nullptr, 248 *s6 = nullptr; 249 sd_bus_message_read(m, "isssssssi", &a, &s0, &s1, &s2, &s3, &s4, 250 &s5, &s6, &b); 251 assert(a == 1); 252 assert(b == 5); 253 assert(0 == strcmp("asdf", s0)); 254 assert(0 == strcmp("ASDF", s1)); 255 assert(0 == strcmp("jkl;", s2)); 256 assert(0 == strcmp("JKL:", s3)); 257 assert(0 == strcmp("1234", s4)); 258 assert(0 == strcmp("5678", s5)); 259 assert(0 == strcmp("!@#$", s6)); 260 assert(b == 5); 261 } 262 }; 263 verifyCallback = &verify::op; 264 265 b.call_noreply(m); 266 } 267 268 // Test object_path and signature. 269 { 270 auto m = newMethodCall__test(b); 271 auto o = sdbusplus::message::object_path("/asdf"); 272 auto s = sdbusplus::message::signature("iii"); 273 m.append(1, o, s, 4); 274 verifyTypeString = "iogi"; 275 276 struct verify 277 { 278 static void op(sd_bus_message* m) 279 { 280 int32_t a = 0, b = 0; 281 const char *s0 = nullptr, *s1 = nullptr; 282 sd_bus_message_read(m, "iogi", &a, &s0, &s1, &b); 283 assert(a == 1); 284 assert(b == 4); 285 assert(0 == strcmp("/asdf", s0)); 286 assert(0 == strcmp("iii", s1)); 287 } 288 }; 289 verifyCallback = &verify::op; 290 291 b.call_noreply(m); 292 } 293 294 // Test vector. 295 { 296 auto m = newMethodCall__test(b); 297 std::vector<std::string> s{"1", "2", "3"}; 298 m.append(1, s, 2); 299 verifyTypeString = "iasi"; 300 301 struct verify 302 { 303 static void op(sd_bus_message* m) 304 { 305 int32_t a = 0; 306 sd_bus_message_read(m, "i", &a); 307 assert(a == 1); 308 309 auto rc = 310 sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "s"); 311 assert(0 <= rc); 312 313 const char* s = nullptr; 314 sd_bus_message_read_basic(m, 's', &s); 315 assert(0 == strcmp("1", s)); 316 sd_bus_message_read_basic(m, 's', &s); 317 assert(0 == strcmp("2", s)); 318 sd_bus_message_read_basic(m, 's', &s); 319 assert(0 == strcmp("3", s)); 320 assert(1 == sd_bus_message_at_end(m, false)); 321 322 sd_bus_message_exit_container(m); 323 324 sd_bus_message_read(m, "i", &a); 325 assert(a == 2); 326 } 327 }; 328 verifyCallback = &verify::op; 329 330 b.call_noreply(m); 331 } 332 333 // Test map. 334 { 335 auto m = newMethodCall__test(b); 336 std::map<std::string, int> s = {{"asdf", 3}, {"jkl;", 4}}; 337 m.append(1, s, 2); 338 verifyTypeString = "ia{si}i"; 339 340 struct verify 341 { 342 static void op(sd_bus_message* m) 343 { 344 int32_t a = 0; 345 sd_bus_message_read(m, "i", &a); 346 assert(a == 1); 347 348 auto rc = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, 349 "{si}"); 350 assert(0 <= rc); 351 352 rc = sd_bus_message_enter_container(m, SD_BUS_TYPE_DICT_ENTRY, 353 "si"); 354 assert(0 <= rc); 355 356 const char* s = nullptr; 357 sd_bus_message_read_basic(m, 's', &s); 358 assert(0 == strcmp("asdf", s)); 359 sd_bus_message_read_basic(m, 'i', &a); 360 assert(a == 3); 361 362 assert(1 == sd_bus_message_at_end(m, false)); 363 sd_bus_message_exit_container(m); 364 365 rc = sd_bus_message_enter_container(m, SD_BUS_TYPE_DICT_ENTRY, 366 "si"); 367 assert(0 <= rc); 368 369 sd_bus_message_read_basic(m, 's', &s); 370 assert(0 == strcmp("jkl;", s)); 371 sd_bus_message_read_basic(m, 'i', &a); 372 assert(a == 4); 373 374 assert(1 == sd_bus_message_at_end(m, false)); 375 sd_bus_message_exit_container(m); 376 377 assert(1 == sd_bus_message_at_end(m, false)); 378 sd_bus_message_exit_container(m); 379 380 sd_bus_message_read(m, "i", &a); 381 assert(a == 2); 382 } 383 }; 384 verifyCallback = &verify::op; 385 386 b.call_noreply(m); 387 } 388 389 // Test unordered_map. 390 { 391 auto m = newMethodCall__test(b); 392 std::unordered_map<std::string, int> s = {{"asdf", 3}, {"jkl;", 4}}; 393 m.append(1, s, 2); 394 verifyTypeString = "ia{si}i"; 395 396 struct verify 397 { 398 static void op(sd_bus_message* m) 399 { 400 int32_t a = 0; 401 sd_bus_message_read(m, "i", &a); 402 assert(a == 1); 403 404 auto rc = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, 405 "{si}"); 406 assert(0 <= rc); 407 408 rc = sd_bus_message_enter_container(m, SD_BUS_TYPE_DICT_ENTRY, 409 "si"); 410 assert(0 <= rc); 411 412 const char* s = nullptr; 413 sd_bus_message_read_basic(m, 's', &s); 414 sd_bus_message_read_basic(m, 'i', &a); 415 assert((0 == strcmp("asdf", s) && a == 3) || 416 (a = 4 && 0 == strcmp("jkl;", s))); 417 418 assert(1 == sd_bus_message_at_end(m, false)); 419 sd_bus_message_exit_container(m); 420 421 rc = sd_bus_message_enter_container(m, SD_BUS_TYPE_DICT_ENTRY, 422 "si"); 423 assert(0 <= rc); 424 425 sd_bus_message_read_basic(m, 's', &s); 426 sd_bus_message_read_basic(m, 'i', &a); 427 assert((0 == strcmp("asdf", s) && a == 3) || 428 (a = 4 && 0 == strcmp("jkl;", s))); 429 430 assert(1 == sd_bus_message_at_end(m, false)); 431 sd_bus_message_exit_container(m); 432 433 assert(1 == sd_bus_message_at_end(m, false)); 434 sd_bus_message_exit_container(m); 435 436 sd_bus_message_read(m, "i", &a); 437 assert(a == 2); 438 } 439 }; 440 verifyCallback = &verify::op; 441 442 b.call_noreply(m); 443 } 444 445 // Test set. 446 { 447 auto m = newMethodCall__test(b); 448 std::set<std::string> s = {{"asdf"}, {"jkl;"}}; 449 m.append(1, s, 2); 450 verifyTypeString = "iasi"; 451 452 struct verify 453 { 454 static void op(sd_bus_message* m) 455 { 456 int32_t a = 0; 457 sd_bus_message_read(m, "i", &a); 458 assert(a == 1); 459 460 auto rc = 461 sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "s"); 462 assert(0 <= rc); 463 464 const char* s = nullptr; 465 sd_bus_message_read_basic(m, 's', &s); 466 assert(0 == strcmp("asdf", s)); 467 468 sd_bus_message_read_basic(m, 's', &s); 469 assert(0 == strcmp("jkl;", s)); 470 471 assert(1 == sd_bus_message_at_end(m, false)); 472 sd_bus_message_exit_container(m); 473 474 sd_bus_message_read(m, "i", &a); 475 assert(a == 2); 476 } 477 }; 478 verifyCallback = &verify::op; 479 480 b.call_noreply(m); 481 } 482 483 // Test array. 484 { 485 auto m = newMethodCall__test(b); 486 std::array<std::string, 3> s{"1", "2", "3"}; 487 m.append(1, s, 2); 488 verifyTypeString = "iasi"; 489 490 struct verify 491 { 492 static void op(sd_bus_message* m) 493 { 494 int32_t a = 0; 495 sd_bus_message_read(m, "i", &a); 496 assert(a == 1); 497 498 auto rc = 499 sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "s"); 500 assert(0 <= rc); 501 502 const char* s = nullptr; 503 sd_bus_message_read_basic(m, 's', &s); 504 assert(0 == strcmp("1", s)); 505 sd_bus_message_read_basic(m, 's', &s); 506 assert(0 == strcmp("2", s)); 507 sd_bus_message_read_basic(m, 's', &s); 508 assert(0 == strcmp("3", s)); 509 assert(1 == sd_bus_message_at_end(m, false)); 510 511 sd_bus_message_exit_container(m); 512 513 sd_bus_message_read(m, "i", &a); 514 assert(a == 2); 515 } 516 }; 517 verifyCallback = &verify::op; 518 519 b.call_noreply(m); 520 } 521 522 // Test tuple. 523 { 524 auto m = newMethodCall__test(b); 525 std::tuple<int, double, std::string> a{3, 4.1, "asdf"}; 526 m.append(1, a, 2); 527 verifyTypeString = "i(ids)i"; 528 529 struct verify 530 { 531 static void op(sd_bus_message* m) 532 { 533 int32_t a = 0; 534 double b = 0; 535 const char* c = nullptr; 536 537 sd_bus_message_read(m, "i", &a); 538 assert(a == 1); 539 540 auto rc = sd_bus_message_enter_container(m, SD_BUS_TYPE_STRUCT, 541 "ids"); 542 assert(0 <= rc); 543 544 sd_bus_message_read(m, "ids", &a, &b, &c); 545 assert(a == 3); 546 assert(b == 4.1); 547 assert(0 == strcmp(c, "asdf")); 548 549 sd_bus_message_exit_container(m); 550 551 sd_bus_message_read(m, "i", &a); 552 assert(a == 2); 553 } 554 }; 555 verifyCallback = &verify::op; 556 557 b.call_noreply(m); 558 } 559 560 // Test variant. 561 { 562 auto m = newMethodCall__test(b); 563 sdbusplus::message::variant<int, double> a1{3.1}, a2{4}; 564 m.append(1, a1, a2, 2); 565 verifyTypeString = "ivvi"; 566 567 struct verify 568 { 569 static void op(sd_bus_message* m) 570 { 571 int32_t a = 0; 572 double b = 0; 573 574 sd_bus_message_read(m, "i", &a); 575 assert(a == 1); 576 577 sd_bus_message_enter_container(m, SD_BUS_TYPE_VARIANT, "d"); 578 sd_bus_message_read(m, "d", &b); 579 assert(b == 3.1); 580 sd_bus_message_exit_container(m); 581 582 sd_bus_message_enter_container(m, SD_BUS_TYPE_VARIANT, "i"); 583 sd_bus_message_read(m, "i", &a); 584 assert(a == 4); 585 sd_bus_message_exit_container(m); 586 587 sd_bus_message_read(m, "i", &a); 588 assert(a == 2); 589 } 590 }; 591 verifyCallback = &verify::op; 592 593 b.call_noreply(m); 594 } 595 596 // Test map-variant. 597 { 598 auto m = newMethodCall__test(b); 599 std::map<std::string, sdbusplus::message::variant<int, double>> a1 = { 600 {"asdf", 3}, {"jkl;", 4.1}}; 601 m.append(1, a1, 2); 602 verifyTypeString = "ia{sv}i"; 603 604 struct verify 605 { 606 static void op(sd_bus_message* m) 607 { 608 int32_t a = 0; 609 double b = 0; 610 const char* c = nullptr; 611 612 sd_bus_message_read(m, "i", &a); 613 assert(a == 1); 614 615 sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "{sv}"); 616 sd_bus_message_enter_container(m, SD_BUS_TYPE_DICT_ENTRY, "sv"); 617 sd_bus_message_read(m, "s", &c); 618 assert(0 == strcmp("asdf", c)); 619 sd_bus_message_enter_container(m, SD_BUS_TYPE_VARIANT, "i"); 620 sd_bus_message_read(m, "i", &a); 621 assert(a == 3); 622 sd_bus_message_exit_container(m); 623 sd_bus_message_exit_container(m); 624 sd_bus_message_enter_container(m, SD_BUS_TYPE_DICT_ENTRY, "sv"); 625 sd_bus_message_read(m, "s", &c); 626 assert(0 == strcmp("jkl;", c)); 627 sd_bus_message_enter_container(m, SD_BUS_TYPE_VARIANT, "d"); 628 sd_bus_message_read(m, "d", &b); 629 assert(b == 4.1); 630 sd_bus_message_exit_container(m); 631 sd_bus_message_exit_container(m); 632 sd_bus_message_exit_container(m); 633 634 sd_bus_message_read(m, "i", &a); 635 assert(a == 2); 636 } 637 }; 638 verifyCallback = &verify::op; 639 640 b.call_noreply(m); 641 } 642 643 // Shutdown server. 644 { 645 auto m = b.new_method_call(SERVICE, "/", INTERFACE, QUIT_METHOD); 646 b.call_noreply(m); 647 } 648 } 649 650 int main() 651 { 652 653 // Initialize and start server thread. 654 pthread_t t; 655 { 656 auto b = serverInit(); 657 pthread_create(&t, NULL, server, b.release()); 658 } 659 660 runTests(); 661 662 // Wait for server thread to exit. 663 pthread_join(t, NULL); 664 665 return 0; 666 } 667