D-Bus 1.2.24
|
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 #include "dbus-object-tree.h" 00024 #include "dbus-connection-internal.h" 00025 #include "dbus-internals.h" 00026 #include "dbus-hash.h" 00027 #include "dbus-protocol.h" 00028 #include "dbus-string.h" 00029 #include <string.h> 00030 #include <stdlib.h> 00031 00044 typedef struct DBusObjectSubtree DBusObjectSubtree; 00045 00046 static DBusObjectSubtree* _dbus_object_subtree_new (const char *name, 00047 const DBusObjectPathVTable *vtable, 00048 void *user_data); 00049 static DBusObjectSubtree* _dbus_object_subtree_ref (DBusObjectSubtree *subtree); 00050 static void _dbus_object_subtree_unref (DBusObjectSubtree *subtree); 00051 00055 struct DBusObjectTree 00056 { 00057 int refcount; 00058 DBusConnection *connection; 00060 DBusObjectSubtree *root; 00061 }; 00062 00068 struct DBusObjectSubtree 00069 { 00070 DBusAtomic refcount; 00071 DBusObjectSubtree *parent; 00072 DBusObjectPathUnregisterFunction unregister_function; 00073 DBusObjectPathMessageFunction message_function; 00074 void *user_data; 00075 DBusObjectSubtree **subtrees; 00076 int n_subtrees; 00077 int max_subtrees; 00078 unsigned int invoke_as_fallback : 1; 00079 char name[1]; 00080 }; 00081 00089 DBusObjectTree* 00090 _dbus_object_tree_new (DBusConnection *connection) 00091 { 00092 DBusObjectTree *tree; 00093 00094 /* the connection passed in here isn't fully constructed, 00095 * so don't do anything more than store a pointer to 00096 * it 00097 */ 00098 00099 tree = dbus_new0 (DBusObjectTree, 1); 00100 if (tree == NULL) 00101 goto oom; 00102 00103 tree->refcount = 1; 00104 tree->connection = connection; 00105 tree->root = _dbus_object_subtree_new ("/", NULL, NULL); 00106 if (tree->root == NULL) 00107 goto oom; 00108 tree->root->invoke_as_fallback = TRUE; 00109 00110 return tree; 00111 00112 oom: 00113 if (tree) 00114 { 00115 dbus_free (tree); 00116 } 00117 00118 return NULL; 00119 } 00120 00126 DBusObjectTree * 00127 _dbus_object_tree_ref (DBusObjectTree *tree) 00128 { 00129 _dbus_assert (tree->refcount > 0); 00130 00131 tree->refcount += 1; 00132 00133 return tree; 00134 } 00135 00140 void 00141 _dbus_object_tree_unref (DBusObjectTree *tree) 00142 { 00143 _dbus_assert (tree->refcount > 0); 00144 00145 tree->refcount -= 1; 00146 00147 if (tree->refcount == 0) 00148 { 00149 _dbus_object_tree_free_all_unlocked (tree); 00150 00151 dbus_free (tree); 00152 } 00153 } 00154 00158 #define VERBOSE_FIND 0 00159 00160 static DBusObjectSubtree* 00161 find_subtree_recurse (DBusObjectSubtree *subtree, 00162 const char **path, 00163 dbus_bool_t create_if_not_found, 00164 int *index_in_parent, 00165 dbus_bool_t *exact_match) 00166 { 00167 int i, j; 00168 dbus_bool_t return_deepest_match; 00169 00170 return_deepest_match = exact_match != NULL; 00171 00172 _dbus_assert (!(return_deepest_match && create_if_not_found)); 00173 00174 if (path[0] == NULL) 00175 { 00176 #if VERBOSE_FIND 00177 _dbus_verbose (" path exhausted, returning %s\n", 00178 subtree->name); 00179 #endif 00180 if (exact_match != NULL) 00181 *exact_match = TRUE; 00182 return subtree; 00183 } 00184 00185 #if VERBOSE_FIND 00186 _dbus_verbose (" searching children of %s for %s\n", 00187 subtree->name, path[0]); 00188 #endif 00189 00190 i = 0; 00191 j = subtree->n_subtrees; 00192 while (i < j) 00193 { 00194 int k, v; 00195 00196 k = (i + j) / 2; 00197 v = strcmp (path[0], subtree->subtrees[k]->name); 00198 00199 #if VERBOSE_FIND 00200 _dbus_verbose (" %s cmp %s = %d\n", 00201 path[0], subtree->subtrees[k]->name, 00202 v); 00203 #endif 00204 00205 if (v == 0) 00206 { 00207 if (index_in_parent) 00208 { 00209 #if VERBOSE_FIND 00210 _dbus_verbose (" storing parent index %d\n", k); 00211 #endif 00212 *index_in_parent = k; 00213 } 00214 00215 if (return_deepest_match) 00216 { 00217 DBusObjectSubtree *next; 00218 00219 next = find_subtree_recurse (subtree->subtrees[k], 00220 &path[1], create_if_not_found, 00221 index_in_parent, exact_match); 00222 if (next == NULL && 00223 subtree->invoke_as_fallback) 00224 { 00225 #if VERBOSE_FIND 00226 _dbus_verbose (" no deeper match found, returning %s\n", 00227 subtree->name); 00228 #endif 00229 if (exact_match != NULL) 00230 *exact_match = FALSE; 00231 return subtree; 00232 } 00233 else 00234 return next; 00235 } 00236 else 00237 return find_subtree_recurse (subtree->subtrees[k], 00238 &path[1], create_if_not_found, 00239 index_in_parent, exact_match); 00240 } 00241 else if (v < 0) 00242 { 00243 j = k; 00244 } 00245 else 00246 { 00247 i = k + 1; 00248 } 00249 } 00250 00251 #if VERBOSE_FIND 00252 _dbus_verbose (" no match found, current tree %s, create_if_not_found = %d\n", 00253 subtree->name, create_if_not_found); 00254 #endif 00255 00256 if (create_if_not_found) 00257 { 00258 DBusObjectSubtree* child; 00259 int child_pos, new_n_subtrees; 00260 00261 #if VERBOSE_FIND 00262 _dbus_verbose (" creating subtree %s\n", 00263 path[0]); 00264 #endif 00265 00266 child = _dbus_object_subtree_new (path[0], 00267 NULL, NULL); 00268 if (child == NULL) 00269 return NULL; 00270 00271 new_n_subtrees = subtree->n_subtrees + 1; 00272 if (new_n_subtrees > subtree->max_subtrees) 00273 { 00274 int new_max_subtrees; 00275 DBusObjectSubtree **new_subtrees; 00276 00277 new_max_subtrees = subtree->max_subtrees == 0 ? 1 : 2 * subtree->max_subtrees; 00278 new_subtrees = dbus_realloc (subtree->subtrees, 00279 new_max_subtrees * sizeof (DBusObjectSubtree*)); 00280 if (new_subtrees == NULL) 00281 { 00282 _dbus_object_subtree_unref (child); 00283 return NULL; 00284 } 00285 subtree->subtrees = new_subtrees; 00286 subtree->max_subtrees = new_max_subtrees; 00287 } 00288 00289 /* The binary search failed, so i == j points to the 00290 place the child should be inserted. */ 00291 child_pos = i; 00292 _dbus_assert (child_pos < new_n_subtrees && 00293 new_n_subtrees <= subtree->max_subtrees); 00294 if (child_pos + 1 < new_n_subtrees) 00295 { 00296 memmove (&subtree->subtrees[child_pos+1], 00297 &subtree->subtrees[child_pos], 00298 (new_n_subtrees - child_pos - 1) * 00299 sizeof subtree->subtrees[0]); 00300 } 00301 subtree->subtrees[child_pos] = child; 00302 00303 if (index_in_parent) 00304 *index_in_parent = child_pos; 00305 subtree->n_subtrees = new_n_subtrees; 00306 child->parent = subtree; 00307 00308 return find_subtree_recurse (child, 00309 &path[1], create_if_not_found, 00310 index_in_parent, exact_match); 00311 } 00312 else 00313 { 00314 if (exact_match != NULL) 00315 *exact_match = FALSE; 00316 return (return_deepest_match && subtree->invoke_as_fallback) ? subtree : NULL; 00317 } 00318 } 00319 00320 static DBusObjectSubtree* 00321 find_subtree (DBusObjectTree *tree, 00322 const char **path, 00323 int *index_in_parent) 00324 { 00325 DBusObjectSubtree *subtree; 00326 00327 #if VERBOSE_FIND 00328 _dbus_verbose ("Looking for exact registered subtree\n"); 00329 #endif 00330 00331 subtree = find_subtree_recurse (tree->root, path, FALSE, index_in_parent, NULL); 00332 00333 if (subtree && subtree->message_function == NULL) 00334 return NULL; 00335 else 00336 return subtree; 00337 } 00338 00339 static DBusObjectSubtree* 00340 lookup_subtree (DBusObjectTree *tree, 00341 const char **path) 00342 { 00343 #if VERBOSE_FIND 00344 _dbus_verbose ("Looking for subtree\n"); 00345 #endif 00346 return find_subtree_recurse (tree->root, path, FALSE, NULL, NULL); 00347 } 00348 00349 static DBusObjectSubtree* 00350 find_handler (DBusObjectTree *tree, 00351 const char **path, 00352 dbus_bool_t *exact_match) 00353 { 00354 #if VERBOSE_FIND 00355 _dbus_verbose ("Looking for deepest handler\n"); 00356 #endif 00357 _dbus_assert (exact_match != NULL); 00358 00359 *exact_match = FALSE; /* ensure always initialized */ 00360 00361 return find_subtree_recurse (tree->root, path, FALSE, NULL, exact_match); 00362 } 00363 00364 static DBusObjectSubtree* 00365 ensure_subtree (DBusObjectTree *tree, 00366 const char **path) 00367 { 00368 #if VERBOSE_FIND 00369 _dbus_verbose ("Ensuring subtree\n"); 00370 #endif 00371 return find_subtree_recurse (tree->root, path, TRUE, NULL, NULL); 00372 } 00373 00374 static char *flatten_path (const char **path); 00375 00388 dbus_bool_t 00389 _dbus_object_tree_register (DBusObjectTree *tree, 00390 dbus_bool_t fallback, 00391 const char **path, 00392 const DBusObjectPathVTable *vtable, 00393 void *user_data, 00394 DBusError *error) 00395 { 00396 DBusObjectSubtree *subtree; 00397 00398 _dbus_assert (tree != NULL); 00399 _dbus_assert (vtable->message_function != NULL); 00400 _dbus_assert (path != NULL); 00401 00402 subtree = ensure_subtree (tree, path); 00403 if (subtree == NULL) 00404 { 00405 _DBUS_SET_OOM (error); 00406 return FALSE; 00407 } 00408 00409 if (subtree->message_function != NULL) 00410 { 00411 if (error != NULL) 00412 { 00413 char *complete_path = flatten_path (path); 00414 00415 dbus_set_error (error, DBUS_ERROR_OBJECT_PATH_IN_USE, 00416 "A handler is already registered for %s", 00417 complete_path ? complete_path 00418 : "(cannot represent path: out of memory!)"); 00419 00420 dbus_free (complete_path); 00421 } 00422 00423 return FALSE; 00424 } 00425 00426 subtree->message_function = vtable->message_function; 00427 subtree->unregister_function = vtable->unregister_function; 00428 subtree->user_data = user_data; 00429 subtree->invoke_as_fallback = fallback != FALSE; 00430 00431 return TRUE; 00432 } 00433 00441 void 00442 _dbus_object_tree_unregister_and_unlock (DBusObjectTree *tree, 00443 const char **path) 00444 { 00445 int i; 00446 DBusObjectSubtree *subtree; 00447 DBusObjectPathUnregisterFunction unregister_function; 00448 void *user_data; 00449 DBusConnection *connection; 00450 00451 _dbus_assert (path != NULL); 00452 00453 unregister_function = NULL; 00454 user_data = NULL; 00455 00456 subtree = find_subtree (tree, path, &i); 00457 00458 #ifndef DBUS_DISABLE_CHECKS 00459 if (subtree == NULL) 00460 { 00461 _dbus_warn ("Attempted to unregister path (path[0] = %s path[1] = %s) which isn't registered\n", 00462 path[0] ? path[0] : "null", 00463 path[1] ? path[1] : "null"); 00464 goto unlock; 00465 } 00466 #else 00467 _dbus_assert (subtree != NULL); 00468 #endif 00469 00470 _dbus_assert (subtree->parent == NULL || 00471 (i >= 0 && subtree->parent->subtrees[i] == subtree)); 00472 00473 subtree->message_function = NULL; 00474 00475 unregister_function = subtree->unregister_function; 00476 user_data = subtree->user_data; 00477 00478 subtree->unregister_function = NULL; 00479 subtree->user_data = NULL; 00480 00481 /* If we have no subtrees of our own, remove from 00482 * our parent (FIXME could also be more aggressive 00483 * and remove our parent if it becomes empty) 00484 */ 00485 if (subtree->parent && subtree->n_subtrees == 0) 00486 { 00487 /* assumes a 0-byte memmove is OK */ 00488 memmove (&subtree->parent->subtrees[i], 00489 &subtree->parent->subtrees[i+1], 00490 (subtree->parent->n_subtrees - i - 1) * 00491 sizeof (subtree->parent->subtrees[0])); 00492 subtree->parent->n_subtrees -= 1; 00493 00494 subtree->parent = NULL; 00495 00496 _dbus_object_subtree_unref (subtree); 00497 } 00498 subtree = NULL; 00499 00500 unlock: 00501 connection = tree->connection; 00502 00503 /* Unlock and call application code */ 00504 #ifdef DBUS_BUILD_TESTS 00505 if (connection) 00506 #endif 00507 { 00508 _dbus_connection_ref_unlocked (connection); 00509 _dbus_verbose ("unlock %s\n", _DBUS_FUNCTION_NAME); 00510 _dbus_connection_unlock (connection); 00511 } 00512 00513 if (unregister_function) 00514 (* unregister_function) (connection, user_data); 00515 00516 #ifdef DBUS_BUILD_TESTS 00517 if (connection) 00518 #endif 00519 dbus_connection_unref (connection); 00520 } 00521 00522 static void 00523 free_subtree_recurse (DBusConnection *connection, 00524 DBusObjectSubtree *subtree) 00525 { 00526 /* Delete them from the end, for slightly 00527 * more robustness against odd reentrancy. 00528 */ 00529 while (subtree->n_subtrees > 0) 00530 { 00531 DBusObjectSubtree *child; 00532 00533 child = subtree->subtrees[subtree->n_subtrees - 1]; 00534 subtree->subtrees[subtree->n_subtrees - 1] = NULL; 00535 subtree->n_subtrees -= 1; 00536 child->parent = NULL; 00537 00538 free_subtree_recurse (connection, child); 00539 } 00540 00541 /* Call application code */ 00542 if (subtree->unregister_function) 00543 (* subtree->unregister_function) (connection, 00544 subtree->user_data); 00545 00546 subtree->message_function = NULL; 00547 subtree->unregister_function = NULL; 00548 subtree->user_data = NULL; 00549 00550 /* Now free ourselves */ 00551 _dbus_object_subtree_unref (subtree); 00552 } 00553 00560 void 00561 _dbus_object_tree_free_all_unlocked (DBusObjectTree *tree) 00562 { 00563 if (tree->root) 00564 free_subtree_recurse (tree->connection, 00565 tree->root); 00566 tree->root = NULL; 00567 } 00568 00569 static dbus_bool_t 00570 _dbus_object_tree_list_registered_unlocked (DBusObjectTree *tree, 00571 const char **parent_path, 00572 char ***child_entries) 00573 { 00574 DBusObjectSubtree *subtree; 00575 char **retval; 00576 00577 _dbus_assert (parent_path != NULL); 00578 _dbus_assert (child_entries != NULL); 00579 00580 *child_entries = NULL; 00581 00582 subtree = lookup_subtree (tree, parent_path); 00583 if (subtree == NULL) 00584 { 00585 retval = dbus_new0 (char *, 1); 00586 } 00587 else 00588 { 00589 int i; 00590 retval = dbus_new0 (char*, subtree->n_subtrees + 1); 00591 if (retval == NULL) 00592 goto out; 00593 i = 0; 00594 while (i < subtree->n_subtrees) 00595 { 00596 retval[i] = _dbus_strdup (subtree->subtrees[i]->name); 00597 if (retval[i] == NULL) 00598 { 00599 dbus_free_string_array (retval); 00600 retval = NULL; 00601 goto out; 00602 } 00603 ++i; 00604 } 00605 } 00606 00607 out: 00608 00609 *child_entries = retval; 00610 return retval != NULL; 00611 } 00612 00613 static DBusHandlerResult 00614 handle_default_introspect_and_unlock (DBusObjectTree *tree, 00615 DBusMessage *message, 00616 const char **path) 00617 { 00618 DBusString xml; 00619 DBusHandlerResult result; 00620 char **children; 00621 int i; 00622 DBusMessage *reply; 00623 DBusMessageIter iter; 00624 const char *v_STRING; 00625 dbus_bool_t already_unlocked; 00626 00627 /* We have the connection lock here */ 00628 00629 already_unlocked = FALSE; 00630 00631 _dbus_verbose (" considering default Introspect() handler...\n"); 00632 00633 reply = NULL; 00634 00635 if (!dbus_message_is_method_call (message, 00636 DBUS_INTERFACE_INTROSPECTABLE, 00637 "Introspect")) 00638 { 00639 #ifdef DBUS_BUILD_TESTS 00640 if (tree->connection) 00641 #endif 00642 { 00643 _dbus_verbose ("unlock %s %d\n", _DBUS_FUNCTION_NAME, __LINE__); 00644 _dbus_connection_unlock (tree->connection); 00645 } 00646 00647 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; 00648 } 00649 00650 _dbus_verbose (" using default Introspect() handler!\n"); 00651 00652 if (!_dbus_string_init (&xml)) 00653 { 00654 #ifdef DBUS_BUILD_TESTS 00655 if (tree->connection) 00656 #endif 00657 { 00658 _dbus_verbose ("unlock %s %d\n", _DBUS_FUNCTION_NAME, __LINE__); 00659 _dbus_connection_unlock (tree->connection); 00660 } 00661 00662 return DBUS_HANDLER_RESULT_NEED_MEMORY; 00663 } 00664 00665 result = DBUS_HANDLER_RESULT_NEED_MEMORY; 00666 00667 children = NULL; 00668 if (!_dbus_object_tree_list_registered_unlocked (tree, path, &children)) 00669 goto out; 00670 00671 if (!_dbus_string_append (&xml, DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE)) 00672 goto out; 00673 00674 if (!_dbus_string_append (&xml, "<node>\n")) 00675 goto out; 00676 00677 i = 0; 00678 while (children[i] != NULL) 00679 { 00680 if (!_dbus_string_append_printf (&xml, " <node name=\"%s\"/>\n", 00681 children[i])) 00682 goto out; 00683 00684 ++i; 00685 } 00686 00687 if (!_dbus_string_append (&xml, "</node>\n")) 00688 goto out; 00689 00690 reply = dbus_message_new_method_return (message); 00691 if (reply == NULL) 00692 goto out; 00693 00694 dbus_message_iter_init_append (reply, &iter); 00695 v_STRING = _dbus_string_get_const_data (&xml); 00696 if (!dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &v_STRING)) 00697 goto out; 00698 00699 #ifdef DBUS_BUILD_TESTS 00700 if (tree->connection) 00701 #endif 00702 { 00703 already_unlocked = TRUE; 00704 00705 if (!_dbus_connection_send_and_unlock (tree->connection, reply, NULL)) 00706 goto out; 00707 } 00708 00709 result = DBUS_HANDLER_RESULT_HANDLED; 00710 00711 out: 00712 #ifdef DBUS_BUILD_TESTS 00713 if (tree->connection) 00714 #endif 00715 { 00716 if (!already_unlocked) 00717 { 00718 _dbus_verbose ("unlock %s %d\n", _DBUS_FUNCTION_NAME, __LINE__); 00719 _dbus_connection_unlock (tree->connection); 00720 } 00721 } 00722 00723 _dbus_string_free (&xml); 00724 dbus_free_string_array (children); 00725 if (reply) 00726 dbus_message_unref (reply); 00727 00728 return result; 00729 } 00730 00744 DBusHandlerResult 00745 _dbus_object_tree_dispatch_and_unlock (DBusObjectTree *tree, 00746 DBusMessage *message) 00747 { 00748 char **path; 00749 dbus_bool_t exact_match; 00750 DBusList *list; 00751 DBusList *link; 00752 DBusHandlerResult result; 00753 DBusObjectSubtree *subtree; 00754 00755 #if 0 00756 _dbus_verbose ("Dispatch of message by object path\n"); 00757 #endif 00758 00759 path = NULL; 00760 if (!dbus_message_get_path_decomposed (message, &path)) 00761 { 00762 #ifdef DBUS_BUILD_TESTS 00763 if (tree->connection) 00764 #endif 00765 { 00766 _dbus_verbose ("unlock %s\n", _DBUS_FUNCTION_NAME); 00767 _dbus_connection_unlock (tree->connection); 00768 } 00769 00770 _dbus_verbose ("No memory to get decomposed path\n"); 00771 00772 return DBUS_HANDLER_RESULT_NEED_MEMORY; 00773 } 00774 00775 if (path == NULL) 00776 { 00777 #ifdef DBUS_BUILD_TESTS 00778 if (tree->connection) 00779 #endif 00780 { 00781 _dbus_verbose ("unlock %s\n", _DBUS_FUNCTION_NAME); 00782 _dbus_connection_unlock (tree->connection); 00783 } 00784 00785 _dbus_verbose ("No path field in message\n"); 00786 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; 00787 } 00788 00789 /* Find the deepest path that covers the path in the message */ 00790 subtree = find_handler (tree, (const char**) path, &exact_match); 00791 00792 /* Build a list of all paths that cover the path in the message */ 00793 00794 list = NULL; 00795 00796 while (subtree != NULL) 00797 { 00798 if (subtree->message_function != NULL && (exact_match || subtree->invoke_as_fallback)) 00799 { 00800 _dbus_object_subtree_ref (subtree); 00801 00802 /* run deepest paths first */ 00803 if (!_dbus_list_append (&list, subtree)) 00804 { 00805 result = DBUS_HANDLER_RESULT_NEED_MEMORY; 00806 _dbus_object_subtree_unref (subtree); 00807 goto free_and_return; 00808 } 00809 } 00810 00811 exact_match = FALSE; 00812 subtree = subtree->parent; 00813 } 00814 00815 _dbus_verbose ("%d handlers in the path tree for this message\n", 00816 _dbus_list_get_length (&list)); 00817 00818 /* Invoke each handler in the list */ 00819 00820 result = DBUS_HANDLER_RESULT_NOT_YET_HANDLED; 00821 00822 link = _dbus_list_get_first_link (&list); 00823 while (link != NULL) 00824 { 00825 DBusList *next = _dbus_list_get_next_link (&list, link); 00826 subtree = link->data; 00827 00828 /* message_function is NULL if we're unregistered 00829 * due to reentrancy 00830 */ 00831 if (subtree->message_function) 00832 { 00833 DBusObjectPathMessageFunction message_function; 00834 void *user_data; 00835 00836 message_function = subtree->message_function; 00837 user_data = subtree->user_data; 00838 00839 #if 0 00840 _dbus_verbose (" (invoking a handler)\n"); 00841 #endif 00842 00843 #ifdef DBUS_BUILD_TESTS 00844 if (tree->connection) 00845 #endif 00846 { 00847 _dbus_verbose ("unlock %s\n", _DBUS_FUNCTION_NAME); 00848 _dbus_connection_unlock (tree->connection); 00849 } 00850 00851 /* FIXME you could unregister the subtree in another thread 00852 * before we invoke the callback, and I can't figure out a 00853 * good way to solve this. 00854 */ 00855 00856 result = (* message_function) (tree->connection, 00857 message, 00858 user_data); 00859 00860 #ifdef DBUS_BUILD_TESTS 00861 if (tree->connection) 00862 #endif 00863 _dbus_connection_lock (tree->connection); 00864 00865 if (result != DBUS_HANDLER_RESULT_NOT_YET_HANDLED) 00866 goto free_and_return; 00867 } 00868 00869 link = next; 00870 } 00871 00872 free_and_return: 00873 00874 if (result == DBUS_HANDLER_RESULT_NOT_YET_HANDLED) 00875 { 00876 /* This hardcoded default handler does a minimal Introspect() 00877 */ 00878 result = handle_default_introspect_and_unlock (tree, message, 00879 (const char**) path); 00880 } 00881 else 00882 { 00883 #ifdef DBUS_BUILD_TESTS 00884 if (tree->connection) 00885 #endif 00886 { 00887 _dbus_verbose ("unlock %s\n", _DBUS_FUNCTION_NAME); 00888 _dbus_connection_unlock (tree->connection); 00889 } 00890 } 00891 00892 while (list != NULL) 00893 { 00894 link = _dbus_list_get_first_link (&list); 00895 _dbus_object_subtree_unref (link->data); 00896 _dbus_list_remove_link (&list, link); 00897 } 00898 00899 dbus_free_string_array (path); 00900 00901 return result; 00902 } 00903 00912 void* 00913 _dbus_object_tree_get_user_data_unlocked (DBusObjectTree *tree, 00914 const char **path) 00915 { 00916 dbus_bool_t exact_match; 00917 DBusObjectSubtree *subtree; 00918 00919 _dbus_assert (tree != NULL); 00920 _dbus_assert (path != NULL); 00921 00922 /* Find the deepest path that covers the path in the message */ 00923 subtree = find_handler (tree, (const char**) path, &exact_match); 00924 00925 if ((subtree == NULL) || !exact_match) 00926 { 00927 _dbus_verbose ("%s: No object at specified path found\n", 00928 _DBUS_FUNCTION_NAME); 00929 return NULL; 00930 } 00931 00932 return subtree->user_data; 00933 } 00934 00941 static DBusObjectSubtree* 00942 allocate_subtree_object (const char *name) 00943 { 00944 int len; 00945 DBusObjectSubtree *subtree; 00946 const size_t front_padding = _DBUS_STRUCT_OFFSET (DBusObjectSubtree, name); 00947 00948 _dbus_assert (name != NULL); 00949 00950 len = strlen (name); 00951 00952 subtree = dbus_malloc (MAX (front_padding + (len + 1), sizeof (DBusObjectSubtree))); 00953 00954 if (subtree == NULL) 00955 return NULL; 00956 00957 memcpy (subtree->name, name, len + 1); 00958 00959 return subtree; 00960 } 00961 00962 static DBusObjectSubtree* 00963 _dbus_object_subtree_new (const char *name, 00964 const DBusObjectPathVTable *vtable, 00965 void *user_data) 00966 { 00967 DBusObjectSubtree *subtree; 00968 00969 subtree = allocate_subtree_object (name); 00970 if (subtree == NULL) 00971 goto oom; 00972 00973 _dbus_assert (name != NULL); 00974 00975 subtree->parent = NULL; 00976 00977 if (vtable) 00978 { 00979 subtree->message_function = vtable->message_function; 00980 subtree->unregister_function = vtable->unregister_function; 00981 } 00982 else 00983 { 00984 subtree->message_function = NULL; 00985 subtree->unregister_function = NULL; 00986 } 00987 00988 subtree->user_data = user_data; 00989 subtree->refcount.value = 1; 00990 subtree->subtrees = NULL; 00991 subtree->n_subtrees = 0; 00992 subtree->max_subtrees = 0; 00993 subtree->invoke_as_fallback = FALSE; 00994 00995 return subtree; 00996 00997 oom: 00998 return NULL; 00999 } 01000 01001 static DBusObjectSubtree * 01002 _dbus_object_subtree_ref (DBusObjectSubtree *subtree) 01003 { 01004 _dbus_assert (subtree->refcount.value > 0); 01005 _dbus_atomic_inc (&subtree->refcount); 01006 01007 return subtree; 01008 } 01009 01010 static void 01011 _dbus_object_subtree_unref (DBusObjectSubtree *subtree) 01012 { 01013 _dbus_assert (subtree->refcount.value > 0); 01014 01015 if (_dbus_atomic_dec (&subtree->refcount) == 1) 01016 { 01017 _dbus_assert (subtree->unregister_function == NULL); 01018 _dbus_assert (subtree->message_function == NULL); 01019 01020 dbus_free (subtree->subtrees); 01021 dbus_free (subtree); 01022 } 01023 } 01024 01035 dbus_bool_t 01036 _dbus_object_tree_list_registered_and_unlock (DBusObjectTree *tree, 01037 const char **parent_path, 01038 char ***child_entries) 01039 { 01040 dbus_bool_t result; 01041 01042 result = _dbus_object_tree_list_registered_unlocked (tree, 01043 parent_path, 01044 child_entries); 01045 01046 #ifdef DBUS_BUILD_TESTS 01047 if (tree->connection) 01048 #endif 01049 { 01050 _dbus_verbose ("unlock %s\n", _DBUS_FUNCTION_NAME); 01051 _dbus_connection_unlock (tree->connection); 01052 } 01053 01054 return result; 01055 } 01056 01057 01059 #define VERBOSE_DECOMPOSE 0 01060 01071 dbus_bool_t 01072 _dbus_decompose_path (const char* data, 01073 int len, 01074 char ***path, 01075 int *path_len) 01076 { 01077 char **retval; 01078 int n_components; 01079 int i, j, comp; 01080 01081 _dbus_assert (data != NULL); 01082 01083 #if VERBOSE_DECOMPOSE 01084 _dbus_verbose ("Decomposing path \"%s\"\n", 01085 data); 01086 #endif 01087 01088 n_components = 0; 01089 if (len > 1) /* if path is not just "/" */ 01090 { 01091 i = 0; 01092 while (i < len) 01093 { 01094 if (data[i] == '/') 01095 n_components += 1; 01096 ++i; 01097 } 01098 } 01099 01100 retval = dbus_new0 (char*, n_components + 1); 01101 01102 if (retval == NULL) 01103 return FALSE; 01104 01105 comp = 0; 01106 if (n_components == 0) 01107 i = 1; 01108 else 01109 i = 0; 01110 while (comp < n_components) 01111 { 01112 _dbus_assert (i < len); 01113 01114 if (data[i] == '/') 01115 ++i; 01116 j = i; 01117 01118 while (j < len && data[j] != '/') 01119 ++j; 01120 01121 /* Now [i, j) is the path component */ 01122 _dbus_assert (i < j); 01123 _dbus_assert (data[i] != '/'); 01124 _dbus_assert (j == len || data[j] == '/'); 01125 01126 #if VERBOSE_DECOMPOSE 01127 _dbus_verbose (" (component in [%d,%d))\n", 01128 i, j); 01129 #endif 01130 01131 retval[comp] = _dbus_memdup (&data[i], j - i + 1); 01132 if (retval[comp] == NULL) 01133 { 01134 dbus_free_string_array (retval); 01135 return FALSE; 01136 } 01137 retval[comp][j-i] = '\0'; 01138 #if VERBOSE_DECOMPOSE 01139 _dbus_verbose (" (component %d = \"%s\")\n", 01140 comp, retval[comp]); 01141 #endif 01142 01143 ++comp; 01144 i = j; 01145 } 01146 _dbus_assert (i == len); 01147 01148 *path = retval; 01149 if (path_len) 01150 *path_len = n_components; 01151 01152 return TRUE; 01153 } 01154 01157 static char* 01158 flatten_path (const char **path) 01159 { 01160 DBusString str; 01161 char *s; 01162 01163 if (!_dbus_string_init (&str)) 01164 return NULL; 01165 01166 if (path[0] == NULL) 01167 { 01168 if (!_dbus_string_append_byte (&str, '/')) 01169 goto nomem; 01170 } 01171 else 01172 { 01173 int i; 01174 01175 i = 0; 01176 while (path[i]) 01177 { 01178 if (!_dbus_string_append_byte (&str, '/')) 01179 goto nomem; 01180 01181 if (!_dbus_string_append (&str, path[i])) 01182 goto nomem; 01183 01184 ++i; 01185 } 01186 } 01187 01188 if (!_dbus_string_steal_data (&str, &s)) 01189 goto nomem; 01190 01191 _dbus_string_free (&str); 01192 01193 return s; 01194 01195 nomem: 01196 _dbus_string_free (&str); 01197 return NULL; 01198 } 01199 01200 01201 #ifdef DBUS_BUILD_TESTS 01202 01203 #ifndef DOXYGEN_SHOULD_SKIP_THIS 01204 01205 #include "dbus-test.h" 01206 #include <stdio.h> 01207 01208 typedef enum 01209 { 01210 STR_EQUAL, 01211 STR_PREFIX, 01212 STR_DIFFERENT 01213 } StrComparison; 01214 01215 /* Returns TRUE if container is a parent of child 01216 */ 01217 static StrComparison 01218 path_contains (const char **container, 01219 const char **child) 01220 { 01221 int i; 01222 01223 i = 0; 01224 while (child[i] != NULL) 01225 { 01226 int v; 01227 01228 if (container[i] == NULL) 01229 return STR_PREFIX; /* container ran out, child continues; 01230 * thus the container is a parent of the 01231 * child. 01232 */ 01233 01234 _dbus_assert (container[i] != NULL); 01235 _dbus_assert (child[i] != NULL); 01236 01237 v = strcmp (container[i], child[i]); 01238 01239 if (v != 0) 01240 return STR_DIFFERENT; /* they overlap until here and then are different, 01241 * not overlapping 01242 */ 01243 01244 ++i; 01245 } 01246 01247 /* Child ran out; if container also did, they are equal; 01248 * otherwise, the child is a parent of the container. 01249 */ 01250 if (container[i] == NULL) 01251 return STR_EQUAL; 01252 else 01253 return STR_DIFFERENT; 01254 } 01255 01256 #if 0 01257 static void 01258 spew_subtree_recurse (DBusObjectSubtree *subtree, 01259 int indent) 01260 { 01261 int i; 01262 01263 i = 0; 01264 while (i < indent) 01265 { 01266 _dbus_verbose (" "); 01267 ++i; 01268 } 01269 01270 _dbus_verbose ("%s (%d children)\n", 01271 subtree->name, subtree->n_subtrees); 01272 01273 i = 0; 01274 while (i < subtree->n_subtrees) 01275 { 01276 spew_subtree_recurse (subtree->subtrees[i], indent + 2); 01277 01278 ++i; 01279 } 01280 } 01281 01282 static void 01283 spew_tree (DBusObjectTree *tree) 01284 { 01285 spew_subtree_recurse (tree->root, 0); 01286 } 01287 #endif 01288 01292 typedef struct 01293 { 01294 const char **path; 01295 dbus_bool_t handler_fallback; 01296 dbus_bool_t message_handled; 01297 dbus_bool_t handler_unregistered; 01298 } TreeTestData; 01299 01300 01301 static void 01302 test_unregister_function (DBusConnection *connection, 01303 void *user_data) 01304 { 01305 TreeTestData *ttd = user_data; 01306 01307 ttd->handler_unregistered = TRUE; 01308 } 01309 01310 static DBusHandlerResult 01311 test_message_function (DBusConnection *connection, 01312 DBusMessage *message, 01313 void *user_data) 01314 { 01315 TreeTestData *ttd = user_data; 01316 01317 ttd->message_handled = TRUE; 01318 01319 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; 01320 } 01321 01322 static dbus_bool_t 01323 do_register (DBusObjectTree *tree, 01324 const char **path, 01325 dbus_bool_t fallback, 01326 int i, 01327 TreeTestData *tree_test_data) 01328 { 01329 DBusObjectPathVTable vtable = { test_unregister_function, 01330 test_message_function, NULL }; 01331 01332 tree_test_data[i].message_handled = FALSE; 01333 tree_test_data[i].handler_unregistered = FALSE; 01334 tree_test_data[i].handler_fallback = fallback; 01335 tree_test_data[i].path = path; 01336 01337 if (!_dbus_object_tree_register (tree, fallback, path, 01338 &vtable, 01339 &tree_test_data[i], 01340 NULL)) 01341 return FALSE; 01342 01343 _dbus_assert (_dbus_object_tree_get_user_data_unlocked (tree, path) == 01344 &tree_test_data[i]); 01345 01346 return TRUE; 01347 } 01348 01349 static dbus_bool_t 01350 do_test_dispatch (DBusObjectTree *tree, 01351 const char **path, 01352 int i, 01353 TreeTestData *tree_test_data, 01354 int n_test_data) 01355 { 01356 DBusMessage *message; 01357 int j; 01358 DBusHandlerResult result; 01359 char *flat; 01360 01361 message = NULL; 01362 01363 flat = flatten_path (path); 01364 if (flat == NULL) 01365 goto oom; 01366 01367 message = dbus_message_new_method_call (NULL, 01368 flat, 01369 "org.freedesktop.TestInterface", 01370 "Foo"); 01371 dbus_free (flat); 01372 if (message == NULL) 01373 goto oom; 01374 01375 j = 0; 01376 while (j < n_test_data) 01377 { 01378 tree_test_data[j].message_handled = FALSE; 01379 ++j; 01380 } 01381 01382 result = _dbus_object_tree_dispatch_and_unlock (tree, message); 01383 if (result == DBUS_HANDLER_RESULT_NEED_MEMORY) 01384 goto oom; 01385 01386 _dbus_assert (tree_test_data[i].message_handled); 01387 01388 j = 0; 01389 while (j < n_test_data) 01390 { 01391 if (tree_test_data[j].message_handled) 01392 { 01393 if (tree_test_data[j].handler_fallback) 01394 _dbus_assert (path_contains (tree_test_data[j].path, 01395 path) != STR_DIFFERENT); 01396 else 01397 _dbus_assert (path_contains (tree_test_data[j].path, path) == STR_EQUAL); 01398 } 01399 else 01400 { 01401 if (tree_test_data[j].handler_fallback) 01402 _dbus_assert (path_contains (tree_test_data[j].path, 01403 path) == STR_DIFFERENT); 01404 else 01405 _dbus_assert (path_contains (tree_test_data[j].path, path) != STR_EQUAL); 01406 } 01407 01408 ++j; 01409 } 01410 01411 dbus_message_unref (message); 01412 01413 return TRUE; 01414 01415 oom: 01416 if (message) 01417 dbus_message_unref (message); 01418 return FALSE; 01419 } 01420 01421 static size_t 01422 string_array_length (const char **array) 01423 { 01424 size_t i; 01425 for (i = 0; array[i]; i++) ; 01426 return i; 01427 } 01428 01429 typedef struct 01430 { 01431 const char *path; 01432 const char *result[20]; 01433 } DecomposePathTest; 01434 01435 static DecomposePathTest decompose_tests[] = { 01436 { "/foo", { "foo", NULL } }, 01437 { "/foo/bar", { "foo", "bar", NULL } }, 01438 { "/", { NULL } }, 01439 { "/a/b", { "a", "b", NULL } }, 01440 { "/a/b/c", { "a", "b", "c", NULL } }, 01441 { "/a/b/c/d", { "a", "b", "c", "d", NULL } }, 01442 { "/foo/bar/q", { "foo", "bar", "q", NULL } }, 01443 { "/foo/bar/this/is/longer", { "foo", "bar", "this", "is", "longer", NULL } } 01444 }; 01445 01446 static dbus_bool_t 01447 run_decompose_tests (void) 01448 { 01449 int i; 01450 01451 i = 0; 01452 while (i < _DBUS_N_ELEMENTS (decompose_tests)) 01453 { 01454 char **result; 01455 int result_len; 01456 int expected_len; 01457 01458 if (!_dbus_decompose_path (decompose_tests[i].path, 01459 strlen (decompose_tests[i].path), 01460 &result, &result_len)) 01461 return FALSE; 01462 01463 expected_len = string_array_length (decompose_tests[i].result); 01464 01465 if (result_len != (int) string_array_length ((const char**)result) || 01466 expected_len != result_len || 01467 path_contains (decompose_tests[i].result, 01468 (const char**) result) != STR_EQUAL) 01469 { 01470 int real_len = string_array_length ((const char**)result); 01471 _dbus_warn ("Expected decompose of %s to have len %d, returned %d, appears to have %d\n", 01472 decompose_tests[i].path, expected_len, result_len, 01473 real_len); 01474 _dbus_warn ("Decompose resulted in elements: { "); 01475 i = 0; 01476 while (i < real_len) 01477 { 01478 _dbus_warn ("\"%s\"%s", result[i], 01479 (i + 1) == real_len ? "" : ", "); 01480 ++i; 01481 } 01482 _dbus_warn ("}\n"); 01483 _dbus_assert_not_reached ("path decompose failed\n"); 01484 } 01485 01486 dbus_free_string_array (result); 01487 01488 ++i; 01489 } 01490 01491 return TRUE; 01492 } 01493 01494 static dbus_bool_t 01495 object_tree_test_iteration (void *data) 01496 { 01497 const char *path0[] = { NULL }; 01498 const char *path1[] = { "foo", NULL }; 01499 const char *path2[] = { "foo", "bar", NULL }; 01500 const char *path3[] = { "foo", "bar", "baz", NULL }; 01501 const char *path4[] = { "foo", "bar", "boo", NULL }; 01502 const char *path5[] = { "blah", NULL }; 01503 const char *path6[] = { "blah", "boof", NULL }; 01504 const char *path7[] = { "blah", "boof", "this", "is", "really", "long", NULL }; 01505 const char *path8[] = { "childless", NULL }; 01506 DBusObjectTree *tree; 01507 TreeTestData tree_test_data[9]; 01508 int i; 01509 dbus_bool_t exact_match; 01510 01511 if (!run_decompose_tests ()) 01512 return FALSE; 01513 01514 tree = NULL; 01515 01516 tree = _dbus_object_tree_new (NULL); 01517 if (tree == NULL) 01518 goto out; 01519 01520 if (!do_register (tree, path0, TRUE, 0, tree_test_data)) 01521 goto out; 01522 01523 _dbus_assert (find_subtree (tree, path0, NULL)); 01524 _dbus_assert (!find_subtree (tree, path1, NULL)); 01525 _dbus_assert (!find_subtree (tree, path2, NULL)); 01526 _dbus_assert (!find_subtree (tree, path3, NULL)); 01527 _dbus_assert (!find_subtree (tree, path4, NULL)); 01528 _dbus_assert (!find_subtree (tree, path5, NULL)); 01529 _dbus_assert (!find_subtree (tree, path6, NULL)); 01530 _dbus_assert (!find_subtree (tree, path7, NULL)); 01531 _dbus_assert (!find_subtree (tree, path8, NULL)); 01532 01533 _dbus_assert (find_handler (tree, path0, &exact_match) && exact_match); 01534 _dbus_assert (find_handler (tree, path1, &exact_match) == tree->root && !exact_match); 01535 _dbus_assert (find_handler (tree, path2, &exact_match) == tree->root && !exact_match); 01536 _dbus_assert (find_handler (tree, path3, &exact_match) == tree->root && !exact_match); 01537 _dbus_assert (find_handler (tree, path4, &exact_match) == tree->root && !exact_match); 01538 _dbus_assert (find_handler (tree, path5, &exact_match) == tree->root && !exact_match); 01539 _dbus_assert (find_handler (tree, path6, &exact_match) == tree->root && !exact_match); 01540 _dbus_assert (find_handler (tree, path7, &exact_match) == tree->root && !exact_match); 01541 _dbus_assert (find_handler (tree, path8, &exact_match) == tree->root && !exact_match); 01542 01543 if (!do_register (tree, path1, TRUE, 1, tree_test_data)) 01544 goto out; 01545 01546 _dbus_assert (find_subtree (tree, path0, NULL)); 01547 _dbus_assert (find_subtree (tree, path1, NULL)); 01548 _dbus_assert (!find_subtree (tree, path2, NULL)); 01549 _dbus_assert (!find_subtree (tree, path3, NULL)); 01550 _dbus_assert (!find_subtree (tree, path4, NULL)); 01551 _dbus_assert (!find_subtree (tree, path5, NULL)); 01552 _dbus_assert (!find_subtree (tree, path6, NULL)); 01553 _dbus_assert (!find_subtree (tree, path7, NULL)); 01554 _dbus_assert (!find_subtree (tree, path8, NULL)); 01555 01556 _dbus_assert (find_handler (tree, path0, &exact_match) && exact_match); 01557 _dbus_assert (find_handler (tree, path1, &exact_match) && exact_match); 01558 _dbus_assert (find_handler (tree, path2, &exact_match) && !exact_match); 01559 _dbus_assert (find_handler (tree, path3, &exact_match) && !exact_match); 01560 _dbus_assert (find_handler (tree, path4, &exact_match) && !exact_match); 01561 _dbus_assert (find_handler (tree, path5, &exact_match) == tree->root && !exact_match); 01562 _dbus_assert (find_handler (tree, path6, &exact_match) == tree->root && !exact_match); 01563 _dbus_assert (find_handler (tree, path7, &exact_match) == tree->root && !exact_match); 01564 _dbus_assert (find_handler (tree, path8, &exact_match) == tree->root && !exact_match); 01565 01566 if (!do_register (tree, path2, TRUE, 2, tree_test_data)) 01567 goto out; 01568 01569 _dbus_assert (find_subtree (tree, path1, NULL)); 01570 _dbus_assert (find_subtree (tree, path2, NULL)); 01571 _dbus_assert (!find_subtree (tree, path3, NULL)); 01572 _dbus_assert (!find_subtree (tree, path4, NULL)); 01573 _dbus_assert (!find_subtree (tree, path5, NULL)); 01574 _dbus_assert (!find_subtree (tree, path6, NULL)); 01575 _dbus_assert (!find_subtree (tree, path7, NULL)); 01576 _dbus_assert (!find_subtree (tree, path8, NULL)); 01577 01578 if (!do_register (tree, path3, TRUE, 3, tree_test_data)) 01579 goto out; 01580 01581 _dbus_assert (find_subtree (tree, path0, NULL)); 01582 _dbus_assert (find_subtree (tree, path1, NULL)); 01583 _dbus_assert (find_subtree (tree, path2, NULL)); 01584 _dbus_assert (find_subtree (tree, path3, NULL)); 01585 _dbus_assert (!find_subtree (tree, path4, NULL)); 01586 _dbus_assert (!find_subtree (tree, path5, NULL)); 01587 _dbus_assert (!find_subtree (tree, path6, NULL)); 01588 _dbus_assert (!find_subtree (tree, path7, NULL)); 01589 _dbus_assert (!find_subtree (tree, path8, NULL)); 01590 01591 if (!do_register (tree, path4, TRUE, 4, tree_test_data)) 01592 goto out; 01593 01594 _dbus_assert (find_subtree (tree, path0, NULL)); 01595 _dbus_assert (find_subtree (tree, path1, NULL)); 01596 _dbus_assert (find_subtree (tree, path2, NULL)); 01597 _dbus_assert (find_subtree (tree, path3, NULL)); 01598 _dbus_assert (find_subtree (tree, path4, NULL)); 01599 _dbus_assert (!find_subtree (tree, path5, NULL)); 01600 _dbus_assert (!find_subtree (tree, path6, NULL)); 01601 _dbus_assert (!find_subtree (tree, path7, NULL)); 01602 _dbus_assert (!find_subtree (tree, path8, NULL)); 01603 01604 if (!do_register (tree, path5, TRUE, 5, tree_test_data)) 01605 goto out; 01606 01607 _dbus_assert (find_subtree (tree, path0, NULL)); 01608 _dbus_assert (find_subtree (tree, path1, NULL)); 01609 _dbus_assert (find_subtree (tree, path2, NULL)); 01610 _dbus_assert (find_subtree (tree, path3, NULL)); 01611 _dbus_assert (find_subtree (tree, path4, NULL)); 01612 _dbus_assert (find_subtree (tree, path5, NULL)); 01613 _dbus_assert (!find_subtree (tree, path6, NULL)); 01614 _dbus_assert (!find_subtree (tree, path7, NULL)); 01615 _dbus_assert (!find_subtree (tree, path8, NULL)); 01616 01617 _dbus_assert (find_handler (tree, path0, &exact_match) == tree->root && exact_match); 01618 _dbus_assert (find_handler (tree, path1, &exact_match) != tree->root && exact_match); 01619 _dbus_assert (find_handler (tree, path2, &exact_match) != tree->root && exact_match); 01620 _dbus_assert (find_handler (tree, path3, &exact_match) != tree->root && exact_match); 01621 _dbus_assert (find_handler (tree, path4, &exact_match) != tree->root && exact_match); 01622 _dbus_assert (find_handler (tree, path5, &exact_match) != tree->root && exact_match); 01623 _dbus_assert (find_handler (tree, path6, &exact_match) != tree->root && !exact_match); 01624 _dbus_assert (find_handler (tree, path7, &exact_match) != tree->root && !exact_match); 01625 _dbus_assert (find_handler (tree, path8, &exact_match) == tree->root && !exact_match); 01626 01627 if (!do_register (tree, path6, TRUE, 6, tree_test_data)) 01628 goto out; 01629 01630 _dbus_assert (find_subtree (tree, path0, NULL)); 01631 _dbus_assert (find_subtree (tree, path1, NULL)); 01632 _dbus_assert (find_subtree (tree, path2, NULL)); 01633 _dbus_assert (find_subtree (tree, path3, NULL)); 01634 _dbus_assert (find_subtree (tree, path4, NULL)); 01635 _dbus_assert (find_subtree (tree, path5, NULL)); 01636 _dbus_assert (find_subtree (tree, path6, NULL)); 01637 _dbus_assert (!find_subtree (tree, path7, NULL)); 01638 _dbus_assert (!find_subtree (tree, path8, NULL)); 01639 01640 if (!do_register (tree, path7, TRUE, 7, tree_test_data)) 01641 goto out; 01642 01643 _dbus_assert (find_subtree (tree, path0, NULL)); 01644 _dbus_assert (find_subtree (tree, path1, NULL)); 01645 _dbus_assert (find_subtree (tree, path2, NULL)); 01646 _dbus_assert (find_subtree (tree, path3, NULL)); 01647 _dbus_assert (find_subtree (tree, path4, NULL)); 01648 _dbus_assert (find_subtree (tree, path5, NULL)); 01649 _dbus_assert (find_subtree (tree, path6, NULL)); 01650 _dbus_assert (find_subtree (tree, path7, NULL)); 01651 _dbus_assert (!find_subtree (tree, path8, NULL)); 01652 01653 if (!do_register (tree, path8, TRUE, 8, tree_test_data)) 01654 goto out; 01655 01656 _dbus_assert (find_subtree (tree, path0, NULL)); 01657 _dbus_assert (find_subtree (tree, path1, NULL)); 01658 _dbus_assert (find_subtree (tree, path2, NULL)); 01659 _dbus_assert (find_subtree (tree, path3, NULL)); 01660 _dbus_assert (find_subtree (tree, path4, NULL)); 01661 _dbus_assert (find_subtree (tree, path5, NULL)); 01662 _dbus_assert (find_subtree (tree, path6, NULL)); 01663 _dbus_assert (find_subtree (tree, path7, NULL)); 01664 _dbus_assert (find_subtree (tree, path8, NULL)); 01665 01666 _dbus_assert (find_handler (tree, path0, &exact_match) == tree->root && exact_match); 01667 _dbus_assert (find_handler (tree, path1, &exact_match) != tree->root && exact_match); 01668 _dbus_assert (find_handler (tree, path2, &exact_match) != tree->root && exact_match); 01669 _dbus_assert (find_handler (tree, path3, &exact_match) != tree->root && exact_match); 01670 _dbus_assert (find_handler (tree, path4, &exact_match) != tree->root && exact_match); 01671 _dbus_assert (find_handler (tree, path5, &exact_match) != tree->root && exact_match); 01672 _dbus_assert (find_handler (tree, path6, &exact_match) != tree->root && exact_match); 01673 _dbus_assert (find_handler (tree, path7, &exact_match) != tree->root && exact_match); 01674 _dbus_assert (find_handler (tree, path8, &exact_match) != tree->root && exact_match); 01675 01676 /* test the list_registered function */ 01677 01678 { 01679 const char *root[] = { NULL }; 01680 char **child_entries; 01681 int nb; 01682 01683 _dbus_object_tree_list_registered_unlocked (tree, path1, &child_entries); 01684 if (child_entries != NULL) 01685 { 01686 nb = string_array_length ((const char**)child_entries); 01687 _dbus_assert (nb == 1); 01688 dbus_free_string_array (child_entries); 01689 } 01690 01691 _dbus_object_tree_list_registered_unlocked (tree, path2, &child_entries); 01692 if (child_entries != NULL) 01693 { 01694 nb = string_array_length ((const char**)child_entries); 01695 _dbus_assert (nb == 2); 01696 dbus_free_string_array (child_entries); 01697 } 01698 01699 _dbus_object_tree_list_registered_unlocked (tree, path8, &child_entries); 01700 if (child_entries != NULL) 01701 { 01702 nb = string_array_length ((const char**)child_entries); 01703 _dbus_assert (nb == 0); 01704 dbus_free_string_array (child_entries); 01705 } 01706 01707 _dbus_object_tree_list_registered_unlocked (tree, root, &child_entries); 01708 if (child_entries != NULL) 01709 { 01710 nb = string_array_length ((const char**)child_entries); 01711 _dbus_assert (nb == 3); 01712 dbus_free_string_array (child_entries); 01713 } 01714 } 01715 01716 /* Check that destroying tree calls unregister funcs */ 01717 _dbus_object_tree_unref (tree); 01718 01719 i = 0; 01720 while (i < (int) _DBUS_N_ELEMENTS (tree_test_data)) 01721 { 01722 _dbus_assert (tree_test_data[i].handler_unregistered); 01723 _dbus_assert (!tree_test_data[i].message_handled); 01724 ++i; 01725 } 01726 01727 /* Now start again and try the individual unregister function */ 01728 tree = _dbus_object_tree_new (NULL); 01729 if (tree == NULL) 01730 goto out; 01731 01732 if (!do_register (tree, path0, TRUE, 0, tree_test_data)) 01733 goto out; 01734 if (!do_register (tree, path1, TRUE, 1, tree_test_data)) 01735 goto out; 01736 if (!do_register (tree, path2, TRUE, 2, tree_test_data)) 01737 goto out; 01738 if (!do_register (tree, path3, TRUE, 3, tree_test_data)) 01739 goto out; 01740 if (!do_register (tree, path4, TRUE, 4, tree_test_data)) 01741 goto out; 01742 if (!do_register (tree, path5, TRUE, 5, tree_test_data)) 01743 goto out; 01744 if (!do_register (tree, path6, TRUE, 6, tree_test_data)) 01745 goto out; 01746 if (!do_register (tree, path7, TRUE, 7, tree_test_data)) 01747 goto out; 01748 if (!do_register (tree, path8, TRUE, 8, tree_test_data)) 01749 goto out; 01750 01751 _dbus_object_tree_unregister_and_unlock (tree, path0); 01752 _dbus_assert (_dbus_object_tree_get_user_data_unlocked (tree, path0) == NULL); 01753 01754 _dbus_assert (!find_subtree (tree, path0, NULL)); 01755 _dbus_assert (find_subtree (tree, path1, NULL)); 01756 _dbus_assert (find_subtree (tree, path2, NULL)); 01757 _dbus_assert (find_subtree (tree, path3, NULL)); 01758 _dbus_assert (find_subtree (tree, path4, NULL)); 01759 _dbus_assert (find_subtree (tree, path5, NULL)); 01760 _dbus_assert (find_subtree (tree, path6, NULL)); 01761 _dbus_assert (find_subtree (tree, path7, NULL)); 01762 _dbus_assert (find_subtree (tree, path8, NULL)); 01763 01764 _dbus_object_tree_unregister_and_unlock (tree, path1); 01765 _dbus_assert (_dbus_object_tree_get_user_data_unlocked (tree, path1) == NULL); 01766 01767 _dbus_assert (!find_subtree (tree, path0, NULL)); 01768 _dbus_assert (!find_subtree (tree, path1, NULL)); 01769 _dbus_assert (find_subtree (tree, path2, NULL)); 01770 _dbus_assert (find_subtree (tree, path3, NULL)); 01771 _dbus_assert (find_subtree (tree, path4, NULL)); 01772 _dbus_assert (find_subtree (tree, path5, NULL)); 01773 _dbus_assert (find_subtree (tree, path6, NULL)); 01774 _dbus_assert (find_subtree (tree, path7, NULL)); 01775 _dbus_assert (find_subtree (tree, path8, NULL)); 01776 01777 _dbus_object_tree_unregister_and_unlock (tree, path2); 01778 _dbus_assert (_dbus_object_tree_get_user_data_unlocked (tree, path2) == NULL); 01779 01780 _dbus_assert (!find_subtree (tree, path0, NULL)); 01781 _dbus_assert (!find_subtree (tree, path1, NULL)); 01782 _dbus_assert (!find_subtree (tree, path2, NULL)); 01783 _dbus_assert (find_subtree (tree, path3, NULL)); 01784 _dbus_assert (find_subtree (tree, path4, NULL)); 01785 _dbus_assert (find_subtree (tree, path5, NULL)); 01786 _dbus_assert (find_subtree (tree, path6, NULL)); 01787 _dbus_assert (find_subtree (tree, path7, NULL)); 01788 _dbus_assert (find_subtree (tree, path8, NULL)); 01789 01790 _dbus_object_tree_unregister_and_unlock (tree, path3); 01791 _dbus_assert (_dbus_object_tree_get_user_data_unlocked (tree, path3) == NULL); 01792 01793 _dbus_assert (!find_subtree (tree, path0, NULL)); 01794 _dbus_assert (!find_subtree (tree, path1, NULL)); 01795 _dbus_assert (!find_subtree (tree, path2, NULL)); 01796 _dbus_assert (!find_subtree (tree, path3, NULL)); 01797 _dbus_assert (find_subtree (tree, path4, NULL)); 01798 _dbus_assert (find_subtree (tree, path5, NULL)); 01799 _dbus_assert (find_subtree (tree, path6, NULL)); 01800 _dbus_assert (find_subtree (tree, path7, NULL)); 01801 _dbus_assert (find_subtree (tree, path8, NULL)); 01802 01803 _dbus_object_tree_unregister_and_unlock (tree, path4); 01804 _dbus_assert (_dbus_object_tree_get_user_data_unlocked (tree, path4) == NULL); 01805 01806 _dbus_assert (!find_subtree (tree, path0, NULL)); 01807 _dbus_assert (!find_subtree (tree, path1, NULL)); 01808 _dbus_assert (!find_subtree (tree, path2, NULL)); 01809 _dbus_assert (!find_subtree (tree, path3, NULL)); 01810 _dbus_assert (!find_subtree (tree, path4, NULL)); 01811 _dbus_assert (find_subtree (tree, path5, NULL)); 01812 _dbus_assert (find_subtree (tree, path6, NULL)); 01813 _dbus_assert (find_subtree (tree, path7, NULL)); 01814 _dbus_assert (find_subtree (tree, path8, NULL)); 01815 01816 _dbus_object_tree_unregister_and_unlock (tree, path5); 01817 _dbus_assert (_dbus_object_tree_get_user_data_unlocked (tree, path5) == NULL); 01818 01819 _dbus_assert (!find_subtree (tree, path0, NULL)); 01820 _dbus_assert (!find_subtree (tree, path1, NULL)); 01821 _dbus_assert (!find_subtree (tree, path2, NULL)); 01822 _dbus_assert (!find_subtree (tree, path3, NULL)); 01823 _dbus_assert (!find_subtree (tree, path4, NULL)); 01824 _dbus_assert (!find_subtree (tree, path5, NULL)); 01825 _dbus_assert (find_subtree (tree, path6, NULL)); 01826 _dbus_assert (find_subtree (tree, path7, NULL)); 01827 _dbus_assert (find_subtree (tree, path8, NULL)); 01828 01829 _dbus_object_tree_unregister_and_unlock (tree, path6); 01830 _dbus_assert (_dbus_object_tree_get_user_data_unlocked (tree, path6) == NULL); 01831 01832 _dbus_assert (!find_subtree (tree, path0, NULL)); 01833 _dbus_assert (!find_subtree (tree, path1, NULL)); 01834 _dbus_assert (!find_subtree (tree, path2, NULL)); 01835 _dbus_assert (!find_subtree (tree, path3, NULL)); 01836 _dbus_assert (!find_subtree (tree, path4, NULL)); 01837 _dbus_assert (!find_subtree (tree, path5, NULL)); 01838 _dbus_assert (!find_subtree (tree, path6, NULL)); 01839 _dbus_assert (find_subtree (tree, path7, NULL)); 01840 _dbus_assert (find_subtree (tree, path8, NULL)); 01841 01842 _dbus_object_tree_unregister_and_unlock (tree, path7); 01843 _dbus_assert (_dbus_object_tree_get_user_data_unlocked (tree, path7) == NULL); 01844 01845 _dbus_assert (!find_subtree (tree, path0, NULL)); 01846 _dbus_assert (!find_subtree (tree, path1, NULL)); 01847 _dbus_assert (!find_subtree (tree, path2, NULL)); 01848 _dbus_assert (!find_subtree (tree, path3, NULL)); 01849 _dbus_assert (!find_subtree (tree, path4, NULL)); 01850 _dbus_assert (!find_subtree (tree, path5, NULL)); 01851 _dbus_assert (!find_subtree (tree, path6, NULL)); 01852 _dbus_assert (!find_subtree (tree, path7, NULL)); 01853 _dbus_assert (find_subtree (tree, path8, NULL)); 01854 01855 _dbus_object_tree_unregister_and_unlock (tree, path8); 01856 _dbus_assert (_dbus_object_tree_get_user_data_unlocked (tree, path8) == NULL); 01857 01858 _dbus_assert (!find_subtree (tree, path0, NULL)); 01859 _dbus_assert (!find_subtree (tree, path1, NULL)); 01860 _dbus_assert (!find_subtree (tree, path2, NULL)); 01861 _dbus_assert (!find_subtree (tree, path3, NULL)); 01862 _dbus_assert (!find_subtree (tree, path4, NULL)); 01863 _dbus_assert (!find_subtree (tree, path5, NULL)); 01864 _dbus_assert (!find_subtree (tree, path6, NULL)); 01865 _dbus_assert (!find_subtree (tree, path7, NULL)); 01866 _dbus_assert (!find_subtree (tree, path8, NULL)); 01867 01868 i = 0; 01869 while (i < (int) _DBUS_N_ELEMENTS (tree_test_data)) 01870 { 01871 _dbus_assert (tree_test_data[i].handler_unregistered); 01872 _dbus_assert (!tree_test_data[i].message_handled); 01873 ++i; 01874 } 01875 01876 /* Register it all again, and test dispatch */ 01877 01878 if (!do_register (tree, path0, TRUE, 0, tree_test_data)) 01879 goto out; 01880 if (!do_register (tree, path1, FALSE, 1, tree_test_data)) 01881 goto out; 01882 if (!do_register (tree, path2, TRUE, 2, tree_test_data)) 01883 goto out; 01884 if (!do_register (tree, path3, TRUE, 3, tree_test_data)) 01885 goto out; 01886 if (!do_register (tree, path4, TRUE, 4, tree_test_data)) 01887 goto out; 01888 if (!do_register (tree, path5, TRUE, 5, tree_test_data)) 01889 goto out; 01890 if (!do_register (tree, path6, FALSE, 6, tree_test_data)) 01891 goto out; 01892 if (!do_register (tree, path7, TRUE, 7, tree_test_data)) 01893 goto out; 01894 if (!do_register (tree, path8, TRUE, 8, tree_test_data)) 01895 goto out; 01896 01897 #if 0 01898 spew_tree (tree); 01899 #endif 01900 01901 if (!do_test_dispatch (tree, path0, 0, tree_test_data, _DBUS_N_ELEMENTS (tree_test_data))) 01902 goto out; 01903 if (!do_test_dispatch (tree, path1, 1, tree_test_data, _DBUS_N_ELEMENTS (tree_test_data))) 01904 goto out; 01905 if (!do_test_dispatch (tree, path2, 2, tree_test_data, _DBUS_N_ELEMENTS (tree_test_data))) 01906 goto out; 01907 if (!do_test_dispatch (tree, path3, 3, tree_test_data, _DBUS_N_ELEMENTS (tree_test_data))) 01908 goto out; 01909 if (!do_test_dispatch (tree, path4, 4, tree_test_data, _DBUS_N_ELEMENTS (tree_test_data))) 01910 goto out; 01911 if (!do_test_dispatch (tree, path5, 5, tree_test_data, _DBUS_N_ELEMENTS (tree_test_data))) 01912 goto out; 01913 if (!do_test_dispatch (tree, path6, 6, tree_test_data, _DBUS_N_ELEMENTS (tree_test_data))) 01914 goto out; 01915 if (!do_test_dispatch (tree, path7, 7, tree_test_data, _DBUS_N_ELEMENTS (tree_test_data))) 01916 goto out; 01917 if (!do_test_dispatch (tree, path8, 8, tree_test_data, _DBUS_N_ELEMENTS (tree_test_data))) 01918 goto out; 01919 01920 out: 01921 if (tree) 01922 { 01923 /* test ref */ 01924 _dbus_object_tree_ref (tree); 01925 _dbus_object_tree_unref (tree); 01926 _dbus_object_tree_unref (tree); 01927 } 01928 01929 return TRUE; 01930 } 01931 01937 dbus_bool_t 01938 _dbus_object_tree_test (void) 01939 { 01940 _dbus_test_oom_handling ("object tree", 01941 object_tree_test_iteration, 01942 NULL); 01943 01944 return TRUE; 01945 } 01946 01947 #endif /* !DOXYGEN_SHOULD_SKIP_THIS */ 01948 01949 #endif /* DBUS_BUILD_TESTS */