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 m.append(t, true, false, 1.1); 152 verifyTypeString = "bbbd"; 153 154 struct verify 155 { 156 static void op(sd_bus_message* m) 157 { 158 bool t1, t2, f1; 159 double d; 160 sd_bus_message_read(m, "bbbd", &t1, &t2, &f1, &d); 161 assert(t1); 162 assert(t2); 163 assert(!f1); 164 assert(d == 1.1); 165 } 166 }; 167 verifyCallback = &verify::op; 168 169 b.call_noreply(m); 170 } 171 172 // Test r-value string. 173 { 174 auto m = newMethodCall__test(b); 175 m.append("asdf"s); 176 verifyTypeString = "s"; 177 178 struct verify 179 { 180 static void op(sd_bus_message* m) 181 { 182 const char* s = nullptr; 183 sd_bus_message_read_basic(m, 's', &s); 184 assert(0 == strcmp("asdf", s)); 185 } 186 }; 187 verifyCallback = &verify::op; 188 189 b.call_noreply(m); 190 } 191 192 // Test multiple strings, various forms. 193 { 194 auto m = newMethodCall__test(b); 195 auto str = "jkl;"s; 196 auto str2 = "JKL:"s; 197 m.append(1, "asdf", "ASDF"s, str, 198 std::move(str2), 5); 199 verifyTypeString = "issssi"; 200 201 struct verify 202 { 203 static void op(sd_bus_message* m) 204 { 205 int32_t a = 0, b = 0; 206 const char *s0 = nullptr, *s1 = nullptr, *s2 = nullptr, 207 *s3 = nullptr; 208 sd_bus_message_read(m, "issssi", &a, &s0, &s1, &s2, &s3, &b); 209 assert(a == 1); 210 assert(b == 5); 211 assert(0 == strcmp("asdf", s0)); 212 assert(0 == strcmp("ASDF", s1)); 213 assert(0 == strcmp("jkl;", s2)); 214 assert(0 == strcmp("JKL:", s3)); 215 } 216 }; 217 verifyCallback = &verify::op; 218 219 b.call_noreply(m); 220 } 221 222 // Test vector. 223 { 224 auto m = newMethodCall__test(b); 225 std::vector<std::string> s{ "1", "2", "3"}; 226 m.append(1, s, 2); 227 verifyTypeString = "iasi"; 228 229 struct verify 230 { 231 static void op(sd_bus_message* m) 232 { 233 int32_t a = 0; 234 sd_bus_message_read(m, "i", &a); 235 assert(a == 1); 236 237 auto rc = sd_bus_message_enter_container(m, 238 SD_BUS_TYPE_ARRAY, 239 "s"); 240 assert(0 <= rc); 241 242 const char* s = nullptr; 243 sd_bus_message_read_basic(m, 's', &s); 244 assert(0 == strcmp("1", s)); 245 sd_bus_message_read_basic(m, 's', &s); 246 assert(0 == strcmp("2", s)); 247 sd_bus_message_read_basic(m, 's', &s); 248 assert(0 == strcmp("3", s)); 249 assert(1 == sd_bus_message_at_end(m, false)); 250 251 sd_bus_message_exit_container(m); 252 253 sd_bus_message_read(m, "i", &a); 254 assert(a == 2); 255 256 } 257 }; 258 verifyCallback = &verify::op; 259 260 261 b.call_noreply(m); 262 } 263 264 // Test map. 265 { 266 auto m = newMethodCall__test(b); 267 std::map<std::string, int> s = { { "asdf", 3 }, { "jkl;", 4 } }; 268 m.append(1, s, 2); 269 verifyTypeString = "ia{si}i"; 270 271 struct verify 272 { 273 static void op(sd_bus_message* m) 274 { 275 int32_t a = 0; 276 sd_bus_message_read(m, "i", &a); 277 assert(a == 1); 278 279 auto rc = sd_bus_message_enter_container(m, 280 SD_BUS_TYPE_ARRAY, 281 "{si}"); 282 assert(0 <= rc); 283 284 rc = sd_bus_message_enter_container(m, 285 SD_BUS_TYPE_DICT_ENTRY, 286 "si"); 287 assert(0 <= rc); 288 289 const char* s = nullptr; 290 sd_bus_message_read_basic(m, 's', &s); 291 assert(0 == strcmp("asdf", s)); 292 sd_bus_message_read_basic(m, 'i', &a); 293 assert(a == 3); 294 295 assert(1 == sd_bus_message_at_end(m, false)); 296 sd_bus_message_exit_container(m); 297 298 rc = sd_bus_message_enter_container(m, 299 SD_BUS_TYPE_DICT_ENTRY, 300 "si"); 301 assert(0 <= rc); 302 303 sd_bus_message_read_basic(m, 's', &s); 304 assert(0 == strcmp("jkl;", s)); 305 sd_bus_message_read_basic(m, 'i', &a); 306 assert(a == 4); 307 308 assert(1 == sd_bus_message_at_end(m, false)); 309 sd_bus_message_exit_container(m); 310 311 assert(1 == sd_bus_message_at_end(m, false)); 312 sd_bus_message_exit_container(m); 313 314 sd_bus_message_read(m, "i", &a); 315 assert(a == 2); 316 } 317 }; 318 verifyCallback = &verify::op; 319 320 b.call_noreply(m); 321 } 322 323 // Test tuple. 324 { 325 auto m = newMethodCall__test(b); 326 std::tuple<int, double, std::string> a{ 3, 4.1, "asdf" }; 327 m.append(1, a, 2); 328 verifyTypeString = "i(ids)i"; 329 330 struct verify 331 { 332 static void op(sd_bus_message* m) 333 { 334 int32_t a = 0; 335 double b = 0; 336 const char* c = nullptr; 337 338 sd_bus_message_read(m, "i", &a); 339 assert(a == 1); 340 341 auto rc = sd_bus_message_enter_container(m, 342 SD_BUS_TYPE_STRUCT, 343 "ids"); 344 assert(0 <= rc); 345 346 sd_bus_message_read(m, "ids", &a, &b, &c); 347 assert(a == 3); 348 assert(b == 4.1); 349 assert(0 == strcmp(c, "asdf")); 350 351 sd_bus_message_exit_container(m); 352 353 sd_bus_message_read(m, "i", &a); 354 assert(a == 2); 355 } 356 }; 357 verifyCallback = &verify::op; 358 359 b.call_noreply(m); 360 } 361 362 // Test variant. 363 { 364 auto m = newMethodCall__test(b); 365 sdbusplus::message::variant<int, double> a1{3.1}, a2{4}; 366 m.append(1, a1, a2, 2); 367 verifyTypeString = "ivvi"; 368 369 struct verify 370 { 371 static void op(sd_bus_message* m) 372 { 373 int32_t a = 0; 374 double b = 0; 375 376 sd_bus_message_read(m, "i", &a); 377 assert(a == 1); 378 379 sd_bus_message_enter_container(m, SD_BUS_TYPE_VARIANT, "d"); 380 sd_bus_message_read(m, "d", &b); 381 assert(b == 3.1); 382 sd_bus_message_exit_container(m); 383 384 sd_bus_message_enter_container(m, SD_BUS_TYPE_VARIANT, "i"); 385 sd_bus_message_read(m, "i", &a); 386 assert(a == 4); 387 sd_bus_message_exit_container(m); 388 389 sd_bus_message_read(m, "i", &a); 390 assert(a == 2); 391 } 392 }; 393 verifyCallback = &verify::op; 394 395 b.call_noreply(m); 396 } 397 398 // Test map-variant. 399 { 400 auto m = newMethodCall__test(b); 401 std::map<std::string, sdbusplus::message::variant<int, double>> a1 = 402 { { "asdf", 3 }, { "jkl;", 4.1 } }; 403 m.append(1, a1, 2); 404 verifyTypeString = "ia{sv}i"; 405 406 struct verify 407 { 408 static void op(sd_bus_message* m) 409 { 410 int32_t a = 0; 411 double b = 0; 412 const char* c = nullptr; 413 414 sd_bus_message_read(m, "i", &a); 415 assert(a == 1); 416 417 sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "{sv}"); 418 sd_bus_message_enter_container(m, SD_BUS_TYPE_DICT_ENTRY, "sv"); 419 sd_bus_message_read(m, "s", &c); 420 assert(0 == strcmp("asdf", c)); 421 sd_bus_message_enter_container(m, SD_BUS_TYPE_VARIANT, "i"); 422 sd_bus_message_read(m, "i", &a); 423 assert(a == 3); 424 sd_bus_message_exit_container(m); 425 sd_bus_message_exit_container(m); 426 sd_bus_message_enter_container(m, SD_BUS_TYPE_DICT_ENTRY, "sv"); 427 sd_bus_message_read(m, "s", &c); 428 assert(0 == strcmp("jkl;", c)); 429 sd_bus_message_enter_container(m, SD_BUS_TYPE_VARIANT, "d"); 430 sd_bus_message_read(m, "d", &b); 431 assert(b == 4.1); 432 sd_bus_message_exit_container(m); 433 sd_bus_message_exit_container(m); 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 // Shutdown server. 446 { 447 auto m = b.new_method_call(SERVICE, "/", INTERFACE, QUIT_METHOD); 448 b.call_noreply(m); 449 } 450 } 451 452 int main() 453 { 454 455 // Initialize and start server thread. 456 pthread_t t; 457 { 458 auto b = serverInit(); 459 pthread_create(&t, NULL, server, b.release()); 460 } 461 462 runTests(); 463 464 // Wait for server thread to exit. 465 pthread_join(t, NULL); 466 467 return 0; 468 } 469