1#include <stdio.h> 2#include <stdlib.h> 3#include <unistd.h> 4#include <string.h> 5#include <dbus/dbus.h> 6#include <dbus/dbus-connection-internal.h> 7 8#define REMOVE_CONNECTION 0 9#define ADD_CONNECTION 1 10#define ALLOW_REPLACEMENT DBUS_NAME_FLAG_ALLOW_REPLACEMENT 11#define REPLACE_EXISTING DBUS_NAME_FLAG_REPLACE_EXISTING 12#define DO_NOT_QUEUE DBUS_NAME_FLAG_DO_NOT_QUEUE 13 14#define PRIMARY_OWNER DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER 15#define IN_QUEUE DBUS_REQUEST_NAME_REPLY_IN_QUEUE 16#define EXISTS DBUS_REQUEST_NAME_REPLY_EXISTS 17#define ALREADY_OWNER DBUS_REQUEST_NAME_REPLY_ALREADY_OWNER 18 19#define RELEASED DBUS_RELEASE_NAME_REPLY_RELEASED 20#define NON_EXISTANT DBUS_RELEASE_NAME_REPLY_NON_EXISTENT 21#define NOT_OWNER DBUS_RELEASE_NAME_REPLY_NOT_OWNER 22 23#define NUM_CONN 4 24#define TEST_NAME "org.freedesktop.DBus.TestSuite.NameTest" 25#define NUM_TRIES_TIL_FAIL 15 26 27typedef struct { 28 int command; 29 30 int connection_number; 31 dbus_uint32_t flags; 32 33 dbus_uint32_t expected_result; 34 35 int expected_queue[NUM_CONN]; 36} CommandAndResult; 37 38CommandAndResult test_data[] = { 39 {ADD_CONNECTION, 0, ALLOW_REPLACEMENT | REPLACE_EXISTING, 40 PRIMARY_OWNER, {0,-1,-1,-1}}, 41 {ADD_CONNECTION, 0, REPLACE_EXISTING, 42 ALREADY_OWNER, {0,-1,-1,-1}}, 43 {ADD_CONNECTION, 1, ALLOW_REPLACEMENT | REPLACE_EXISTING, 44 IN_QUEUE, {0,1,-1,-1}}, 45 {REMOVE_CONNECTION, 0, 0, 46 RELEASED, {1,-1,-1,-1}}, 47 {ADD_CONNECTION, 0, REPLACE_EXISTING | DO_NOT_QUEUE, 48 PRIMARY_OWNER, {0,1,-1,-1}}, 49 {ADD_CONNECTION, 2, ALLOW_REPLACEMENT, 50 IN_QUEUE, {0,1,2,-1}}, 51 {ADD_CONNECTION, 2, ALLOW_REPLACEMENT | REPLACE_EXISTING, 52 IN_QUEUE, {0,2,1,-1}}, 53 {ADD_CONNECTION, 0, ALLOW_REPLACEMENT | DO_NOT_QUEUE, 54 ALREADY_OWNER, {0,2,1,-1}}, 55 {ADD_CONNECTION, 1, ALLOW_REPLACEMENT | REPLACE_EXISTING, 56 PRIMARY_OWNER, {1,2,-1,-1}}, 57 {ADD_CONNECTION, 0, REPLACE_EXISTING, 58 PRIMARY_OWNER, {0,1,2,-1}}, 59 {ADD_CONNECTION, 2, DO_NOT_QUEUE, 60 EXISTS, {0,1,-1,-1}}, 61 {REMOVE_CONNECTION, 2, 0, 62 NOT_OWNER, {0,1,-1,-1}}, 63 {ADD_CONNECTION, 3, 0, 64 IN_QUEUE, {0,1,3,-1}}, 65 {ADD_CONNECTION, 0, ALLOW_REPLACEMENT, 66 ALREADY_OWNER, {0,1,3,-1}}, 67 {ADD_CONNECTION, 2, ALLOW_REPLACEMENT, 68 IN_QUEUE, {0,1,3,2}} 69}; 70 71static dbus_bool_t 72check_connection (DBusConnection *conn, 73 int iteration, 74 DBusConnection *uniq_conn[NUM_CONN]) 75{ 76 DBusMessage *reply; 77 DBusMessage *method; 78 DBusError error; 79 char **list; 80 int len, i; 81 const char *name; 82 83 reply = NULL; 84 method = NULL; 85 list = NULL; 86 87 dbus_error_init (&error); 88 89 name = TEST_NAME; 90 method = dbus_message_new_method_call (DBUS_SERVICE_DBUS, 91 DBUS_PATH_DBUS, 92 DBUS_INTERFACE_DBUS, 93 "ListQueuedOwners"); 94 95 if (method == NULL) 96 goto out; 97 98 if (!dbus_message_append_args (method, 99 DBUS_TYPE_STRING, &name, 100 DBUS_TYPE_INVALID)) 101 { 102 fprintf (stderr, "Error appending args\n") ; 103 goto out; 104 } 105 106 reply = dbus_connection_send_with_reply_and_block (conn, 107 method, 108 -1, 109 &error); 110 111 if (reply == NULL) 112 { 113 fprintf (stderr, "Error calling ListQueuedOwners: %s\n", error.message); 114 dbus_error_free (&error); 115 goto out; 116 } 117 118 119 120 if (!dbus_message_get_args (reply, 121 &error, 122 DBUS_TYPE_ARRAY, DBUS_TYPE_STRING, 123 &list, &len, 124 DBUS_TYPE_INVALID)) 125 { 126 fprintf (stderr, "Error getting args: %s\n", error.message); 127 dbus_error_free (&error); 128 goto out; 129 } 130 131 printf ("Iteration %i: ", iteration); 132 133 if (len > NUM_CONN) 134 { 135 fprintf (stderr, "There are %i connections in the queue," 136 " we are only expecting up to %i connections!\n", 137 len, 138 NUM_CONN); 139 goto out; 140 } 141 142 for (i = 0; i < len; i++) 143 { 144 int expected_conn_num; 145 const char *expected_uname; 146 147 if (i > 0) 148 printf (", "); 149 150 printf ("%s", list[i]); 151 152 expected_conn_num = test_data[iteration].expected_queue[i]; 153 154 if (expected_conn_num == -1) 155 { 156 fprintf (stderr, 157 "\nDid not expect this last connection" 158 " to be in the queue!\n"); 159 goto out; 160 } 161 162 expected_uname = 163 dbus_bus_get_unique_name (uniq_conn[expected_conn_num]); 164 165 if (strcmp (list[i], expected_uname) != 0) 166 { 167 fprintf (stderr, 168 "\n%s expected but %s is in the queue!\n", 169 expected_uname, 170 list[i]); 171 172 goto out; 173 } 174 } 175 176 printf ("\n"); 177 178 dbus_message_unref (method); 179 dbus_message_unref (reply); 180 dbus_free_string_array (list); 181 return TRUE; 182 183 out: 184 if (method != NULL) 185 dbus_message_unref (method); 186 187 if (reply != NULL) 188 dbus_message_unref (reply); 189 190 if (list != NULL) 191 dbus_free_string_array (list); 192 193 return FALSE; 194} 195 196static dbus_bool_t 197match_acquired_or_lost_signal (DBusConnection *conn, const char *member, const char *name) 198{ 199 int tries; 200 DBusMessage *msg; 201 const char *interface = "org.freedesktop.DBus"; 202 203 for (tries = 0; tries < NUM_TRIES_TIL_FAIL; tries++) 204 { 205 _dbus_connection_lock (conn); 206 _dbus_connection_do_iteration_unlocked (conn, 207 DBUS_ITERATION_DO_READING | 208 DBUS_ITERATION_DO_WRITING | 209 DBUS_ITERATION_BLOCK, 210 0); 211 _dbus_connection_unlock (conn); 212 msg = dbus_connection_pop_message (conn); 213 if (msg != NULL) 214 { 215 if (dbus_message_is_signal (msg, 216 interface, 217 member)) 218 { 219 const char *n; 220 DBusError error; 221 dbus_error_init (&error); 222 223 dbus_message_get_args (msg, &error, DBUS_TYPE_STRING, &n, DBUS_TYPE_INVALID); 224 225 if (dbus_error_is_set (&error)) 226 { 227 fprintf (stderr, "Error getting args: %s\n", error.message); 228 dbus_error_free (&error); 229 dbus_message_unref (msg); 230 return FALSE; 231 } 232 233 if (strcmp (n, name) == 0) 234 { 235 dbus_message_unref (msg); 236 break; 237 } 238 } 239 dbus_message_unref (msg); 240 } 241 } 242 243 if (tries == NUM_TRIES_TIL_FAIL) 244 { 245 fprintf (stderr, "Did not recive the expected %s.%s signal!!!\n", interface, member); 246 return FALSE; 247 } 248 249 return TRUE; 250} 251 252static dbus_bool_t 253match_name_owner_changed_signal (DBusConnection *conn, const char *bus_name, const char *lost_name, const char *acquired_name) 254{ 255 int tries; 256 DBusMessage *msg; 257 258 for (tries = 0; tries < NUM_TRIES_TIL_FAIL; tries++) 259 { 260 _dbus_connection_lock (conn); 261 _dbus_connection_do_iteration_unlocked (conn, 262 DBUS_ITERATION_DO_READING | 263 DBUS_ITERATION_DO_WRITING | 264 DBUS_ITERATION_BLOCK, 265 0); 266 _dbus_connection_unlock (conn); 267 msg = dbus_connection_pop_message (conn); 268 269 if (msg != NULL) 270 { 271 if (dbus_message_is_signal (msg, 272 "org.freedesktop.DBus", 273 "NameOwnerChanged")) 274 { 275 const char *n; 276 const char *ln; 277 const char *an; 278 DBusError error; 279 dbus_error_init (&error); 280 281 dbus_message_get_args (msg, &error, DBUS_TYPE_STRING, &n, DBUS_TYPE_STRING, &ln, DBUS_TYPE_STRING, &an, DBUS_TYPE_INVALID); 282 283 if (dbus_error_is_set (&error)) 284 { 285 fprintf (stderr, "Error getting args: %s\n", error.message); 286 dbus_error_free (&error); 287 dbus_message_unref (msg); 288 return FALSE; 289 } 290 291 if (strcmp (n, bus_name) == 0) 292 { 293 if ((lost_name == NULL && strcmp (ln, "") == 0) 294 || strcmp (lost_name, ln) == 0) 295 { 296 if ((acquired_name == NULL && strcmp (an, "") == 0) 297 || strcmp (acquired_name, an) == 0) 298 { 299 dbus_message_unref (msg); 300 break; 301 } 302 else 303 { 304 fprintf (stderr, "Error: name %s was expected to be acquired but we got %s instead\n", acquired_name, an); 305 dbus_message_unref (msg); 306 return FALSE; 307 } 308 } 309 else 310 { 311 fprintf (stderr, "Error: name %s was expected to be lost but we got %s instead\n", lost_name, ln); 312 dbus_message_unref (msg); 313 return FALSE; 314 } 315 } 316 } 317 dbus_message_unref (msg); 318 } 319 } 320 321 if (tries == NUM_TRIES_TIL_FAIL) 322 { 323 fprintf (stderr, "Did not recive the expected NameOwnerChanged signal!!!\n"); 324 return FALSE; 325 } 326 327 return TRUE; 328} 329 330 331static dbus_bool_t 332check_signals (DBusConnection *monitor, 333 int iteration, 334 DBusConnection *conn[NUM_CONN]) 335{ 336 DBusConnection *lost_conn = NULL; 337 DBusConnection *acquired_conn = NULL; 338 const char *lost_name; 339 const char *acquired_name; 340 341 if (iteration == 0) 342 { 343 int i; 344 i = test_data[iteration].expected_queue[0]; 345 346 if (i >= 0) 347 acquired_conn = conn[i]; 348 } 349 else 350 { 351 int i; 352 i = test_data[iteration - 1].expected_queue[0]; 353 354 if (i >= 0) 355 lost_conn = conn[i]; 356 357 i = test_data[iteration].expected_queue[0]; 358 359 if (i >= 0) 360 acquired_conn = conn[i]; 361 362 if (acquired_conn == lost_conn) 363 acquired_conn = lost_conn = NULL; 364 } 365 366 lost_name = lost_conn == NULL? NULL : 367 dbus_bus_get_unique_name (lost_conn); 368 369 acquired_name = acquired_conn == NULL? NULL : 370 dbus_bus_get_unique_name (acquired_conn); 371 372 if (lost_name != NULL) 373 if (!match_acquired_or_lost_signal (lost_conn, 374 "NameLost", 375 TEST_NAME)) 376 return FALSE; 377 378 if (acquired_name != NULL) 379 if (!match_acquired_or_lost_signal (acquired_conn, 380 "NameAcquired", 381 TEST_NAME)) 382 return FALSE; 383 384 if (acquired_name != NULL || lost_name != NULL) 385 if (!match_name_owner_changed_signal (monitor, 386 TEST_NAME, 387 lost_name, 388 acquired_name)) 389 return FALSE; 390 391 return TRUE; 392} 393 394int 395main (int argc, char *argv[]) 396{ 397 DBusConnection *conn[NUM_CONN]; 398 DBusConnection *monitor; 399 DBusError error; 400 int i; 401 int test_data_len; 402 403 test_data_len = sizeof (test_data) / sizeof (CommandAndResult); 404 405 dbus_error_init (&error); 406 407 conn[0] = dbus_bus_get_private (DBUS_BUS_SESSION, &error); 408 if (dbus_error_is_set (&error)) 409 { 410 fprintf (stderr, "*** Failed to open connection 0 to session bus: %s\n", 411 error.message); 412 dbus_error_free (&error); 413 return 1; 414 } 415 416 if (!match_acquired_or_lost_signal (conn[0], 417 "NameAcquired", 418 dbus_bus_get_unique_name (conn[0]))) 419 return 1; 420 421 conn[1] = dbus_bus_get_private (DBUS_BUS_SESSION, &error); 422 if (dbus_error_is_set (&error)) 423 { 424 fprintf (stderr, "*** Failed to open connection 1 to session bus: %s\n", 425 error.message); 426 dbus_error_free (&error); 427 return 1; 428 } 429 430 if (!match_acquired_or_lost_signal (conn[1], 431 "NameAcquired", 432 dbus_bus_get_unique_name (conn[1]))) 433 return 1; 434 435 436 conn[2] = dbus_bus_get_private (DBUS_BUS_SESSION, &error); 437 if (dbus_error_is_set (&error)) 438 { 439 fprintf (stderr, "*** Failed to open connection 2 to session bus: %s\n", 440 error.message); 441 dbus_error_free (&error); 442 return 1; 443 } 444 445 if (!match_acquired_or_lost_signal (conn[2], 446 "NameAcquired", 447 dbus_bus_get_unique_name (conn[2]))) 448 return 1; 449 450 451 conn[3] = dbus_bus_get_private (DBUS_BUS_SESSION, &error); 452 if (dbus_error_is_set (&error)) 453 { 454 fprintf (stderr, "*** Failed to open connection 3 to session bus: %s\n", 455 error.message); 456 dbus_error_free (&error); 457 return 1; 458 } 459 460 if (!match_acquired_or_lost_signal (conn[3], 461 "NameAcquired", 462 dbus_bus_get_unique_name (conn[3]))) 463 return 1; 464 465 466 monitor = dbus_bus_get (DBUS_BUS_SESSION, &error); 467 if (dbus_error_is_set (&error)) 468 { 469 fprintf (stderr, "*** Failed to open monitoring connection to session bus: %s\n", 470 error.message); 471 dbus_error_free (&error); 472 return 1; 473 } 474 475 if (!match_acquired_or_lost_signal (monitor, 476 "NameAcquired", 477 dbus_bus_get_unique_name (monitor))) 478 return 1; 479 480 dbus_bus_add_match (monitor, "", &error); 481 if (dbus_error_is_set (&error)) 482 { 483 fprintf (stderr, "*** Failed to set filter on monitoring connection: %s\n", 484 error.message); 485 dbus_error_free (&error); 486 return 1; 487 } 488 489 490 for (i = 0; i < NUM_CONN; i++) 491 dbus_connection_set_exit_on_disconnect (conn[i], FALSE); 492 493 for (i = 0; i < test_data_len; i++) 494 { 495 dbus_uint32_t result; 496 result = 0; 497 498 if (test_data[i].command == ADD_CONNECTION) 499 { 500 result = dbus_bus_request_name (conn[test_data[i].connection_number], 501 TEST_NAME, 502 test_data[i].flags, 503 &error); 504 505 if (dbus_error_is_set (&error)) 506 { 507 fprintf (stderr, "Error on addition in iteration %i: %s\n", i, error.message); 508 dbus_error_free (&error); 509 return 1; 510 } 511 } 512 else if (test_data[i].command == REMOVE_CONNECTION) 513 { 514 result = dbus_bus_release_name (conn[test_data[i].connection_number], 515 TEST_NAME, 516 &error); 517 if (dbus_error_is_set (&error)) 518 { 519 fprintf (stderr, "*** Failed to remove connection %i in iteration %i: %s\n", 520 test_data[i].connection_number, 521 i, 522 error.message); 523 dbus_error_free (&error); 524 return 1; 525 } 526 } 527 else 528 { 529 fprintf (stderr, "Command #%i not a valid command!\n", test_data[i].command); 530 return 1; 531 } 532 533 534 if (result != test_data[i].expected_result) 535 { 536 fprintf (stderr, "Results recived (%i) are not the expected results (%i) in iteration %i\n", 537 result, 538 test_data[i].expected_result, 539 i); 540 return 1; 541 } 542 543 if (!check_connection (monitor, i, conn)) 544 { 545 fprintf (stderr, "Failed at iteration %i\n", i); 546 return 1; 547 } 548 549 if (!check_signals (monitor, i, conn)) 550 { 551 fprintf (stderr, "Failed at iteration %i\n", i); 552 return 1; 553 } 554 } 555 556 return 0; 557} 558