D-Bus
1.10.12
|
00001 /* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ 00002 /* dbus-object-tree.c DBusObjectTree (internals of DBusConnection) 00003 * 00004 * Copyright (C) 2003, 2005 Red Hat Inc. 00005 * 00006 * Licensed under the Academic Free License version 2.1 00007 * 00008 * This program is free software; you can redistribute it and/or modify 00009 * it under the terms of the GNU General Public License as published by 00010 * the Free Software Foundation; either version 2 of the License, or 00011 * (at your option) any later version. 00012 * 00013 * This program is distributed in the hope that it will be useful, 00014 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00015 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00016 * GNU General Public License for more details. 00017 * 00018 * You should have received a copy of the GNU General Public License 00019 * along with this program; if not, write to the Free Software 00020 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 00021 * 00022 */ 00023 00024 #include <config.h> 00025 #include "dbus-object-tree.h" 00026 #include "dbus-connection-internal.h" 00027 #include "dbus-internals.h" 00028 #include "dbus-hash.h" 00029 #include "dbus-protocol.h" 00030 #include "dbus-string.h" 00031 #include <string.h> 00032 #include <stdlib.h> 00033 00046 typedef struct DBusObjectSubtree DBusObjectSubtree; 00047 00048 static DBusObjectSubtree* _dbus_object_subtree_new (const char *name, 00049 const DBusObjectPathVTable *vtable, 00050 void *user_data); 00051 static DBusObjectSubtree* _dbus_object_subtree_ref (DBusObjectSubtree *subtree); 00052 static void _dbus_object_subtree_unref (DBusObjectSubtree *subtree); 00053 00057 struct DBusObjectTree 00058 { 00059 int refcount; 00060 DBusConnection *connection; 00062 DBusObjectSubtree *root; 00063 }; 00064 00070 struct DBusObjectSubtree 00071 { 00072 DBusAtomic refcount; 00073 DBusObjectSubtree *parent; 00074 DBusObjectPathUnregisterFunction unregister_function; 00075 DBusObjectPathMessageFunction message_function; 00076 void *user_data; 00077 DBusObjectSubtree **subtrees; 00078 int n_subtrees; 00079 int max_subtrees; 00080 unsigned int invoke_as_fallback : 1; 00081 char name[1]; 00082 }; 00083 00091 DBusObjectTree* 00092 _dbus_object_tree_new (DBusConnection *connection) 00093 { 00094 DBusObjectTree *tree; 00095 00096 /* the connection passed in here isn't fully constructed, 00097 * so don't do anything more than store a pointer to 00098 * it 00099 */ 00100 00101 tree = dbus_new0 (DBusObjectTree, 1); 00102 if (tree == NULL) 00103 goto oom; 00104 00105 tree->refcount = 1; 00106 tree->connection = connection; 00107 tree->root = _dbus_object_subtree_new ("/", NULL, NULL); 00108 if (tree->root == NULL) 00109 goto oom; 00110 tree->root->invoke_as_fallback = TRUE; 00111 00112 return tree; 00113 00114 oom: 00115 if (tree) 00116 { 00117 dbus_free (tree); 00118 } 00119 00120 return NULL; 00121 } 00122 00128 DBusObjectTree * 00129 _dbus_object_tree_ref (DBusObjectTree *tree) 00130 { 00131 _dbus_assert (tree->refcount > 0); 00132 00133 tree->refcount += 1; 00134 00135 return tree; 00136 } 00137 00142 void 00143 _dbus_object_tree_unref (DBusObjectTree *tree) 00144 { 00145 _dbus_assert (tree->refcount > 0); 00146 00147 tree->refcount -= 1; 00148 00149 if (tree->refcount == 0) 00150 { 00151 _dbus_object_tree_free_all_unlocked (tree); 00152 00153 dbus_free (tree); 00154 } 00155 } 00156 00160 #define VERBOSE_FIND 0 00161 00162 static DBusObjectSubtree* 00163 find_subtree_recurse (DBusObjectSubtree *subtree, 00164 const char **path, 00165 dbus_bool_t create_if_not_found, 00166 int *index_in_parent, 00167 dbus_bool_t *exact_match) 00168 { 00169 int i, j; 00170 dbus_bool_t return_deepest_match; 00171 00172 return_deepest_match = exact_match != NULL; 00173 00174 _dbus_assert (!(return_deepest_match && create_if_not_found)); 00175 00176 if (path[0] == NULL) 00177 { 00178 #if VERBOSE_FIND 00179 _dbus_verbose (" path exhausted, returning %s\n", 00180 subtree->name); 00181 #endif 00182 if (exact_match != NULL) 00183 *exact_match = TRUE; 00184 return subtree; 00185 } 00186 00187 #if VERBOSE_FIND 00188 _dbus_verbose (" searching children of %s for %s\n", 00189 subtree->name, path[0]); 00190 #endif 00191 00192 i = 0; 00193 j = subtree->n_subtrees; 00194 while (i < j) 00195 { 00196 int k, v; 00197 00198 k = (i + j) / 2; 00199 v = strcmp (path[0], subtree->subtrees[k]->name); 00200 00201 #if VERBOSE_FIND 00202 _dbus_verbose (" %s cmp %s = %d\n", 00203 path[0], subtree->subtrees[k]->name, 00204 v); 00205 #endif 00206 00207 if (v == 0) 00208 { 00209 if (index_in_parent) 00210 { 00211 #if VERBOSE_FIND 00212 _dbus_verbose (" storing parent index %d\n", k); 00213 #endif 00214 *index_in_parent = k; 00215 } 00216 00217 if (return_deepest_match) 00218 { 00219 DBusObjectSubtree *next; 00220 00221 next = find_subtree_recurse (subtree->subtrees[k], 00222 &path[1], create_if_not_found, 00223 index_in_parent, exact_match); 00224 if (next == NULL && 00225 subtree->invoke_as_fallback) 00226 { 00227 #if VERBOSE_FIND 00228 _dbus_verbose (" no deeper match found, returning %s\n", 00229 subtree->name); 00230 #endif 00231 if (exact_match != NULL) 00232 *exact_match = FALSE; 00233 return subtree; 00234 } 00235 else 00236 return next; 00237 } 00238 else 00239 return find_subtree_recurse (subtree->subtrees[k], 00240 &path[1], create_if_not_found, 00241 index_in_parent, exact_match); 00242 } 00243 else if (v < 0) 00244 { 00245 j = k; 00246 } 00247 else 00248 { 00249 i = k + 1; 00250 } 00251 } 00252 00253 #if VERBOSE_FIND 00254 _dbus_verbose (" no match found, current tree %s, create_if_not_found = %d\n", 00255 subtree->name, create_if_not_found); 00256 #endif 00257 00258 if (create_if_not_found) 00259 { 00260 DBusObjectSubtree* child; 00261 int child_pos, new_n_subtrees; 00262 00263 #if VERBOSE_FIND 00264 _dbus_verbose (" creating subtree %s\n", 00265 path[0]); 00266 #endif 00267 00268 child = _dbus_object_subtree_new (path[0], 00269 NULL, NULL); 00270 if (child == NULL) 00271 return NULL; 00272 00273 new_n_subtrees = subtree->n_subtrees + 1; 00274 if (new_n_subtrees > subtree->max_subtrees) 00275 { 00276 int new_max_subtrees; 00277 DBusObjectSubtree **new_subtrees; 00278 00279 new_max_subtrees = subtree->max_subtrees == 0 ? 1 : 2 * subtree->max_subtrees; 00280 new_subtrees = dbus_realloc (subtree->subtrees, 00281 new_max_subtrees * sizeof (DBusObjectSubtree*)); 00282 if (new_subtrees == NULL) 00283 { 00284 _dbus_object_subtree_unref (child); 00285 return NULL; 00286 } 00287 subtree->subtrees = new_subtrees; 00288 subtree->max_subtrees = new_max_subtrees; 00289 } 00290 00291 /* The binary search failed, so i == j points to the 00292 place the child should be inserted. */ 00293 child_pos = i; 00294 _dbus_assert (child_pos < new_n_subtrees && 00295 new_n_subtrees <= subtree->max_subtrees); 00296 if (child_pos + 1 < new_n_subtrees) 00297 { 00298 memmove (&subtree->subtrees[child_pos+1], 00299 &subtree->subtrees[child_pos], 00300 (new_n_subtrees - child_pos - 1) * 00301 sizeof subtree->subtrees[0]); 00302 } 00303 subtree->subtrees[child_pos] = child; 00304 00305 if (index_in_parent) 00306 *index_in_parent = child_pos; 00307 subtree->n_subtrees = new_n_subtrees; 00308 child->parent = subtree; 00309 00310 return find_subtree_recurse (child, 00311 &path[1], create_if_not_found, 00312 index_in_parent, exact_match); 00313 } 00314 else 00315 { 00316 if (exact_match != NULL) 00317 *exact_match = FALSE; 00318 return (return_deepest_match && subtree->invoke_as_fallback) ? subtree : NULL; 00319 } 00320 } 00321 00322 #ifdef DBUS_ENABLE_EMBEDDED_TESTS 00323 static DBusObjectSubtree* 00324 find_subtree (DBusObjectTree *tree, 00325 const char **path, 00326 int *index_in_parent) 00327 { 00328 DBusObjectSubtree *subtree; 00329 00330 #if VERBOSE_FIND 00331 _dbus_verbose ("Looking for exact registered subtree\n"); 00332 #endif 00333 00334 subtree = find_subtree_recurse (tree->root, path, FALSE, index_in_parent, NULL); 00335 00336 if (subtree && subtree->message_function == NULL) 00337 return NULL; 00338 else 00339 return subtree; 00340 } 00341 #endif 00342 00343 static DBusObjectSubtree* 00344 lookup_subtree (DBusObjectTree *tree, 00345 const char **path) 00346 { 00347 #if VERBOSE_FIND 00348 _dbus_verbose ("Looking for subtree\n"); 00349 #endif 00350 return find_subtree_recurse (tree->root, path, FALSE, NULL, NULL); 00351 } 00352 00353 static DBusObjectSubtree* 00354 find_handler (DBusObjectTree *tree, 00355 const char **path, 00356 dbus_bool_t *exact_match) 00357 { 00358 #if VERBOSE_FIND 00359 _dbus_verbose ("Looking for deepest handler\n"); 00360 #endif 00361 _dbus_assert (exact_match != NULL); 00362 00363 *exact_match = FALSE; /* ensure always initialized */ 00364 00365 return find_subtree_recurse (tree->root, path, FALSE, NULL, exact_match); 00366 } 00367 00368 static DBusObjectSubtree* 00369 ensure_subtree (DBusObjectTree *tree, 00370 const char **path) 00371 { 00372 #if VERBOSE_FIND 00373 _dbus_verbose ("Ensuring subtree\n"); 00374 #endif 00375 return find_subtree_recurse (tree->root, path, TRUE, NULL, NULL); 00376 } 00377 00378 static char *flatten_path (const char **path); 00379 00392 dbus_bool_t 00393 _dbus_object_tree_register (DBusObjectTree *tree, 00394 dbus_bool_t fallback, 00395 const char **path, 00396 const DBusObjectPathVTable *vtable, 00397 void *user_data, 00398 DBusError *error) 00399 { 00400 DBusObjectSubtree *subtree; 00401 00402 _dbus_assert (tree != NULL); 00403 _dbus_assert (vtable->message_function != NULL); 00404 _dbus_assert (path != NULL); 00405 00406 subtree = ensure_subtree (tree, path); 00407 if (subtree == NULL) 00408 { 00409 _DBUS_SET_OOM (error); 00410 return FALSE; 00411 } 00412 00413 if (subtree->message_function != NULL) 00414 { 00415 if (error != NULL) 00416 { 00417 char *complete_path = flatten_path (path); 00418 00419 dbus_set_error (error, DBUS_ERROR_OBJECT_PATH_IN_USE, 00420 "A handler is already registered for %s", 00421 complete_path ? complete_path 00422 : "(cannot represent path: out of memory!)"); 00423 00424 dbus_free (complete_path); 00425 } 00426 00427 return FALSE; 00428 } 00429 00430 subtree->message_function = vtable->message_function; 00431 subtree->unregister_function = vtable->unregister_function; 00432 subtree->user_data = user_data; 00433 subtree->invoke_as_fallback = fallback != FALSE; 00434 00435 return TRUE; 00436 } 00437 00449 static dbus_bool_t 00450 unregister_subtree (DBusObjectSubtree *subtree, 00451 DBusObjectPathUnregisterFunction *unregister_function_out, 00452 void **user_data_out) 00453 { 00454 _dbus_assert (subtree != NULL); 00455 _dbus_assert (unregister_function_out != NULL); 00456 _dbus_assert (user_data_out != NULL); 00457 00458 /* Confirm subtree is registered */ 00459 if (subtree->message_function != NULL) 00460 { 00461 subtree->message_function = NULL; 00462 00463 *unregister_function_out = subtree->unregister_function; 00464 *user_data_out = subtree->user_data; 00465 00466 subtree->unregister_function = NULL; 00467 subtree->user_data = NULL; 00468 00469 return TRUE; 00470 } 00471 else 00472 { 00473 /* Assert that this unregistered subtree is either the root node or has 00474 children, otherwise we have a dangling path which should never 00475 happen */ 00476 _dbus_assert (subtree->parent == NULL || subtree->n_subtrees > 0); 00477 00478 /* The subtree is not registered */ 00479 return FALSE; 00480 } 00481 } 00482 00494 static dbus_bool_t 00495 attempt_child_removal (DBusObjectSubtree *parent, 00496 int child_index) 00497 { 00498 /* Candidate for removal */ 00499 DBusObjectSubtree* candidate; 00500 00501 _dbus_assert (parent != NULL); 00502 _dbus_assert (child_index >= 0 && child_index < parent->n_subtrees); 00503 00504 candidate = parent->subtrees[child_index]; 00505 _dbus_assert (candidate != NULL); 00506 00507 if (candidate->n_subtrees == 0 && candidate->message_function == NULL) 00508 { 00509 /* The candidate node is childless and is not a registered 00510 path, so... */ 00511 00512 /* ... remove it from its parent... */ 00513 /* Assumes a 0-byte memmove is OK */ 00514 memmove (&parent->subtrees[child_index], 00515 &parent->subtrees[child_index + 1], 00516 (parent->n_subtrees - child_index - 1) 00517 * sizeof (parent->subtrees[0])); 00518 parent->n_subtrees -= 1; 00519 00520 /* ... and free it */ 00521 candidate->parent = NULL; 00522 _dbus_object_subtree_unref (candidate); 00523 00524 return TRUE; 00525 } 00526 return FALSE; 00527 } 00528 00566 static dbus_bool_t 00567 unregister_and_free_path_recurse 00568 (DBusObjectSubtree *subtree, 00569 const char **path, 00570 dbus_bool_t *continue_removal_attempts, 00571 DBusObjectPathUnregisterFunction *unregister_function_out, 00572 void **user_data_out) 00573 { 00574 int i, j; 00575 00576 _dbus_assert (continue_removal_attempts != NULL); 00577 _dbus_assert (*continue_removal_attempts); 00578 _dbus_assert (unregister_function_out != NULL); 00579 _dbus_assert (user_data_out != NULL); 00580 00581 if (path[0] == NULL) 00582 return unregister_subtree (subtree, unregister_function_out, user_data_out); 00583 00584 i = 0; 00585 j = subtree->n_subtrees; 00586 while (i < j) 00587 { 00588 int k, v; 00589 00590 k = (i + j) / 2; 00591 v = strcmp (path[0], subtree->subtrees[k]->name); 00592 00593 if (v == 0) 00594 { 00595 dbus_bool_t freed; 00596 freed = unregister_and_free_path_recurse (subtree->subtrees[k], 00597 &path[1], 00598 continue_removal_attempts, 00599 unregister_function_out, 00600 user_data_out); 00601 if (freed && *continue_removal_attempts) 00602 *continue_removal_attempts = attempt_child_removal (subtree, k); 00603 return freed; 00604 } 00605 else if (v < 0) 00606 { 00607 j = k; 00608 } 00609 else 00610 { 00611 i = k + 1; 00612 } 00613 } 00614 return FALSE; 00615 } 00616 00624 void 00625 _dbus_object_tree_unregister_and_unlock (DBusObjectTree *tree, 00626 const char **path) 00627 { 00628 dbus_bool_t found_subtree; 00629 dbus_bool_t continue_removal_attempts; 00630 DBusObjectPathUnregisterFunction unregister_function; 00631 void *user_data; 00632 DBusConnection *connection; 00633 00634 _dbus_assert (tree != NULL); 00635 _dbus_assert (path != NULL); 00636 00637 continue_removal_attempts = TRUE; 00638 unregister_function = NULL; 00639 user_data = NULL; 00640 00641 found_subtree = unregister_and_free_path_recurse (tree->root, 00642 path, 00643 &continue_removal_attempts, 00644 &unregister_function, 00645 &user_data); 00646 00647 #ifndef DBUS_DISABLE_CHECKS 00648 if (found_subtree == FALSE) 00649 { 00650 _dbus_warn ("Attempted to unregister path (path[0] = %s path[1] = %s) which isn't registered\n", 00651 path[0] ? path[0] : "null", 00652 (path[0] && path[1]) ? path[1] : "null"); 00653 goto unlock; 00654 } 00655 #else 00656 _dbus_assert (found_subtree == TRUE); 00657 #endif 00658 00659 unlock: 00660 connection = tree->connection; 00661 00662 /* Unlock and call application code */ 00663 #ifdef DBUS_ENABLE_EMBEDDED_TESTS 00664 if (connection) 00665 #endif 00666 { 00667 _dbus_connection_ref_unlocked (connection); 00668 _dbus_verbose ("unlock\n"); 00669 _dbus_connection_unlock (connection); 00670 } 00671 00672 if (unregister_function) 00673 (* unregister_function) (connection, user_data); 00674 00675 #ifdef DBUS_ENABLE_EMBEDDED_TESTS 00676 if (connection) 00677 #endif 00678 dbus_connection_unref (connection); 00679 } 00680 00681 static void 00682 free_subtree_recurse (DBusConnection *connection, 00683 DBusObjectSubtree *subtree) 00684 { 00685 /* Delete them from the end, for slightly 00686 * more robustness against odd reentrancy. 00687 */ 00688 while (subtree->n_subtrees > 0) 00689 { 00690 DBusObjectSubtree *child; 00691 00692 child = subtree->subtrees[subtree->n_subtrees - 1]; 00693 subtree->subtrees[subtree->n_subtrees - 1] = NULL; 00694 subtree->n_subtrees -= 1; 00695 child->parent = NULL; 00696 00697 free_subtree_recurse (connection, child); 00698 } 00699 00700 /* Call application code */ 00701 if (subtree->unregister_function) 00702 (* subtree->unregister_function) (connection, 00703 subtree->user_data); 00704 00705 subtree->message_function = NULL; 00706 subtree->unregister_function = NULL; 00707 subtree->user_data = NULL; 00708 00709 /* Now free ourselves */ 00710 _dbus_object_subtree_unref (subtree); 00711 } 00712 00719 void 00720 _dbus_object_tree_free_all_unlocked (DBusObjectTree *tree) 00721 { 00722 if (tree->root) 00723 free_subtree_recurse (tree->connection, 00724 tree->root); 00725 tree->root = NULL; 00726 } 00727 00728 static dbus_bool_t 00729 _dbus_object_tree_list_registered_unlocked (DBusObjectTree *tree, 00730 const char **parent_path, 00731 char ***child_entries) 00732 { 00733 DBusObjectSubtree *subtree; 00734 char **retval; 00735 00736 _dbus_assert (parent_path != NULL); 00737 _dbus_assert (child_entries != NULL); 00738 00739 *child_entries = NULL; 00740 00741 subtree = lookup_subtree (tree, parent_path); 00742 if (subtree == NULL) 00743 { 00744 retval = dbus_new0 (char *, 1); 00745 } 00746 else 00747 { 00748 int i; 00749 retval = dbus_new0 (char*, subtree->n_subtrees + 1); 00750 if (retval == NULL) 00751 goto out; 00752 i = 0; 00753 while (i < subtree->n_subtrees) 00754 { 00755 retval[i] = _dbus_strdup (subtree->subtrees[i]->name); 00756 if (retval[i] == NULL) 00757 { 00758 dbus_free_string_array (retval); 00759 retval = NULL; 00760 goto out; 00761 } 00762 ++i; 00763 } 00764 } 00765 00766 out: 00767 00768 *child_entries = retval; 00769 return retval != NULL; 00770 } 00771 00772 static DBusHandlerResult 00773 handle_default_introspect_and_unlock (DBusObjectTree *tree, 00774 DBusMessage *message, 00775 const char **path) 00776 { 00777 DBusString xml; 00778 DBusHandlerResult result; 00779 char **children; 00780 int i; 00781 DBusMessage *reply; 00782 DBusMessageIter iter; 00783 const char *v_STRING; 00784 dbus_bool_t already_unlocked; 00785 00786 /* We have the connection lock here */ 00787 00788 already_unlocked = FALSE; 00789 00790 _dbus_verbose (" considering default Introspect() handler...\n"); 00791 00792 reply = NULL; 00793 00794 if (!dbus_message_is_method_call (message, 00795 DBUS_INTERFACE_INTROSPECTABLE, 00796 "Introspect")) 00797 { 00798 #ifdef DBUS_ENABLE_EMBEDDED_TESTS 00799 if (tree->connection) 00800 #endif 00801 { 00802 _dbus_verbose ("unlock\n"); 00803 _dbus_connection_unlock (tree->connection); 00804 } 00805 00806 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; 00807 } 00808 00809 _dbus_verbose (" using default Introspect() handler!\n"); 00810 00811 if (!_dbus_string_init (&xml)) 00812 { 00813 #ifdef DBUS_ENABLE_EMBEDDED_TESTS 00814 if (tree->connection) 00815 #endif 00816 { 00817 _dbus_verbose ("unlock\n"); 00818 _dbus_connection_unlock (tree->connection); 00819 } 00820 00821 return DBUS_HANDLER_RESULT_NEED_MEMORY; 00822 } 00823 00824 result = DBUS_HANDLER_RESULT_NEED_MEMORY; 00825 00826 children = NULL; 00827 if (!_dbus_object_tree_list_registered_unlocked (tree, path, &children)) 00828 goto out; 00829 00830 if (!_dbus_string_append (&xml, DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE)) 00831 goto out; 00832 00833 if (!_dbus_string_append (&xml, "<node>\n")) 00834 goto out; 00835 00836 i = 0; 00837 while (children[i] != NULL) 00838 { 00839 if (!_dbus_string_append_printf (&xml, " <node name=\"%s\"/>\n", 00840 children[i])) 00841 goto out; 00842 00843 ++i; 00844 } 00845 00846 if (!_dbus_string_append (&xml, "</node>\n")) 00847 goto out; 00848 00849 reply = dbus_message_new_method_return (message); 00850 if (reply == NULL) 00851 goto out; 00852 00853 dbus_message_iter_init_append (reply, &iter); 00854 v_STRING = _dbus_string_get_const_data (&xml); 00855 if (!dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &v_STRING)) 00856 goto out; 00857 00858 #ifdef DBUS_ENABLE_EMBEDDED_TESTS 00859 if (tree->connection) 00860 #endif 00861 { 00862 already_unlocked = TRUE; 00863 00864 if (!_dbus_connection_send_and_unlock (tree->connection, reply, NULL)) 00865 goto out; 00866 } 00867 00868 result = DBUS_HANDLER_RESULT_HANDLED; 00869 00870 out: 00871 #ifdef DBUS_ENABLE_EMBEDDED_TESTS 00872 if (tree->connection) 00873 #endif 00874 { 00875 if (!already_unlocked) 00876 { 00877 _dbus_verbose ("unlock\n"); 00878 _dbus_connection_unlock (tree->connection); 00879 } 00880 } 00881 00882 _dbus_string_free (&xml); 00883 dbus_free_string_array (children); 00884 if (reply) 00885 dbus_message_unref (reply); 00886 00887 return result; 00888 } 00889 00904 DBusHandlerResult 00905 _dbus_object_tree_dispatch_and_unlock (DBusObjectTree *tree, 00906 DBusMessage *message, 00907 dbus_bool_t *found_object) 00908 { 00909 char **path; 00910 dbus_bool_t exact_match; 00911 DBusList *list; 00912 DBusList *link; 00913 DBusHandlerResult result; 00914 DBusObjectSubtree *subtree; 00915 00916 #if 0 00917 _dbus_verbose ("Dispatch of message by object path\n"); 00918 #endif 00919 00920 path = NULL; 00921 if (!dbus_message_get_path_decomposed (message, &path)) 00922 { 00923 #ifdef DBUS_ENABLE_EMBEDDED_TESTS 00924 if (tree->connection) 00925 #endif 00926 { 00927 _dbus_verbose ("unlock\n"); 00928 _dbus_connection_unlock (tree->connection); 00929 } 00930 00931 _dbus_verbose ("No memory to get decomposed path\n"); 00932 00933 return DBUS_HANDLER_RESULT_NEED_MEMORY; 00934 } 00935 00936 if (path == NULL) 00937 { 00938 #ifdef DBUS_ENABLE_EMBEDDED_TESTS 00939 if (tree->connection) 00940 #endif 00941 { 00942 _dbus_verbose ("unlock\n"); 00943 _dbus_connection_unlock (tree->connection); 00944 } 00945 00946 _dbus_verbose ("No path field in message\n"); 00947 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; 00948 } 00949 00950 /* Find the deepest path that covers the path in the message */ 00951 subtree = find_handler (tree, (const char**) path, &exact_match); 00952 00953 if (found_object) 00954 *found_object = !!subtree; 00955 00956 /* Build a list of all paths that cover the path in the message */ 00957 00958 list = NULL; 00959 00960 while (subtree != NULL) 00961 { 00962 if (subtree->message_function != NULL && (exact_match || subtree->invoke_as_fallback)) 00963 { 00964 _dbus_object_subtree_ref (subtree); 00965 00966 /* run deepest paths first */ 00967 if (!_dbus_list_append (&list, subtree)) 00968 { 00969 result = DBUS_HANDLER_RESULT_NEED_MEMORY; 00970 _dbus_object_subtree_unref (subtree); 00971 goto free_and_return; 00972 } 00973 } 00974 00975 exact_match = FALSE; 00976 subtree = subtree->parent; 00977 } 00978 00979 _dbus_verbose ("%d handlers in the path tree for this message\n", 00980 _dbus_list_get_length (&list)); 00981 00982 /* Invoke each handler in the list */ 00983 00984 result = DBUS_HANDLER_RESULT_NOT_YET_HANDLED; 00985 00986 link = _dbus_list_get_first_link (&list); 00987 while (link != NULL) 00988 { 00989 DBusList *next = _dbus_list_get_next_link (&list, link); 00990 subtree = link->data; 00991 00992 /* message_function is NULL if we're unregistered 00993 * due to reentrancy 00994 */ 00995 if (subtree->message_function) 00996 { 00997 DBusObjectPathMessageFunction message_function; 00998 void *user_data; 00999 01000 message_function = subtree->message_function; 01001 user_data = subtree->user_data; 01002 01003 #if 0 01004 _dbus_verbose (" (invoking a handler)\n"); 01005 #endif 01006 01007 #ifdef DBUS_ENABLE_EMBEDDED_TESTS 01008 if (tree->connection) 01009 #endif 01010 { 01011 _dbus_verbose ("unlock\n"); 01012 _dbus_connection_unlock (tree->connection); 01013 } 01014 01015 /* FIXME you could unregister the subtree in another thread 01016 * before we invoke the callback, and I can't figure out a 01017 * good way to solve this. 01018 */ 01019 01020 result = (* message_function) (tree->connection, 01021 message, 01022 user_data); 01023 01024 #ifdef DBUS_ENABLE_EMBEDDED_TESTS 01025 if (tree->connection) 01026 #endif 01027 _dbus_connection_lock (tree->connection); 01028 01029 if (result != DBUS_HANDLER_RESULT_NOT_YET_HANDLED) 01030 goto free_and_return; 01031 } 01032 01033 link = next; 01034 } 01035 01036 free_and_return: 01037 01038 if (result == DBUS_HANDLER_RESULT_NOT_YET_HANDLED) 01039 { 01040 /* This hardcoded default handler does a minimal Introspect() 01041 */ 01042 result = handle_default_introspect_and_unlock (tree, message, 01043 (const char**) path); 01044 } 01045 else 01046 { 01047 #ifdef DBUS_ENABLE_EMBEDDED_TESTS 01048 if (tree->connection) 01049 #endif 01050 { 01051 _dbus_verbose ("unlock\n"); 01052 _dbus_connection_unlock (tree->connection); 01053 } 01054 } 01055 01056 while (list != NULL) 01057 { 01058 link = _dbus_list_get_first_link (&list); 01059 _dbus_object_subtree_unref (link->data); 01060 _dbus_list_remove_link (&list, link); 01061 } 01062 01063 dbus_free_string_array (path); 01064 01065 return result; 01066 } 01067 01076 void* 01077 _dbus_object_tree_get_user_data_unlocked (DBusObjectTree *tree, 01078 const char **path) 01079 { 01080 dbus_bool_t exact_match; 01081 DBusObjectSubtree *subtree; 01082 01083 _dbus_assert (tree != NULL); 01084 _dbus_assert (path != NULL); 01085 01086 /* Find the deepest path that covers the path in the message */ 01087 subtree = find_handler (tree, (const char**) path, &exact_match); 01088 01089 if ((subtree == NULL) || !exact_match) 01090 { 01091 _dbus_verbose ("No object at specified path found\n"); 01092 return NULL; 01093 } 01094 01095 return subtree->user_data; 01096 } 01097 01104 static DBusObjectSubtree* 01105 allocate_subtree_object (const char *name) 01106 { 01107 int len; 01108 DBusObjectSubtree *subtree; 01109 const size_t front_padding = _DBUS_STRUCT_OFFSET (DBusObjectSubtree, name); 01110 01111 _dbus_assert (name != NULL); 01112 01113 len = strlen (name); 01114 01115 subtree = dbus_malloc0 (MAX (front_padding + (len + 1), sizeof (DBusObjectSubtree))); 01116 01117 if (subtree == NULL) 01118 return NULL; 01119 01120 memcpy (subtree->name, name, len + 1); 01121 01122 return subtree; 01123 } 01124 01125 static DBusObjectSubtree* 01126 _dbus_object_subtree_new (const char *name, 01127 const DBusObjectPathVTable *vtable, 01128 void *user_data) 01129 { 01130 DBusObjectSubtree *subtree; 01131 01132 subtree = allocate_subtree_object (name); 01133 if (subtree == NULL) 01134 goto oom; 01135 01136 _dbus_assert (name != NULL); 01137 01138 subtree->parent = NULL; 01139 01140 if (vtable) 01141 { 01142 subtree->message_function = vtable->message_function; 01143 subtree->unregister_function = vtable->unregister_function; 01144 } 01145 else 01146 { 01147 subtree->message_function = NULL; 01148 subtree->unregister_function = NULL; 01149 } 01150 01151 subtree->user_data = user_data; 01152 _dbus_atomic_inc (&subtree->refcount); 01153 subtree->subtrees = NULL; 01154 subtree->n_subtrees = 0; 01155 subtree->max_subtrees = 0; 01156 subtree->invoke_as_fallback = FALSE; 01157 01158 return subtree; 01159 01160 oom: 01161 return NULL; 01162 } 01163 01164 static DBusObjectSubtree * 01165 _dbus_object_subtree_ref (DBusObjectSubtree *subtree) 01166 { 01167 #ifdef DBUS_DISABLE_ASSERT 01168 _dbus_atomic_inc (&subtree->refcount); 01169 #else 01170 dbus_int32_t old_value; 01171 01172 old_value = _dbus_atomic_inc (&subtree->refcount); 01173 _dbus_assert (old_value > 0); 01174 #endif 01175 01176 return subtree; 01177 } 01178 01179 static void 01180 _dbus_object_subtree_unref (DBusObjectSubtree *subtree) 01181 { 01182 dbus_int32_t old_value; 01183 01184 old_value = _dbus_atomic_dec (&subtree->refcount); 01185 _dbus_assert (old_value > 0); 01186 01187 if (old_value == 1) 01188 { 01189 _dbus_assert (subtree->unregister_function == NULL); 01190 _dbus_assert (subtree->message_function == NULL); 01191 01192 dbus_free (subtree->subtrees); 01193 dbus_free (subtree); 01194 } 01195 } 01196 01207 dbus_bool_t 01208 _dbus_object_tree_list_registered_and_unlock (DBusObjectTree *tree, 01209 const char **parent_path, 01210 char ***child_entries) 01211 { 01212 dbus_bool_t result; 01213 01214 result = _dbus_object_tree_list_registered_unlocked (tree, 01215 parent_path, 01216 child_entries); 01217 01218 #ifdef DBUS_ENABLE_EMBEDDED_TESTS 01219 if (tree->connection) 01220 #endif 01221 { 01222 _dbus_verbose ("unlock\n"); 01223 _dbus_connection_unlock (tree->connection); 01224 } 01225 01226 return result; 01227 } 01228 01229 01231 #define VERBOSE_DECOMPOSE 0 01232 01243 dbus_bool_t 01244 _dbus_decompose_path (const char* data, 01245 int len, 01246 char ***path, 01247 int *path_len) 01248 { 01249 char **retval; 01250 int n_components; 01251 int i, j, comp; 01252 01253 _dbus_assert (data != NULL); 01254 _dbus_assert (path != NULL); 01255 01256 #if VERBOSE_DECOMPOSE 01257 _dbus_verbose ("Decomposing path \"%s\"\n", 01258 data); 01259 #endif 01260 01261 n_components = 0; 01262 if (len > 1) /* if path is not just "/" */ 01263 { 01264 i = 0; 01265 while (i < len) 01266 { 01267 _dbus_assert (data[i] != '\0'); 01268 if (data[i] == '/') 01269 n_components += 1; 01270 ++i; 01271 } 01272 } 01273 01274 retval = dbus_new0 (char*, n_components + 1); 01275 01276 if (retval == NULL) 01277 return FALSE; 01278 01279 comp = 0; 01280 if (n_components == 0) 01281 i = 1; 01282 else 01283 i = 0; 01284 while (comp < n_components) 01285 { 01286 _dbus_assert (i < len); 01287 01288 if (data[i] == '/') 01289 ++i; 01290 j = i; 01291 01292 while (j < len && data[j] != '/') 01293 ++j; 01294 01295 /* Now [i, j) is the path component */ 01296 _dbus_assert (i < j); 01297 _dbus_assert (data[i] != '/'); 01298 _dbus_assert (j == len || data[j] == '/'); 01299 01300 #if VERBOSE_DECOMPOSE 01301 _dbus_verbose (" (component in [%d,%d))\n", 01302 i, j); 01303 #endif 01304 01305 retval[comp] = _dbus_memdup (&data[i], j - i + 1); 01306 if (retval[comp] == NULL) 01307 { 01308 dbus_free_string_array (retval); 01309 return FALSE; 01310 } 01311 retval[comp][j-i] = '\0'; 01312 #if VERBOSE_DECOMPOSE 01313 _dbus_verbose (" (component %d = \"%s\")\n", 01314 comp, retval[comp]); 01315 #endif 01316 01317 ++comp; 01318 i = j; 01319 } 01320 _dbus_assert (i == len); 01321 01322 *path = retval; 01323 if (path_len) 01324 *path_len = n_components; 01325 01326 return TRUE; 01327 } 01328 01331 static char* 01332 flatten_path (const char **path) 01333 { 01334 DBusString str; 01335 char *s; 01336 01337 if (!_dbus_string_init (&str)) 01338 return NULL; 01339 01340 if (path[0] == NULL) 01341 { 01342 if (!_dbus_string_append_byte (&str, '/')) 01343 goto nomem; 01344 } 01345 else 01346 { 01347 int i; 01348 01349 i = 0; 01350 while (path[i]) 01351 { 01352 if (!_dbus_string_append_byte (&str, '/')) 01353 goto nomem; 01354 01355 if (!_dbus_string_append (&str, path[i])) 01356 goto nomem; 01357 01358 ++i; 01359 } 01360 } 01361 01362 if (!_dbus_string_steal_data (&str, &s)) 01363 goto nomem; 01364 01365 _dbus_string_free (&str); 01366 01367 return s; 01368 01369 nomem: 01370 _dbus_string_free (&str); 01371 return NULL; 01372 } 01373 01374 01375 #ifdef DBUS_ENABLE_EMBEDDED_TESTS 01376 01377 #ifndef DOXYGEN_SHOULD_SKIP_THIS 01378 01379 #include "dbus-test.h" 01380 #include <stdio.h> 01381 01382 typedef enum 01383 { 01384 STR_EQUAL, 01385 STR_PREFIX, 01386 STR_DIFFERENT 01387 } StrComparison; 01388 01389 /* Returns TRUE if container is a parent of child 01390 */ 01391 static StrComparison 01392 path_contains (const char **container, 01393 const char **child) 01394 { 01395 int i; 01396 01397 i = 0; 01398 while (child[i] != NULL) 01399 { 01400 int v; 01401 01402 if (container[i] == NULL) 01403 return STR_PREFIX; /* container ran out, child continues; 01404 * thus the container is a parent of the 01405 * child. 01406 */ 01407 01408 _dbus_assert (container[i] != NULL); 01409 _dbus_assert (child[i] != NULL); 01410 01411 v = strcmp (container[i], child[i]); 01412 01413 if (v != 0) 01414 return STR_DIFFERENT; /* they overlap until here and then are different, 01415 * not overlapping 01416 */ 01417 01418 ++i; 01419 } 01420 01421 /* Child ran out; if container also did, they are equal; 01422 * otherwise, the child is a parent of the container. 01423 */ 01424 if (container[i] == NULL) 01425 return STR_EQUAL; 01426 else 01427 return STR_DIFFERENT; 01428 } 01429 01430 #if 0 01431 static void 01432 spew_subtree_recurse (DBusObjectSubtree *subtree, 01433 int indent) 01434 { 01435 int i; 01436 01437 i = 0; 01438 while (i < indent) 01439 { 01440 _dbus_verbose (" "); 01441 ++i; 01442 } 01443 01444 _dbus_verbose ("%s (%d children)\n", 01445 subtree->name, subtree->n_subtrees); 01446 01447 i = 0; 01448 while (i < subtree->n_subtrees) 01449 { 01450 spew_subtree_recurse (subtree->subtrees[i], indent + 2); 01451 01452 ++i; 01453 } 01454 } 01455 01456 static void 01457 spew_tree (DBusObjectTree *tree) 01458 { 01459 spew_subtree_recurse (tree->root, 0); 01460 } 01461 #endif 01462 01466 typedef struct 01467 { 01468 const char **path; 01469 dbus_bool_t handler_fallback; 01470 dbus_bool_t message_handled; 01471 dbus_bool_t handler_unregistered; 01472 } TreeTestData; 01473 01474 01475 static void 01476 test_unregister_function (DBusConnection *connection, 01477 void *user_data) 01478 { 01479 TreeTestData *ttd = user_data; 01480 01481 ttd->handler_unregistered = TRUE; 01482 } 01483 01484 static DBusHandlerResult 01485 test_message_function (DBusConnection *connection, 01486 DBusMessage *message, 01487 void *user_data) 01488 { 01489 TreeTestData *ttd = user_data; 01490 01491 ttd->message_handled = TRUE; 01492 01493 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; 01494 } 01495 01496 static dbus_bool_t 01497 do_register (DBusObjectTree *tree, 01498 const char **path, 01499 dbus_bool_t fallback, 01500 int i, 01501 TreeTestData *tree_test_data) 01502 { 01503 DBusObjectPathVTable vtable = { test_unregister_function, 01504 test_message_function, NULL }; 01505 01506 tree_test_data[i].message_handled = FALSE; 01507 tree_test_data[i].handler_unregistered = FALSE; 01508 tree_test_data[i].handler_fallback = fallback; 01509 tree_test_data[i].path = path; 01510 01511 if (!_dbus_object_tree_register (tree, fallback, path, 01512 &vtable, 01513 &tree_test_data[i], 01514 NULL)) 01515 return FALSE; 01516 01517 _dbus_assert (_dbus_object_tree_get_user_data_unlocked (tree, path) == 01518 &tree_test_data[i]); 01519 01520 return TRUE; 01521 } 01522 01523 static dbus_bool_t 01524 do_test_dispatch (DBusObjectTree *tree, 01525 const char **path, 01526 int i, 01527 TreeTestData *tree_test_data, 01528 int n_test_data) 01529 { 01530 DBusMessage *message; 01531 int j; 01532 DBusHandlerResult result; 01533 char *flat; 01534 01535 message = NULL; 01536 01537 flat = flatten_path (path); 01538 if (flat == NULL) 01539 goto oom; 01540 01541 message = dbus_message_new_method_call (NULL, 01542 flat, 01543 "org.freedesktop.TestInterface", 01544 "Foo"); 01545 dbus_free (flat); 01546 if (message == NULL) 01547 goto oom; 01548 01549 j = 0; 01550 while (j < n_test_data) 01551 { 01552 tree_test_data[j].message_handled = FALSE; 01553 ++j; 01554 } 01555 01556 result = _dbus_object_tree_dispatch_and_unlock (tree, message, NULL); 01557 if (result == DBUS_HANDLER_RESULT_NEED_MEMORY) 01558 goto oom; 01559 01560 _dbus_assert (tree_test_data[i].message_handled); 01561 01562 j = 0; 01563 while (j < n_test_data) 01564 { 01565 if (tree_test_data[j].message_handled) 01566 { 01567 if (tree_test_data[j].handler_fallback) 01568 _dbus_assert (path_contains (tree_test_data[j].path, 01569 path) != STR_DIFFERENT); 01570 else 01571 _dbus_assert (path_contains (tree_test_data[j].path, path) == STR_EQUAL); 01572 } 01573 else 01574 { 01575 if (tree_test_data[j].handler_fallback) 01576 _dbus_assert (path_contains (tree_test_data[j].path, 01577 path) == STR_DIFFERENT); 01578 else 01579 _dbus_assert (path_contains (tree_test_data[j].path, path) != STR_EQUAL); 01580 } 01581 01582 ++j; 01583 } 01584 01585 dbus_message_unref (message); 01586 01587 return TRUE; 01588 01589 oom: 01590 if (message) 01591 dbus_message_unref (message); 01592 return FALSE; 01593 } 01594 01595 static size_t 01596 string_array_length (const char **array) 01597 { 01598 size_t i; 01599 for (i = 0; array[i]; i++) ; 01600 return i; 01601 } 01602 01603 typedef struct 01604 { 01605 const char *path; 01606 const char *result[20]; 01607 } DecomposePathTest; 01608 01609 static DecomposePathTest decompose_tests[] = { 01610 { "/foo", { "foo", NULL } }, 01611 { "/foo/bar", { "foo", "bar", NULL } }, 01612 { "/", { NULL } }, 01613 { "/a/b", { "a", "b", NULL } }, 01614 { "/a/b/c", { "a", "b", "c", NULL } }, 01615 { "/a/b/c/d", { "a", "b", "c", "d", NULL } }, 01616 { "/foo/bar/q", { "foo", "bar", "q", NULL } }, 01617 { "/foo/bar/this/is/longer", { "foo", "bar", "this", "is", "longer", NULL } } 01618 }; 01619 01620 static dbus_bool_t 01621 run_decompose_tests (void) 01622 { 01623 int i; 01624 01625 i = 0; 01626 while (i < _DBUS_N_ELEMENTS (decompose_tests)) 01627 { 01628 char **result; 01629 int result_len; 01630 int expected_len; 01631 01632 if (!_dbus_decompose_path (decompose_tests[i].path, 01633 strlen (decompose_tests[i].path), 01634 &result, &result_len)) 01635 return FALSE; 01636 01637 expected_len = string_array_length (decompose_tests[i].result); 01638 01639 if (result_len != (int) string_array_length ((const char**)result) || 01640 expected_len != result_len || 01641 path_contains (decompose_tests[i].result, 01642 (const char**) result) != STR_EQUAL) 01643 { 01644 int real_len = string_array_length ((const char**)result); 01645 _dbus_warn ("Expected decompose of %s to have len %d, returned %d, appears to have %d\n", 01646 decompose_tests[i].path, expected_len, result_len, 01647 real_len); 01648 _dbus_warn ("Decompose resulted in elements: { "); 01649 i = 0; 01650 while (i < real_len) 01651 { 01652 _dbus_warn ("\"%s\"%s", result[i], 01653 (i + 1) == real_len ? "" : ", "); 01654 ++i; 01655 } 01656 _dbus_warn ("}\n"); 01657 _dbus_assert_not_reached ("path decompose failed\n"); 01658 } 01659 01660 dbus_free_string_array (result); 01661 01662 ++i; 01663 } 01664 01665 return TRUE; 01666 } 01667 01668 static DBusObjectSubtree* 01669 find_subtree_registered_or_unregistered (DBusObjectTree *tree, 01670 const char **path) 01671 { 01672 #if VERBOSE_FIND 01673 _dbus_verbose ("Looking for exact subtree, registered or unregistered\n"); 01674 #endif 01675 01676 return find_subtree_recurse (tree->root, path, FALSE, NULL, NULL); 01677 } 01678 01679 static dbus_bool_t 01680 object_tree_test_iteration (void *data) 01681 { 01682 const char *path0[] = { NULL }; 01683 const char *path1[] = { "foo", NULL }; 01684 const char *path2[] = { "foo", "bar", NULL }; 01685 const char *path3[] = { "foo", "bar", "baz", NULL }; 01686 const char *path4[] = { "foo", "bar", "boo", NULL }; 01687 const char *path5[] = { "blah", NULL }; 01688 const char *path6[] = { "blah", "boof", NULL }; 01689 const char *path7[] = { "blah", "boof", "this", "is", "really", "long", NULL }; 01690 const char *path8[] = { "childless", NULL }; 01691 const char *path9[] = { "blah", "a", NULL }; 01692 const char *path10[] = { "blah", "b", NULL }; 01693 const char *path11[] = { "blah", "c", NULL }; 01694 const char *path12[] = { "blah", "a", "d", NULL }; 01695 const char *path13[] = { "blah", "b", "d", NULL }; 01696 const char *path14[] = { "blah", "c", "d", NULL }; 01697 DBusObjectPathVTable test_vtable = { NULL, test_message_function, NULL }; 01698 DBusObjectTree *tree; 01699 TreeTestData tree_test_data[9]; 01700 int i; 01701 dbus_bool_t exact_match; 01702 01703 if (!run_decompose_tests ()) 01704 return FALSE; 01705 01706 tree = NULL; 01707 01708 tree = _dbus_object_tree_new (NULL); 01709 if (tree == NULL) 01710 goto out; 01711 01712 if (!do_register (tree, path0, TRUE, 0, tree_test_data)) 01713 goto out; 01714 01715 _dbus_assert (find_subtree (tree, path0, NULL)); 01716 _dbus_assert (!find_subtree (tree, path1, NULL)); 01717 _dbus_assert (!find_subtree (tree, path2, NULL)); 01718 _dbus_assert (!find_subtree (tree, path3, NULL)); 01719 _dbus_assert (!find_subtree (tree, path4, NULL)); 01720 _dbus_assert (!find_subtree (tree, path5, NULL)); 01721 _dbus_assert (!find_subtree (tree, path6, NULL)); 01722 _dbus_assert (!find_subtree (tree, path7, NULL)); 01723 _dbus_assert (!find_subtree (tree, path8, NULL)); 01724 01725 _dbus_assert (find_handler (tree, path0, &exact_match) && exact_match); 01726 _dbus_assert (find_handler (tree, path1, &exact_match) == tree->root && !exact_match); 01727 _dbus_assert (find_handler (tree, path2, &exact_match) == tree->root && !exact_match); 01728 _dbus_assert (find_handler (tree, path3, &exact_match) == tree->root && !exact_match); 01729 _dbus_assert (find_handler (tree, path4, &exact_match) == tree->root && !exact_match); 01730 _dbus_assert (find_handler (tree, path5, &exact_match) == tree->root && !exact_match); 01731 _dbus_assert (find_handler (tree, path6, &exact_match) == tree->root && !exact_match); 01732 _dbus_assert (find_handler (tree, path7, &exact_match) == tree->root && !exact_match); 01733 _dbus_assert (find_handler (tree, path8, &exact_match) == tree->root && !exact_match); 01734 01735 if (!do_register (tree, path1, TRUE, 1, tree_test_data)) 01736 goto out; 01737 01738 _dbus_assert (find_subtree (tree, path0, NULL)); 01739 _dbus_assert (find_subtree (tree, path1, NULL)); 01740 _dbus_assert (!find_subtree (tree, path2, NULL)); 01741 _dbus_assert (!find_subtree (tree, path3, NULL)); 01742 _dbus_assert (!find_subtree (tree, path4, NULL)); 01743 _dbus_assert (!find_subtree (tree, path5, NULL)); 01744 _dbus_assert (!find_subtree (tree, path6, NULL)); 01745 _dbus_assert (!find_subtree (tree, path7, NULL)); 01746 _dbus_assert (!find_subtree (tree, path8, NULL)); 01747 01748 _dbus_assert (find_handler (tree, path0, &exact_match) && exact_match); 01749 _dbus_assert (find_handler (tree, path1, &exact_match) && exact_match); 01750 _dbus_assert (find_handler (tree, path2, &exact_match) && !exact_match); 01751 _dbus_assert (find_handler (tree, path3, &exact_match) && !exact_match); 01752 _dbus_assert (find_handler (tree, path4, &exact_match) && !exact_match); 01753 _dbus_assert (find_handler (tree, path5, &exact_match) == tree->root && !exact_match); 01754 _dbus_assert (find_handler (tree, path6, &exact_match) == tree->root && !exact_match); 01755 _dbus_assert (find_handler (tree, path7, &exact_match) == tree->root && !exact_match); 01756 _dbus_assert (find_handler (tree, path8, &exact_match) == tree->root && !exact_match); 01757 01758 if (!do_register (tree, path2, TRUE, 2, tree_test_data)) 01759 goto out; 01760 01761 _dbus_assert (find_subtree (tree, path1, NULL)); 01762 _dbus_assert (find_subtree (tree, path2, NULL)); 01763 _dbus_assert (!find_subtree (tree, path3, NULL)); 01764 _dbus_assert (!find_subtree (tree, path4, NULL)); 01765 _dbus_assert (!find_subtree (tree, path5, NULL)); 01766 _dbus_assert (!find_subtree (tree, path6, NULL)); 01767 _dbus_assert (!find_subtree (tree, path7, NULL)); 01768 _dbus_assert (!find_subtree (tree, path8, NULL)); 01769 01770 if (!do_register (tree, path3, TRUE, 3, tree_test_data)) 01771 goto out; 01772 01773 _dbus_assert (find_subtree (tree, path0, NULL)); 01774 _dbus_assert (find_subtree (tree, path1, NULL)); 01775 _dbus_assert (find_subtree (tree, path2, NULL)); 01776 _dbus_assert (find_subtree (tree, path3, NULL)); 01777 _dbus_assert (!find_subtree (tree, path4, NULL)); 01778 _dbus_assert (!find_subtree (tree, path5, NULL)); 01779 _dbus_assert (!find_subtree (tree, path6, NULL)); 01780 _dbus_assert (!find_subtree (tree, path7, NULL)); 01781 _dbus_assert (!find_subtree (tree, path8, NULL)); 01782 01783 if (!do_register (tree, path4, TRUE, 4, tree_test_data)) 01784 goto out; 01785 01786 _dbus_assert (find_subtree (tree, path0, NULL)); 01787 _dbus_assert (find_subtree (tree, path1, NULL)); 01788 _dbus_assert (find_subtree (tree, path2, NULL)); 01789 _dbus_assert (find_subtree (tree, path3, NULL)); 01790 _dbus_assert (find_subtree (tree, path4, NULL)); 01791 _dbus_assert (!find_subtree (tree, path5, NULL)); 01792 _dbus_assert (!find_subtree (tree, path6, NULL)); 01793 _dbus_assert (!find_subtree (tree, path7, NULL)); 01794 _dbus_assert (!find_subtree (tree, path8, NULL)); 01795 01796 if (!do_register (tree, path5, TRUE, 5, tree_test_data)) 01797 goto out; 01798 01799 _dbus_assert (find_subtree (tree, path0, NULL)); 01800 _dbus_assert (find_subtree (tree, path1, NULL)); 01801 _dbus_assert (find_subtree (tree, path2, NULL)); 01802 _dbus_assert (find_subtree (tree, path3, NULL)); 01803 _dbus_assert (find_subtree (tree, path4, NULL)); 01804 _dbus_assert (find_subtree (tree, path5, NULL)); 01805 _dbus_assert (!find_subtree (tree, path6, NULL)); 01806 _dbus_assert (!find_subtree (tree, path7, NULL)); 01807 _dbus_assert (!find_subtree (tree, path8, NULL)); 01808 01809 _dbus_assert (find_handler (tree, path0, &exact_match) == tree->root && exact_match); 01810 _dbus_assert (find_handler (tree, path1, &exact_match) != tree->root && exact_match); 01811 _dbus_assert (find_handler (tree, path2, &exact_match) != tree->root && exact_match); 01812 _dbus_assert (find_handler (tree, path3, &exact_match) != tree->root && exact_match); 01813 _dbus_assert (find_handler (tree, path4, &exact_match) != tree->root && exact_match); 01814 _dbus_assert (find_handler (tree, path5, &exact_match) != tree->root && exact_match); 01815 _dbus_assert (find_handler (tree, path6, &exact_match) != tree->root && !exact_match); 01816 _dbus_assert (find_handler (tree, path7, &exact_match) != tree->root && !exact_match); 01817 _dbus_assert (find_handler (tree, path8, &exact_match) == tree->root && !exact_match); 01818 01819 if (!do_register (tree, path6, TRUE, 6, tree_test_data)) 01820 goto out; 01821 01822 _dbus_assert (find_subtree (tree, path0, NULL)); 01823 _dbus_assert (find_subtree (tree, path1, NULL)); 01824 _dbus_assert (find_subtree (tree, path2, NULL)); 01825 _dbus_assert (find_subtree (tree, path3, NULL)); 01826 _dbus_assert (find_subtree (tree, path4, NULL)); 01827 _dbus_assert (find_subtree (tree, path5, NULL)); 01828 _dbus_assert (find_subtree (tree, path6, NULL)); 01829 _dbus_assert (!find_subtree (tree, path7, NULL)); 01830 _dbus_assert (!find_subtree (tree, path8, NULL)); 01831 01832 if (!do_register (tree, path7, TRUE, 7, tree_test_data)) 01833 goto out; 01834 01835 _dbus_assert (find_subtree (tree, path0, NULL)); 01836 _dbus_assert (find_subtree (tree, path1, NULL)); 01837 _dbus_assert (find_subtree (tree, path2, NULL)); 01838 _dbus_assert (find_subtree (tree, path3, NULL)); 01839 _dbus_assert (find_subtree (tree, path4, NULL)); 01840 _dbus_assert (find_subtree (tree, path5, NULL)); 01841 _dbus_assert (find_subtree (tree, path6, NULL)); 01842 _dbus_assert (find_subtree (tree, path7, NULL)); 01843 _dbus_assert (!find_subtree (tree, path8, NULL)); 01844 01845 if (!do_register (tree, path8, TRUE, 8, tree_test_data)) 01846 goto out; 01847 01848 _dbus_assert (find_subtree (tree, path0, NULL)); 01849 _dbus_assert (find_subtree (tree, path1, NULL)); 01850 _dbus_assert (find_subtree (tree, path2, NULL)); 01851 _dbus_assert (find_subtree (tree, path3, NULL)); 01852 _dbus_assert (find_subtree (tree, path4, NULL)); 01853 _dbus_assert (find_subtree (tree, path5, NULL)); 01854 _dbus_assert (find_subtree (tree, path6, NULL)); 01855 _dbus_assert (find_subtree (tree, path7, NULL)); 01856 _dbus_assert (find_subtree (tree, path8, NULL)); 01857 01858 _dbus_assert (find_handler (tree, path0, &exact_match) == tree->root && exact_match); 01859 _dbus_assert (find_handler (tree, path1, &exact_match) != tree->root && exact_match); 01860 _dbus_assert (find_handler (tree, path2, &exact_match) != tree->root && exact_match); 01861 _dbus_assert (find_handler (tree, path3, &exact_match) != tree->root && exact_match); 01862 _dbus_assert (find_handler (tree, path4, &exact_match) != tree->root && exact_match); 01863 _dbus_assert (find_handler (tree, path5, &exact_match) != tree->root && exact_match); 01864 _dbus_assert (find_handler (tree, path6, &exact_match) != tree->root && exact_match); 01865 _dbus_assert (find_handler (tree, path7, &exact_match) != tree->root && exact_match); 01866 _dbus_assert (find_handler (tree, path8, &exact_match) != tree->root && exact_match); 01867 01868 /* test the list_registered function */ 01869 01870 { 01871 const char *root[] = { NULL }; 01872 char **child_entries; 01873 int nb; 01874 01875 _dbus_object_tree_list_registered_unlocked (tree, path1, &child_entries); 01876 if (child_entries != NULL) 01877 { 01878 nb = string_array_length ((const char**)child_entries); 01879 _dbus_assert (nb == 1); 01880 dbus_free_string_array (child_entries); 01881 } 01882 01883 _dbus_object_tree_list_registered_unlocked (tree, path2, &child_entries); 01884 if (child_entries != NULL) 01885 { 01886 nb = string_array_length ((const char**)child_entries); 01887 _dbus_assert (nb == 2); 01888 dbus_free_string_array (child_entries); 01889 } 01890 01891 _dbus_object_tree_list_registered_unlocked (tree, path8, &child_entries); 01892 if (child_entries != NULL) 01893 { 01894 nb = string_array_length ((const char**)child_entries); 01895 _dbus_assert (nb == 0); 01896 dbus_free_string_array (child_entries); 01897 } 01898 01899 _dbus_object_tree_list_registered_unlocked (tree, root, &child_entries); 01900 if (child_entries != NULL) 01901 { 01902 nb = string_array_length ((const char**)child_entries); 01903 _dbus_assert (nb == 3); 01904 dbus_free_string_array (child_entries); 01905 } 01906 } 01907 01908 /* Check that destroying tree calls unregister funcs */ 01909 _dbus_object_tree_unref (tree); 01910 01911 i = 0; 01912 while (i < (int) _DBUS_N_ELEMENTS (tree_test_data)) 01913 { 01914 _dbus_assert (tree_test_data[i].handler_unregistered); 01915 _dbus_assert (!tree_test_data[i].message_handled); 01916 ++i; 01917 } 01918 01919 /* Now start again and try the individual unregister function */ 01920 tree = _dbus_object_tree_new (NULL); 01921 if (tree == NULL) 01922 goto out; 01923 01924 if (!do_register (tree, path0, TRUE, 0, tree_test_data)) 01925 goto out; 01926 if (!do_register (tree, path1, TRUE, 1, tree_test_data)) 01927 goto out; 01928 if (!do_register (tree, path2, TRUE, 2, tree_test_data)) 01929 goto out; 01930 if (!do_register (tree, path3, TRUE, 3, tree_test_data)) 01931 goto out; 01932 if (!do_register (tree, path4, TRUE, 4, tree_test_data)) 01933 goto out; 01934 if (!do_register (tree, path5, TRUE, 5, tree_test_data)) 01935 goto out; 01936 if (!do_register (tree, path6, TRUE, 6, tree_test_data)) 01937 goto out; 01938 if (!do_register (tree, path7, TRUE, 7, tree_test_data)) 01939 goto out; 01940 if (!do_register (tree, path8, TRUE, 8, tree_test_data)) 01941 goto out; 01942 01943 _dbus_object_tree_unregister_and_unlock (tree, path0); 01944 _dbus_assert (_dbus_object_tree_get_user_data_unlocked (tree, path0) == NULL); 01945 01946 _dbus_assert (!find_subtree (tree, path0, NULL)); 01947 _dbus_assert (find_subtree (tree, path1, NULL)); 01948 _dbus_assert (find_subtree (tree, path2, NULL)); 01949 _dbus_assert (find_subtree (tree, path3, NULL)); 01950 _dbus_assert (find_subtree (tree, path4, NULL)); 01951 _dbus_assert (find_subtree (tree, path5, NULL)); 01952 _dbus_assert (find_subtree (tree, path6, NULL)); 01953 _dbus_assert (find_subtree (tree, path7, NULL)); 01954 _dbus_assert (find_subtree (tree, path8, NULL)); 01955 01956 _dbus_object_tree_unregister_and_unlock (tree, path1); 01957 _dbus_assert (_dbus_object_tree_get_user_data_unlocked (tree, path1) == NULL); 01958 01959 _dbus_assert (!find_subtree (tree, path0, NULL)); 01960 _dbus_assert (!find_subtree (tree, path1, NULL)); 01961 _dbus_assert (find_subtree (tree, path2, NULL)); 01962 _dbus_assert (find_subtree (tree, path3, NULL)); 01963 _dbus_assert (find_subtree (tree, path4, NULL)); 01964 _dbus_assert (find_subtree (tree, path5, NULL)); 01965 _dbus_assert (find_subtree (tree, path6, NULL)); 01966 _dbus_assert (find_subtree (tree, path7, NULL)); 01967 _dbus_assert (find_subtree (tree, path8, NULL)); 01968 01969 _dbus_object_tree_unregister_and_unlock (tree, path2); 01970 _dbus_assert (_dbus_object_tree_get_user_data_unlocked (tree, path2) == NULL); 01971 01972 _dbus_assert (!find_subtree (tree, path0, NULL)); 01973 _dbus_assert (!find_subtree (tree, path1, NULL)); 01974 _dbus_assert (!find_subtree (tree, path2, NULL)); 01975 _dbus_assert (find_subtree (tree, path3, NULL)); 01976 _dbus_assert (find_subtree (tree, path4, NULL)); 01977 _dbus_assert (find_subtree (tree, path5, NULL)); 01978 _dbus_assert (find_subtree (tree, path6, NULL)); 01979 _dbus_assert (find_subtree (tree, path7, NULL)); 01980 _dbus_assert (find_subtree (tree, path8, NULL)); 01981 01982 _dbus_object_tree_unregister_and_unlock (tree, path3); 01983 _dbus_assert (_dbus_object_tree_get_user_data_unlocked (tree, path3) == NULL); 01984 01985 _dbus_assert (!find_subtree (tree, path0, NULL)); 01986 _dbus_assert (!find_subtree (tree, path1, NULL)); 01987 _dbus_assert (!find_subtree (tree, path2, NULL)); 01988 _dbus_assert (!find_subtree (tree, path3, NULL)); 01989 _dbus_assert (find_subtree (tree, path4, NULL)); 01990 _dbus_assert (find_subtree (tree, path5, NULL)); 01991 _dbus_assert (find_subtree (tree, path6, NULL)); 01992 _dbus_assert (find_subtree (tree, path7, NULL)); 01993 _dbus_assert (find_subtree (tree, path8, NULL)); 01994 01995 _dbus_object_tree_unregister_and_unlock (tree, path4); 01996 _dbus_assert (_dbus_object_tree_get_user_data_unlocked (tree, path4) == NULL); 01997 01998 _dbus_assert (!find_subtree (tree, path0, NULL)); 01999 _dbus_assert (!find_subtree (tree, path1, NULL)); 02000 _dbus_assert (!find_subtree (tree, path2, NULL)); 02001 _dbus_assert (!find_subtree (tree, path3, NULL)); 02002 _dbus_assert (!find_subtree (tree, path4, NULL)); 02003 _dbus_assert (find_subtree (tree, path5, NULL)); 02004 _dbus_assert (find_subtree (tree, path6, NULL)); 02005 _dbus_assert (find_subtree (tree, path7, NULL)); 02006 _dbus_assert (find_subtree (tree, path8, NULL)); 02007 02008 _dbus_object_tree_unregister_and_unlock (tree, path5); 02009 _dbus_assert (_dbus_object_tree_get_user_data_unlocked (tree, path5) == NULL); 02010 02011 _dbus_assert (!find_subtree (tree, path0, NULL)); 02012 _dbus_assert (!find_subtree (tree, path1, NULL)); 02013 _dbus_assert (!find_subtree (tree, path2, NULL)); 02014 _dbus_assert (!find_subtree (tree, path3, NULL)); 02015 _dbus_assert (!find_subtree (tree, path4, NULL)); 02016 _dbus_assert (!find_subtree (tree, path5, NULL)); 02017 _dbus_assert (find_subtree (tree, path6, NULL)); 02018 _dbus_assert (find_subtree (tree, path7, NULL)); 02019 _dbus_assert (find_subtree (tree, path8, NULL)); 02020 02021 _dbus_object_tree_unregister_and_unlock (tree, path6); 02022 _dbus_assert (_dbus_object_tree_get_user_data_unlocked (tree, path6) == NULL); 02023 02024 _dbus_assert (!find_subtree (tree, path0, NULL)); 02025 _dbus_assert (!find_subtree (tree, path1, NULL)); 02026 _dbus_assert (!find_subtree (tree, path2, NULL)); 02027 _dbus_assert (!find_subtree (tree, path3, NULL)); 02028 _dbus_assert (!find_subtree (tree, path4, NULL)); 02029 _dbus_assert (!find_subtree (tree, path5, NULL)); 02030 _dbus_assert (!find_subtree (tree, path6, NULL)); 02031 _dbus_assert (find_subtree (tree, path7, NULL)); 02032 _dbus_assert (find_subtree (tree, path8, NULL)); 02033 02034 _dbus_object_tree_unregister_and_unlock (tree, path7); 02035 _dbus_assert (_dbus_object_tree_get_user_data_unlocked (tree, path7) == NULL); 02036 02037 _dbus_assert (!find_subtree (tree, path0, NULL)); 02038 _dbus_assert (!find_subtree (tree, path1, NULL)); 02039 _dbus_assert (!find_subtree (tree, path2, NULL)); 02040 _dbus_assert (!find_subtree (tree, path3, NULL)); 02041 _dbus_assert (!find_subtree (tree, path4, NULL)); 02042 _dbus_assert (!find_subtree (tree, path5, NULL)); 02043 _dbus_assert (!find_subtree (tree, path6, NULL)); 02044 _dbus_assert (!find_subtree (tree, path7, NULL)); 02045 _dbus_assert (find_subtree (tree, path8, NULL)); 02046 02047 _dbus_object_tree_unregister_and_unlock (tree, path8); 02048 _dbus_assert (_dbus_object_tree_get_user_data_unlocked (tree, path8) == NULL); 02049 02050 _dbus_assert (!find_subtree (tree, path0, NULL)); 02051 _dbus_assert (!find_subtree (tree, path1, NULL)); 02052 _dbus_assert (!find_subtree (tree, path2, NULL)); 02053 _dbus_assert (!find_subtree (tree, path3, NULL)); 02054 _dbus_assert (!find_subtree (tree, path4, NULL)); 02055 _dbus_assert (!find_subtree (tree, path5, NULL)); 02056 _dbus_assert (!find_subtree (tree, path6, NULL)); 02057 _dbus_assert (!find_subtree (tree, path7, NULL)); 02058 _dbus_assert (!find_subtree (tree, path8, NULL)); 02059 02060 i = 0; 02061 while (i < (int) _DBUS_N_ELEMENTS (tree_test_data)) 02062 { 02063 _dbus_assert (tree_test_data[i].handler_unregistered); 02064 _dbus_assert (!tree_test_data[i].message_handled); 02065 ++i; 02066 } 02067 02068 /* Test removal of newly-childless unregistered nodes */ 02069 if (!do_register (tree, path2, TRUE, 2, tree_test_data)) 02070 goto out; 02071 02072 _dbus_object_tree_unregister_and_unlock (tree, path2); 02073 _dbus_assert (!find_subtree_registered_or_unregistered (tree, path2)); 02074 _dbus_assert (!find_subtree_registered_or_unregistered (tree, path1)); 02075 _dbus_assert (find_subtree_registered_or_unregistered (tree, path0)); 02076 02077 /* Test that unregistered parents cannot be freed out from under their 02078 children */ 02079 if (!do_register (tree, path2, TRUE, 2, tree_test_data)) 02080 goto out; 02081 02082 _dbus_assert (!find_subtree (tree, path1, NULL)); 02083 _dbus_assert (find_subtree_registered_or_unregistered (tree, path1)); 02084 _dbus_assert (find_subtree_registered_or_unregistered (tree, path0)); 02085 02086 #if 0 02087 /* This triggers the "Attempted to unregister path ..." warning message */ 02088 _dbus_object_tree_unregister_and_unlock (tree, path1); 02089 #endif 02090 _dbus_assert (find_subtree (tree, path2, NULL)); 02091 _dbus_assert (!find_subtree (tree, path1, NULL)); 02092 _dbus_assert (find_subtree_registered_or_unregistered (tree, path1)); 02093 _dbus_assert (find_subtree_registered_or_unregistered (tree, path0)); 02094 02095 _dbus_object_tree_unregister_and_unlock (tree, path2); 02096 _dbus_assert (!find_subtree (tree, path2, NULL)); 02097 _dbus_assert (!find_subtree_registered_or_unregistered (tree, path2)); 02098 _dbus_assert (!find_subtree_registered_or_unregistered (tree, path1)); 02099 _dbus_assert (find_subtree_registered_or_unregistered (tree, path0)); 02100 02101 /* Test that registered parents cannot be freed out from under their 02102 children, and that if they are unregistered before their children, they 02103 are still freed when their children are unregistered */ 02104 if (!do_register (tree, path1, TRUE, 1, tree_test_data)) 02105 goto out; 02106 if (!do_register (tree, path2, TRUE, 2, tree_test_data)) 02107 goto out; 02108 02109 _dbus_assert (find_subtree (tree, path1, NULL)); 02110 _dbus_assert (find_subtree (tree, path2, NULL)); 02111 02112 _dbus_object_tree_unregister_and_unlock (tree, path1); 02113 _dbus_assert (!find_subtree (tree, path1, NULL)); 02114 _dbus_assert (find_subtree (tree, path2, NULL)); 02115 _dbus_assert (find_subtree_registered_or_unregistered (tree, path1)); 02116 _dbus_assert (find_subtree_registered_or_unregistered (tree, path0)); 02117 02118 _dbus_object_tree_unregister_and_unlock (tree, path2); 02119 _dbus_assert (!find_subtree (tree, path1, NULL)); 02120 _dbus_assert (!find_subtree_registered_or_unregistered (tree, path1)); 02121 _dbus_assert (!find_subtree (tree, path2, NULL)); 02122 _dbus_assert (!find_subtree_registered_or_unregistered (tree, path2)); 02123 _dbus_assert (find_subtree_registered_or_unregistered (tree, path0)); 02124 02125 /* Test with NULL unregister_function and user_data */ 02126 if (!_dbus_object_tree_register (tree, TRUE, path2, 02127 &test_vtable, 02128 NULL, 02129 NULL)) 02130 goto out; 02131 02132 _dbus_assert (_dbus_object_tree_get_user_data_unlocked (tree, path2) == NULL); 02133 _dbus_object_tree_unregister_and_unlock (tree, path2); 02134 _dbus_assert (!find_subtree (tree, path2, NULL)); 02135 _dbus_assert (!find_subtree_registered_or_unregistered (tree, path2)); 02136 _dbus_assert (!find_subtree_registered_or_unregistered (tree, path1)); 02137 _dbus_assert (find_subtree_registered_or_unregistered (tree, path0)); 02138 02139 /* Test freeing a long path */ 02140 if (!do_register (tree, path3, TRUE, 3, tree_test_data)) 02141 goto out; 02142 02143 _dbus_object_tree_unregister_and_unlock (tree, path3); 02144 _dbus_assert (!find_subtree (tree, path3, NULL)); 02145 _dbus_assert (!find_subtree_registered_or_unregistered (tree, path3)); 02146 _dbus_assert (!find_subtree_registered_or_unregistered (tree, path2)); 02147 _dbus_assert (!find_subtree_registered_or_unregistered (tree, path1)); 02148 _dbus_assert (find_subtree_registered_or_unregistered (tree, path0)); 02149 02150 /* Test freeing multiple children from the same path */ 02151 if (!do_register (tree, path3, TRUE, 3, tree_test_data)) 02152 goto out; 02153 if (!do_register (tree, path4, TRUE, 4, tree_test_data)) 02154 goto out; 02155 02156 _dbus_assert (find_subtree (tree, path3, NULL)); 02157 _dbus_assert (find_subtree (tree, path4, NULL)); 02158 02159 _dbus_object_tree_unregister_and_unlock (tree, path3); 02160 _dbus_assert (!find_subtree (tree, path3, NULL)); 02161 _dbus_assert (!find_subtree_registered_or_unregistered (tree, path3)); 02162 _dbus_assert (find_subtree (tree, path4, NULL)); 02163 _dbus_assert (find_subtree_registered_or_unregistered (tree, path4)); 02164 _dbus_assert (find_subtree_registered_or_unregistered (tree, path2)); 02165 _dbus_assert (find_subtree_registered_or_unregistered (tree, path1)); 02166 02167 _dbus_object_tree_unregister_and_unlock (tree, path4); 02168 _dbus_assert (!find_subtree (tree, path4, NULL)); 02169 _dbus_assert (!find_subtree_registered_or_unregistered (tree, path4)); 02170 _dbus_assert (!find_subtree (tree, path3, NULL)); 02171 _dbus_assert (!find_subtree_registered_or_unregistered (tree, path3)); 02172 _dbus_assert (!find_subtree_registered_or_unregistered (tree, path2)); 02173 _dbus_assert (!find_subtree_registered_or_unregistered (tree, path1)); 02174 02175 /* Test subtree removal */ 02176 if (!_dbus_object_tree_register (tree, TRUE, path12, 02177 &test_vtable, 02178 NULL, 02179 NULL)) 02180 goto out; 02181 02182 _dbus_assert (find_subtree (tree, path12, NULL)); 02183 02184 if (!_dbus_object_tree_register (tree, TRUE, path13, 02185 &test_vtable, 02186 NULL, 02187 NULL)) 02188 goto out; 02189 02190 _dbus_assert (find_subtree (tree, path13, NULL)); 02191 02192 if (!_dbus_object_tree_register (tree, TRUE, path14, 02193 &test_vtable, 02194 NULL, 02195 NULL)) 02196 goto out; 02197 02198 _dbus_assert (find_subtree (tree, path14, NULL)); 02199 02200 _dbus_object_tree_unregister_and_unlock (tree, path12); 02201 02202 _dbus_assert (!find_subtree_registered_or_unregistered (tree, path12)); 02203 _dbus_assert (find_subtree (tree, path13, NULL)); 02204 _dbus_assert (find_subtree (tree, path14, NULL)); 02205 _dbus_assert (!find_subtree_registered_or_unregistered (tree, path9)); 02206 _dbus_assert (find_subtree_registered_or_unregistered (tree, path5)); 02207 02208 if (!_dbus_object_tree_register (tree, TRUE, path12, 02209 &test_vtable, 02210 NULL, 02211 NULL)) 02212 goto out; 02213 02214 _dbus_assert (find_subtree (tree, path12, NULL)); 02215 02216 _dbus_object_tree_unregister_and_unlock (tree, path13); 02217 02218 _dbus_assert (find_subtree (tree, path12, NULL)); 02219 _dbus_assert (!find_subtree_registered_or_unregistered (tree, path13)); 02220 _dbus_assert (find_subtree (tree, path14, NULL)); 02221 _dbus_assert (!find_subtree_registered_or_unregistered (tree, path10)); 02222 _dbus_assert (find_subtree_registered_or_unregistered (tree, path5)); 02223 02224 if (!_dbus_object_tree_register (tree, TRUE, path13, 02225 &test_vtable, 02226 NULL, 02227 NULL)) 02228 goto out; 02229 02230 _dbus_assert (find_subtree (tree, path13, NULL)); 02231 02232 _dbus_object_tree_unregister_and_unlock (tree, path14); 02233 02234 _dbus_assert (find_subtree (tree, path12, NULL)); 02235 _dbus_assert (find_subtree (tree, path13, NULL)); 02236 _dbus_assert (!find_subtree_registered_or_unregistered (tree, path14)); 02237 _dbus_assert (!find_subtree_registered_or_unregistered (tree, path11)); 02238 _dbus_assert (find_subtree_registered_or_unregistered (tree, path5)); 02239 02240 _dbus_object_tree_unregister_and_unlock (tree, path12); 02241 02242 _dbus_assert (!find_subtree_registered_or_unregistered (tree, path12)); 02243 _dbus_assert (!find_subtree_registered_or_unregistered (tree, path9)); 02244 _dbus_assert (find_subtree_registered_or_unregistered (tree, path5)); 02245 02246 _dbus_object_tree_unregister_and_unlock (tree, path13); 02247 02248 _dbus_assert (!find_subtree_registered_or_unregistered (tree, path13)); 02249 _dbus_assert (!find_subtree_registered_or_unregistered (tree, path10)); 02250 _dbus_assert (!find_subtree_registered_or_unregistered (tree, path5)); 02251 02252 #if 0 02253 /* Test attempting to unregister non-existent paths. These trigger 02254 "Attempted to unregister path ..." warning messages */ 02255 _dbus_object_tree_unregister_and_unlock (tree, path0); 02256 _dbus_object_tree_unregister_and_unlock (tree, path1); 02257 _dbus_object_tree_unregister_and_unlock (tree, path2); 02258 _dbus_object_tree_unregister_and_unlock (tree, path3); 02259 _dbus_object_tree_unregister_and_unlock (tree, path4); 02260 #endif 02261 02262 /* Register it all again, and test dispatch */ 02263 02264 if (!do_register (tree, path0, TRUE, 0, tree_test_data)) 02265 goto out; 02266 if (!do_register (tree, path1, FALSE, 1, tree_test_data)) 02267 goto out; 02268 if (!do_register (tree, path2, TRUE, 2, tree_test_data)) 02269 goto out; 02270 if (!do_register (tree, path3, TRUE, 3, tree_test_data)) 02271 goto out; 02272 if (!do_register (tree, path4, TRUE, 4, tree_test_data)) 02273 goto out; 02274 if (!do_register (tree, path5, TRUE, 5, tree_test_data)) 02275 goto out; 02276 if (!do_register (tree, path6, FALSE, 6, tree_test_data)) 02277 goto out; 02278 if (!do_register (tree, path7, TRUE, 7, tree_test_data)) 02279 goto out; 02280 if (!do_register (tree, path8, TRUE, 8, tree_test_data)) 02281 goto out; 02282 02283 #if 0 02284 spew_tree (tree); 02285 #endif 02286 02287 if (!do_test_dispatch (tree, path0, 0, tree_test_data, _DBUS_N_ELEMENTS (tree_test_data))) 02288 goto out; 02289 if (!do_test_dispatch (tree, path1, 1, tree_test_data, _DBUS_N_ELEMENTS (tree_test_data))) 02290 goto out; 02291 if (!do_test_dispatch (tree, path2, 2, tree_test_data, _DBUS_N_ELEMENTS (tree_test_data))) 02292 goto out; 02293 if (!do_test_dispatch (tree, path3, 3, tree_test_data, _DBUS_N_ELEMENTS (tree_test_data))) 02294 goto out; 02295 if (!do_test_dispatch (tree, path4, 4, tree_test_data, _DBUS_N_ELEMENTS (tree_test_data))) 02296 goto out; 02297 if (!do_test_dispatch (tree, path5, 5, tree_test_data, _DBUS_N_ELEMENTS (tree_test_data))) 02298 goto out; 02299 if (!do_test_dispatch (tree, path6, 6, tree_test_data, _DBUS_N_ELEMENTS (tree_test_data))) 02300 goto out; 02301 if (!do_test_dispatch (tree, path7, 7, tree_test_data, _DBUS_N_ELEMENTS (tree_test_data))) 02302 goto out; 02303 if (!do_test_dispatch (tree, path8, 8, tree_test_data, _DBUS_N_ELEMENTS (tree_test_data))) 02304 goto out; 02305 02306 out: 02307 if (tree) 02308 { 02309 /* test ref */ 02310 _dbus_object_tree_ref (tree); 02311 _dbus_object_tree_unref (tree); 02312 _dbus_object_tree_unref (tree); 02313 } 02314 02315 return TRUE; 02316 } 02317 02323 dbus_bool_t 02324 _dbus_object_tree_test (void) 02325 { 02326 _dbus_test_oom_handling ("object tree", 02327 object_tree_test_iteration, 02328 NULL); 02329 02330 return TRUE; 02331 } 02332 02333 #endif /* !DOXYGEN_SHOULD_SKIP_THIS */ 02334 02335 #endif /* DBUS_ENABLE_EMBEDDED_TESTS */