D-Bus 1.6.12
|
00001 /* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ 00002 /* dbus-object-tree.c DBusObjectTree (internals of DBusConnection) 00003 * 00004 * Copyright (C) 2003, 2005 Red Hat Inc. 00005 * 00006 * Licensed under the Academic Free License version 2.1 00007 * 00008 * This program is free software; you can redistribute it and/or modify 00009 * it under the terms of the GNU General Public License as published by 00010 * the Free Software Foundation; either version 2 of the License, or 00011 * (at your option) any later version. 00012 * 00013 * This program is distributed in the hope that it will be useful, 00014 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00015 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00016 * GNU General Public License for more details. 00017 * 00018 * You should have received a copy of the GNU General Public License 00019 * along with this program; if not, write to the Free Software 00020 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 00021 * 00022 */ 00023 00024 #include <config.h> 00025 #include "dbus-object-tree.h" 00026 #include "dbus-connection-internal.h" 00027 #include "dbus-internals.h" 00028 #include "dbus-hash.h" 00029 #include "dbus-protocol.h" 00030 #include "dbus-string.h" 00031 #include <string.h> 00032 #include <stdlib.h> 00033 00046 typedef struct DBusObjectSubtree DBusObjectSubtree; 00047 00048 static DBusObjectSubtree* _dbus_object_subtree_new (const char *name, 00049 const DBusObjectPathVTable *vtable, 00050 void *user_data); 00051 static DBusObjectSubtree* _dbus_object_subtree_ref (DBusObjectSubtree *subtree); 00052 static void _dbus_object_subtree_unref (DBusObjectSubtree *subtree); 00053 00057 struct DBusObjectTree 00058 { 00059 int refcount; 00060 DBusConnection *connection; 00062 DBusObjectSubtree *root; 00063 }; 00064 00070 struct DBusObjectSubtree 00071 { 00072 DBusAtomic refcount; 00073 DBusObjectSubtree *parent; 00074 DBusObjectPathUnregisterFunction unregister_function; 00075 DBusObjectPathMessageFunction message_function; 00076 void *user_data; 00077 DBusObjectSubtree **subtrees; 00078 int n_subtrees; 00079 int max_subtrees; 00080 unsigned int invoke_as_fallback : 1; 00081 char name[1]; 00082 }; 00083 00091 DBusObjectTree* 00092 _dbus_object_tree_new (DBusConnection *connection) 00093 { 00094 DBusObjectTree *tree; 00095 00096 /* the connection passed in here isn't fully constructed, 00097 * so don't do anything more than store a pointer to 00098 * it 00099 */ 00100 00101 tree = dbus_new0 (DBusObjectTree, 1); 00102 if (tree == NULL) 00103 goto oom; 00104 00105 tree->refcount = 1; 00106 tree->connection = connection; 00107 tree->root = _dbus_object_subtree_new ("/", NULL, NULL); 00108 if (tree->root == NULL) 00109 goto oom; 00110 tree->root->invoke_as_fallback = TRUE; 00111 00112 return tree; 00113 00114 oom: 00115 if (tree) 00116 { 00117 dbus_free (tree); 00118 } 00119 00120 return NULL; 00121 } 00122 00128 DBusObjectTree * 00129 _dbus_object_tree_ref (DBusObjectTree *tree) 00130 { 00131 _dbus_assert (tree->refcount > 0); 00132 00133 tree->refcount += 1; 00134 00135 return tree; 00136 } 00137 00142 void 00143 _dbus_object_tree_unref (DBusObjectTree *tree) 00144 { 00145 _dbus_assert (tree->refcount > 0); 00146 00147 tree->refcount -= 1; 00148 00149 if (tree->refcount == 0) 00150 { 00151 _dbus_object_tree_free_all_unlocked (tree); 00152 00153 dbus_free (tree); 00154 } 00155 } 00156 00160 #define VERBOSE_FIND 0 00161 00162 static DBusObjectSubtree* 00163 find_subtree_recurse (DBusObjectSubtree *subtree, 00164 const char **path, 00165 dbus_bool_t create_if_not_found, 00166 int *index_in_parent, 00167 dbus_bool_t *exact_match) 00168 { 00169 int i, j; 00170 dbus_bool_t return_deepest_match; 00171 00172 return_deepest_match = exact_match != NULL; 00173 00174 _dbus_assert (!(return_deepest_match && create_if_not_found)); 00175 00176 if (path[0] == NULL) 00177 { 00178 #if VERBOSE_FIND 00179 _dbus_verbose (" path exhausted, returning %s\n", 00180 subtree->name); 00181 #endif 00182 if (exact_match != NULL) 00183 *exact_match = TRUE; 00184 return subtree; 00185 } 00186 00187 #if VERBOSE_FIND 00188 _dbus_verbose (" searching children of %s for %s\n", 00189 subtree->name, path[0]); 00190 #endif 00191 00192 i = 0; 00193 j = subtree->n_subtrees; 00194 while (i < j) 00195 { 00196 int k, v; 00197 00198 k = (i + j) / 2; 00199 v = strcmp (path[0], subtree->subtrees[k]->name); 00200 00201 #if VERBOSE_FIND 00202 _dbus_verbose (" %s cmp %s = %d\n", 00203 path[0], subtree->subtrees[k]->name, 00204 v); 00205 #endif 00206 00207 if (v == 0) 00208 { 00209 if (index_in_parent) 00210 { 00211 #if VERBOSE_FIND 00212 _dbus_verbose (" storing parent index %d\n", k); 00213 #endif 00214 *index_in_parent = k; 00215 } 00216 00217 if (return_deepest_match) 00218 { 00219 DBusObjectSubtree *next; 00220 00221 next = find_subtree_recurse (subtree->subtrees[k], 00222 &path[1], create_if_not_found, 00223 index_in_parent, exact_match); 00224 if (next == NULL && 00225 subtree->invoke_as_fallback) 00226 { 00227 #if VERBOSE_FIND 00228 _dbus_verbose (" no deeper match found, returning %s\n", 00229 subtree->name); 00230 #endif 00231 if (exact_match != NULL) 00232 *exact_match = FALSE; 00233 return subtree; 00234 } 00235 else 00236 return next; 00237 } 00238 else 00239 return find_subtree_recurse (subtree->subtrees[k], 00240 &path[1], create_if_not_found, 00241 index_in_parent, exact_match); 00242 } 00243 else if (v < 0) 00244 { 00245 j = k; 00246 } 00247 else 00248 { 00249 i = k + 1; 00250 } 00251 } 00252 00253 #if VERBOSE_FIND 00254 _dbus_verbose (" no match found, current tree %s, create_if_not_found = %d\n", 00255 subtree->name, create_if_not_found); 00256 #endif 00257 00258 if (create_if_not_found) 00259 { 00260 DBusObjectSubtree* child; 00261 int child_pos, new_n_subtrees; 00262 00263 #if VERBOSE_FIND 00264 _dbus_verbose (" creating subtree %s\n", 00265 path[0]); 00266 #endif 00267 00268 child = _dbus_object_subtree_new (path[0], 00269 NULL, NULL); 00270 if (child == NULL) 00271 return NULL; 00272 00273 new_n_subtrees = subtree->n_subtrees + 1; 00274 if (new_n_subtrees > subtree->max_subtrees) 00275 { 00276 int new_max_subtrees; 00277 DBusObjectSubtree **new_subtrees; 00278 00279 new_max_subtrees = subtree->max_subtrees == 0 ? 1 : 2 * subtree->max_subtrees; 00280 new_subtrees = dbus_realloc (subtree->subtrees, 00281 new_max_subtrees * sizeof (DBusObjectSubtree*)); 00282 if (new_subtrees == NULL) 00283 { 00284 _dbus_object_subtree_unref (child); 00285 return NULL; 00286 } 00287 subtree->subtrees = new_subtrees; 00288 subtree->max_subtrees = new_max_subtrees; 00289 } 00290 00291 /* The binary search failed, so i == j points to the 00292 place the child should be inserted. */ 00293 child_pos = i; 00294 _dbus_assert (child_pos < new_n_subtrees && 00295 new_n_subtrees <= subtree->max_subtrees); 00296 if (child_pos + 1 < new_n_subtrees) 00297 { 00298 memmove (&subtree->subtrees[child_pos+1], 00299 &subtree->subtrees[child_pos], 00300 (new_n_subtrees - child_pos - 1) * 00301 sizeof subtree->subtrees[0]); 00302 } 00303 subtree->subtrees[child_pos] = child; 00304 00305 if (index_in_parent) 00306 *index_in_parent = child_pos; 00307 subtree->n_subtrees = new_n_subtrees; 00308 child->parent = subtree; 00309 00310 return find_subtree_recurse (child, 00311 &path[1], create_if_not_found, 00312 index_in_parent, exact_match); 00313 } 00314 else 00315 { 00316 if (exact_match != NULL) 00317 *exact_match = FALSE; 00318 return (return_deepest_match && subtree->invoke_as_fallback) ? subtree : NULL; 00319 } 00320 } 00321 00322 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 dbus_bool_t *found_object) 00750 { 00751 char **path; 00752 dbus_bool_t exact_match; 00753 DBusList *list; 00754 DBusList *link; 00755 DBusHandlerResult result; 00756 DBusObjectSubtree *subtree; 00757 00758 #if 0 00759 _dbus_verbose ("Dispatch of message by object path\n"); 00760 #endif 00761 00762 path = NULL; 00763 if (!dbus_message_get_path_decomposed (message, &path)) 00764 { 00765 #ifdef DBUS_BUILD_TESTS 00766 if (tree->connection) 00767 #endif 00768 { 00769 _dbus_verbose ("unlock\n"); 00770 _dbus_connection_unlock (tree->connection); 00771 } 00772 00773 _dbus_verbose ("No memory to get decomposed path\n"); 00774 00775 return DBUS_HANDLER_RESULT_NEED_MEMORY; 00776 } 00777 00778 if (path == NULL) 00779 { 00780 #ifdef DBUS_BUILD_TESTS 00781 if (tree->connection) 00782 #endif 00783 { 00784 _dbus_verbose ("unlock\n"); 00785 _dbus_connection_unlock (tree->connection); 00786 } 00787 00788 _dbus_verbose ("No path field in message\n"); 00789 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; 00790 } 00791 00792 /* Find the deepest path that covers the path in the message */ 00793 subtree = find_handler (tree, (const char**) path, &exact_match); 00794 00795 if (found_object) 00796 *found_object = !!subtree; 00797 00798 /* Build a list of all paths that cover the path in the message */ 00799 00800 list = NULL; 00801 00802 while (subtree != NULL) 00803 { 00804 if (subtree->message_function != NULL && (exact_match || subtree->invoke_as_fallback)) 00805 { 00806 _dbus_object_subtree_ref (subtree); 00807 00808 /* run deepest paths first */ 00809 if (!_dbus_list_append (&list, subtree)) 00810 { 00811 result = DBUS_HANDLER_RESULT_NEED_MEMORY; 00812 _dbus_object_subtree_unref (subtree); 00813 goto free_and_return; 00814 } 00815 } 00816 00817 exact_match = FALSE; 00818 subtree = subtree->parent; 00819 } 00820 00821 _dbus_verbose ("%d handlers in the path tree for this message\n", 00822 _dbus_list_get_length (&list)); 00823 00824 /* Invoke each handler in the list */ 00825 00826 result = DBUS_HANDLER_RESULT_NOT_YET_HANDLED; 00827 00828 link = _dbus_list_get_first_link (&list); 00829 while (link != NULL) 00830 { 00831 DBusList *next = _dbus_list_get_next_link (&list, link); 00832 subtree = link->data; 00833 00834 /* message_function is NULL if we're unregistered 00835 * due to reentrancy 00836 */ 00837 if (subtree->message_function) 00838 { 00839 DBusObjectPathMessageFunction message_function; 00840 void *user_data; 00841 00842 message_function = subtree->message_function; 00843 user_data = subtree->user_data; 00844 00845 #if 0 00846 _dbus_verbose (" (invoking a handler)\n"); 00847 #endif 00848 00849 #ifdef DBUS_BUILD_TESTS 00850 if (tree->connection) 00851 #endif 00852 { 00853 _dbus_verbose ("unlock\n"); 00854 _dbus_connection_unlock (tree->connection); 00855 } 00856 00857 /* FIXME you could unregister the subtree in another thread 00858 * before we invoke the callback, and I can't figure out a 00859 * good way to solve this. 00860 */ 00861 00862 result = (* message_function) (tree->connection, 00863 message, 00864 user_data); 00865 00866 #ifdef DBUS_BUILD_TESTS 00867 if (tree->connection) 00868 #endif 00869 _dbus_connection_lock (tree->connection); 00870 00871 if (result != DBUS_HANDLER_RESULT_NOT_YET_HANDLED) 00872 goto free_and_return; 00873 } 00874 00875 link = next; 00876 } 00877 00878 free_and_return: 00879 00880 if (result == DBUS_HANDLER_RESULT_NOT_YET_HANDLED) 00881 { 00882 /* This hardcoded default handler does a minimal Introspect() 00883 */ 00884 result = handle_default_introspect_and_unlock (tree, message, 00885 (const char**) path); 00886 } 00887 else 00888 { 00889 #ifdef DBUS_BUILD_TESTS 00890 if (tree->connection) 00891 #endif 00892 { 00893 _dbus_verbose ("unlock\n"); 00894 _dbus_connection_unlock (tree->connection); 00895 } 00896 } 00897 00898 while (list != NULL) 00899 { 00900 link = _dbus_list_get_first_link (&list); 00901 _dbus_object_subtree_unref (link->data); 00902 _dbus_list_remove_link (&list, link); 00903 } 00904 00905 dbus_free_string_array (path); 00906 00907 return result; 00908 } 00909 00918 void* 00919 _dbus_object_tree_get_user_data_unlocked (DBusObjectTree *tree, 00920 const char **path) 00921 { 00922 dbus_bool_t exact_match; 00923 DBusObjectSubtree *subtree; 00924 00925 _dbus_assert (tree != NULL); 00926 _dbus_assert (path != NULL); 00927 00928 /* Find the deepest path that covers the path in the message */ 00929 subtree = find_handler (tree, (const char**) path, &exact_match); 00930 00931 if ((subtree == NULL) || !exact_match) 00932 { 00933 _dbus_verbose ("No object at specified path found\n"); 00934 return NULL; 00935 } 00936 00937 return subtree->user_data; 00938 } 00939 00946 static DBusObjectSubtree* 00947 allocate_subtree_object (const char *name) 00948 { 00949 int len; 00950 DBusObjectSubtree *subtree; 00951 const size_t front_padding = _DBUS_STRUCT_OFFSET (DBusObjectSubtree, name); 00952 00953 _dbus_assert (name != NULL); 00954 00955 len = strlen (name); 00956 00957 subtree = dbus_malloc0 (MAX (front_padding + (len + 1), sizeof (DBusObjectSubtree))); 00958 00959 if (subtree == NULL) 00960 return NULL; 00961 00962 memcpy (subtree->name, name, len + 1); 00963 00964 return subtree; 00965 } 00966 00967 static DBusObjectSubtree* 00968 _dbus_object_subtree_new (const char *name, 00969 const DBusObjectPathVTable *vtable, 00970 void *user_data) 00971 { 00972 DBusObjectSubtree *subtree; 00973 00974 subtree = allocate_subtree_object (name); 00975 if (subtree == NULL) 00976 goto oom; 00977 00978 _dbus_assert (name != NULL); 00979 00980 subtree->parent = NULL; 00981 00982 if (vtable) 00983 { 00984 subtree->message_function = vtable->message_function; 00985 subtree->unregister_function = vtable->unregister_function; 00986 } 00987 else 00988 { 00989 subtree->message_function = NULL; 00990 subtree->unregister_function = NULL; 00991 } 00992 00993 subtree->user_data = user_data; 00994 _dbus_atomic_inc (&subtree->refcount); 00995 subtree->subtrees = NULL; 00996 subtree->n_subtrees = 0; 00997 subtree->max_subtrees = 0; 00998 subtree->invoke_as_fallback = FALSE; 00999 01000 return subtree; 01001 01002 oom: 01003 return NULL; 01004 } 01005 01006 static DBusObjectSubtree * 01007 _dbus_object_subtree_ref (DBusObjectSubtree *subtree) 01008 { 01009 #ifdef DBUS_DISABLE_ASSERT 01010 _dbus_atomic_inc (&subtree->refcount); 01011 #else 01012 dbus_int32_t old_value; 01013 01014 old_value = _dbus_atomic_inc (&subtree->refcount); 01015 _dbus_assert (old_value > 0); 01016 #endif 01017 01018 return subtree; 01019 } 01020 01021 static void 01022 _dbus_object_subtree_unref (DBusObjectSubtree *subtree) 01023 { 01024 dbus_int32_t old_value; 01025 01026 old_value = _dbus_atomic_dec (&subtree->refcount); 01027 _dbus_assert (old_value > 0); 01028 01029 if (old_value == 1) 01030 { 01031 _dbus_assert (subtree->unregister_function == NULL); 01032 _dbus_assert (subtree->message_function == NULL); 01033 01034 dbus_free (subtree->subtrees); 01035 dbus_free (subtree); 01036 } 01037 } 01038 01049 dbus_bool_t 01050 _dbus_object_tree_list_registered_and_unlock (DBusObjectTree *tree, 01051 const char **parent_path, 01052 char ***child_entries) 01053 { 01054 dbus_bool_t result; 01055 01056 result = _dbus_object_tree_list_registered_unlocked (tree, 01057 parent_path, 01058 child_entries); 01059 01060 #ifdef DBUS_BUILD_TESTS 01061 if (tree->connection) 01062 #endif 01063 { 01064 _dbus_verbose ("unlock\n"); 01065 _dbus_connection_unlock (tree->connection); 01066 } 01067 01068 return result; 01069 } 01070 01071 01073 #define VERBOSE_DECOMPOSE 0 01074 01085 dbus_bool_t 01086 _dbus_decompose_path (const char* data, 01087 int len, 01088 char ***path, 01089 int *path_len) 01090 { 01091 char **retval; 01092 int n_components; 01093 int i, j, comp; 01094 01095 _dbus_assert (data != NULL); 01096 _dbus_assert (path != NULL); 01097 01098 #if VERBOSE_DECOMPOSE 01099 _dbus_verbose ("Decomposing path \"%s\"\n", 01100 data); 01101 #endif 01102 01103 n_components = 0; 01104 if (len > 1) /* if path is not just "/" */ 01105 { 01106 i = 0; 01107 while (i < len) 01108 { 01109 _dbus_assert (data[i] != '\0'); 01110 if (data[i] == '/') 01111 n_components += 1; 01112 ++i; 01113 } 01114 } 01115 01116 retval = dbus_new0 (char*, n_components + 1); 01117 01118 if (retval == NULL) 01119 return FALSE; 01120 01121 comp = 0; 01122 if (n_components == 0) 01123 i = 1; 01124 else 01125 i = 0; 01126 while (comp < n_components) 01127 { 01128 _dbus_assert (i < len); 01129 01130 if (data[i] == '/') 01131 ++i; 01132 j = i; 01133 01134 while (j < len && data[j] != '/') 01135 ++j; 01136 01137 /* Now [i, j) is the path component */ 01138 _dbus_assert (i < j); 01139 _dbus_assert (data[i] != '/'); 01140 _dbus_assert (j == len || data[j] == '/'); 01141 01142 #if VERBOSE_DECOMPOSE 01143 _dbus_verbose (" (component in [%d,%d))\n", 01144 i, j); 01145 #endif 01146 01147 retval[comp] = _dbus_memdup (&data[i], j - i + 1); 01148 if (retval[comp] == NULL) 01149 { 01150 dbus_free_string_array (retval); 01151 return FALSE; 01152 } 01153 retval[comp][j-i] = '\0'; 01154 #if VERBOSE_DECOMPOSE 01155 _dbus_verbose (" (component %d = \"%s\")\n", 01156 comp, retval[comp]); 01157 #endif 01158 01159 ++comp; 01160 i = j; 01161 } 01162 _dbus_assert (i == len); 01163 01164 *path = retval; 01165 if (path_len) 01166 *path_len = n_components; 01167 01168 return TRUE; 01169 } 01170 01173 static char* 01174 flatten_path (const char **path) 01175 { 01176 DBusString str; 01177 char *s; 01178 01179 if (!_dbus_string_init (&str)) 01180 return NULL; 01181 01182 if (path[0] == NULL) 01183 { 01184 if (!_dbus_string_append_byte (&str, '/')) 01185 goto nomem; 01186 } 01187 else 01188 { 01189 int i; 01190 01191 i = 0; 01192 while (path[i]) 01193 { 01194 if (!_dbus_string_append_byte (&str, '/')) 01195 goto nomem; 01196 01197 if (!_dbus_string_append (&str, path[i])) 01198 goto nomem; 01199 01200 ++i; 01201 } 01202 } 01203 01204 if (!_dbus_string_steal_data (&str, &s)) 01205 goto nomem; 01206 01207 _dbus_string_free (&str); 01208 01209 return s; 01210 01211 nomem: 01212 _dbus_string_free (&str); 01213 return NULL; 01214 } 01215 01216 01217 #ifdef DBUS_BUILD_TESTS 01218 01219 #ifndef DOXYGEN_SHOULD_SKIP_THIS 01220 01221 #include "dbus-test.h" 01222 #include <stdio.h> 01223 01224 typedef enum 01225 { 01226 STR_EQUAL, 01227 STR_PREFIX, 01228 STR_DIFFERENT 01229 } StrComparison; 01230 01231 /* Returns TRUE if container is a parent of child 01232 */ 01233 static StrComparison 01234 path_contains (const char **container, 01235 const char **child) 01236 { 01237 int i; 01238 01239 i = 0; 01240 while (child[i] != NULL) 01241 { 01242 int v; 01243 01244 if (container[i] == NULL) 01245 return STR_PREFIX; /* container ran out, child continues; 01246 * thus the container is a parent of the 01247 * child. 01248 */ 01249 01250 _dbus_assert (container[i] != NULL); 01251 _dbus_assert (child[i] != NULL); 01252 01253 v = strcmp (container[i], child[i]); 01254 01255 if (v != 0) 01256 return STR_DIFFERENT; /* they overlap until here and then are different, 01257 * not overlapping 01258 */ 01259 01260 ++i; 01261 } 01262 01263 /* Child ran out; if container also did, they are equal; 01264 * otherwise, the child is a parent of the container. 01265 */ 01266 if (container[i] == NULL) 01267 return STR_EQUAL; 01268 else 01269 return STR_DIFFERENT; 01270 } 01271 01272 #if 0 01273 static void 01274 spew_subtree_recurse (DBusObjectSubtree *subtree, 01275 int indent) 01276 { 01277 int i; 01278 01279 i = 0; 01280 while (i < indent) 01281 { 01282 _dbus_verbose (" "); 01283 ++i; 01284 } 01285 01286 _dbus_verbose ("%s (%d children)\n", 01287 subtree->name, subtree->n_subtrees); 01288 01289 i = 0; 01290 while (i < subtree->n_subtrees) 01291 { 01292 spew_subtree_recurse (subtree->subtrees[i], indent + 2); 01293 01294 ++i; 01295 } 01296 } 01297 01298 static void 01299 spew_tree (DBusObjectTree *tree) 01300 { 01301 spew_subtree_recurse (tree->root, 0); 01302 } 01303 #endif 01304 01308 typedef struct 01309 { 01310 const char **path; 01311 dbus_bool_t handler_fallback; 01312 dbus_bool_t message_handled; 01313 dbus_bool_t handler_unregistered; 01314 } TreeTestData; 01315 01316 01317 static void 01318 test_unregister_function (DBusConnection *connection, 01319 void *user_data) 01320 { 01321 TreeTestData *ttd = user_data; 01322 01323 ttd->handler_unregistered = TRUE; 01324 } 01325 01326 static DBusHandlerResult 01327 test_message_function (DBusConnection *connection, 01328 DBusMessage *message, 01329 void *user_data) 01330 { 01331 TreeTestData *ttd = user_data; 01332 01333 ttd->message_handled = TRUE; 01334 01335 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; 01336 } 01337 01338 static dbus_bool_t 01339 do_register (DBusObjectTree *tree, 01340 const char **path, 01341 dbus_bool_t fallback, 01342 int i, 01343 TreeTestData *tree_test_data) 01344 { 01345 DBusObjectPathVTable vtable = { test_unregister_function, 01346 test_message_function, NULL }; 01347 01348 tree_test_data[i].message_handled = FALSE; 01349 tree_test_data[i].handler_unregistered = FALSE; 01350 tree_test_data[i].handler_fallback = fallback; 01351 tree_test_data[i].path = path; 01352 01353 if (!_dbus_object_tree_register (tree, fallback, path, 01354 &vtable, 01355 &tree_test_data[i], 01356 NULL)) 01357 return FALSE; 01358 01359 _dbus_assert (_dbus_object_tree_get_user_data_unlocked (tree, path) == 01360 &tree_test_data[i]); 01361 01362 return TRUE; 01363 } 01364 01365 static dbus_bool_t 01366 do_test_dispatch (DBusObjectTree *tree, 01367 const char **path, 01368 int i, 01369 TreeTestData *tree_test_data, 01370 int n_test_data) 01371 { 01372 DBusMessage *message; 01373 int j; 01374 DBusHandlerResult result; 01375 char *flat; 01376 01377 message = NULL; 01378 01379 flat = flatten_path (path); 01380 if (flat == NULL) 01381 goto oom; 01382 01383 message = dbus_message_new_method_call (NULL, 01384 flat, 01385 "org.freedesktop.TestInterface", 01386 "Foo"); 01387 dbus_free (flat); 01388 if (message == NULL) 01389 goto oom; 01390 01391 j = 0; 01392 while (j < n_test_data) 01393 { 01394 tree_test_data[j].message_handled = FALSE; 01395 ++j; 01396 } 01397 01398 result = _dbus_object_tree_dispatch_and_unlock (tree, message, NULL); 01399 if (result == DBUS_HANDLER_RESULT_NEED_MEMORY) 01400 goto oom; 01401 01402 _dbus_assert (tree_test_data[i].message_handled); 01403 01404 j = 0; 01405 while (j < n_test_data) 01406 { 01407 if (tree_test_data[j].message_handled) 01408 { 01409 if (tree_test_data[j].handler_fallback) 01410 _dbus_assert (path_contains (tree_test_data[j].path, 01411 path) != STR_DIFFERENT); 01412 else 01413 _dbus_assert (path_contains (tree_test_data[j].path, path) == STR_EQUAL); 01414 } 01415 else 01416 { 01417 if (tree_test_data[j].handler_fallback) 01418 _dbus_assert (path_contains (tree_test_data[j].path, 01419 path) == STR_DIFFERENT); 01420 else 01421 _dbus_assert (path_contains (tree_test_data[j].path, path) != STR_EQUAL); 01422 } 01423 01424 ++j; 01425 } 01426 01427 dbus_message_unref (message); 01428 01429 return TRUE; 01430 01431 oom: 01432 if (message) 01433 dbus_message_unref (message); 01434 return FALSE; 01435 } 01436 01437 static size_t 01438 string_array_length (const char **array) 01439 { 01440 size_t i; 01441 for (i = 0; array[i]; i++) ; 01442 return i; 01443 } 01444 01445 typedef struct 01446 { 01447 const char *path; 01448 const char *result[20]; 01449 } DecomposePathTest; 01450 01451 static DecomposePathTest decompose_tests[] = { 01452 { "/foo", { "foo", NULL } }, 01453 { "/foo/bar", { "foo", "bar", NULL } }, 01454 { "/", { NULL } }, 01455 { "/a/b", { "a", "b", NULL } }, 01456 { "/a/b/c", { "a", "b", "c", NULL } }, 01457 { "/a/b/c/d", { "a", "b", "c", "d", NULL } }, 01458 { "/foo/bar/q", { "foo", "bar", "q", NULL } }, 01459 { "/foo/bar/this/is/longer", { "foo", "bar", "this", "is", "longer", NULL } } 01460 }; 01461 01462 static dbus_bool_t 01463 run_decompose_tests (void) 01464 { 01465 int i; 01466 01467 i = 0; 01468 while (i < _DBUS_N_ELEMENTS (decompose_tests)) 01469 { 01470 char **result; 01471 int result_len; 01472 int expected_len; 01473 01474 if (!_dbus_decompose_path (decompose_tests[i].path, 01475 strlen (decompose_tests[i].path), 01476 &result, &result_len)) 01477 return FALSE; 01478 01479 expected_len = string_array_length (decompose_tests[i].result); 01480 01481 if (result_len != (int) string_array_length ((const char**)result) || 01482 expected_len != result_len || 01483 path_contains (decompose_tests[i].result, 01484 (const char**) result) != STR_EQUAL) 01485 { 01486 int real_len = string_array_length ((const char**)result); 01487 _dbus_warn ("Expected decompose of %s to have len %d, returned %d, appears to have %d\n", 01488 decompose_tests[i].path, expected_len, result_len, 01489 real_len); 01490 _dbus_warn ("Decompose resulted in elements: { "); 01491 i = 0; 01492 while (i < real_len) 01493 { 01494 _dbus_warn ("\"%s\"%s", result[i], 01495 (i + 1) == real_len ? "" : ", "); 01496 ++i; 01497 } 01498 _dbus_warn ("}\n"); 01499 _dbus_assert_not_reached ("path decompose failed\n"); 01500 } 01501 01502 dbus_free_string_array (result); 01503 01504 ++i; 01505 } 01506 01507 return TRUE; 01508 } 01509 01510 static dbus_bool_t 01511 object_tree_test_iteration (void *data) 01512 { 01513 const char *path0[] = { NULL }; 01514 const char *path1[] = { "foo", NULL }; 01515 const char *path2[] = { "foo", "bar", NULL }; 01516 const char *path3[] = { "foo", "bar", "baz", NULL }; 01517 const char *path4[] = { "foo", "bar", "boo", NULL }; 01518 const char *path5[] = { "blah", NULL }; 01519 const char *path6[] = { "blah", "boof", NULL }; 01520 const char *path7[] = { "blah", "boof", "this", "is", "really", "long", NULL }; 01521 const char *path8[] = { "childless", NULL }; 01522 DBusObjectTree *tree; 01523 TreeTestData tree_test_data[9]; 01524 int i; 01525 dbus_bool_t exact_match; 01526 01527 if (!run_decompose_tests ()) 01528 return FALSE; 01529 01530 tree = NULL; 01531 01532 tree = _dbus_object_tree_new (NULL); 01533 if (tree == NULL) 01534 goto out; 01535 01536 if (!do_register (tree, path0, TRUE, 0, tree_test_data)) 01537 goto out; 01538 01539 _dbus_assert (find_subtree (tree, path0, NULL)); 01540 _dbus_assert (!find_subtree (tree, path1, NULL)); 01541 _dbus_assert (!find_subtree (tree, path2, NULL)); 01542 _dbus_assert (!find_subtree (tree, path3, NULL)); 01543 _dbus_assert (!find_subtree (tree, path4, NULL)); 01544 _dbus_assert (!find_subtree (tree, path5, NULL)); 01545 _dbus_assert (!find_subtree (tree, path6, NULL)); 01546 _dbus_assert (!find_subtree (tree, path7, NULL)); 01547 _dbus_assert (!find_subtree (tree, path8, NULL)); 01548 01549 _dbus_assert (find_handler (tree, path0, &exact_match) && exact_match); 01550 _dbus_assert (find_handler (tree, path1, &exact_match) == tree->root && !exact_match); 01551 _dbus_assert (find_handler (tree, path2, &exact_match) == tree->root && !exact_match); 01552 _dbus_assert (find_handler (tree, path3, &exact_match) == tree->root && !exact_match); 01553 _dbus_assert (find_handler (tree, path4, &exact_match) == tree->root && !exact_match); 01554 _dbus_assert (find_handler (tree, path5, &exact_match) == tree->root && !exact_match); 01555 _dbus_assert (find_handler (tree, path6, &exact_match) == tree->root && !exact_match); 01556 _dbus_assert (find_handler (tree, path7, &exact_match) == tree->root && !exact_match); 01557 _dbus_assert (find_handler (tree, path8, &exact_match) == tree->root && !exact_match); 01558 01559 if (!do_register (tree, path1, TRUE, 1, tree_test_data)) 01560 goto out; 01561 01562 _dbus_assert (find_subtree (tree, path0, NULL)); 01563 _dbus_assert (find_subtree (tree, path1, NULL)); 01564 _dbus_assert (!find_subtree (tree, path2, NULL)); 01565 _dbus_assert (!find_subtree (tree, path3, NULL)); 01566 _dbus_assert (!find_subtree (tree, path4, NULL)); 01567 _dbus_assert (!find_subtree (tree, path5, NULL)); 01568 _dbus_assert (!find_subtree (tree, path6, NULL)); 01569 _dbus_assert (!find_subtree (tree, path7, NULL)); 01570 _dbus_assert (!find_subtree (tree, path8, NULL)); 01571 01572 _dbus_assert (find_handler (tree, path0, &exact_match) && exact_match); 01573 _dbus_assert (find_handler (tree, path1, &exact_match) && exact_match); 01574 _dbus_assert (find_handler (tree, path2, &exact_match) && !exact_match); 01575 _dbus_assert (find_handler (tree, path3, &exact_match) && !exact_match); 01576 _dbus_assert (find_handler (tree, path4, &exact_match) && !exact_match); 01577 _dbus_assert (find_handler (tree, path5, &exact_match) == tree->root && !exact_match); 01578 _dbus_assert (find_handler (tree, path6, &exact_match) == tree->root && !exact_match); 01579 _dbus_assert (find_handler (tree, path7, &exact_match) == tree->root && !exact_match); 01580 _dbus_assert (find_handler (tree, path8, &exact_match) == tree->root && !exact_match); 01581 01582 if (!do_register (tree, path2, TRUE, 2, tree_test_data)) 01583 goto out; 01584 01585 _dbus_assert (find_subtree (tree, path1, NULL)); 01586 _dbus_assert (find_subtree (tree, path2, NULL)); 01587 _dbus_assert (!find_subtree (tree, path3, NULL)); 01588 _dbus_assert (!find_subtree (tree, path4, NULL)); 01589 _dbus_assert (!find_subtree (tree, path5, NULL)); 01590 _dbus_assert (!find_subtree (tree, path6, NULL)); 01591 _dbus_assert (!find_subtree (tree, path7, NULL)); 01592 _dbus_assert (!find_subtree (tree, path8, NULL)); 01593 01594 if (!do_register (tree, path3, TRUE, 3, tree_test_data)) 01595 goto out; 01596 01597 _dbus_assert (find_subtree (tree, path0, NULL)); 01598 _dbus_assert (find_subtree (tree, path1, NULL)); 01599 _dbus_assert (find_subtree (tree, path2, NULL)); 01600 _dbus_assert (find_subtree (tree, path3, NULL)); 01601 _dbus_assert (!find_subtree (tree, path4, NULL)); 01602 _dbus_assert (!find_subtree (tree, path5, NULL)); 01603 _dbus_assert (!find_subtree (tree, path6, NULL)); 01604 _dbus_assert (!find_subtree (tree, path7, NULL)); 01605 _dbus_assert (!find_subtree (tree, path8, NULL)); 01606 01607 if (!do_register (tree, path4, TRUE, 4, tree_test_data)) 01608 goto out; 01609 01610 _dbus_assert (find_subtree (tree, path0, NULL)); 01611 _dbus_assert (find_subtree (tree, path1, NULL)); 01612 _dbus_assert (find_subtree (tree, path2, NULL)); 01613 _dbus_assert (find_subtree (tree, path3, NULL)); 01614 _dbus_assert (find_subtree (tree, path4, NULL)); 01615 _dbus_assert (!find_subtree (tree, path5, NULL)); 01616 _dbus_assert (!find_subtree (tree, path6, NULL)); 01617 _dbus_assert (!find_subtree (tree, path7, NULL)); 01618 _dbus_assert (!find_subtree (tree, path8, NULL)); 01619 01620 if (!do_register (tree, path5, TRUE, 5, tree_test_data)) 01621 goto out; 01622 01623 _dbus_assert (find_subtree (tree, path0, NULL)); 01624 _dbus_assert (find_subtree (tree, path1, NULL)); 01625 _dbus_assert (find_subtree (tree, path2, NULL)); 01626 _dbus_assert (find_subtree (tree, path3, NULL)); 01627 _dbus_assert (find_subtree (tree, path4, NULL)); 01628 _dbus_assert (find_subtree (tree, path5, NULL)); 01629 _dbus_assert (!find_subtree (tree, path6, NULL)); 01630 _dbus_assert (!find_subtree (tree, path7, NULL)); 01631 _dbus_assert (!find_subtree (tree, path8, NULL)); 01632 01633 _dbus_assert (find_handler (tree, path0, &exact_match) == tree->root && exact_match); 01634 _dbus_assert (find_handler (tree, path1, &exact_match) != tree->root && exact_match); 01635 _dbus_assert (find_handler (tree, path2, &exact_match) != tree->root && exact_match); 01636 _dbus_assert (find_handler (tree, path3, &exact_match) != tree->root && exact_match); 01637 _dbus_assert (find_handler (tree, path4, &exact_match) != tree->root && exact_match); 01638 _dbus_assert (find_handler (tree, path5, &exact_match) != tree->root && exact_match); 01639 _dbus_assert (find_handler (tree, path6, &exact_match) != tree->root && !exact_match); 01640 _dbus_assert (find_handler (tree, path7, &exact_match) != tree->root && !exact_match); 01641 _dbus_assert (find_handler (tree, path8, &exact_match) == tree->root && !exact_match); 01642 01643 if (!do_register (tree, path6, TRUE, 6, tree_test_data)) 01644 goto out; 01645 01646 _dbus_assert (find_subtree (tree, path0, NULL)); 01647 _dbus_assert (find_subtree (tree, path1, NULL)); 01648 _dbus_assert (find_subtree (tree, path2, NULL)); 01649 _dbus_assert (find_subtree (tree, path3, NULL)); 01650 _dbus_assert (find_subtree (tree, path4, NULL)); 01651 _dbus_assert (find_subtree (tree, path5, NULL)); 01652 _dbus_assert (find_subtree (tree, path6, NULL)); 01653 _dbus_assert (!find_subtree (tree, path7, NULL)); 01654 _dbus_assert (!find_subtree (tree, path8, NULL)); 01655 01656 if (!do_register (tree, path7, TRUE, 7, tree_test_data)) 01657 goto out; 01658 01659 _dbus_assert (find_subtree (tree, path0, NULL)); 01660 _dbus_assert (find_subtree (tree, path1, NULL)); 01661 _dbus_assert (find_subtree (tree, path2, NULL)); 01662 _dbus_assert (find_subtree (tree, path3, NULL)); 01663 _dbus_assert (find_subtree (tree, path4, NULL)); 01664 _dbus_assert (find_subtree (tree, path5, NULL)); 01665 _dbus_assert (find_subtree (tree, path6, NULL)); 01666 _dbus_assert (find_subtree (tree, path7, NULL)); 01667 _dbus_assert (!find_subtree (tree, path8, NULL)); 01668 01669 if (!do_register (tree, path8, TRUE, 8, tree_test_data)) 01670 goto out; 01671 01672 _dbus_assert (find_subtree (tree, path0, NULL)); 01673 _dbus_assert (find_subtree (tree, path1, NULL)); 01674 _dbus_assert (find_subtree (tree, path2, NULL)); 01675 _dbus_assert (find_subtree (tree, path3, NULL)); 01676 _dbus_assert (find_subtree (tree, path4, NULL)); 01677 _dbus_assert (find_subtree (tree, path5, NULL)); 01678 _dbus_assert (find_subtree (tree, path6, NULL)); 01679 _dbus_assert (find_subtree (tree, path7, NULL)); 01680 _dbus_assert (find_subtree (tree, path8, NULL)); 01681 01682 _dbus_assert (find_handler (tree, path0, &exact_match) == tree->root && exact_match); 01683 _dbus_assert (find_handler (tree, path1, &exact_match) != tree->root && exact_match); 01684 _dbus_assert (find_handler (tree, path2, &exact_match) != tree->root && exact_match); 01685 _dbus_assert (find_handler (tree, path3, &exact_match) != tree->root && exact_match); 01686 _dbus_assert (find_handler (tree, path4, &exact_match) != tree->root && exact_match); 01687 _dbus_assert (find_handler (tree, path5, &exact_match) != tree->root && exact_match); 01688 _dbus_assert (find_handler (tree, path6, &exact_match) != tree->root && exact_match); 01689 _dbus_assert (find_handler (tree, path7, &exact_match) != tree->root && exact_match); 01690 _dbus_assert (find_handler (tree, path8, &exact_match) != tree->root && exact_match); 01691 01692 /* test the list_registered function */ 01693 01694 { 01695 const char *root[] = { NULL }; 01696 char **child_entries; 01697 int nb; 01698 01699 _dbus_object_tree_list_registered_unlocked (tree, path1, &child_entries); 01700 if (child_entries != NULL) 01701 { 01702 nb = string_array_length ((const char**)child_entries); 01703 _dbus_assert (nb == 1); 01704 dbus_free_string_array (child_entries); 01705 } 01706 01707 _dbus_object_tree_list_registered_unlocked (tree, path2, &child_entries); 01708 if (child_entries != NULL) 01709 { 01710 nb = string_array_length ((const char**)child_entries); 01711 _dbus_assert (nb == 2); 01712 dbus_free_string_array (child_entries); 01713 } 01714 01715 _dbus_object_tree_list_registered_unlocked (tree, path8, &child_entries); 01716 if (child_entries != NULL) 01717 { 01718 nb = string_array_length ((const char**)child_entries); 01719 _dbus_assert (nb == 0); 01720 dbus_free_string_array (child_entries); 01721 } 01722 01723 _dbus_object_tree_list_registered_unlocked (tree, root, &child_entries); 01724 if (child_entries != NULL) 01725 { 01726 nb = string_array_length ((const char**)child_entries); 01727 _dbus_assert (nb == 3); 01728 dbus_free_string_array (child_entries); 01729 } 01730 } 01731 01732 /* Check that destroying tree calls unregister funcs */ 01733 _dbus_object_tree_unref (tree); 01734 01735 i = 0; 01736 while (i < (int) _DBUS_N_ELEMENTS (tree_test_data)) 01737 { 01738 _dbus_assert (tree_test_data[i].handler_unregistered); 01739 _dbus_assert (!tree_test_data[i].message_handled); 01740 ++i; 01741 } 01742 01743 /* Now start again and try the individual unregister function */ 01744 tree = _dbus_object_tree_new (NULL); 01745 if (tree == NULL) 01746 goto out; 01747 01748 if (!do_register (tree, path0, TRUE, 0, tree_test_data)) 01749 goto out; 01750 if (!do_register (tree, path1, TRUE, 1, tree_test_data)) 01751 goto out; 01752 if (!do_register (tree, path2, TRUE, 2, tree_test_data)) 01753 goto out; 01754 if (!do_register (tree, path3, TRUE, 3, tree_test_data)) 01755 goto out; 01756 if (!do_register (tree, path4, TRUE, 4, tree_test_data)) 01757 goto out; 01758 if (!do_register (tree, path5, TRUE, 5, tree_test_data)) 01759 goto out; 01760 if (!do_register (tree, path6, TRUE, 6, tree_test_data)) 01761 goto out; 01762 if (!do_register (tree, path7, TRUE, 7, tree_test_data)) 01763 goto out; 01764 if (!do_register (tree, path8, TRUE, 8, tree_test_data)) 01765 goto out; 01766 01767 _dbus_object_tree_unregister_and_unlock (tree, path0); 01768 _dbus_assert (_dbus_object_tree_get_user_data_unlocked (tree, path0) == NULL); 01769 01770 _dbus_assert (!find_subtree (tree, path0, NULL)); 01771 _dbus_assert (find_subtree (tree, path1, NULL)); 01772 _dbus_assert (find_subtree (tree, path2, NULL)); 01773 _dbus_assert (find_subtree (tree, path3, NULL)); 01774 _dbus_assert (find_subtree (tree, path4, NULL)); 01775 _dbus_assert (find_subtree (tree, path5, NULL)); 01776 _dbus_assert (find_subtree (tree, path6, NULL)); 01777 _dbus_assert (find_subtree (tree, path7, NULL)); 01778 _dbus_assert (find_subtree (tree, path8, NULL)); 01779 01780 _dbus_object_tree_unregister_and_unlock (tree, path1); 01781 _dbus_assert (_dbus_object_tree_get_user_data_unlocked (tree, path1) == NULL); 01782 01783 _dbus_assert (!find_subtree (tree, path0, NULL)); 01784 _dbus_assert (!find_subtree (tree, path1, NULL)); 01785 _dbus_assert (find_subtree (tree, path2, NULL)); 01786 _dbus_assert (find_subtree (tree, path3, NULL)); 01787 _dbus_assert (find_subtree (tree, path4, NULL)); 01788 _dbus_assert (find_subtree (tree, path5, NULL)); 01789 _dbus_assert (find_subtree (tree, path6, NULL)); 01790 _dbus_assert (find_subtree (tree, path7, NULL)); 01791 _dbus_assert (find_subtree (tree, path8, NULL)); 01792 01793 _dbus_object_tree_unregister_and_unlock (tree, path2); 01794 _dbus_assert (_dbus_object_tree_get_user_data_unlocked (tree, path2) == NULL); 01795 01796 _dbus_assert (!find_subtree (tree, path0, NULL)); 01797 _dbus_assert (!find_subtree (tree, path1, NULL)); 01798 _dbus_assert (!find_subtree (tree, path2, NULL)); 01799 _dbus_assert (find_subtree (tree, path3, NULL)); 01800 _dbus_assert (find_subtree (tree, path4, NULL)); 01801 _dbus_assert (find_subtree (tree, path5, NULL)); 01802 _dbus_assert (find_subtree (tree, path6, NULL)); 01803 _dbus_assert (find_subtree (tree, path7, NULL)); 01804 _dbus_assert (find_subtree (tree, path8, NULL)); 01805 01806 _dbus_object_tree_unregister_and_unlock (tree, path3); 01807 _dbus_assert (_dbus_object_tree_get_user_data_unlocked (tree, path3) == NULL); 01808 01809 _dbus_assert (!find_subtree (tree, path0, NULL)); 01810 _dbus_assert (!find_subtree (tree, path1, NULL)); 01811 _dbus_assert (!find_subtree (tree, path2, NULL)); 01812 _dbus_assert (!find_subtree (tree, path3, NULL)); 01813 _dbus_assert (find_subtree (tree, path4, NULL)); 01814 _dbus_assert (find_subtree (tree, path5, NULL)); 01815 _dbus_assert (find_subtree (tree, path6, NULL)); 01816 _dbus_assert (find_subtree (tree, path7, NULL)); 01817 _dbus_assert (find_subtree (tree, path8, NULL)); 01818 01819 _dbus_object_tree_unregister_and_unlock (tree, path4); 01820 _dbus_assert (_dbus_object_tree_get_user_data_unlocked (tree, path4) == NULL); 01821 01822 _dbus_assert (!find_subtree (tree, path0, NULL)); 01823 _dbus_assert (!find_subtree (tree, path1, NULL)); 01824 _dbus_assert (!find_subtree (tree, path2, NULL)); 01825 _dbus_assert (!find_subtree (tree, path3, NULL)); 01826 _dbus_assert (!find_subtree (tree, path4, NULL)); 01827 _dbus_assert (find_subtree (tree, path5, NULL)); 01828 _dbus_assert (find_subtree (tree, path6, NULL)); 01829 _dbus_assert (find_subtree (tree, path7, NULL)); 01830 _dbus_assert (find_subtree (tree, path8, NULL)); 01831 01832 _dbus_object_tree_unregister_and_unlock (tree, path5); 01833 _dbus_assert (_dbus_object_tree_get_user_data_unlocked (tree, path5) == NULL); 01834 01835 _dbus_assert (!find_subtree (tree, path0, NULL)); 01836 _dbus_assert (!find_subtree (tree, path1, NULL)); 01837 _dbus_assert (!find_subtree (tree, path2, NULL)); 01838 _dbus_assert (!find_subtree (tree, path3, NULL)); 01839 _dbus_assert (!find_subtree (tree, path4, NULL)); 01840 _dbus_assert (!find_subtree (tree, path5, NULL)); 01841 _dbus_assert (find_subtree (tree, path6, NULL)); 01842 _dbus_assert (find_subtree (tree, path7, NULL)); 01843 _dbus_assert (find_subtree (tree, path8, NULL)); 01844 01845 _dbus_object_tree_unregister_and_unlock (tree, path6); 01846 _dbus_assert (_dbus_object_tree_get_user_data_unlocked (tree, path6) == NULL); 01847 01848 _dbus_assert (!find_subtree (tree, path0, NULL)); 01849 _dbus_assert (!find_subtree (tree, path1, NULL)); 01850 _dbus_assert (!find_subtree (tree, path2, NULL)); 01851 _dbus_assert (!find_subtree (tree, path3, NULL)); 01852 _dbus_assert (!find_subtree (tree, path4, NULL)); 01853 _dbus_assert (!find_subtree (tree, path5, NULL)); 01854 _dbus_assert (!find_subtree (tree, path6, NULL)); 01855 _dbus_assert (find_subtree (tree, path7, NULL)); 01856 _dbus_assert (find_subtree (tree, path8, NULL)); 01857 01858 _dbus_object_tree_unregister_and_unlock (tree, path7); 01859 _dbus_assert (_dbus_object_tree_get_user_data_unlocked (tree, path7) == NULL); 01860 01861 _dbus_assert (!find_subtree (tree, path0, NULL)); 01862 _dbus_assert (!find_subtree (tree, path1, NULL)); 01863 _dbus_assert (!find_subtree (tree, path2, NULL)); 01864 _dbus_assert (!find_subtree (tree, path3, NULL)); 01865 _dbus_assert (!find_subtree (tree, path4, NULL)); 01866 _dbus_assert (!find_subtree (tree, path5, NULL)); 01867 _dbus_assert (!find_subtree (tree, path6, NULL)); 01868 _dbus_assert (!find_subtree (tree, path7, NULL)); 01869 _dbus_assert (find_subtree (tree, path8, NULL)); 01870 01871 _dbus_object_tree_unregister_and_unlock (tree, path8); 01872 _dbus_assert (_dbus_object_tree_get_user_data_unlocked (tree, path8) == NULL); 01873 01874 _dbus_assert (!find_subtree (tree, path0, NULL)); 01875 _dbus_assert (!find_subtree (tree, path1, NULL)); 01876 _dbus_assert (!find_subtree (tree, path2, NULL)); 01877 _dbus_assert (!find_subtree (tree, path3, NULL)); 01878 _dbus_assert (!find_subtree (tree, path4, NULL)); 01879 _dbus_assert (!find_subtree (tree, path5, NULL)); 01880 _dbus_assert (!find_subtree (tree, path6, NULL)); 01881 _dbus_assert (!find_subtree (tree, path7, NULL)); 01882 _dbus_assert (!find_subtree (tree, path8, NULL)); 01883 01884 i = 0; 01885 while (i < (int) _DBUS_N_ELEMENTS (tree_test_data)) 01886 { 01887 _dbus_assert (tree_test_data[i].handler_unregistered); 01888 _dbus_assert (!tree_test_data[i].message_handled); 01889 ++i; 01890 } 01891 01892 /* Register it all again, and test dispatch */ 01893 01894 if (!do_register (tree, path0, TRUE, 0, tree_test_data)) 01895 goto out; 01896 if (!do_register (tree, path1, FALSE, 1, tree_test_data)) 01897 goto out; 01898 if (!do_register (tree, path2, TRUE, 2, tree_test_data)) 01899 goto out; 01900 if (!do_register (tree, path3, TRUE, 3, tree_test_data)) 01901 goto out; 01902 if (!do_register (tree, path4, TRUE, 4, tree_test_data)) 01903 goto out; 01904 if (!do_register (tree, path5, TRUE, 5, tree_test_data)) 01905 goto out; 01906 if (!do_register (tree, path6, FALSE, 6, tree_test_data)) 01907 goto out; 01908 if (!do_register (tree, path7, TRUE, 7, tree_test_data)) 01909 goto out; 01910 if (!do_register (tree, path8, TRUE, 8, tree_test_data)) 01911 goto out; 01912 01913 #if 0 01914 spew_tree (tree); 01915 #endif 01916 01917 if (!do_test_dispatch (tree, path0, 0, tree_test_data, _DBUS_N_ELEMENTS (tree_test_data))) 01918 goto out; 01919 if (!do_test_dispatch (tree, path1, 1, tree_test_data, _DBUS_N_ELEMENTS (tree_test_data))) 01920 goto out; 01921 if (!do_test_dispatch (tree, path2, 2, tree_test_data, _DBUS_N_ELEMENTS (tree_test_data))) 01922 goto out; 01923 if (!do_test_dispatch (tree, path3, 3, tree_test_data, _DBUS_N_ELEMENTS (tree_test_data))) 01924 goto out; 01925 if (!do_test_dispatch (tree, path4, 4, tree_test_data, _DBUS_N_ELEMENTS (tree_test_data))) 01926 goto out; 01927 if (!do_test_dispatch (tree, path5, 5, tree_test_data, _DBUS_N_ELEMENTS (tree_test_data))) 01928 goto out; 01929 if (!do_test_dispatch (tree, path6, 6, tree_test_data, _DBUS_N_ELEMENTS (tree_test_data))) 01930 goto out; 01931 if (!do_test_dispatch (tree, path7, 7, tree_test_data, _DBUS_N_ELEMENTS (tree_test_data))) 01932 goto out; 01933 if (!do_test_dispatch (tree, path8, 8, tree_test_data, _DBUS_N_ELEMENTS (tree_test_data))) 01934 goto out; 01935 01936 out: 01937 if (tree) 01938 { 01939 /* test ref */ 01940 _dbus_object_tree_ref (tree); 01941 _dbus_object_tree_unref (tree); 01942 _dbus_object_tree_unref (tree); 01943 } 01944 01945 return TRUE; 01946 } 01947 01953 dbus_bool_t 01954 _dbus_object_tree_test (void) 01955 { 01956 _dbus_test_oom_handling ("object tree", 01957 object_tree_test_iteration, 01958 NULL); 01959 01960 return TRUE; 01961 } 01962 01963 #endif /* !DOXYGEN_SHOULD_SKIP_THIS */ 01964 01965 #endif /* DBUS_BUILD_TESTS */