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 multiple strings, various forms. 197 { 198 auto m = newMethodCall__test(b); 199 auto str = "jkl;"s; 200 auto str2 = "JKL:"s; 201 m.append(1, "asdf", "ASDF"s, str, 202 std::move(str2), 5); 203 verifyTypeString = "issssi"; 204 205 struct verify 206 { 207 static void op(sd_bus_message* m) 208 { 209 int32_t a = 0, b = 0; 210 const char *s0 = nullptr, *s1 = nullptr, *s2 = nullptr, 211 *s3 = nullptr; 212 sd_bus_message_read(m, "issssi", &a, &s0, &s1, &s2, &s3, &b); 213 assert(a == 1); 214 assert(b == 5); 215 assert(0 == strcmp("asdf", s0)); 216 assert(0 == strcmp("ASDF", s1)); 217 assert(0 == strcmp("jkl;", s2)); 218 assert(0 == strcmp("JKL:", s3)); 219 } 220 }; 221 verifyCallback = &verify::op; 222 223 b.call_noreply(m); 224 } 225 226 // Test object_path and signature. 227 { 228 auto m = newMethodCall__test(b); 229 auto o = sdbusplus::message::object_path("/asdf"); 230 auto s = sdbusplus::message::signature("iii"); 231 m.append(1, o, s, 4); 232 verifyTypeString = "iogi"; 233 234 struct verify 235 { 236 static void op(sd_bus_message* m) 237 { 238 int32_t a = 0, b = 0; 239 const char *s0 = nullptr, *s1 = nullptr; 240 sd_bus_message_read(m, "iogi", &a, &s0, &s1, &b); 241 assert(a == 1); 242 assert(b == 4); 243 assert(0 == strcmp("/asdf", s0)); 244 assert(0 == strcmp("iii", s1)); 245 246 } 247 }; 248 verifyCallback = &verify::op; 249 250 b.call_noreply(m); 251 } 252 253 // Test vector. 254 { 255 auto m = newMethodCall__test(b); 256 std::vector<std::string> s{ "1", "2", "3"}; 257 m.append(1, s, 2); 258 verifyTypeString = "iasi"; 259 260 struct verify 261 { 262 static void op(sd_bus_message* m) 263 { 264 int32_t a = 0; 265 sd_bus_message_read(m, "i", &a); 266 assert(a == 1); 267 268 auto rc = sd_bus_message_enter_container(m, 269 SD_BUS_TYPE_ARRAY, 270 "s"); 271 assert(0 <= rc); 272 273 const char* s = nullptr; 274 sd_bus_message_read_basic(m, 's', &s); 275 assert(0 == strcmp("1", s)); 276 sd_bus_message_read_basic(m, 's', &s); 277 assert(0 == strcmp("2", s)); 278 sd_bus_message_read_basic(m, 's', &s); 279 assert(0 == strcmp("3", s)); 280 assert(1 == sd_bus_message_at_end(m, false)); 281 282 sd_bus_message_exit_container(m); 283 284 sd_bus_message_read(m, "i", &a); 285 assert(a == 2); 286 287 } 288 }; 289 verifyCallback = &verify::op; 290 291 292 b.call_noreply(m); 293 } 294 295 // Test map. 296 { 297 auto m = newMethodCall__test(b); 298 std::map<std::string, int> s = { { "asdf", 3 }, { "jkl;", 4 } }; 299 m.append(1, s, 2); 300 verifyTypeString = "ia{si}i"; 301 302 struct verify 303 { 304 static void op(sd_bus_message* m) 305 { 306 int32_t a = 0; 307 sd_bus_message_read(m, "i", &a); 308 assert(a == 1); 309 310 auto rc = sd_bus_message_enter_container(m, 311 SD_BUS_TYPE_ARRAY, 312 "{si}"); 313 assert(0 <= rc); 314 315 rc = sd_bus_message_enter_container(m, 316 SD_BUS_TYPE_DICT_ENTRY, 317 "si"); 318 assert(0 <= rc); 319 320 const char* s = nullptr; 321 sd_bus_message_read_basic(m, 's', &s); 322 assert(0 == strcmp("asdf", s)); 323 sd_bus_message_read_basic(m, 'i', &a); 324 assert(a == 3); 325 326 assert(1 == sd_bus_message_at_end(m, false)); 327 sd_bus_message_exit_container(m); 328 329 rc = sd_bus_message_enter_container(m, 330 SD_BUS_TYPE_DICT_ENTRY, 331 "si"); 332 assert(0 <= rc); 333 334 sd_bus_message_read_basic(m, 's', &s); 335 assert(0 == strcmp("jkl;", s)); 336 sd_bus_message_read_basic(m, 'i', &a); 337 assert(a == 4); 338 339 assert(1 == sd_bus_message_at_end(m, false)); 340 sd_bus_message_exit_container(m); 341 342 assert(1 == sd_bus_message_at_end(m, false)); 343 sd_bus_message_exit_container(m); 344 345 sd_bus_message_read(m, "i", &a); 346 assert(a == 2); 347 } 348 }; 349 verifyCallback = &verify::op; 350 351 b.call_noreply(m); 352 } 353 354 // Test tuple. 355 { 356 auto m = newMethodCall__test(b); 357 std::tuple<int, double, std::string> a{ 3, 4.1, "asdf" }; 358 m.append(1, a, 2); 359 verifyTypeString = "i(ids)i"; 360 361 struct verify 362 { 363 static void op(sd_bus_message* m) 364 { 365 int32_t a = 0; 366 double b = 0; 367 const char* c = nullptr; 368 369 sd_bus_message_read(m, "i", &a); 370 assert(a == 1); 371 372 auto rc = sd_bus_message_enter_container(m, 373 SD_BUS_TYPE_STRUCT, 374 "ids"); 375 assert(0 <= rc); 376 377 sd_bus_message_read(m, "ids", &a, &b, &c); 378 assert(a == 3); 379 assert(b == 4.1); 380 assert(0 == strcmp(c, "asdf")); 381 382 sd_bus_message_exit_container(m); 383 384 sd_bus_message_read(m, "i", &a); 385 assert(a == 2); 386 } 387 }; 388 verifyCallback = &verify::op; 389 390 b.call_noreply(m); 391 } 392 393 // Test variant. 394 { 395 auto m = newMethodCall__test(b); 396 sdbusplus::message::variant<int, double> a1{3.1}, a2{4}; 397 m.append(1, a1, a2, 2); 398 verifyTypeString = "ivvi"; 399 400 struct verify 401 { 402 static void op(sd_bus_message* m) 403 { 404 int32_t a = 0; 405 double b = 0; 406 407 sd_bus_message_read(m, "i", &a); 408 assert(a == 1); 409 410 sd_bus_message_enter_container(m, SD_BUS_TYPE_VARIANT, "d"); 411 sd_bus_message_read(m, "d", &b); 412 assert(b == 3.1); 413 sd_bus_message_exit_container(m); 414 415 sd_bus_message_enter_container(m, SD_BUS_TYPE_VARIANT, "i"); 416 sd_bus_message_read(m, "i", &a); 417 assert(a == 4); 418 sd_bus_message_exit_container(m); 419 420 sd_bus_message_read(m, "i", &a); 421 assert(a == 2); 422 } 423 }; 424 verifyCallback = &verify::op; 425 426 b.call_noreply(m); 427 } 428 429 // Test map-variant. 430 { 431 auto m = newMethodCall__test(b); 432 std::map<std::string, sdbusplus::message::variant<int, double>> a1 = 433 { { "asdf", 3 }, { "jkl;", 4.1 } }; 434 m.append(1, a1, 2); 435 verifyTypeString = "ia{sv}i"; 436 437 struct verify 438 { 439 static void op(sd_bus_message* m) 440 { 441 int32_t a = 0; 442 double b = 0; 443 const char* c = nullptr; 444 445 sd_bus_message_read(m, "i", &a); 446 assert(a == 1); 447 448 sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "{sv}"); 449 sd_bus_message_enter_container(m, SD_BUS_TYPE_DICT_ENTRY, "sv"); 450 sd_bus_message_read(m, "s", &c); 451 assert(0 == strcmp("asdf", c)); 452 sd_bus_message_enter_container(m, SD_BUS_TYPE_VARIANT, "i"); 453 sd_bus_message_read(m, "i", &a); 454 assert(a == 3); 455 sd_bus_message_exit_container(m); 456 sd_bus_message_exit_container(m); 457 sd_bus_message_enter_container(m, SD_BUS_TYPE_DICT_ENTRY, "sv"); 458 sd_bus_message_read(m, "s", &c); 459 assert(0 == strcmp("jkl;", c)); 460 sd_bus_message_enter_container(m, SD_BUS_TYPE_VARIANT, "d"); 461 sd_bus_message_read(m, "d", &b); 462 assert(b == 4.1); 463 sd_bus_message_exit_container(m); 464 sd_bus_message_exit_container(m); 465 sd_bus_message_exit_container(m); 466 467 sd_bus_message_read(m, "i", &a); 468 assert(a == 2); 469 } 470 }; 471 verifyCallback = &verify::op; 472 473 b.call_noreply(m); 474 } 475 476 // Shutdown server. 477 { 478 auto m = b.new_method_call(SERVICE, "/", INTERFACE, QUIT_METHOD); 479 b.call_noreply(m); 480 } 481 } 482 483 int main() 484 { 485 486 // Initialize and start server thread. 487 pthread_t t; 488 { 489 auto b = serverInit(); 490 pthread_create(&t, NULL, server, b.release()); 491 } 492 493 runTests(); 494 495 // Wait for server thread to exit. 496 pthread_join(t, NULL); 497 498 return 0; 499 } 500