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(*)(sd_bus_message*); 10 verifyCallback_t verifyCallback = nullptr; 11 12 static constexpr auto SERVICE = "sdbusplus.test.message.append"; 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().release(); 35 36 if(m == nullptr) 37 { 38 bus.wait(); 39 continue; 40 } 41 42 if (sd_bus_message_is_method_call(m, INTERFACE, TEST_METHOD)) 43 { 44 // Verify the message type matches what the test expects. 45 assert(verifyTypeString == sd_bus_message_get_signature(m, true)); 46 if (verifyCallback) 47 { 48 verifyCallback(m); 49 verifyCallback = nullptr; 50 } 51 else 52 { 53 std::cout << "Warning: No verification for " 54 << verifyTypeString << std::endl; 55 } 56 // Reply to client. 57 sd_bus_reply_method_return(m, nullptr); 58 } 59 else if (sd_bus_message_is_method_call(m, INTERFACE, QUIT_METHOD)) 60 { 61 // Reply and exit. 62 sd_bus_reply_method_return(m, nullptr); 63 break; 64 } 65 } 66 67 return nullptr; 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(sd_bus_message* m) 91 { 92 int32_t i = 0; 93 sd_bus_message_read_basic(m, 'i', &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(sd_bus_message* m) 111 { 112 int32_t a = 0, b = 0; 113 sd_bus_message_read(m, "ii", &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(sd_bus_message* m) 132 { 133 int32_t a = 0, b = 0, c = 0, d = 0, e = 0; 134 sd_bus_message_read(m, "iiiii", &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 double and bool. 148 { 149 auto m = newMethodCall__test(b); 150 bool t = true; 151 bool f = false; 152 bool f2 = false; 153 m.append(t, true, f, std::move(f2), false, 1.1); 154 verifyTypeString = "bbbbbd"; 155 156 struct verify 157 { 158 static void op(sd_bus_message* m) 159 { 160 bool t1, t2, f1, f2, f3; 161 double d; 162 sd_bus_message_read(m, "bbbbbd", &t1, &t2, &f1, &f2, &f3, &d); 163 assert(t1); 164 assert(t2); 165 assert(!f1); 166 assert(!f2); 167 assert(!f3); 168 assert(d == 1.1); 169 } 170 }; 171 verifyCallback = &verify::op; 172 173 b.call_noreply(m); 174 } 175 176 // Test r-value string. 177 { 178 auto m = newMethodCall__test(b); 179 m.append("asdf"s); 180 verifyTypeString = "s"; 181 182 struct verify 183 { 184 static void op(sd_bus_message* m) 185 { 186 const char* s = nullptr; 187 sd_bus_message_read_basic(m, 's', &s); 188 assert(0 == strcmp("asdf", s)); 189 } 190 }; 191 verifyCallback = &verify::op; 192 193 b.call_noreply(m); 194 } 195 196 // Test const string owned by const struct. openbmc/openbmc#1025 197 { 198 struct 199 { 200 const char* foo; 201 202 void insert(sdbusplus::message::message& m) 203 { 204 m.append(foo); 205 } 206 } s; 207 208 auto m = newMethodCall__test(b); 209 s.foo = "1234"; 210 s.insert(m); 211 212 verifyTypeString = "s"; 213 214 struct verify 215 { 216 static void op(sd_bus_message* m) 217 { 218 const char* s = nullptr; 219 sd_bus_message_read_basic(m, 's', &s); 220 assert(0 == strcmp("1234", s)); 221 } 222 }; 223 verifyCallback = &verify::op; 224 225 b.call_noreply(m); 226 } 227 228 // Test multiple strings, various forms. 229 { 230 auto m = newMethodCall__test(b); 231 auto str = "jkl;"s; 232 auto str2 = "JKL:"s; 233 const char* str3 = "1234"; 234 const char* const str4 = "5678"; 235 const auto str5 = "!@#$"; 236 m.append(1, "asdf", "ASDF"s, str, 237 std::move(str2), str3, str4, str5, 5); 238 verifyTypeString = "isssssssi"; 239 240 struct verify 241 { 242 static void op(sd_bus_message* m) 243 { 244 int32_t a = 0, b = 0; 245 const char *s0 = nullptr, *s1 = nullptr, *s2 = nullptr, 246 *s3 = nullptr, *s4 = nullptr, *s5 = nullptr, 247 *s6 = nullptr; 248 sd_bus_message_read(m, "isssssssi", &a, &s0, &s1, &s2, &s3, 249 &s4, &s5, &s6, &b); 250 assert(a == 1); 251 assert(b == 5); 252 assert(0 == strcmp("asdf", s0)); 253 assert(0 == strcmp("ASDF", s1)); 254 assert(0 == strcmp("jkl;", s2)); 255 assert(0 == strcmp("JKL:", s3)); 256 assert(0 == strcmp("1234", s4)); 257 assert(0 == strcmp("5678", s5)); 258 assert(0 == strcmp("!@#$", s6)); 259 assert(b == 5); 260 } 261 }; 262 verifyCallback = &verify::op; 263 264 b.call_noreply(m); 265 } 266 267 // Test object_path and signature. 268 { 269 auto m = newMethodCall__test(b); 270 auto o = sdbusplus::message::object_path("/asdf"); 271 auto s = sdbusplus::message::signature("iii"); 272 m.append(1, o, s, 4); 273 verifyTypeString = "iogi"; 274 275 struct verify 276 { 277 static void op(sd_bus_message* m) 278 { 279 int32_t a = 0, b = 0; 280 const char *s0 = nullptr, *s1 = nullptr; 281 sd_bus_message_read(m, "iogi", &a, &s0, &s1, &b); 282 assert(a == 1); 283 assert(b == 4); 284 assert(0 == strcmp("/asdf", s0)); 285 assert(0 == strcmp("iii", s1)); 286 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 = sd_bus_message_enter_container(m, 310 SD_BUS_TYPE_ARRAY, 311 "s"); 312 assert(0 <= rc); 313 314 const char* s = nullptr; 315 sd_bus_message_read_basic(m, 's', &s); 316 assert(0 == strcmp("1", s)); 317 sd_bus_message_read_basic(m, 's', &s); 318 assert(0 == strcmp("2", s)); 319 sd_bus_message_read_basic(m, 's', &s); 320 assert(0 == strcmp("3", s)); 321 assert(1 == sd_bus_message_at_end(m, false)); 322 323 sd_bus_message_exit_container(m); 324 325 sd_bus_message_read(m, "i", &a); 326 assert(a == 2); 327 328 } 329 }; 330 verifyCallback = &verify::op; 331 332 333 b.call_noreply(m); 334 } 335 336 // Test map. 337 { 338 auto m = newMethodCall__test(b); 339 std::map<std::string, int> s = { { "asdf", 3 }, { "jkl;", 4 } }; 340 m.append(1, s, 2); 341 verifyTypeString = "ia{si}i"; 342 343 struct verify 344 { 345 static void op(sd_bus_message* m) 346 { 347 int32_t a = 0; 348 sd_bus_message_read(m, "i", &a); 349 assert(a == 1); 350 351 auto rc = sd_bus_message_enter_container(m, 352 SD_BUS_TYPE_ARRAY, 353 "{si}"); 354 assert(0 <= rc); 355 356 rc = sd_bus_message_enter_container(m, 357 SD_BUS_TYPE_DICT_ENTRY, 358 "si"); 359 assert(0 <= rc); 360 361 const char* s = nullptr; 362 sd_bus_message_read_basic(m, 's', &s); 363 assert(0 == strcmp("asdf", s)); 364 sd_bus_message_read_basic(m, 'i', &a); 365 assert(a == 3); 366 367 assert(1 == sd_bus_message_at_end(m, false)); 368 sd_bus_message_exit_container(m); 369 370 rc = sd_bus_message_enter_container(m, 371 SD_BUS_TYPE_DICT_ENTRY, 372 "si"); 373 assert(0 <= rc); 374 375 sd_bus_message_read_basic(m, 's', &s); 376 assert(0 == strcmp("jkl;", s)); 377 sd_bus_message_read_basic(m, 'i', &a); 378 assert(a == 4); 379 380 assert(1 == sd_bus_message_at_end(m, false)); 381 sd_bus_message_exit_container(m); 382 383 assert(1 == sd_bus_message_at_end(m, false)); 384 sd_bus_message_exit_container(m); 385 386 sd_bus_message_read(m, "i", &a); 387 assert(a == 2); 388 } 389 }; 390 verifyCallback = &verify::op; 391 392 b.call_noreply(m); 393 } 394 395 // Test tuple. 396 { 397 auto m = newMethodCall__test(b); 398 std::tuple<int, double, std::string> a{ 3, 4.1, "asdf" }; 399 m.append(1, a, 2); 400 verifyTypeString = "i(ids)i"; 401 402 struct verify 403 { 404 static void op(sd_bus_message* m) 405 { 406 int32_t a = 0; 407 double b = 0; 408 const char* c = nullptr; 409 410 sd_bus_message_read(m, "i", &a); 411 assert(a == 1); 412 413 auto rc = sd_bus_message_enter_container(m, 414 SD_BUS_TYPE_STRUCT, 415 "ids"); 416 assert(0 <= rc); 417 418 sd_bus_message_read(m, "ids", &a, &b, &c); 419 assert(a == 3); 420 assert(b == 4.1); 421 assert(0 == strcmp(c, "asdf")); 422 423 sd_bus_message_exit_container(m); 424 425 sd_bus_message_read(m, "i", &a); 426 assert(a == 2); 427 } 428 }; 429 verifyCallback = &verify::op; 430 431 b.call_noreply(m); 432 } 433 434 // Test variant. 435 { 436 auto m = newMethodCall__test(b); 437 sdbusplus::message::variant<int, double> a1{3.1}, a2{4}; 438 m.append(1, a1, a2, 2); 439 verifyTypeString = "ivvi"; 440 441 struct verify 442 { 443 static void op(sd_bus_message* m) 444 { 445 int32_t a = 0; 446 double b = 0; 447 448 sd_bus_message_read(m, "i", &a); 449 assert(a == 1); 450 451 sd_bus_message_enter_container(m, SD_BUS_TYPE_VARIANT, "d"); 452 sd_bus_message_read(m, "d", &b); 453 assert(b == 3.1); 454 sd_bus_message_exit_container(m); 455 456 sd_bus_message_enter_container(m, SD_BUS_TYPE_VARIANT, "i"); 457 sd_bus_message_read(m, "i", &a); 458 assert(a == 4); 459 sd_bus_message_exit_container(m); 460 461 sd_bus_message_read(m, "i", &a); 462 assert(a == 2); 463 } 464 }; 465 verifyCallback = &verify::op; 466 467 b.call_noreply(m); 468 } 469 470 // Test map-variant. 471 { 472 auto m = newMethodCall__test(b); 473 std::map<std::string, sdbusplus::message::variant<int, double>> a1 = 474 { { "asdf", 3 }, { "jkl;", 4.1 } }; 475 m.append(1, a1, 2); 476 verifyTypeString = "ia{sv}i"; 477 478 struct verify 479 { 480 static void op(sd_bus_message* m) 481 { 482 int32_t a = 0; 483 double b = 0; 484 const char* c = nullptr; 485 486 sd_bus_message_read(m, "i", &a); 487 assert(a == 1); 488 489 sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "{sv}"); 490 sd_bus_message_enter_container(m, SD_BUS_TYPE_DICT_ENTRY, "sv"); 491 sd_bus_message_read(m, "s", &c); 492 assert(0 == strcmp("asdf", c)); 493 sd_bus_message_enter_container(m, SD_BUS_TYPE_VARIANT, "i"); 494 sd_bus_message_read(m, "i", &a); 495 assert(a == 3); 496 sd_bus_message_exit_container(m); 497 sd_bus_message_exit_container(m); 498 sd_bus_message_enter_container(m, SD_BUS_TYPE_DICT_ENTRY, "sv"); 499 sd_bus_message_read(m, "s", &c); 500 assert(0 == strcmp("jkl;", c)); 501 sd_bus_message_enter_container(m, SD_BUS_TYPE_VARIANT, "d"); 502 sd_bus_message_read(m, "d", &b); 503 assert(b == 4.1); 504 sd_bus_message_exit_container(m); 505 sd_bus_message_exit_container(m); 506 sd_bus_message_exit_container(m); 507 508 sd_bus_message_read(m, "i", &a); 509 assert(a == 2); 510 } 511 }; 512 verifyCallback = &verify::op; 513 514 b.call_noreply(m); 515 } 516 517 // Shutdown server. 518 { 519 auto m = b.new_method_call(SERVICE, "/", INTERFACE, QUIT_METHOD); 520 b.call_noreply(m); 521 } 522 } 523 524 int main() 525 { 526 527 // Initialize and start server thread. 528 pthread_t t; 529 { 530 auto b = serverInit(); 531 pthread_create(&t, NULL, server, b.release()); 532 } 533 534 runTests(); 535 536 // Wait for server thread to exit. 537 pthread_join(t, NULL); 538 539 return 0; 540 } 541