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