D-Bus 1.4.6
|
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_malloc (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 subtree->refcount.value = 1; 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 _dbus_assert (subtree->refcount.value > 0); 01006 _dbus_atomic_inc (&subtree->refcount); 01007 01008 return subtree; 01009 } 01010 01011 static void 01012 _dbus_object_subtree_unref (DBusObjectSubtree *subtree) 01013 { 01014 _dbus_assert (subtree->refcount.value > 0); 01015 01016 if (_dbus_atomic_dec (&subtree->refcount) == 1) 01017 { 01018 _dbus_assert (subtree->unregister_function == NULL); 01019 _dbus_assert (subtree->message_function == NULL); 01020 01021 dbus_free (subtree->subtrees); 01022 dbus_free (subtree); 01023 } 01024 } 01025 01036 dbus_bool_t 01037 _dbus_object_tree_list_registered_and_unlock (DBusObjectTree *tree, 01038 const char **parent_path, 01039 char ***child_entries) 01040 { 01041 dbus_bool_t result; 01042 01043 result = _dbus_object_tree_list_registered_unlocked (tree, 01044 parent_path, 01045 child_entries); 01046 01047 #ifdef DBUS_BUILD_TESTS 01048 if (tree->connection) 01049 #endif 01050 { 01051 _dbus_verbose ("unlock\n"); 01052 _dbus_connection_unlock (tree->connection); 01053 } 01054 01055 return result; 01056 } 01057 01058 01060 #define VERBOSE_DECOMPOSE 0 01061 01072 dbus_bool_t 01073 _dbus_decompose_path (const char* data, 01074 int len, 01075 char ***path, 01076 int *path_len) 01077 { 01078 char **retval; 01079 int n_components; 01080 int i, j, comp; 01081 01082 _dbus_assert (data != NULL); 01083 _dbus_assert (path != NULL); 01084 01085 #if VERBOSE_DECOMPOSE 01086 _dbus_verbose ("Decomposing path \"%s\"\n", 01087 data); 01088 #endif 01089 01090 n_components = 0; 01091 if (len > 1) /* if path is not just "/" */ 01092 { 01093 i = 0; 01094 while (i < len) 01095 { 01096 _dbus_assert (data[i] != '\0'); 01097 if (data[i] == '/') 01098 n_components += 1; 01099 ++i; 01100 } 01101 } 01102 01103 retval = dbus_new0 (char*, n_components + 1); 01104 01105 if (retval == NULL) 01106 return FALSE; 01107 01108 comp = 0; 01109 if (n_components == 0) 01110 i = 1; 01111 else 01112 i = 0; 01113 while (comp < n_components) 01114 { 01115 _dbus_assert (i < len); 01116 01117 if (data[i] == '/') 01118 ++i; 01119 j = i; 01120 01121 while (j < len && data[j] != '/') 01122 ++j; 01123 01124 /* Now [i, j) is the path component */ 01125 _dbus_assert (i < j); 01126 _dbus_assert (data[i] != '/'); 01127 _dbus_assert (j == len || data[j] == '/'); 01128 01129 #if VERBOSE_DECOMPOSE 01130 _dbus_verbose (" (component in [%d,%d))\n", 01131 i, j); 01132 #endif 01133 01134 retval[comp] = _dbus_memdup (&data[i], j - i + 1); 01135 if (retval[comp] == NULL) 01136 { 01137 dbus_free_string_array (retval); 01138 return FALSE; 01139 } 01140 retval[comp][j-i] = '\0'; 01141 #if VERBOSE_DECOMPOSE 01142 _dbus_verbose (" (component %d = \"%s\")\n", 01143 comp, retval[comp]); 01144 #endif 01145 01146 ++comp; 01147 i = j; 01148 } 01149 _dbus_assert (i == len); 01150 01151 *path = retval; 01152 if (path_len) 01153 *path_len = n_components; 01154 01155 return TRUE; 01156 } 01157 01160 static char* 01161 flatten_path (const char **path) 01162 { 01163 DBusString str; 01164 char *s; 01165 01166 if (!_dbus_string_init (&str)) 01167 return NULL; 01168 01169 if (path[0] == NULL) 01170 { 01171 if (!_dbus_string_append_byte (&str, '/')) 01172 goto nomem; 01173 } 01174 else 01175 { 01176 int i; 01177 01178 i = 0; 01179 while (path[i]) 01180 { 01181 if (!_dbus_string_append_byte (&str, '/')) 01182 goto nomem; 01183 01184 if (!_dbus_string_append (&str, path[i])) 01185 goto nomem; 01186 01187 ++i; 01188 } 01189 } 01190 01191 if (!_dbus_string_steal_data (&str, &s)) 01192 goto nomem; 01193 01194 _dbus_string_free (&str); 01195 01196 return s; 01197 01198 nomem: 01199 _dbus_string_free (&str); 01200 return NULL; 01201 } 01202 01203 01204 #ifdef DBUS_BUILD_TESTS 01205 01206 #ifndef DOXYGEN_SHOULD_SKIP_THIS 01207 01208 #include "dbus-test.h" 01209 #include <stdio.h> 01210 01211 typedef enum 01212 { 01213 STR_EQUAL, 01214 STR_PREFIX, 01215 STR_DIFFERENT 01216 } StrComparison; 01217 01218 /* Returns TRUE if container is a parent of child 01219 */ 01220 static StrComparison 01221 path_contains (const char **container, 01222 const char **child) 01223 { 01224 int i; 01225 01226 i = 0; 01227 while (child[i] != NULL) 01228 { 01229 int v; 01230 01231 if (container[i] == NULL) 01232 return STR_PREFIX; /* container ran out, child continues; 01233 * thus the container is a parent of the 01234 * child. 01235 */ 01236 01237 _dbus_assert (container[i] != NULL); 01238 _dbus_assert (child[i] != NULL); 01239 01240 v = strcmp (container[i], child[i]); 01241 01242 if (v != 0) 01243 return STR_DIFFERENT; /* they overlap until here and then are different, 01244 * not overlapping 01245 */ 01246 01247 ++i; 01248 } 01249 01250 /* Child ran out; if container also did, they are equal; 01251 * otherwise, the child is a parent of the container. 01252 */ 01253 if (container[i] == NULL) 01254 return STR_EQUAL; 01255 else 01256 return STR_DIFFERENT; 01257 } 01258 01259 #if 0 01260 static void 01261 spew_subtree_recurse (DBusObjectSubtree *subtree, 01262 int indent) 01263 { 01264 int i; 01265 01266 i = 0; 01267 while (i < indent) 01268 { 01269 _dbus_verbose (" "); 01270 ++i; 01271 } 01272 01273 _dbus_verbose ("%s (%d children)\n", 01274 subtree->name, subtree->n_subtrees); 01275 01276 i = 0; 01277 while (i < subtree->n_subtrees) 01278 { 01279 spew_subtree_recurse (subtree->subtrees[i], indent + 2); 01280 01281 ++i; 01282 } 01283 } 01284 01285 static void 01286 spew_tree (DBusObjectTree *tree) 01287 { 01288 spew_subtree_recurse (tree->root, 0); 01289 } 01290 #endif 01291 01295 typedef struct 01296 { 01297 const char **path; 01298 dbus_bool_t handler_fallback; 01299 dbus_bool_t message_handled; 01300 dbus_bool_t handler_unregistered; 01301 } TreeTestData; 01302 01303 01304 static void 01305 test_unregister_function (DBusConnection *connection, 01306 void *user_data) 01307 { 01308 TreeTestData *ttd = user_data; 01309 01310 ttd->handler_unregistered = TRUE; 01311 } 01312 01313 static DBusHandlerResult 01314 test_message_function (DBusConnection *connection, 01315 DBusMessage *message, 01316 void *user_data) 01317 { 01318 TreeTestData *ttd = user_data; 01319 01320 ttd->message_handled = TRUE; 01321 01322 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; 01323 } 01324 01325 static dbus_bool_t 01326 do_register (DBusObjectTree *tree, 01327 const char **path, 01328 dbus_bool_t fallback, 01329 int i, 01330 TreeTestData *tree_test_data) 01331 { 01332 DBusObjectPathVTable vtable = { test_unregister_function, 01333 test_message_function, NULL }; 01334 01335 tree_test_data[i].message_handled = FALSE; 01336 tree_test_data[i].handler_unregistered = FALSE; 01337 tree_test_data[i].handler_fallback = fallback; 01338 tree_test_data[i].path = path; 01339 01340 if (!_dbus_object_tree_register (tree, fallback, path, 01341 &vtable, 01342 &tree_test_data[i], 01343 NULL)) 01344 return FALSE; 01345 01346 _dbus_assert (_dbus_object_tree_get_user_data_unlocked (tree, path) == 01347 &tree_test_data[i]); 01348 01349 return TRUE; 01350 } 01351 01352 static dbus_bool_t 01353 do_test_dispatch (DBusObjectTree *tree, 01354 const char **path, 01355 int i, 01356 TreeTestData *tree_test_data, 01357 int n_test_data) 01358 { 01359 DBusMessage *message; 01360 int j; 01361 DBusHandlerResult result; 01362 char *flat; 01363 01364 message = NULL; 01365 01366 flat = flatten_path (path); 01367 if (flat == NULL) 01368 goto oom; 01369 01370 message = dbus_message_new_method_call (NULL, 01371 flat, 01372 "org.freedesktop.TestInterface", 01373 "Foo"); 01374 dbus_free (flat); 01375 if (message == NULL) 01376 goto oom; 01377 01378 j = 0; 01379 while (j < n_test_data) 01380 { 01381 tree_test_data[j].message_handled = FALSE; 01382 ++j; 01383 } 01384 01385 result = _dbus_object_tree_dispatch_and_unlock (tree, message); 01386 if (result == DBUS_HANDLER_RESULT_NEED_MEMORY) 01387 goto oom; 01388 01389 _dbus_assert (tree_test_data[i].message_handled); 01390 01391 j = 0; 01392 while (j < n_test_data) 01393 { 01394 if (tree_test_data[j].message_handled) 01395 { 01396 if (tree_test_data[j].handler_fallback) 01397 _dbus_assert (path_contains (tree_test_data[j].path, 01398 path) != STR_DIFFERENT); 01399 else 01400 _dbus_assert (path_contains (tree_test_data[j].path, path) == STR_EQUAL); 01401 } 01402 else 01403 { 01404 if (tree_test_data[j].handler_fallback) 01405 _dbus_assert (path_contains (tree_test_data[j].path, 01406 path) == STR_DIFFERENT); 01407 else 01408 _dbus_assert (path_contains (tree_test_data[j].path, path) != STR_EQUAL); 01409 } 01410 01411 ++j; 01412 } 01413 01414 dbus_message_unref (message); 01415 01416 return TRUE; 01417 01418 oom: 01419 if (message) 01420 dbus_message_unref (message); 01421 return FALSE; 01422 } 01423 01424 static size_t 01425 string_array_length (const char **array) 01426 { 01427 size_t i; 01428 for (i = 0; array[i]; i++) ; 01429 return i; 01430 } 01431 01432 typedef struct 01433 { 01434 const char *path; 01435 const char *result[20]; 01436 } DecomposePathTest; 01437 01438 static DecomposePathTest decompose_tests[] = { 01439 { "/foo", { "foo", NULL } }, 01440 { "/foo/bar", { "foo", "bar", NULL } }, 01441 { "/", { NULL } }, 01442 { "/a/b", { "a", "b", NULL } }, 01443 { "/a/b/c", { "a", "b", "c", NULL } }, 01444 { "/a/b/c/d", { "a", "b", "c", "d", NULL } }, 01445 { "/foo/bar/q", { "foo", "bar", "q", NULL } }, 01446 { "/foo/bar/this/is/longer", { "foo", "bar", "this", "is", "longer", NULL } } 01447 }; 01448 01449 static dbus_bool_t 01450 run_decompose_tests (void) 01451 { 01452 int i; 01453 01454 i = 0; 01455 while (i < _DBUS_N_ELEMENTS (decompose_tests)) 01456 { 01457 char **result; 01458 int result_len; 01459 int expected_len; 01460 01461 if (!_dbus_decompose_path (decompose_tests[i].path, 01462 strlen (decompose_tests[i].path), 01463 &result, &result_len)) 01464 return FALSE; 01465 01466 expected_len = string_array_length (decompose_tests[i].result); 01467 01468 if (result_len != (int) string_array_length ((const char**)result) || 01469 expected_len != result_len || 01470 path_contains (decompose_tests[i].result, 01471 (const char**) result) != STR_EQUAL) 01472 { 01473 int real_len = string_array_length ((const char**)result); 01474 _dbus_warn ("Expected decompose of %s to have len %d, returned %d, appears to have %d\n", 01475 decompose_tests[i].path, expected_len, result_len, 01476 real_len); 01477 _dbus_warn ("Decompose resulted in elements: { "); 01478 i = 0; 01479 while (i < real_len) 01480 { 01481 _dbus_warn ("\"%s\"%s", result[i], 01482 (i + 1) == real_len ? "" : ", "); 01483 ++i; 01484 } 01485 _dbus_warn ("}\n"); 01486 _dbus_assert_not_reached ("path decompose failed\n"); 01487 } 01488 01489 dbus_free_string_array (result); 01490 01491 ++i; 01492 } 01493 01494 return TRUE; 01495 } 01496 01497 static dbus_bool_t 01498 object_tree_test_iteration (void *data) 01499 { 01500 const char *path0[] = { NULL }; 01501 const char *path1[] = { "foo", NULL }; 01502 const char *path2[] = { "foo", "bar", NULL }; 01503 const char *path3[] = { "foo", "bar", "baz", NULL }; 01504 const char *path4[] = { "foo", "bar", "boo", NULL }; 01505 const char *path5[] = { "blah", NULL }; 01506 const char *path6[] = { "blah", "boof", NULL }; 01507 const char *path7[] = { "blah", "boof", "this", "is", "really", "long", NULL }; 01508 const char *path8[] = { "childless", NULL }; 01509 DBusObjectTree *tree; 01510 TreeTestData tree_test_data[9]; 01511 int i; 01512 dbus_bool_t exact_match; 01513 01514 if (!run_decompose_tests ()) 01515 return FALSE; 01516 01517 tree = NULL; 01518 01519 tree = _dbus_object_tree_new (NULL); 01520 if (tree == NULL) 01521 goto out; 01522 01523 if (!do_register (tree, path0, TRUE, 0, tree_test_data)) 01524 goto out; 01525 01526 _dbus_assert (find_subtree (tree, path0, NULL)); 01527 _dbus_assert (!find_subtree (tree, path1, NULL)); 01528 _dbus_assert (!find_subtree (tree, path2, NULL)); 01529 _dbus_assert (!find_subtree (tree, path3, NULL)); 01530 _dbus_assert (!find_subtree (tree, path4, NULL)); 01531 _dbus_assert (!find_subtree (tree, path5, NULL)); 01532 _dbus_assert (!find_subtree (tree, path6, NULL)); 01533 _dbus_assert (!find_subtree (tree, path7, NULL)); 01534 _dbus_assert (!find_subtree (tree, path8, NULL)); 01535 01536 _dbus_assert (find_handler (tree, path0, &exact_match) && exact_match); 01537 _dbus_assert (find_handler (tree, path1, &exact_match) == tree->root && !exact_match); 01538 _dbus_assert (find_handler (tree, path2, &exact_match) == tree->root && !exact_match); 01539 _dbus_assert (find_handler (tree, path3, &exact_match) == tree->root && !exact_match); 01540 _dbus_assert (find_handler (tree, path4, &exact_match) == tree->root && !exact_match); 01541 _dbus_assert (find_handler (tree, path5, &exact_match) == tree->root && !exact_match); 01542 _dbus_assert (find_handler (tree, path6, &exact_match) == tree->root && !exact_match); 01543 _dbus_assert (find_handler (tree, path7, &exact_match) == tree->root && !exact_match); 01544 _dbus_assert (find_handler (tree, path8, &exact_match) == tree->root && !exact_match); 01545 01546 if (!do_register (tree, path1, TRUE, 1, tree_test_data)) 01547 goto out; 01548 01549 _dbus_assert (find_subtree (tree, path0, NULL)); 01550 _dbus_assert (find_subtree (tree, path1, NULL)); 01551 _dbus_assert (!find_subtree (tree, path2, NULL)); 01552 _dbus_assert (!find_subtree (tree, path3, NULL)); 01553 _dbus_assert (!find_subtree (tree, path4, NULL)); 01554 _dbus_assert (!find_subtree (tree, path5, NULL)); 01555 _dbus_assert (!find_subtree (tree, path6, NULL)); 01556 _dbus_assert (!find_subtree (tree, path7, NULL)); 01557 _dbus_assert (!find_subtree (tree, path8, NULL)); 01558 01559 _dbus_assert (find_handler (tree, path0, &exact_match) && exact_match); 01560 _dbus_assert (find_handler (tree, path1, &exact_match) && exact_match); 01561 _dbus_assert (find_handler (tree, path2, &exact_match) && !exact_match); 01562 _dbus_assert (find_handler (tree, path3, &exact_match) && !exact_match); 01563 _dbus_assert (find_handler (tree, path4, &exact_match) && !exact_match); 01564 _dbus_assert (find_handler (tree, path5, &exact_match) == tree->root && !exact_match); 01565 _dbus_assert (find_handler (tree, path6, &exact_match) == tree->root && !exact_match); 01566 _dbus_assert (find_handler (tree, path7, &exact_match) == tree->root && !exact_match); 01567 _dbus_assert (find_handler (tree, path8, &exact_match) == tree->root && !exact_match); 01568 01569 if (!do_register (tree, path2, TRUE, 2, tree_test_data)) 01570 goto out; 01571 01572 _dbus_assert (find_subtree (tree, path1, NULL)); 01573 _dbus_assert (find_subtree (tree, path2, NULL)); 01574 _dbus_assert (!find_subtree (tree, path3, NULL)); 01575 _dbus_assert (!find_subtree (tree, path4, NULL)); 01576 _dbus_assert (!find_subtree (tree, path5, NULL)); 01577 _dbus_assert (!find_subtree (tree, path6, NULL)); 01578 _dbus_assert (!find_subtree (tree, path7, NULL)); 01579 _dbus_assert (!find_subtree (tree, path8, NULL)); 01580 01581 if (!do_register (tree, path3, TRUE, 3, tree_test_data)) 01582 goto out; 01583 01584 _dbus_assert (find_subtree (tree, path0, NULL)); 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, path4, TRUE, 4, 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, path5, TRUE, 5, 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 _dbus_assert (find_handler (tree, path0, &exact_match) == tree->root && exact_match); 01621 _dbus_assert (find_handler (tree, path1, &exact_match) != tree->root && exact_match); 01622 _dbus_assert (find_handler (tree, path2, &exact_match) != tree->root && exact_match); 01623 _dbus_assert (find_handler (tree, path3, &exact_match) != tree->root && exact_match); 01624 _dbus_assert (find_handler (tree, path4, &exact_match) != tree->root && exact_match); 01625 _dbus_assert (find_handler (tree, path5, &exact_match) != tree->root && exact_match); 01626 _dbus_assert (find_handler (tree, path6, &exact_match) != tree->root && !exact_match); 01627 _dbus_assert (find_handler (tree, path7, &exact_match) != tree->root && !exact_match); 01628 _dbus_assert (find_handler (tree, path8, &exact_match) == tree->root && !exact_match); 01629 01630 if (!do_register (tree, path6, TRUE, 6, tree_test_data)) 01631 goto out; 01632 01633 _dbus_assert (find_subtree (tree, path0, NULL)); 01634 _dbus_assert (find_subtree (tree, path1, NULL)); 01635 _dbus_assert (find_subtree (tree, path2, NULL)); 01636 _dbus_assert (find_subtree (tree, path3, NULL)); 01637 _dbus_assert (find_subtree (tree, path4, NULL)); 01638 _dbus_assert (find_subtree (tree, path5, NULL)); 01639 _dbus_assert (find_subtree (tree, path6, NULL)); 01640 _dbus_assert (!find_subtree (tree, path7, NULL)); 01641 _dbus_assert (!find_subtree (tree, path8, NULL)); 01642 01643 if (!do_register (tree, path7, TRUE, 7, 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, path8, TRUE, 8, 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 _dbus_assert (find_handler (tree, path0, &exact_match) == tree->root && exact_match); 01670 _dbus_assert (find_handler (tree, path1, &exact_match) != tree->root && exact_match); 01671 _dbus_assert (find_handler (tree, path2, &exact_match) != tree->root && exact_match); 01672 _dbus_assert (find_handler (tree, path3, &exact_match) != tree->root && exact_match); 01673 _dbus_assert (find_handler (tree, path4, &exact_match) != tree->root && exact_match); 01674 _dbus_assert (find_handler (tree, path5, &exact_match) != tree->root && exact_match); 01675 _dbus_assert (find_handler (tree, path6, &exact_match) != tree->root && exact_match); 01676 _dbus_assert (find_handler (tree, path7, &exact_match) != tree->root && exact_match); 01677 _dbus_assert (find_handler (tree, path8, &exact_match) != tree->root && exact_match); 01678 01679 /* test the list_registered function */ 01680 01681 { 01682 const char *root[] = { NULL }; 01683 char **child_entries; 01684 int nb; 01685 01686 _dbus_object_tree_list_registered_unlocked (tree, path1, &child_entries); 01687 if (child_entries != NULL) 01688 { 01689 nb = string_array_length ((const char**)child_entries); 01690 _dbus_assert (nb == 1); 01691 dbus_free_string_array (child_entries); 01692 } 01693 01694 _dbus_object_tree_list_registered_unlocked (tree, path2, &child_entries); 01695 if (child_entries != NULL) 01696 { 01697 nb = string_array_length ((const char**)child_entries); 01698 _dbus_assert (nb == 2); 01699 dbus_free_string_array (child_entries); 01700 } 01701 01702 _dbus_object_tree_list_registered_unlocked (tree, path8, &child_entries); 01703 if (child_entries != NULL) 01704 { 01705 nb = string_array_length ((const char**)child_entries); 01706 _dbus_assert (nb == 0); 01707 dbus_free_string_array (child_entries); 01708 } 01709 01710 _dbus_object_tree_list_registered_unlocked (tree, root, &child_entries); 01711 if (child_entries != NULL) 01712 { 01713 nb = string_array_length ((const char**)child_entries); 01714 _dbus_assert (nb == 3); 01715 dbus_free_string_array (child_entries); 01716 } 01717 } 01718 01719 /* Check that destroying tree calls unregister funcs */ 01720 _dbus_object_tree_unref (tree); 01721 01722 i = 0; 01723 while (i < (int) _DBUS_N_ELEMENTS (tree_test_data)) 01724 { 01725 _dbus_assert (tree_test_data[i].handler_unregistered); 01726 _dbus_assert (!tree_test_data[i].message_handled); 01727 ++i; 01728 } 01729 01730 /* Now start again and try the individual unregister function */ 01731 tree = _dbus_object_tree_new (NULL); 01732 if (tree == NULL) 01733 goto out; 01734 01735 if (!do_register (tree, path0, TRUE, 0, tree_test_data)) 01736 goto out; 01737 if (!do_register (tree, path1, TRUE, 1, tree_test_data)) 01738 goto out; 01739 if (!do_register (tree, path2, TRUE, 2, tree_test_data)) 01740 goto out; 01741 if (!do_register (tree, path3, TRUE, 3, tree_test_data)) 01742 goto out; 01743 if (!do_register (tree, path4, TRUE, 4, tree_test_data)) 01744 goto out; 01745 if (!do_register (tree, path5, TRUE, 5, tree_test_data)) 01746 goto out; 01747 if (!do_register (tree, path6, TRUE, 6, tree_test_data)) 01748 goto out; 01749 if (!do_register (tree, path7, TRUE, 7, tree_test_data)) 01750 goto out; 01751 if (!do_register (tree, path8, TRUE, 8, tree_test_data)) 01752 goto out; 01753 01754 _dbus_object_tree_unregister_and_unlock (tree, path0); 01755 _dbus_assert (_dbus_object_tree_get_user_data_unlocked (tree, path0) == NULL); 01756 01757 _dbus_assert (!find_subtree (tree, path0, NULL)); 01758 _dbus_assert (find_subtree (tree, path1, NULL)); 01759 _dbus_assert (find_subtree (tree, path2, NULL)); 01760 _dbus_assert (find_subtree (tree, path3, NULL)); 01761 _dbus_assert (find_subtree (tree, path4, NULL)); 01762 _dbus_assert (find_subtree (tree, path5, NULL)); 01763 _dbus_assert (find_subtree (tree, path6, NULL)); 01764 _dbus_assert (find_subtree (tree, path7, NULL)); 01765 _dbus_assert (find_subtree (tree, path8, NULL)); 01766 01767 _dbus_object_tree_unregister_and_unlock (tree, path1); 01768 _dbus_assert (_dbus_object_tree_get_user_data_unlocked (tree, path1) == 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, path2); 01781 _dbus_assert (_dbus_object_tree_get_user_data_unlocked (tree, path2) == 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, path3); 01794 _dbus_assert (_dbus_object_tree_get_user_data_unlocked (tree, path3) == 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, path4); 01807 _dbus_assert (_dbus_object_tree_get_user_data_unlocked (tree, path4) == 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, path5); 01820 _dbus_assert (_dbus_object_tree_get_user_data_unlocked (tree, path5) == 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, path6); 01833 _dbus_assert (_dbus_object_tree_get_user_data_unlocked (tree, path6) == 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, path7); 01846 _dbus_assert (_dbus_object_tree_get_user_data_unlocked (tree, path7) == 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, path8); 01859 _dbus_assert (_dbus_object_tree_get_user_data_unlocked (tree, path8) == 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 i = 0; 01872 while (i < (int) _DBUS_N_ELEMENTS (tree_test_data)) 01873 { 01874 _dbus_assert (tree_test_data[i].handler_unregistered); 01875 _dbus_assert (!tree_test_data[i].message_handled); 01876 ++i; 01877 } 01878 01879 /* Register it all again, and test dispatch */ 01880 01881 if (!do_register (tree, path0, TRUE, 0, tree_test_data)) 01882 goto out; 01883 if (!do_register (tree, path1, FALSE, 1, tree_test_data)) 01884 goto out; 01885 if (!do_register (tree, path2, TRUE, 2, tree_test_data)) 01886 goto out; 01887 if (!do_register (tree, path3, TRUE, 3, tree_test_data)) 01888 goto out; 01889 if (!do_register (tree, path4, TRUE, 4, tree_test_data)) 01890 goto out; 01891 if (!do_register (tree, path5, TRUE, 5, tree_test_data)) 01892 goto out; 01893 if (!do_register (tree, path6, FALSE, 6, tree_test_data)) 01894 goto out; 01895 if (!do_register (tree, path7, TRUE, 7, tree_test_data)) 01896 goto out; 01897 if (!do_register (tree, path8, TRUE, 8, tree_test_data)) 01898 goto out; 01899 01900 #if 0 01901 spew_tree (tree); 01902 #endif 01903 01904 if (!do_test_dispatch (tree, path0, 0, tree_test_data, _DBUS_N_ELEMENTS (tree_test_data))) 01905 goto out; 01906 if (!do_test_dispatch (tree, path1, 1, tree_test_data, _DBUS_N_ELEMENTS (tree_test_data))) 01907 goto out; 01908 if (!do_test_dispatch (tree, path2, 2, tree_test_data, _DBUS_N_ELEMENTS (tree_test_data))) 01909 goto out; 01910 if (!do_test_dispatch (tree, path3, 3, tree_test_data, _DBUS_N_ELEMENTS (tree_test_data))) 01911 goto out; 01912 if (!do_test_dispatch (tree, path4, 4, tree_test_data, _DBUS_N_ELEMENTS (tree_test_data))) 01913 goto out; 01914 if (!do_test_dispatch (tree, path5, 5, tree_test_data, _DBUS_N_ELEMENTS (tree_test_data))) 01915 goto out; 01916 if (!do_test_dispatch (tree, path6, 6, tree_test_data, _DBUS_N_ELEMENTS (tree_test_data))) 01917 goto out; 01918 if (!do_test_dispatch (tree, path7, 7, tree_test_data, _DBUS_N_ELEMENTS (tree_test_data))) 01919 goto out; 01920 if (!do_test_dispatch (tree, path8, 8, tree_test_data, _DBUS_N_ELEMENTS (tree_test_data))) 01921 goto out; 01922 01923 out: 01924 if (tree) 01925 { 01926 /* test ref */ 01927 _dbus_object_tree_ref (tree); 01928 _dbus_object_tree_unref (tree); 01929 _dbus_object_tree_unref (tree); 01930 } 01931 01932 return TRUE; 01933 } 01934 01940 dbus_bool_t 01941 _dbus_object_tree_test (void) 01942 { 01943 _dbus_test_oom_handling ("object tree", 01944 object_tree_test_iteration, 01945 NULL); 01946 01947 return TRUE; 01948 } 01949 01950 #endif /* !DOXYGEN_SHOULD_SKIP_THIS */ 01951 01952 #endif /* DBUS_BUILD_TESTS */