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