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"; 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 68 auto newMethodCall__test(sdbusplus::bus::bus& b) 69 { 70 // Allocate a method-call message for INTERFACE,TEST_METHOD. 71 return b.new_method_call(SERVICE, "/", INTERFACE, TEST_METHOD); 72 } 73 74 void runTests() 75 { 76 using namespace std::literals; 77 78 auto b = sdbusplus::bus::new_default(); 79 80 // Test r-value int. 81 { 82 auto m = newMethodCall__test(b); 83 m.append(1); 84 verifyTypeString = "i"; 85 86 struct verify 87 { 88 static void op(sd_bus_message* m) 89 { 90 int32_t i = 0; 91 sd_bus_message_read_basic(m, 'i', &i); 92 assert(i == 1); 93 } 94 }; 95 verifyCallback = &verify::op; 96 97 b.call_noreply(m); 98 } 99 // Test l-value int. 100 { 101 auto m = newMethodCall__test(b); 102 int a = 1; 103 m.append(a, a); 104 verifyTypeString = "ii"; 105 106 struct verify 107 { 108 static void op(sd_bus_message* m) 109 { 110 int32_t a = 0, b = 0; 111 sd_bus_message_read(m, "ii", &a, &b); 112 assert(a == 1); 113 assert(b == 1); 114 } 115 }; 116 verifyCallback = &verify::op; 117 118 b.call_noreply(m); 119 } 120 121 // Test multiple ints. 122 { 123 auto m = newMethodCall__test(b); 124 m.append(1, 2, 3, 4, 5); 125 verifyTypeString = "iiiii"; 126 127 struct verify 128 { 129 static void op(sd_bus_message* m) 130 { 131 int32_t a = 0, b = 0, c = 0, d = 0, e = 0; 132 sd_bus_message_read(m, "iiiii", &a, &b, &c, &d, &e); 133 assert(a == 1); 134 assert(b == 2); 135 assert(c == 3); 136 assert(d == 4); 137 assert(e == 5); 138 } 139 }; 140 verifyCallback = &verify::op; 141 142 b.call_noreply(m); 143 } 144 145 // Test double and bool. 146 { 147 auto m = newMethodCall__test(b); 148 bool t = true; 149 m.append(t, true, false, 1.1); 150 verifyTypeString = "bbbd"; 151 152 struct verify 153 { 154 static void op(sd_bus_message* m) 155 { 156 bool t1, t2, f1; 157 double d; 158 sd_bus_message_read(m, "bbbd", &t1, &t2, &f1, &d); 159 assert(t1); 160 assert(t2); 161 assert(!f1); 162 assert(d == 1.1); 163 } 164 }; 165 verifyCallback = &verify::op; 166 167 b.call_noreply(m); 168 } 169 170 // Test r-value string. 171 { 172 auto m = newMethodCall__test(b); 173 m.append("asdf"s); 174 verifyTypeString = "s"; 175 176 struct verify 177 { 178 static void op(sd_bus_message* m) 179 { 180 const char* s = nullptr; 181 sd_bus_message_read_basic(m, 's', &s); 182 assert(0 == strcmp("asdf", s)); 183 } 184 }; 185 verifyCallback = &verify::op; 186 187 b.call_noreply(m); 188 } 189 190 // Test multiple strings, various forms. 191 { 192 auto m = newMethodCall__test(b); 193 auto str = "jkl;"s; 194 auto str2 = "JKL:"s; 195 m.append(1, "asdf", "ASDF"s, str, 196 std::move(str2), 5); 197 verifyTypeString = "issssi"; 198 199 struct verify 200 { 201 static void op(sd_bus_message* m) 202 { 203 int32_t a = 0, b = 0; 204 const char *s0 = nullptr, *s1 = nullptr, *s2 = nullptr, 205 *s3 = nullptr; 206 sd_bus_message_read(m, "issssi", &a, &s0, &s1, &s2, &s3, &b); 207 assert(a == 1); 208 assert(b == 5); 209 assert(0 == strcmp("asdf", s0)); 210 assert(0 == strcmp("ASDF", s1)); 211 assert(0 == strcmp("jkl;", s2)); 212 assert(0 == strcmp("JKL:", s3)); 213 } 214 }; 215 verifyCallback = &verify::op; 216 217 b.call_noreply(m); 218 } 219 220 // Test vector. 221 { 222 auto m = newMethodCall__test(b); 223 std::vector<std::string> s{ "1", "2", "3"}; 224 m.append(1, s, 2); 225 verifyTypeString = "iasi"; 226 227 struct verify 228 { 229 static void op(sd_bus_message* m) 230 { 231 int32_t a = 0; 232 sd_bus_message_read(m, "i", &a); 233 assert(a == 1); 234 235 auto rc = sd_bus_message_enter_container(m, 236 SD_BUS_TYPE_ARRAY, 237 "s"); 238 assert(0 <= rc); 239 240 const char* s = nullptr; 241 sd_bus_message_read_basic(m, 's', &s); 242 assert(0 == strcmp("1", s)); 243 sd_bus_message_read_basic(m, 's', &s); 244 assert(0 == strcmp("2", s)); 245 sd_bus_message_read_basic(m, 's', &s); 246 assert(0 == strcmp("3", s)); 247 assert(1 == sd_bus_message_at_end(m, false)); 248 249 sd_bus_message_exit_container(m); 250 251 sd_bus_message_read(m, "i", &a); 252 assert(a == 2); 253 254 } 255 }; 256 verifyCallback = &verify::op; 257 258 259 b.call_noreply(m); 260 } 261 262 // Test map. 263 { 264 auto m = newMethodCall__test(b); 265 std::map<std::string, int> s = { { "asdf", 3 }, { "jkl;", 4 } }; 266 m.append(1, s, 2); 267 verifyTypeString = "ia{si}i"; 268 269 struct verify 270 { 271 static void op(sd_bus_message* m) 272 { 273 int32_t a = 0; 274 sd_bus_message_read(m, "i", &a); 275 assert(a == 1); 276 277 auto rc = sd_bus_message_enter_container(m, 278 SD_BUS_TYPE_ARRAY, 279 "{si}"); 280 assert(0 <= rc); 281 282 rc = sd_bus_message_enter_container(m, 283 SD_BUS_TYPE_DICT_ENTRY, 284 "si"); 285 assert(0 <= rc); 286 287 const char* s = nullptr; 288 sd_bus_message_read_basic(m, 's', &s); 289 assert(0 == strcmp("asdf", s)); 290 sd_bus_message_read_basic(m, 'i', &a); 291 assert(a == 3); 292 293 assert(1 == sd_bus_message_at_end(m, false)); 294 sd_bus_message_exit_container(m); 295 296 rc = sd_bus_message_enter_container(m, 297 SD_BUS_TYPE_DICT_ENTRY, 298 "si"); 299 assert(0 <= rc); 300 301 sd_bus_message_read_basic(m, 's', &s); 302 assert(0 == strcmp("jkl;", s)); 303 sd_bus_message_read_basic(m, 'i', &a); 304 assert(a == 4); 305 306 assert(1 == sd_bus_message_at_end(m, false)); 307 sd_bus_message_exit_container(m); 308 309 assert(1 == sd_bus_message_at_end(m, false)); 310 sd_bus_message_exit_container(m); 311 312 sd_bus_message_read(m, "i", &a); 313 assert(a == 2); 314 } 315 }; 316 verifyCallback = &verify::op; 317 318 b.call_noreply(m); 319 } 320 321 // Test tuple. 322 { 323 auto m = newMethodCall__test(b); 324 std::tuple<int, double, std::string> a{ 3, 4.1, "asdf" }; 325 m.append(1, a, 2); 326 verifyTypeString = "i(ids)i"; 327 328 struct verify 329 { 330 static void op(sd_bus_message* m) 331 { 332 int32_t a = 0; 333 double b = 0; 334 const char* c = nullptr; 335 336 sd_bus_message_read(m, "i", &a); 337 assert(a == 1); 338 339 auto rc = sd_bus_message_enter_container(m, 340 SD_BUS_TYPE_STRUCT, 341 "ids"); 342 assert(0 <= rc); 343 344 sd_bus_message_read(m, "ids", &a, &b, &c); 345 assert(a == 3); 346 assert(b == 4.1); 347 assert(0 == strcmp(c, "asdf")); 348 349 sd_bus_message_exit_container(m); 350 351 sd_bus_message_read(m, "i", &a); 352 assert(a == 2); 353 } 354 }; 355 verifyCallback = &verify::op; 356 357 b.call_noreply(m); 358 } 359 360 // Test variant. 361 { 362 auto m = newMethodCall__test(b); 363 sdbusplus::message::variant<int, double> a1{3.1}, a2{4}; 364 m.append(1, a1, a2, 2); 365 verifyTypeString = "ivvi"; 366 367 struct verify 368 { 369 static void op(sd_bus_message* m) 370 { 371 int32_t a = 0; 372 double b = 0; 373 374 sd_bus_message_read(m, "i", &a); 375 assert(a == 1); 376 377 sd_bus_message_enter_container(m, SD_BUS_TYPE_VARIANT, "d"); 378 sd_bus_message_read(m, "d", &b); 379 assert(b == 3.1); 380 sd_bus_message_exit_container(m); 381 382 sd_bus_message_enter_container(m, SD_BUS_TYPE_VARIANT, "i"); 383 sd_bus_message_read(m, "i", &a); 384 assert(a == 4); 385 sd_bus_message_exit_container(m); 386 387 sd_bus_message_read(m, "i", &a); 388 assert(a == 2); 389 } 390 }; 391 verifyCallback = &verify::op; 392 393 b.call_noreply(m); 394 } 395 396 // Test map-variant. 397 { 398 auto m = newMethodCall__test(b); 399 std::map<std::string, sdbusplus::message::variant<int, double>> a1 = 400 { { "asdf", 3 }, { "jkl;", 4.1 } }; 401 m.append(1, a1, 2); 402 verifyTypeString = "ia{sv}i"; 403 404 struct verify 405 { 406 static void op(sd_bus_message* m) 407 { 408 int32_t a = 0; 409 double b = 0; 410 const char* c = nullptr; 411 412 sd_bus_message_read(m, "i", &a); 413 assert(a == 1); 414 415 sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "{sv}"); 416 sd_bus_message_enter_container(m, SD_BUS_TYPE_DICT_ENTRY, "sv"); 417 sd_bus_message_read(m, "s", &c); 418 assert(0 == strcmp("asdf", c)); 419 sd_bus_message_enter_container(m, SD_BUS_TYPE_VARIANT, "i"); 420 sd_bus_message_read(m, "i", &a); 421 assert(a == 3); 422 sd_bus_message_exit_container(m); 423 sd_bus_message_exit_container(m); 424 sd_bus_message_enter_container(m, SD_BUS_TYPE_DICT_ENTRY, "sv"); 425 sd_bus_message_read(m, "s", &c); 426 assert(0 == strcmp("jkl;", c)); 427 sd_bus_message_enter_container(m, SD_BUS_TYPE_VARIANT, "d"); 428 sd_bus_message_read(m, "d", &b); 429 assert(b == 4.1); 430 sd_bus_message_exit_container(m); 431 sd_bus_message_exit_container(m); 432 sd_bus_message_exit_container(m); 433 434 sd_bus_message_read(m, "i", &a); 435 assert(a == 2); 436 } 437 }; 438 verifyCallback = &verify::op; 439 440 b.call_noreply(m); 441 } 442 443 // Shutdown server. 444 { 445 auto m = b.new_method_call(SERVICE, "/", INTERFACE, QUIT_METHOD); 446 b.call_noreply(m); 447 } 448 } 449 450 int main() 451 { 452 453 // Initialize and start server thread. 454 pthread_t t; 455 { 456 auto b = serverInit(); 457 pthread_create(&t, NULL, server, b.release()); 458 } 459 460 runTests(); 461 462 // Wait for server thread to exit. 463 pthread_join(t, NULL); 464 465 return 0; 466 } 467