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