1 /* -*- mode: C; c-file-style: "gnu" -*- */ 2 /* dbus-object-tree.c DBusObjectTree (internals of DBusConnection) 3 * 4 * Copyright (C) 2003, 2005 Red Hat Inc. 5 * 6 * Licensed under the Academic Free License version 2.1 7 * 8 * This program is free software; you can redistribute it and/or modify 9 * it under the terms of the GNU General Public License as published by 10 * the Free Software Foundation; either version 2 of the License, or 11 * (at your option) any later version. 12 * 13 * This program is distributed in the hope that it will be useful, 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 * GNU General Public License for more details. 17 * 18 * You should have received a copy of the GNU General Public License 19 * along with this program; if not, write to the Free Software 20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 21 * 22 */ 23 #include "dbus-object-tree.h" 24 #include "dbus-connection-internal.h" 25 #include "dbus-internals.h" 26 #include "dbus-hash.h" 27 #include "dbus-protocol.h" 28 #include "dbus-string.h" 29 #include <string.h> 30 #include <stdlib.h> 31 32 /** 33 * @defgroup DBusObjectTree A hierarchy of objects with container-contained relationship 34 * @ingroup DBusInternals 35 * @brief DBusObjectTree is used by DBusConnection to track the object tree 36 * 37 * Types and functions related to DBusObjectTree. These 38 * are all library-internal. 39 * 40 * @{ 41 */ 42 43 /** Subnode of the object hierarchy */ 44 typedef struct DBusObjectSubtree DBusObjectSubtree; 45 46 static DBusObjectSubtree* _dbus_object_subtree_new (const char *name, 47 const DBusObjectPathVTable *vtable, 48 void *user_data); 49 static DBusObjectSubtree* _dbus_object_subtree_ref (DBusObjectSubtree *subtree); 50 static void _dbus_object_subtree_unref (DBusObjectSubtree *subtree); 51 52 /** 53 * Internals of DBusObjectTree 54 */ 55 struct DBusObjectTree 56 { 57 int refcount; /**< Reference count */ 58 DBusConnection *connection; /**< Connection this tree belongs to */ 59 60 DBusObjectSubtree *root; /**< Root of the tree ("/" node) */ 61 }; 62 63 /** 64 * Struct representing a single registered subtree handler, or node 65 * that's a parent of a registered subtree handler. If 66 * message_function != NULL there's actually a handler at this node. 67 */ 68 struct DBusObjectSubtree 69 { 70 DBusAtomic refcount; /**< Reference count */ 71 DBusObjectSubtree *parent; /**< Parent node */ 72 DBusObjectPathUnregisterFunction unregister_function; /**< Function to call on unregister */ 73 DBusObjectPathMessageFunction message_function; /**< Function to handle messages */ 74 void *user_data; /**< Data for functions */ 75 DBusObjectSubtree **subtrees; /**< Child nodes */ 76 int n_subtrees; /**< Number of child nodes */ 77 int max_subtrees; /**< Number of allocated entries in subtrees */ 78 unsigned int invoke_as_fallback : 1; /**< Whether to invoke message_function when child nodes don't handle the message */ 79 char name[1]; /**< Allocated as large as necessary */ 80 }; 81 82 /** 83 * Creates a new object tree, representing a mapping from paths 84 * to handler vtables. 85 * 86 * @param connection the connection this tree belongs to 87 * @returns the new tree or #NULL if no memory 88 */ 89 DBusObjectTree* 90 _dbus_object_tree_new (DBusConnection *connection) 91 { 92 DBusObjectTree *tree; 93 94 /* the connection passed in here isn't fully constructed, 95 * so don't do anything more than store a pointer to 96 * it 97 */ 98 99 tree = dbus_new0 (DBusObjectTree, 1); 100 if (tree == NULL) 101 goto oom; 102 103 tree->refcount = 1; 104 tree->connection = connection; 105 tree->root = _dbus_object_subtree_new ("/", NULL, NULL); 106 if (tree->root == NULL) 107 goto oom; 108 tree->root->invoke_as_fallback = TRUE; 109 110 return tree; 111 112 oom: 113 if (tree) 114 { 115 dbus_free (tree); 116 } 117 118 return NULL; 119 } 120 121 /** 122 * Increment the reference count 123 * @param tree the object tree 124 * @returns the object tree 125 */ 126 DBusObjectTree * 127 _dbus_object_tree_ref (DBusObjectTree *tree) 128 { 129 _dbus_assert (tree->refcount > 0); 130 131 tree->refcount += 1; 132 133 return tree; 134 } 135 136 /** 137 * Decrement the reference count 138 * @param tree the object tree 139 */ 140 void 141 _dbus_object_tree_unref (DBusObjectTree *tree) 142 { 143 _dbus_assert (tree->refcount > 0); 144 145 tree->refcount -= 1; 146 147 if (tree->refcount == 0) 148 { 149 _dbus_object_tree_free_all_unlocked (tree); 150 151 dbus_free (tree); 152 } 153 } 154 155 /** Set to 1 to get a bunch of debug spew about finding the 156 * subtree nodes 157 */ 158 #define VERBOSE_FIND 0 159 160 static DBusObjectSubtree* 161 find_subtree_recurse (DBusObjectSubtree *subtree, 162 const char **path, 163 dbus_bool_t create_if_not_found, 164 int *index_in_parent, 165 dbus_bool_t *exact_match) 166 { 167 int i, j; 168 dbus_bool_t return_deepest_match; 169 170 return_deepest_match = exact_match != NULL; 171 172 _dbus_assert (!(return_deepest_match && create_if_not_found)); 173 174 if (path[0] == NULL) 175 { 176 #if VERBOSE_FIND 177 _dbus_verbose (" path exhausted, returning %s\n", 178 subtree->name); 179 #endif 180 if (exact_match != NULL) 181 *exact_match = TRUE; 182 return subtree; 183 } 184 185 #if VERBOSE_FIND 186 _dbus_verbose (" searching children of %s for %s\n", 187 subtree->name, path[0]); 188 #endif 189 190 i = 0; 191 j = subtree->n_subtrees; 192 while (i < j) 193 { 194 int k, v; 195 196 k = (i + j) / 2; 197 v = strcmp (path[0], subtree->subtrees[k]->name); 198 199 #if VERBOSE_FIND 200 _dbus_verbose (" %s cmp %s = %d\n", 201 path[0], subtree->subtrees[k]->name, 202 v); 203 #endif 204 205 if (v == 0) 206 { 207 if (index_in_parent) 208 { 209 #if VERBOSE_FIND 210 _dbus_verbose (" storing parent index %d\n", k); 211 #endif 212 *index_in_parent = k; 213 } 214 215 if (return_deepest_match) 216 { 217 DBusObjectSubtree *next; 218 219 next = find_subtree_recurse (subtree->subtrees[k], 220 &path[1], create_if_not_found, 221 index_in_parent, exact_match); 222 if (next == NULL && 223 subtree->invoke_as_fallback) 224 { 225 #if VERBOSE_FIND 226 _dbus_verbose (" no deeper match found, returning %s\n", 227 subtree->name); 228 #endif 229 if (exact_match != NULL) 230 *exact_match = FALSE; 231 return subtree; 232 } 233 else 234 return next; 235 } 236 else 237 return find_subtree_recurse (subtree->subtrees[k], 238 &path[1], create_if_not_found, 239 index_in_parent, exact_match); 240 } 241 else if (v < 0) 242 { 243 j = k; 244 } 245 else 246 { 247 i = k + 1; 248 } 249 } 250 251 #if VERBOSE_FIND 252 _dbus_verbose (" no match found, current tree %s, create_if_not_found = %d\n", 253 subtree->name, create_if_not_found); 254 #endif 255 256 if (create_if_not_found) 257 { 258 DBusObjectSubtree* child; 259 int child_pos, new_n_subtrees; 260 261 #if VERBOSE_FIND 262 _dbus_verbose (" creating subtree %s\n", 263 path[0]); 264 #endif 265 266 child = _dbus_object_subtree_new (path[0], 267 NULL, NULL); 268 if (child == NULL) 269 return NULL; 270 271 new_n_subtrees = subtree->n_subtrees + 1; 272 if (new_n_subtrees > subtree->max_subtrees) 273 { 274 int new_max_subtrees; 275 DBusObjectSubtree **new_subtrees; 276 277 new_max_subtrees = subtree->max_subtrees == 0 ? 1 : 2 * subtree->max_subtrees; 278 new_subtrees = dbus_realloc (subtree->subtrees, 279 new_max_subtrees * sizeof (DBusObjectSubtree*)); 280 if (new_subtrees == NULL) 281 { 282 _dbus_object_subtree_unref (child); 283 return NULL; 284 } 285 subtree->subtrees = new_subtrees; 286 subtree->max_subtrees = new_max_subtrees; 287 } 288 289 /* The binary search failed, so i == j points to the 290 place the child should be inserted. */ 291 child_pos = i; 292 _dbus_assert (child_pos < new_n_subtrees && 293 new_n_subtrees <= subtree->max_subtrees); 294 if (child_pos + 1 < new_n_subtrees) 295 { 296 memmove (&subtree->subtrees[child_pos+1], 297 &subtree->subtrees[child_pos], 298 (new_n_subtrees - child_pos - 1) * 299 sizeof subtree->subtrees[0]); 300 } 301 subtree->subtrees[child_pos] = child; 302 303 if (index_in_parent) 304 *index_in_parent = child_pos; 305 subtree->n_subtrees = new_n_subtrees; 306 child->parent = subtree; 307 308 return find_subtree_recurse (child, 309 &path[1], create_if_not_found, 310 index_in_parent, exact_match); 311 } 312 else 313 { 314 if (exact_match != NULL) 315 *exact_match = FALSE; 316 return (return_deepest_match && subtree->invoke_as_fallback) ? subtree : NULL; 317 } 318 } 319 320 static DBusObjectSubtree* 321 find_subtree (DBusObjectTree *tree, 322 const char **path, 323 int *index_in_parent) 324 { 325 DBusObjectSubtree *subtree; 326 327 #if VERBOSE_FIND 328 _dbus_verbose ("Looking for exact registered subtree\n"); 329 #endif 330 331 subtree = find_subtree_recurse (tree->root, path, FALSE, index_in_parent, NULL); 332 333 if (subtree && subtree->message_function == NULL) 334 return NULL; 335 else 336 return subtree; 337 } 338 339 static DBusObjectSubtree* 340 lookup_subtree (DBusObjectTree *tree, 341 const char **path) 342 { 343 #if VERBOSE_FIND 344 _dbus_verbose ("Looking for subtree\n"); 345 #endif 346 return find_subtree_recurse (tree->root, path, FALSE, NULL, NULL); 347 } 348 349 static DBusObjectSubtree* 350 find_handler (DBusObjectTree *tree, 351 const char **path, 352 dbus_bool_t *exact_match) 353 { 354 #if VERBOSE_FIND 355 _dbus_verbose ("Looking for deepest handler\n"); 356 #endif 357 _dbus_assert (exact_match != NULL); 358 359 *exact_match = FALSE; /* ensure always initialized */ 360 361 return find_subtree_recurse (tree->root, path, FALSE, NULL, exact_match); 362 } 363 364 static DBusObjectSubtree* 365 ensure_subtree (DBusObjectTree *tree, 366 const char **path) 367 { 368 #if VERBOSE_FIND 369 _dbus_verbose ("Ensuring subtree\n"); 370 #endif 371 return find_subtree_recurse (tree->root, path, TRUE, NULL, NULL); 372 } 373 374 /** 375 * Registers a new subtree in the global object tree. 376 * 377 * @param tree the global object tree 378 * @param fallback #TRUE to handle messages to children of this path 379 * @param path NULL-terminated array of path elements giving path to subtree 380 * @param vtable the vtable used to traverse this subtree 381 * @param user_data user data to pass to methods in the vtable 382 * @returns #FALSE if not enough memory 383 */ 384 dbus_bool_t 385 _dbus_object_tree_register (DBusObjectTree *tree, 386 dbus_bool_t fallback, 387 const char **path, 388 const DBusObjectPathVTable *vtable, 389 void *user_data) 390 { 391 DBusObjectSubtree *subtree; 392 393 _dbus_assert (tree != NULL); 394 _dbus_assert (vtable->message_function != NULL); 395 _dbus_assert (path != NULL); 396 397 subtree = ensure_subtree (tree, path); 398 if (subtree == NULL) 399 return FALSE; 400 401 #ifndef DBUS_DISABLE_CHECKS 402 if (subtree->message_function != NULL) 403 { 404 _dbus_warn ("A handler is already registered for the path starting with path[0] = \"%s\"\n", 405 path[0] ? path[0] : "null"); 406 return FALSE; 407 } 408 #else 409 _dbus_assert (subtree->message_function == NULL); 410 #endif 411 412 subtree->message_function = vtable->message_function; 413 subtree->unregister_function = vtable->unregister_function; 414 subtree->user_data = user_data; 415 subtree->invoke_as_fallback = fallback != FALSE; 416 417 return TRUE; 418 } 419 420 /** 421 * Unregisters an object subtree that was registered with the 422 * same path. 423 * 424 * @param tree the global object tree 425 * @param path path to the subtree (same as the one passed to _dbus_object_tree_register()) 426 */ 427 void 428 _dbus_object_tree_unregister_and_unlock (DBusObjectTree *tree, 429 const char **path) 430 { 431 int i; 432 DBusObjectSubtree *subtree; 433 DBusObjectPathUnregisterFunction unregister_function; 434 void *user_data; 435 DBusConnection *connection; 436 437 _dbus_assert (path != NULL); 438 439 unregister_function = NULL; 440 user_data = NULL; 441 442 subtree = find_subtree (tree, path, &i); 443 444 #ifndef DBUS_DISABLE_CHECKS 445 if (subtree == NULL) 446 { 447 _dbus_warn ("Attempted to unregister path (path[0] = %s path[1] = %s) which isn't registered\n", 448 path[0] ? path[0] : "null", 449 path[1] ? path[1] : "null"); 450 goto unlock; 451 } 452 #else 453 _dbus_assert (subtree != NULL); 454 #endif 455 456 _dbus_assert (subtree->parent == NULL || 457 (i >= 0 && subtree->parent->subtrees[i] == subtree)); 458 459 subtree->message_function = NULL; 460 461 unregister_function = subtree->unregister_function; 462 user_data = subtree->user_data; 463 464 subtree->unregister_function = NULL; 465 subtree->user_data = NULL; 466 467 /* If we have no subtrees of our own, remove from 468 * our parent (FIXME could also be more aggressive 469 * and remove our parent if it becomes empty) 470 */ 471 if (subtree->parent && subtree->n_subtrees == 0) 472 { 473 /* assumes a 0-byte memmove is OK */ 474 memmove (&subtree->parent->subtrees[i], 475 &subtree->parent->subtrees[i+1], 476 (subtree->parent->n_subtrees - i - 1) * 477 sizeof (subtree->parent->subtrees[0])); 478 subtree->parent->n_subtrees -= 1; 479 480 subtree->parent = NULL; 481 482 _dbus_object_subtree_unref (subtree); 483 } 484 subtree = NULL; 485 486 unlock: 487 connection = tree->connection; 488 489 /* Unlock and call application code */ 490 #ifdef DBUS_BUILD_TESTS 491 if (connection) 492 #endif 493 { 494 _dbus_connection_ref_unlocked (connection); 495 _dbus_verbose ("unlock %s\n", _DBUS_FUNCTION_NAME); 496 _dbus_connection_unlock (connection); 497 } 498 499 if (unregister_function) 500 (* unregister_function) (connection, user_data); 501 502 #ifdef DBUS_BUILD_TESTS 503 if (connection) 504 #endif 505 dbus_connection_unref (connection); 506 } 507 508 static void 509 free_subtree_recurse (DBusConnection *connection, 510 DBusObjectSubtree *subtree) 511 { 512 /* Delete them from the end, for slightly 513 * more robustness against odd reentrancy. 514 */ 515 while (subtree->n_subtrees > 0) 516 { 517 DBusObjectSubtree *child; 518 519 child = subtree->subtrees[subtree->n_subtrees - 1]; 520 subtree->subtrees[subtree->n_subtrees - 1] = NULL; 521 subtree->n_subtrees -= 1; 522 child->parent = NULL; 523 524 free_subtree_recurse (connection, child); 525 } 526 527 /* Call application code */ 528 if (subtree->unregister_function) 529 (* subtree->unregister_function) (connection, 530 subtree->user_data); 531 532 subtree->message_function = NULL; 533 subtree->unregister_function = NULL; 534 subtree->user_data = NULL; 535 536 /* Now free ourselves */ 537 _dbus_object_subtree_unref (subtree); 538 } 539 540 /** 541 * Free all the handlers in the tree. Lock on tree's connection 542 * must not be held. 543 * 544 * @param tree the object tree 545 */ 546 void 547 _dbus_object_tree_free_all_unlocked (DBusObjectTree *tree) 548 { 549 if (tree->root) 550 free_subtree_recurse (tree->connection, 551 tree->root); 552 tree->root = NULL; 553 } 554 555 static dbus_bool_t 556 _dbus_object_tree_list_registered_unlocked (DBusObjectTree *tree, 557 const char **parent_path, 558 char ***child_entries) 559 { 560 DBusObjectSubtree *subtree; 561 char **retval; 562 563 _dbus_assert (parent_path != NULL); 564 _dbus_assert (child_entries != NULL); 565 566 *child_entries = NULL; 567 568 subtree = lookup_subtree (tree, parent_path); 569 if (subtree == NULL) 570 { 571 retval = dbus_new0 (char *, 1); 572 } 573 else 574 { 575 int i; 576 retval = dbus_new0 (char*, subtree->n_subtrees + 1); 577 if (retval == NULL) 578 goto out; 579 i = 0; 580 while (i < subtree->n_subtrees) 581 { 582 retval[i] = _dbus_strdup (subtree->subtrees[i]->name); 583 if (retval[i] == NULL) 584 { 585 dbus_free_string_array (retval); 586 retval = NULL; 587 goto out; 588 } 589 ++i; 590 } 591 } 592 593 out: 594 595 *child_entries = retval; 596 return retval != NULL; 597 } 598 599 static DBusHandlerResult 600 handle_default_introspect_and_unlock (DBusObjectTree *tree, 601 DBusMessage *message, 602 const char **path) 603 { 604 DBusString xml; 605 DBusHandlerResult result; 606 char **children; 607 int i; 608 DBusMessage *reply; 609 DBusMessageIter iter; 610 const char *v_STRING; 611 dbus_bool_t already_unlocked; 612 613 /* We have the connection lock here */ 614 615 already_unlocked = FALSE; 616 617 _dbus_verbose (" considering default Introspect() handler...\n"); 618 619 reply = NULL; 620 621 if (!dbus_message_is_method_call (message, 622 DBUS_INTERFACE_INTROSPECTABLE, 623 "Introspect")) 624 { 625 #ifdef DBUS_BUILD_TESTS 626 if (tree->connection) 627 #endif 628 { 629 _dbus_verbose ("unlock %s %d\n", _DBUS_FUNCTION_NAME, __LINE__); 630 _dbus_connection_unlock (tree->connection); 631 } 632 633 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; 634 } 635 636 _dbus_verbose (" using default Introspect() handler!\n"); 637 638 if (!_dbus_string_init (&xml)) 639 { 640 #ifdef DBUS_BUILD_TESTS 641 if (tree->connection) 642 #endif 643 { 644 _dbus_verbose ("unlock %s %d\n", _DBUS_FUNCTION_NAME, __LINE__); 645 _dbus_connection_unlock (tree->connection); 646 } 647 648 return DBUS_HANDLER_RESULT_NEED_MEMORY; 649 } 650 651 result = DBUS_HANDLER_RESULT_NEED_MEMORY; 652 653 children = NULL; 654 if (!_dbus_object_tree_list_registered_unlocked (tree, path, &children)) 655 goto out; 656 657 if (!_dbus_string_append (&xml, DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE)) 658 goto out; 659 660 if (!_dbus_string_append (&xml, "<node>\n")) 661 goto out; 662 663 i = 0; 664 while (children[i] != NULL) 665 { 666 if (!_dbus_string_append_printf (&xml, " <node name=\"%s\"/>\n", 667 children[i])) 668 goto out; 669 670 ++i; 671 } 672 673 if (!_dbus_string_append (&xml, "</node>\n")) 674 goto out; 675 676 reply = dbus_message_new_method_return (message); 677 if (reply == NULL) 678 goto out; 679 680 dbus_message_iter_init_append (reply, &iter); 681 v_STRING = _dbus_string_get_const_data (&xml); 682 if (!dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &v_STRING)) 683 goto out; 684 685 #ifdef DBUS_BUILD_TESTS 686 if (tree->connection) 687 #endif 688 { 689 already_unlocked = TRUE; 690 691 if (!_dbus_connection_send_and_unlock (tree->connection, reply, NULL)) 692 goto out; 693 } 694 695 result = DBUS_HANDLER_RESULT_HANDLED; 696 697 out: 698 #ifdef DBUS_BUILD_TESTS 699 if (tree->connection) 700 #endif 701 { 702 if (!already_unlocked) 703 { 704 _dbus_verbose ("unlock %s %d\n", _DBUS_FUNCTION_NAME, __LINE__); 705 _dbus_connection_unlock (tree->connection); 706 } 707 } 708 709 _dbus_string_free (&xml); 710 dbus_free_string_array (children); 711 if (reply) 712 dbus_message_unref (reply); 713 714 return result; 715 } 716 717 /** 718 * Tries to dispatch a message by directing it to handler for the 719 * object path listed in the message header, if any. Messages are 720 * dispatched first to the registered handler that matches the largest 721 * number of path elements; that is, message to /foo/bar/baz would go 722 * to the handler for /foo/bar before the one for /foo. 723 * 724 * @todo thread problems 725 * 726 * @param tree the global object tree 727 * @param message the message to dispatch 728 * @returns whether message was handled successfully 729 */ 730 DBusHandlerResult 731 _dbus_object_tree_dispatch_and_unlock (DBusObjectTree *tree, 732 DBusMessage *message) 733 { 734 char **path; 735 dbus_bool_t exact_match; 736 DBusList *list; 737 DBusList *link; 738 DBusHandlerResult result; 739 DBusObjectSubtree *subtree; 740 741 #if 0 742 _dbus_verbose ("Dispatch of message by object path\n"); 743 #endif 744 745 path = NULL; 746 if (!dbus_message_get_path_decomposed (message, &path)) 747 { 748 #ifdef DBUS_BUILD_TESTS 749 if (tree->connection) 750 #endif 751 { 752 _dbus_verbose ("unlock %s\n", _DBUS_FUNCTION_NAME); 753 _dbus_connection_unlock (tree->connection); 754 } 755 756 _dbus_verbose ("No memory to get decomposed path\n"); 757 758 return DBUS_HANDLER_RESULT_NEED_MEMORY; 759 } 760 761 if (path == NULL) 762 { 763 #ifdef DBUS_BUILD_TESTS 764 if (tree->connection) 765 #endif 766 { 767 _dbus_verbose ("unlock %s\n", _DBUS_FUNCTION_NAME); 768 _dbus_connection_unlock (tree->connection); 769 } 770 771 _dbus_verbose ("No path field in message\n"); 772 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; 773 } 774 775 /* Find the deepest path that covers the path in the message */ 776 subtree = find_handler (tree, (const char**) path, &exact_match); 777 778 /* Build a list of all paths that cover the path in the message */ 779 780 list = NULL; 781 782 while (subtree != NULL) 783 { 784 if (subtree->message_function != NULL && (exact_match || subtree->invoke_as_fallback)) 785 { 786 _dbus_object_subtree_ref (subtree); 787 788 /* run deepest paths first */ 789 if (!_dbus_list_append (&list, subtree)) 790 { 791 result = DBUS_HANDLER_RESULT_NEED_MEMORY; 792 _dbus_object_subtree_unref (subtree); 793 goto free_and_return; 794 } 795 } 796 797 exact_match = FALSE; 798 subtree = subtree->parent; 799 } 800 801 _dbus_verbose ("%d handlers in the path tree for this message\n", 802 _dbus_list_get_length (&list)); 803 804 /* Invoke each handler in the list */ 805 806 result = DBUS_HANDLER_RESULT_NOT_YET_HANDLED; 807 808 link = _dbus_list_get_first_link (&list); 809 while (link != NULL) 810 { 811 DBusList *next = _dbus_list_get_next_link (&list, link); 812 subtree = link->data; 813 814 /* message_function is NULL if we're unregistered 815 * due to reentrancy 816 */ 817 if (subtree->message_function) 818 { 819 DBusObjectPathMessageFunction message_function; 820 void *user_data; 821 822 message_function = subtree->message_function; 823 user_data = subtree->user_data; 824 825 #if 0 826 _dbus_verbose (" (invoking a handler)\n"); 827 #endif 828 829 #ifdef DBUS_BUILD_TESTS 830 if (tree->connection) 831 #endif 832 { 833 _dbus_verbose ("unlock %s\n", _DBUS_FUNCTION_NAME); 834 _dbus_connection_unlock (tree->connection); 835 } 836 837 /* FIXME you could unregister the subtree in another thread 838 * before we invoke the callback, and I can't figure out a 839 * good way to solve this. 840 */ 841 842 result = (* message_function) (tree->connection, 843 message, 844 user_data); 845 846 #ifdef DBUS_BUILD_TESTS 847 if (tree->connection) 848 #endif 849 _dbus_connection_lock (tree->connection); 850 851 if (result != DBUS_HANDLER_RESULT_NOT_YET_HANDLED) 852 goto free_and_return; 853 } 854 855 link = next; 856 } 857 858 free_and_return: 859 860 if (result == DBUS_HANDLER_RESULT_NOT_YET_HANDLED) 861 { 862 /* This hardcoded default handler does a minimal Introspect() 863 */ 864 result = handle_default_introspect_and_unlock (tree, message, 865 (const char**) path); 866 } 867 else 868 { 869 #ifdef DBUS_BUILD_TESTS 870 if (tree->connection) 871 #endif 872 { 873 _dbus_verbose ("unlock %s\n", _DBUS_FUNCTION_NAME); 874 _dbus_connection_unlock (tree->connection); 875 } 876 } 877 878 while (list != NULL) 879 { 880 link = _dbus_list_get_first_link (&list); 881 _dbus_object_subtree_unref (link->data); 882 _dbus_list_remove_link (&list, link); 883 } 884 885 dbus_free_string_array (path); 886 887 return result; 888 } 889 890 /** 891 * Looks up the data passed to _dbus_object_tree_register() for a 892 * handler at the given path. 893 * 894 * @param tree the global object tree 895 * @param path NULL-terminated array of path elements giving path to subtree 896 * @returns the object's user_data or #NULL if none found 897 */ 898 void* 899 _dbus_object_tree_get_user_data_unlocked (DBusObjectTree *tree, 900 const char **path) 901 { 902 dbus_bool_t exact_match; 903 DBusObjectSubtree *subtree; 904 905 _dbus_assert (tree != NULL); 906 _dbus_assert (path != NULL); 907 908 /* Find the deepest path that covers the path in the message */ 909 subtree = find_handler (tree, (const char**) path, &exact_match); 910 911 if ((subtree == NULL) || !exact_match) 912 { 913 _dbus_verbose ("%s: No object at specified path found\n", 914 _DBUS_FUNCTION_NAME); 915 return NULL; 916 } 917 918 return subtree->user_data; 919 } 920 921 /** 922 * Allocates a subtree object. 923 * 924 * @param name name to duplicate. 925 * @returns newly-allocated subtree 926 */ 927 static DBusObjectSubtree* 928 allocate_subtree_object (const char *name) 929 { 930 int len; 931 DBusObjectSubtree *subtree; 932 const size_t front_padding = _DBUS_STRUCT_OFFSET (DBusObjectSubtree, name); 933 934 _dbus_assert (name != NULL); 935 936 len = strlen (name); 937 938 subtree = dbus_malloc (MAX (front_padding + (len + 1), sizeof (DBusObjectSubtree))); 939 940 if (subtree == NULL) 941 return NULL; 942 943 memcpy (subtree->name, name, len + 1); 944 945 return subtree; 946 } 947 948 static DBusObjectSubtree* 949 _dbus_object_subtree_new (const char *name, 950 const DBusObjectPathVTable *vtable, 951 void *user_data) 952 { 953 DBusObjectSubtree *subtree; 954 955 subtree = allocate_subtree_object (name); 956 if (subtree == NULL) 957 goto oom; 958 959 _dbus_assert (name != NULL); 960 961 subtree->parent = NULL; 962 963 if (vtable) 964 { 965 subtree->message_function = vtable->message_function; 966 subtree->unregister_function = vtable->unregister_function; 967 } 968 else 969 { 970 subtree->message_function = NULL; 971 subtree->unregister_function = NULL; 972 } 973 974 subtree->user_data = user_data; 975 subtree->refcount.value = 1; 976 subtree->subtrees = NULL; 977 subtree->n_subtrees = 0; 978 subtree->max_subtrees = 0; 979 subtree->invoke_as_fallback = FALSE; 980 981 return subtree; 982 983 oom: 984 return NULL; 985 } 986 987 static DBusObjectSubtree * 988 _dbus_object_subtree_ref (DBusObjectSubtree *subtree) 989 { 990 _dbus_assert (subtree->refcount.value > 0); 991 _dbus_atomic_inc (&subtree->refcount); 992 993 return subtree; 994 } 995 996 static void 997 _dbus_object_subtree_unref (DBusObjectSubtree *subtree) 998 { 999 _dbus_assert (subtree->refcount.value > 0); 1000 1001 if (_dbus_atomic_dec (&subtree->refcount) == 1) 1002 { 1003 _dbus_assert (subtree->unregister_function == NULL); 1004 _dbus_assert (subtree->message_function == NULL); 1005 1006 dbus_free (subtree->subtrees); 1007 dbus_free (subtree); 1008 } 1009 } 1010 1011 /** 1012 * Lists the registered fallback handlers and object path handlers at 1013 * the given parent_path. The returned array should be freed with 1014 * dbus_free_string_array(). 1015 * 1016 * @param tree the object tree 1017 * @param parent_path the path to list the child handlers of 1018 * @param child_entries returns #NULL-terminated array of children 1019 * @returns #FALSE if no memory to allocate the child entries 1020 */ 1021 dbus_bool_t 1022 _dbus_object_tree_list_registered_and_unlock (DBusObjectTree *tree, 1023 const char **parent_path, 1024 char ***child_entries) 1025 { 1026 dbus_bool_t result; 1027 1028 result = _dbus_object_tree_list_registered_unlocked (tree, 1029 parent_path, 1030 child_entries); 1031 1032 #ifdef DBUS_BUILD_TESTS 1033 if (tree->connection) 1034 #endif 1035 { 1036 _dbus_verbose ("unlock %s\n", _DBUS_FUNCTION_NAME); 1037 _dbus_connection_unlock (tree->connection); 1038 } 1039 1040 return result; 1041 } 1042 1043 1044 /** Set to 1 to get a bunch of spew about disassembling the path string */ 1045 #define VERBOSE_DECOMPOSE 0 1046 1047 /** 1048 * Decompose an object path. A path of just "/" is 1049 * represented as an empty vector of strings. 1050 * The path need not be nul terminated. 1051 * 1052 * @param data the path data 1053 * @param len the length of the path string 1054 * @param path address to store new object path 1055 * @param path_len length of stored path 1056 */ 1057 dbus_bool_t 1058 _dbus_decompose_path (const char* data, 1059 int len, 1060 char ***path, 1061 int *path_len) 1062 { 1063 char **retval; 1064 int n_components; 1065 int i, j, comp; 1066 1067 _dbus_assert (data != NULL); 1068 1069 #if VERBOSE_DECOMPOSE 1070 _dbus_verbose ("Decomposing path \"%s\"\n", 1071 data); 1072 #endif 1073 1074 n_components = 0; 1075 if (len > 1) /* if path is not just "/" */ 1076 { 1077 i = 0; 1078 while (i < len) 1079 { 1080 if (data[i] == '/') 1081 n_components += 1; 1082 ++i; 1083 } 1084 } 1085 1086 retval = dbus_new0 (char*, n_components + 1); 1087 1088 if (retval == NULL) 1089 return FALSE; 1090 1091 comp = 0; 1092 if (n_components == 0) 1093 i = 1; 1094 else 1095 i = 0; 1096 while (comp < n_components) 1097 { 1098 _dbus_assert (i < len); 1099 1100 if (data[i] == '/') 1101 ++i; 1102 j = i; 1103 1104 while (j < len && data[j] != '/') 1105 ++j; 1106 1107 /* Now [i, j) is the path component */ 1108 _dbus_assert (i < j); 1109 _dbus_assert (data[i] != '/'); 1110 _dbus_assert (j == len || data[j] == '/'); 1111 1112 #if VERBOSE_DECOMPOSE 1113 _dbus_verbose (" (component in [%d,%d))\n", 1114 i, j); 1115 #endif 1116 1117 retval[comp] = _dbus_memdup (&data[i], j - i + 1); 1118 if (retval[comp] == NULL) 1119 { 1120 dbus_free_string_array (retval); 1121 return FALSE; 1122 } 1123 retval[comp][j-i] = '\0'; 1124 #if VERBOSE_DECOMPOSE 1125 _dbus_verbose (" (component %d = \"%s\")\n", 1126 comp, retval[comp]); 1127 #endif 1128 1129 ++comp; 1130 i = j; 1131 } 1132 _dbus_assert (i == len); 1133 1134 *path = retval; 1135 if (path_len) 1136 *path_len = n_components; 1137 1138 return TRUE; 1139 } 1140 1141 /** @} */ 1142 1143 #ifdef DBUS_BUILD_TESTS 1144 1145 #ifndef DOXYGEN_SHOULD_SKIP_THIS 1146 1147 #include "dbus-test.h" 1148 #include <stdio.h> 1149 1150 static char* 1151 flatten_path (const char **path) 1152 { 1153 DBusString str; 1154 char *s; 1155 1156 if (!_dbus_string_init (&str)) 1157 return NULL; 1158 1159 if (path[0] == NULL) 1160 { 1161 if (!_dbus_string_append_byte (&str, '/')) 1162 goto nomem; 1163 } 1164 else 1165 { 1166 int i; 1167 1168 i = 0; 1169 while (path[i]) 1170 { 1171 if (!_dbus_string_append_byte (&str, '/')) 1172 goto nomem; 1173 1174 if (!_dbus_string_append (&str, path[i])) 1175 goto nomem; 1176 1177 ++i; 1178 } 1179 } 1180 1181 if (!_dbus_string_steal_data (&str, &s)) 1182 goto nomem; 1183 1184 _dbus_string_free (&str); 1185 1186 return s; 1187 1188 nomem: 1189 _dbus_string_free (&str); 1190 return NULL; 1191 } 1192 1193 1194 typedef enum 1195 { 1196 STR_EQUAL, 1197 STR_PREFIX, 1198 STR_DIFFERENT 1199 } StrComparison; 1200 1201 /* Returns TRUE if container is a parent of child 1202 */ 1203 static StrComparison 1204 path_contains (const char **container, 1205 const char **child) 1206 { 1207 int i; 1208 1209 i = 0; 1210 while (child[i] != NULL) 1211 { 1212 int v; 1213 1214 if (container[i] == NULL) 1215 return STR_PREFIX; /* container ran out, child continues; 1216 * thus the container is a parent of the 1217 * child. 1218 */ 1219 1220 _dbus_assert (container[i] != NULL); 1221 _dbus_assert (child[i] != NULL); 1222 1223 v = strcmp (container[i], child[i]); 1224 1225 if (v != 0) 1226 return STR_DIFFERENT; /* they overlap until here and then are different, 1227 * not overlapping 1228 */ 1229 1230 ++i; 1231 } 1232 1233 /* Child ran out; if container also did, they are equal; 1234 * otherwise, the child is a parent of the container. 1235 */ 1236 if (container[i] == NULL) 1237 return STR_EQUAL; 1238 else 1239 return STR_DIFFERENT; 1240 } 1241 1242 #if 0 1243 static void 1244 spew_subtree_recurse (DBusObjectSubtree *subtree, 1245 int indent) 1246 { 1247 int i; 1248 1249 i = 0; 1250 while (i < indent) 1251 { 1252 _dbus_verbose (" "); 1253 ++i; 1254 } 1255 1256 _dbus_verbose ("%s (%d children)\n", 1257 subtree->name, subtree->n_subtrees); 1258 1259 i = 0; 1260 while (i < subtree->n_subtrees) 1261 { 1262 spew_subtree_recurse (subtree->subtrees[i], indent + 2); 1263 1264 ++i; 1265 } 1266 } 1267 1268 static void 1269 spew_tree (DBusObjectTree *tree) 1270 { 1271 spew_subtree_recurse (tree->root, 0); 1272 } 1273 #endif 1274 1275 /** 1276 * Callback data used in tests 1277 */ 1278 typedef struct 1279 { 1280 const char **path; /**< Path */ 1281 dbus_bool_t handler_fallback; /**< true if the handler may be called as fallback */ 1282 dbus_bool_t message_handled; /**< Gets set to true if message handler called */ 1283 dbus_bool_t handler_unregistered; /**< gets set to true if handler is unregistered */ 1284 } TreeTestData; 1285 1286 1287 static void 1288 test_unregister_function (DBusConnection *connection, 1289 void *user_data) 1290 { 1291 TreeTestData *ttd = user_data; 1292 1293 ttd->handler_unregistered = TRUE; 1294 } 1295 1296 static DBusHandlerResult 1297 test_message_function (DBusConnection *connection, 1298 DBusMessage *message, 1299 void *user_data) 1300 { 1301 TreeTestData *ttd = user_data; 1302 1303 ttd->message_handled = TRUE; 1304 1305 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; 1306 } 1307 1308 static dbus_bool_t 1309 do_register (DBusObjectTree *tree, 1310 const char **path, 1311 dbus_bool_t fallback, 1312 int i, 1313 TreeTestData *tree_test_data) 1314 { 1315 DBusObjectPathVTable vtable = { test_unregister_function, 1316 test_message_function, NULL }; 1317 1318 tree_test_data[i].message_handled = FALSE; 1319 tree_test_data[i].handler_unregistered = FALSE; 1320 tree_test_data[i].handler_fallback = fallback; 1321 tree_test_data[i].path = path; 1322 1323 if (!_dbus_object_tree_register (tree, fallback, path, 1324 &vtable, 1325 &tree_test_data[i])) 1326 return FALSE; 1327 1328 _dbus_assert (_dbus_object_tree_get_user_data_unlocked (tree, path) == 1329 &tree_test_data[i]); 1330 1331 return TRUE; 1332 } 1333 1334 static dbus_bool_t 1335 do_test_dispatch (DBusObjectTree *tree, 1336 const char **path, 1337 int i, 1338 TreeTestData *tree_test_data, 1339 int n_test_data) 1340 { 1341 DBusMessage *message; 1342 int j; 1343 DBusHandlerResult result; 1344 char *flat; 1345 1346 message = NULL; 1347 1348 flat = flatten_path (path); 1349 if (flat == NULL) 1350 goto oom; 1351 1352 message = dbus_message_new_method_call (NULL, 1353 flat, 1354 "org.freedesktop.TestInterface", 1355 "Foo"); 1356 dbus_free (flat); 1357 if (message == NULL) 1358 goto oom; 1359 1360 j = 0; 1361 while (j < n_test_data) 1362 { 1363 tree_test_data[j].message_handled = FALSE; 1364 ++j; 1365 } 1366 1367 result = _dbus_object_tree_dispatch_and_unlock (tree, message); 1368 if (result == DBUS_HANDLER_RESULT_NEED_MEMORY) 1369 goto oom; 1370 1371 _dbus_assert (tree_test_data[i].message_handled); 1372 1373 j = 0; 1374 while (j < n_test_data) 1375 { 1376 if (tree_test_data[j].message_handled) 1377 { 1378 if (tree_test_data[j].handler_fallback) 1379 _dbus_assert (path_contains (tree_test_data[j].path, 1380 path) != STR_DIFFERENT); 1381 else 1382 _dbus_assert (path_contains (tree_test_data[j].path, path) == STR_EQUAL); 1383 } 1384 else 1385 { 1386 if (tree_test_data[j].handler_fallback) 1387 _dbus_assert (path_contains (tree_test_data[j].path, 1388 path) == STR_DIFFERENT); 1389 else 1390 _dbus_assert (path_contains (tree_test_data[j].path, path) != STR_EQUAL); 1391 } 1392 1393 ++j; 1394 } 1395 1396 dbus_message_unref (message); 1397 1398 return TRUE; 1399 1400 oom: 1401 if (message) 1402 dbus_message_unref (message); 1403 return FALSE; 1404 } 1405 1406 static size_t 1407 string_array_length (const char **array) 1408 { 1409 size_t i; 1410 for (i = 0; array[i]; i++) ; 1411 return i; 1412 } 1413 1414 typedef struct 1415 { 1416 const char *path; 1417 const char *result[20]; 1418 } DecomposePathTest; 1419 1420 static DecomposePathTest decompose_tests[] = { 1421 { "/foo", { "foo", NULL } }, 1422 { "/foo/bar", { "foo", "bar", NULL } }, 1423 { "/", { NULL } }, 1424 { "/a/b", { "a", "b", NULL } }, 1425 { "/a/b/c", { "a", "b", "c", NULL } }, 1426 { "/a/b/c/d", { "a", "b", "c", "d", NULL } }, 1427 { "/foo/bar/q", { "foo", "bar", "q", NULL } }, 1428 { "/foo/bar/this/is/longer", { "foo", "bar", "this", "is", "longer", NULL } } 1429 }; 1430 1431 static dbus_bool_t 1432 run_decompose_tests (void) 1433 { 1434 int i; 1435 1436 i = 0; 1437 while (i < _DBUS_N_ELEMENTS (decompose_tests)) 1438 { 1439 char **result; 1440 int result_len; 1441 int expected_len; 1442 1443 if (!_dbus_decompose_path (decompose_tests[i].path, 1444 strlen (decompose_tests[i].path), 1445 &result, &result_len)) 1446 return FALSE; 1447 1448 expected_len = string_array_length (decompose_tests[i].result); 1449 1450 if (result_len != (int) string_array_length ((const char**)result) || 1451 expected_len != result_len || 1452 path_contains (decompose_tests[i].result, 1453 (const char**) result) != STR_EQUAL) 1454 { 1455 int real_len = string_array_length ((const char**)result); 1456 _dbus_warn ("Expected decompose of %s to have len %d, returned %d, appears to have %d\n", 1457 decompose_tests[i].path, expected_len, result_len, 1458 real_len); 1459 _dbus_warn ("Decompose resulted in elements: { "); 1460 i = 0; 1461 while (i < real_len) 1462 { 1463 _dbus_warn ("\"%s\"%s", result[i], 1464 (i + 1) == real_len ? "" : ", "); 1465 ++i; 1466 } 1467 _dbus_warn ("}\n"); 1468 _dbus_assert_not_reached ("path decompose failed\n"); 1469 } 1470 1471 dbus_free_string_array (result); 1472 1473 ++i; 1474 } 1475 1476 return TRUE; 1477 } 1478 1479 static dbus_bool_t 1480 object_tree_test_iteration (void *data) 1481 { 1482 const char *path0[] = { NULL }; 1483 const char *path1[] = { "foo", NULL }; 1484 const char *path2[] = { "foo", "bar", NULL }; 1485 const char *path3[] = { "foo", "bar", "baz", NULL }; 1486 const char *path4[] = { "foo", "bar", "boo", NULL }; 1487 const char *path5[] = { "blah", NULL }; 1488 const char *path6[] = { "blah", "boof", NULL }; 1489 const char *path7[] = { "blah", "boof", "this", "is", "really", "long", NULL }; 1490 const char *path8[] = { "childless", NULL }; 1491 DBusObjectTree *tree; 1492 TreeTestData tree_test_data[9]; 1493 int i; 1494 dbus_bool_t exact_match; 1495 1496 if (!run_decompose_tests ()) 1497 return FALSE; 1498 1499 tree = NULL; 1500 1501 tree = _dbus_object_tree_new (NULL); 1502 if (tree == NULL) 1503 goto out; 1504 1505 if (!do_register (tree, path0, TRUE, 0, tree_test_data)) 1506 goto out; 1507 1508 _dbus_assert (find_subtree (tree, path0, NULL)); 1509 _dbus_assert (!find_subtree (tree, path1, NULL)); 1510 _dbus_assert (!find_subtree (tree, path2, NULL)); 1511 _dbus_assert (!find_subtree (tree, path3, NULL)); 1512 _dbus_assert (!find_subtree (tree, path4, NULL)); 1513 _dbus_assert (!find_subtree (tree, path5, NULL)); 1514 _dbus_assert (!find_subtree (tree, path6, NULL)); 1515 _dbus_assert (!find_subtree (tree, path7, NULL)); 1516 _dbus_assert (!find_subtree (tree, path8, NULL)); 1517 1518 _dbus_assert (find_handler (tree, path0, &exact_match) && exact_match); 1519 _dbus_assert (find_handler (tree, path1, &exact_match) == tree->root && !exact_match); 1520 _dbus_assert (find_handler (tree, path2, &exact_match) == tree->root && !exact_match); 1521 _dbus_assert (find_handler (tree, path3, &exact_match) == tree->root && !exact_match); 1522 _dbus_assert (find_handler (tree, path4, &exact_match) == tree->root && !exact_match); 1523 _dbus_assert (find_handler (tree, path5, &exact_match) == tree->root && !exact_match); 1524 _dbus_assert (find_handler (tree, path6, &exact_match) == tree->root && !exact_match); 1525 _dbus_assert (find_handler (tree, path7, &exact_match) == tree->root && !exact_match); 1526 _dbus_assert (find_handler (tree, path8, &exact_match) == tree->root && !exact_match); 1527 1528 if (!do_register (tree, path1, TRUE, 1, tree_test_data)) 1529 goto out; 1530 1531 _dbus_assert (find_subtree (tree, path0, NULL)); 1532 _dbus_assert (find_subtree (tree, path1, NULL)); 1533 _dbus_assert (!find_subtree (tree, path2, NULL)); 1534 _dbus_assert (!find_subtree (tree, path3, NULL)); 1535 _dbus_assert (!find_subtree (tree, path4, NULL)); 1536 _dbus_assert (!find_subtree (tree, path5, NULL)); 1537 _dbus_assert (!find_subtree (tree, path6, NULL)); 1538 _dbus_assert (!find_subtree (tree, path7, NULL)); 1539 _dbus_assert (!find_subtree (tree, path8, NULL)); 1540 1541 _dbus_assert (find_handler (tree, path0, &exact_match) && exact_match); 1542 _dbus_assert (find_handler (tree, path1, &exact_match) && exact_match); 1543 _dbus_assert (find_handler (tree, path2, &exact_match) && !exact_match); 1544 _dbus_assert (find_handler (tree, path3, &exact_match) && !exact_match); 1545 _dbus_assert (find_handler (tree, path4, &exact_match) && !exact_match); 1546 _dbus_assert (find_handler (tree, path5, &exact_match) == tree->root && !exact_match); 1547 _dbus_assert (find_handler (tree, path6, &exact_match) == tree->root && !exact_match); 1548 _dbus_assert (find_handler (tree, path7, &exact_match) == tree->root && !exact_match); 1549 _dbus_assert (find_handler (tree, path8, &exact_match) == tree->root && !exact_match); 1550 1551 if (!do_register (tree, path2, TRUE, 2, tree_test_data)) 1552 goto out; 1553 1554 _dbus_assert (find_subtree (tree, path1, NULL)); 1555 _dbus_assert (find_subtree (tree, path2, NULL)); 1556 _dbus_assert (!find_subtree (tree, path3, NULL)); 1557 _dbus_assert (!find_subtree (tree, path4, NULL)); 1558 _dbus_assert (!find_subtree (tree, path5, NULL)); 1559 _dbus_assert (!find_subtree (tree, path6, NULL)); 1560 _dbus_assert (!find_subtree (tree, path7, NULL)); 1561 _dbus_assert (!find_subtree (tree, path8, NULL)); 1562 1563 if (!do_register (tree, path3, TRUE, 3, tree_test_data)) 1564 goto out; 1565 1566 _dbus_assert (find_subtree (tree, path0, NULL)); 1567 _dbus_assert (find_subtree (tree, path1, NULL)); 1568 _dbus_assert (find_subtree (tree, path2, NULL)); 1569 _dbus_assert (find_subtree (tree, path3, NULL)); 1570 _dbus_assert (!find_subtree (tree, path4, NULL)); 1571 _dbus_assert (!find_subtree (tree, path5, NULL)); 1572 _dbus_assert (!find_subtree (tree, path6, NULL)); 1573 _dbus_assert (!find_subtree (tree, path7, NULL)); 1574 _dbus_assert (!find_subtree (tree, path8, NULL)); 1575 1576 if (!do_register (tree, path4, TRUE, 4, tree_test_data)) 1577 goto out; 1578 1579 _dbus_assert (find_subtree (tree, path0, NULL)); 1580 _dbus_assert (find_subtree (tree, path1, NULL)); 1581 _dbus_assert (find_subtree (tree, path2, NULL)); 1582 _dbus_assert (find_subtree (tree, path3, NULL)); 1583 _dbus_assert (find_subtree (tree, path4, NULL)); 1584 _dbus_assert (!find_subtree (tree, path5, NULL)); 1585 _dbus_assert (!find_subtree (tree, path6, NULL)); 1586 _dbus_assert (!find_subtree (tree, path7, NULL)); 1587 _dbus_assert (!find_subtree (tree, path8, NULL)); 1588 1589 if (!do_register (tree, path5, TRUE, 5, tree_test_data)) 1590 goto out; 1591 1592 _dbus_assert (find_subtree (tree, path0, NULL)); 1593 _dbus_assert (find_subtree (tree, path1, NULL)); 1594 _dbus_assert (find_subtree (tree, path2, NULL)); 1595 _dbus_assert (find_subtree (tree, path3, NULL)); 1596 _dbus_assert (find_subtree (tree, path4, NULL)); 1597 _dbus_assert (find_subtree (tree, path5, NULL)); 1598 _dbus_assert (!find_subtree (tree, path6, NULL)); 1599 _dbus_assert (!find_subtree (tree, path7, NULL)); 1600 _dbus_assert (!find_subtree (tree, path8, NULL)); 1601 1602 _dbus_assert (find_handler (tree, path0, &exact_match) == tree->root && exact_match); 1603 _dbus_assert (find_handler (tree, path1, &exact_match) != tree->root && exact_match); 1604 _dbus_assert (find_handler (tree, path2, &exact_match) != tree->root && exact_match); 1605 _dbus_assert (find_handler (tree, path3, &exact_match) != tree->root && exact_match); 1606 _dbus_assert (find_handler (tree, path4, &exact_match) != tree->root && exact_match); 1607 _dbus_assert (find_handler (tree, path5, &exact_match) != tree->root && exact_match); 1608 _dbus_assert (find_handler (tree, path6, &exact_match) != tree->root && !exact_match); 1609 _dbus_assert (find_handler (tree, path7, &exact_match) != tree->root && !exact_match); 1610 _dbus_assert (find_handler (tree, path8, &exact_match) == tree->root && !exact_match); 1611 1612 if (!do_register (tree, path6, TRUE, 6, tree_test_data)) 1613 goto out; 1614 1615 _dbus_assert (find_subtree (tree, path0, NULL)); 1616 _dbus_assert (find_subtree (tree, path1, NULL)); 1617 _dbus_assert (find_subtree (tree, path2, NULL)); 1618 _dbus_assert (find_subtree (tree, path3, NULL)); 1619 _dbus_assert (find_subtree (tree, path4, NULL)); 1620 _dbus_assert (find_subtree (tree, path5, NULL)); 1621 _dbus_assert (find_subtree (tree, path6, NULL)); 1622 _dbus_assert (!find_subtree (tree, path7, NULL)); 1623 _dbus_assert (!find_subtree (tree, path8, NULL)); 1624 1625 if (!do_register (tree, path7, TRUE, 7, tree_test_data)) 1626 goto out; 1627 1628 _dbus_assert (find_subtree (tree, path0, NULL)); 1629 _dbus_assert (find_subtree (tree, path1, NULL)); 1630 _dbus_assert (find_subtree (tree, path2, NULL)); 1631 _dbus_assert (find_subtree (tree, path3, NULL)); 1632 _dbus_assert (find_subtree (tree, path4, NULL)); 1633 _dbus_assert (find_subtree (tree, path5, NULL)); 1634 _dbus_assert (find_subtree (tree, path6, NULL)); 1635 _dbus_assert (find_subtree (tree, path7, NULL)); 1636 _dbus_assert (!find_subtree (tree, path8, NULL)); 1637 1638 if (!do_register (tree, path8, TRUE, 8, tree_test_data)) 1639 goto out; 1640 1641 _dbus_assert (find_subtree (tree, path0, NULL)); 1642 _dbus_assert (find_subtree (tree, path1, NULL)); 1643 _dbus_assert (find_subtree (tree, path2, NULL)); 1644 _dbus_assert (find_subtree (tree, path3, NULL)); 1645 _dbus_assert (find_subtree (tree, path4, NULL)); 1646 _dbus_assert (find_subtree (tree, path5, NULL)); 1647 _dbus_assert (find_subtree (tree, path6, NULL)); 1648 _dbus_assert (find_subtree (tree, path7, NULL)); 1649 _dbus_assert (find_subtree (tree, path8, NULL)); 1650 1651 _dbus_assert (find_handler (tree, path0, &exact_match) == tree->root && exact_match); 1652 _dbus_assert (find_handler (tree, path1, &exact_match) != tree->root && exact_match); 1653 _dbus_assert (find_handler (tree, path2, &exact_match) != tree->root && exact_match); 1654 _dbus_assert (find_handler (tree, path3, &exact_match) != tree->root && exact_match); 1655 _dbus_assert (find_handler (tree, path4, &exact_match) != tree->root && exact_match); 1656 _dbus_assert (find_handler (tree, path5, &exact_match) != tree->root && exact_match); 1657 _dbus_assert (find_handler (tree, path6, &exact_match) != tree->root && exact_match); 1658 _dbus_assert (find_handler (tree, path7, &exact_match) != tree->root && exact_match); 1659 _dbus_assert (find_handler (tree, path8, &exact_match) != tree->root && exact_match); 1660 1661 /* test the list_registered function */ 1662 1663 { 1664 const char *root[] = { NULL }; 1665 char **child_entries; 1666 int nb; 1667 1668 _dbus_object_tree_list_registered_unlocked (tree, path1, &child_entries); 1669 if (child_entries != NULL) 1670 { 1671 nb = string_array_length ((const char**)child_entries); 1672 _dbus_assert (nb == 1); 1673 dbus_free_string_array (child_entries); 1674 } 1675 1676 _dbus_object_tree_list_registered_unlocked (tree, path2, &child_entries); 1677 if (child_entries != NULL) 1678 { 1679 nb = string_array_length ((const char**)child_entries); 1680 _dbus_assert (nb == 2); 1681 dbus_free_string_array (child_entries); 1682 } 1683 1684 _dbus_object_tree_list_registered_unlocked (tree, path8, &child_entries); 1685 if (child_entries != NULL) 1686 { 1687 nb = string_array_length ((const char**)child_entries); 1688 _dbus_assert (nb == 0); 1689 dbus_free_string_array (child_entries); 1690 } 1691 1692 _dbus_object_tree_list_registered_unlocked (tree, root, &child_entries); 1693 if (child_entries != NULL) 1694 { 1695 nb = string_array_length ((const char**)child_entries); 1696 _dbus_assert (nb == 3); 1697 dbus_free_string_array (child_entries); 1698 } 1699 } 1700 1701 /* Check that destroying tree calls unregister funcs */ 1702 _dbus_object_tree_unref (tree); 1703 1704 i = 0; 1705 while (i < (int) _DBUS_N_ELEMENTS (tree_test_data)) 1706 { 1707 _dbus_assert (tree_test_data[i].handler_unregistered); 1708 _dbus_assert (!tree_test_data[i].message_handled); 1709 ++i; 1710 } 1711 1712 /* Now start again and try the individual unregister function */ 1713 tree = _dbus_object_tree_new (NULL); 1714 if (tree == NULL) 1715 goto out; 1716 1717 if (!do_register (tree, path0, TRUE, 0, tree_test_data)) 1718 goto out; 1719 if (!do_register (tree, path1, TRUE, 1, tree_test_data)) 1720 goto out; 1721 if (!do_register (tree, path2, TRUE, 2, tree_test_data)) 1722 goto out; 1723 if (!do_register (tree, path3, TRUE, 3, tree_test_data)) 1724 goto out; 1725 if (!do_register (tree, path4, TRUE, 4, tree_test_data)) 1726 goto out; 1727 if (!do_register (tree, path5, TRUE, 5, tree_test_data)) 1728 goto out; 1729 if (!do_register (tree, path6, TRUE, 6, tree_test_data)) 1730 goto out; 1731 if (!do_register (tree, path7, TRUE, 7, tree_test_data)) 1732 goto out; 1733 if (!do_register (tree, path8, TRUE, 8, tree_test_data)) 1734 goto out; 1735 1736 _dbus_object_tree_unregister_and_unlock (tree, path0); 1737 _dbus_assert (_dbus_object_tree_get_user_data_unlocked (tree, path0) == NULL); 1738 1739 _dbus_assert (!find_subtree (tree, path0, NULL)); 1740 _dbus_assert (find_subtree (tree, path1, NULL)); 1741 _dbus_assert (find_subtree (tree, path2, NULL)); 1742 _dbus_assert (find_subtree (tree, path3, NULL)); 1743 _dbus_assert (find_subtree (tree, path4, NULL)); 1744 _dbus_assert (find_subtree (tree, path5, NULL)); 1745 _dbus_assert (find_subtree (tree, path6, NULL)); 1746 _dbus_assert (find_subtree (tree, path7, NULL)); 1747 _dbus_assert (find_subtree (tree, path8, NULL)); 1748 1749 _dbus_object_tree_unregister_and_unlock (tree, path1); 1750 _dbus_assert (_dbus_object_tree_get_user_data_unlocked (tree, path1) == NULL); 1751 1752 _dbus_assert (!find_subtree (tree, path0, NULL)); 1753 _dbus_assert (!find_subtree (tree, path1, NULL)); 1754 _dbus_assert (find_subtree (tree, path2, NULL)); 1755 _dbus_assert (find_subtree (tree, path3, NULL)); 1756 _dbus_assert (find_subtree (tree, path4, NULL)); 1757 _dbus_assert (find_subtree (tree, path5, NULL)); 1758 _dbus_assert (find_subtree (tree, path6, NULL)); 1759 _dbus_assert (find_subtree (tree, path7, NULL)); 1760 _dbus_assert (find_subtree (tree, path8, NULL)); 1761 1762 _dbus_object_tree_unregister_and_unlock (tree, path2); 1763 _dbus_assert (_dbus_object_tree_get_user_data_unlocked (tree, path2) == NULL); 1764 1765 _dbus_assert (!find_subtree (tree, path0, NULL)); 1766 _dbus_assert (!find_subtree (tree, path1, NULL)); 1767 _dbus_assert (!find_subtree (tree, path2, NULL)); 1768 _dbus_assert (find_subtree (tree, path3, NULL)); 1769 _dbus_assert (find_subtree (tree, path4, NULL)); 1770 _dbus_assert (find_subtree (tree, path5, NULL)); 1771 _dbus_assert (find_subtree (tree, path6, NULL)); 1772 _dbus_assert (find_subtree (tree, path7, NULL)); 1773 _dbus_assert (find_subtree (tree, path8, NULL)); 1774 1775 _dbus_object_tree_unregister_and_unlock (tree, path3); 1776 _dbus_assert (_dbus_object_tree_get_user_data_unlocked (tree, path3) == NULL); 1777 1778 _dbus_assert (!find_subtree (tree, path0, NULL)); 1779 _dbus_assert (!find_subtree (tree, path1, NULL)); 1780 _dbus_assert (!find_subtree (tree, path2, NULL)); 1781 _dbus_assert (!find_subtree (tree, path3, NULL)); 1782 _dbus_assert (find_subtree (tree, path4, NULL)); 1783 _dbus_assert (find_subtree (tree, path5, NULL)); 1784 _dbus_assert (find_subtree (tree, path6, NULL)); 1785 _dbus_assert (find_subtree (tree, path7, NULL)); 1786 _dbus_assert (find_subtree (tree, path8, NULL)); 1787 1788 _dbus_object_tree_unregister_and_unlock (tree, path4); 1789 _dbus_assert (_dbus_object_tree_get_user_data_unlocked (tree, path4) == NULL); 1790 1791 _dbus_assert (!find_subtree (tree, path0, NULL)); 1792 _dbus_assert (!find_subtree (tree, path1, NULL)); 1793 _dbus_assert (!find_subtree (tree, path2, NULL)); 1794 _dbus_assert (!find_subtree (tree, path3, NULL)); 1795 _dbus_assert (!find_subtree (tree, path4, NULL)); 1796 _dbus_assert (find_subtree (tree, path5, NULL)); 1797 _dbus_assert (find_subtree (tree, path6, NULL)); 1798 _dbus_assert (find_subtree (tree, path7, NULL)); 1799 _dbus_assert (find_subtree (tree, path8, NULL)); 1800 1801 _dbus_object_tree_unregister_and_unlock (tree, path5); 1802 _dbus_assert (_dbus_object_tree_get_user_data_unlocked (tree, path5) == NULL); 1803 1804 _dbus_assert (!find_subtree (tree, path0, NULL)); 1805 _dbus_assert (!find_subtree (tree, path1, NULL)); 1806 _dbus_assert (!find_subtree (tree, path2, NULL)); 1807 _dbus_assert (!find_subtree (tree, path3, NULL)); 1808 _dbus_assert (!find_subtree (tree, path4, NULL)); 1809 _dbus_assert (!find_subtree (tree, path5, NULL)); 1810 _dbus_assert (find_subtree (tree, path6, NULL)); 1811 _dbus_assert (find_subtree (tree, path7, NULL)); 1812 _dbus_assert (find_subtree (tree, path8, NULL)); 1813 1814 _dbus_object_tree_unregister_and_unlock (tree, path6); 1815 _dbus_assert (_dbus_object_tree_get_user_data_unlocked (tree, path6) == NULL); 1816 1817 _dbus_assert (!find_subtree (tree, path0, NULL)); 1818 _dbus_assert (!find_subtree (tree, path1, NULL)); 1819 _dbus_assert (!find_subtree (tree, path2, NULL)); 1820 _dbus_assert (!find_subtree (tree, path3, NULL)); 1821 _dbus_assert (!find_subtree (tree, path4, NULL)); 1822 _dbus_assert (!find_subtree (tree, path5, NULL)); 1823 _dbus_assert (!find_subtree (tree, path6, NULL)); 1824 _dbus_assert (find_subtree (tree, path7, NULL)); 1825 _dbus_assert (find_subtree (tree, path8, NULL)); 1826 1827 _dbus_object_tree_unregister_and_unlock (tree, path7); 1828 _dbus_assert (_dbus_object_tree_get_user_data_unlocked (tree, path7) == NULL); 1829 1830 _dbus_assert (!find_subtree (tree, path0, NULL)); 1831 _dbus_assert (!find_subtree (tree, path1, NULL)); 1832 _dbus_assert (!find_subtree (tree, path2, NULL)); 1833 _dbus_assert (!find_subtree (tree, path3, NULL)); 1834 _dbus_assert (!find_subtree (tree, path4, NULL)); 1835 _dbus_assert (!find_subtree (tree, path5, NULL)); 1836 _dbus_assert (!find_subtree (tree, path6, NULL)); 1837 _dbus_assert (!find_subtree (tree, path7, NULL)); 1838 _dbus_assert (find_subtree (tree, path8, NULL)); 1839 1840 _dbus_object_tree_unregister_and_unlock (tree, path8); 1841 _dbus_assert (_dbus_object_tree_get_user_data_unlocked (tree, path8) == NULL); 1842 1843 _dbus_assert (!find_subtree (tree, path0, NULL)); 1844 _dbus_assert (!find_subtree (tree, path1, NULL)); 1845 _dbus_assert (!find_subtree (tree, path2, NULL)); 1846 _dbus_assert (!find_subtree (tree, path3, NULL)); 1847 _dbus_assert (!find_subtree (tree, path4, NULL)); 1848 _dbus_assert (!find_subtree (tree, path5, NULL)); 1849 _dbus_assert (!find_subtree (tree, path6, NULL)); 1850 _dbus_assert (!find_subtree (tree, path7, NULL)); 1851 _dbus_assert (!find_subtree (tree, path8, NULL)); 1852 1853 i = 0; 1854 while (i < (int) _DBUS_N_ELEMENTS (tree_test_data)) 1855 { 1856 _dbus_assert (tree_test_data[i].handler_unregistered); 1857 _dbus_assert (!tree_test_data[i].message_handled); 1858 ++i; 1859 } 1860 1861 /* Register it all again, and test dispatch */ 1862 1863 if (!do_register (tree, path0, TRUE, 0, tree_test_data)) 1864 goto out; 1865 if (!do_register (tree, path1, FALSE, 1, tree_test_data)) 1866 goto out; 1867 if (!do_register (tree, path2, TRUE, 2, tree_test_data)) 1868 goto out; 1869 if (!do_register (tree, path3, TRUE, 3, tree_test_data)) 1870 goto out; 1871 if (!do_register (tree, path4, TRUE, 4, tree_test_data)) 1872 goto out; 1873 if (!do_register (tree, path5, TRUE, 5, tree_test_data)) 1874 goto out; 1875 if (!do_register (tree, path6, FALSE, 6, tree_test_data)) 1876 goto out; 1877 if (!do_register (tree, path7, TRUE, 7, tree_test_data)) 1878 goto out; 1879 if (!do_register (tree, path8, TRUE, 8, tree_test_data)) 1880 goto out; 1881 1882 #if 0 1883 spew_tree (tree); 1884 #endif 1885 1886 if (!do_test_dispatch (tree, path0, 0, tree_test_data, _DBUS_N_ELEMENTS (tree_test_data))) 1887 goto out; 1888 if (!do_test_dispatch (tree, path1, 1, tree_test_data, _DBUS_N_ELEMENTS (tree_test_data))) 1889 goto out; 1890 if (!do_test_dispatch (tree, path2, 2, tree_test_data, _DBUS_N_ELEMENTS (tree_test_data))) 1891 goto out; 1892 if (!do_test_dispatch (tree, path3, 3, tree_test_data, _DBUS_N_ELEMENTS (tree_test_data))) 1893 goto out; 1894 if (!do_test_dispatch (tree, path4, 4, tree_test_data, _DBUS_N_ELEMENTS (tree_test_data))) 1895 goto out; 1896 if (!do_test_dispatch (tree, path5, 5, tree_test_data, _DBUS_N_ELEMENTS (tree_test_data))) 1897 goto out; 1898 if (!do_test_dispatch (tree, path6, 6, tree_test_data, _DBUS_N_ELEMENTS (tree_test_data))) 1899 goto out; 1900 if (!do_test_dispatch (tree, path7, 7, tree_test_data, _DBUS_N_ELEMENTS (tree_test_data))) 1901 goto out; 1902 if (!do_test_dispatch (tree, path8, 8, tree_test_data, _DBUS_N_ELEMENTS (tree_test_data))) 1903 goto out; 1904 1905 out: 1906 if (tree) 1907 { 1908 /* test ref */ 1909 _dbus_object_tree_ref (tree); 1910 _dbus_object_tree_unref (tree); 1911 _dbus_object_tree_unref (tree); 1912 } 1913 1914 return TRUE; 1915 } 1916 1917 /** 1918 * @ingroup DBusObjectTree 1919 * Unit test for DBusObjectTree 1920 * @returns #TRUE on success. 1921 */ 1922 dbus_bool_t 1923 _dbus_object_tree_test (void) 1924 { 1925 _dbus_test_oom_handling ("object tree", 1926 object_tree_test_iteration, 1927 NULL); 1928 1929 return TRUE; 1930 } 1931 1932 #endif /* !DOXYGEN_SHOULD_SKIP_THIS */ 1933 1934 #endif /* DBUS_BUILD_TESTS */ 1935