1 /* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
2 /* dbus-object-tree.c DBusObjectTree (internals of DBusConnection)
4 * Copyright (C) 2003, 2005 Red Hat Inc.
6 * Licensed under the Academic Free License version 2.1
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
25 #include "dbus-object-tree.h"
26 #include "dbus-connection-internal.h"
27 #include "dbus-internals.h"
28 #include "dbus-hash.h"
29 #include "dbus-protocol.h"
30 #include "dbus-string.h"
35 * @defgroup DBusObjectTree A hierarchy of objects with container-contained relationship
36 * @ingroup DBusInternals
37 * @brief DBusObjectTree is used by DBusConnection to track the object tree
39 * Types and functions related to DBusObjectTree. These
40 * are all library-internal.
45 /** Subnode of the object hierarchy */
46 typedef struct DBusObjectSubtree DBusObjectSubtree;
48 static DBusObjectSubtree* _dbus_object_subtree_new (const char *name,
49 const DBusObjectPathVTable *vtable,
51 static DBusObjectSubtree* _dbus_object_subtree_ref (DBusObjectSubtree *subtree);
52 static void _dbus_object_subtree_unref (DBusObjectSubtree *subtree);
55 * Internals of DBusObjectTree
59 int refcount; /**< Reference count */
60 DBusConnection *connection; /**< Connection this tree belongs to */
62 DBusObjectSubtree *root; /**< Root of the tree ("/" node) */
66 * Struct representing a single registered subtree handler, or node
67 * that's a parent of a registered subtree handler. If
68 * message_function != NULL there's actually a handler at this node.
70 struct DBusObjectSubtree
72 DBusAtomic refcount; /**< Reference count */
73 DBusObjectSubtree *parent; /**< Parent node */
74 DBusObjectPathUnregisterFunction unregister_function; /**< Function to call on unregister */
75 DBusObjectPathMessageFunction message_function; /**< Function to handle messages */
76 void *user_data; /**< Data for functions */
77 DBusObjectSubtree **subtrees; /**< Child nodes */
78 int n_subtrees; /**< Number of child nodes */
79 int max_subtrees; /**< Number of allocated entries in subtrees */
80 unsigned int invoke_as_fallback : 1; /**< Whether to invoke message_function when child nodes don't handle the message */
81 char name[1]; /**< Allocated as large as necessary */
85 * Creates a new object tree, representing a mapping from paths
88 * @param connection the connection this tree belongs to
89 * @returns the new tree or #NULL if no memory
92 _dbus_object_tree_new (DBusConnection *connection)
96 /* the connection passed in here isn't fully constructed,
97 * so don't do anything more than store a pointer to
101 tree = dbus_new0 (DBusObjectTree, 1);
106 tree->connection = connection;
107 tree->root = _dbus_object_subtree_new ("/", NULL, NULL);
108 if (tree->root == NULL)
110 tree->root->invoke_as_fallback = TRUE;
124 * Increment the reference count
125 * @param tree the object tree
126 * @returns the object tree
129 _dbus_object_tree_ref (DBusObjectTree *tree)
131 _dbus_assert (tree->refcount > 0);
139 * Decrement the reference count
140 * @param tree the object tree
143 _dbus_object_tree_unref (DBusObjectTree *tree)
145 _dbus_assert (tree->refcount > 0);
149 if (tree->refcount == 0)
151 _dbus_object_tree_free_all_unlocked (tree);
157 /** Set to 1 to get a bunch of debug spew about finding the
160 #define VERBOSE_FIND 0
162 static DBusObjectSubtree*
163 find_subtree_recurse (DBusObjectSubtree *subtree,
165 dbus_bool_t create_if_not_found,
166 int *index_in_parent,
167 dbus_bool_t *exact_match)
170 dbus_bool_t return_deepest_match;
172 return_deepest_match = exact_match != NULL;
174 _dbus_assert (!(return_deepest_match && create_if_not_found));
179 _dbus_verbose (" path exhausted, returning %s\n",
182 if (exact_match != NULL)
188 _dbus_verbose (" searching children of %s for %s\n",
189 subtree->name, path[0]);
193 j = subtree->n_subtrees;
199 v = strcmp (path[0], subtree->subtrees[k]->name);
202 _dbus_verbose (" %s cmp %s = %d\n",
203 path[0], subtree->subtrees[k]->name,
212 _dbus_verbose (" storing parent index %d\n", k);
214 *index_in_parent = k;
217 if (return_deepest_match)
219 DBusObjectSubtree *next;
221 next = find_subtree_recurse (subtree->subtrees[k],
222 &path[1], create_if_not_found,
223 index_in_parent, exact_match);
225 subtree->invoke_as_fallback)
228 _dbus_verbose (" no deeper match found, returning %s\n",
231 if (exact_match != NULL)
232 *exact_match = FALSE;
239 return find_subtree_recurse (subtree->subtrees[k],
240 &path[1], create_if_not_found,
241 index_in_parent, exact_match);
254 _dbus_verbose (" no match found, current tree %s, create_if_not_found = %d\n",
255 subtree->name, create_if_not_found);
258 if (create_if_not_found)
260 DBusObjectSubtree* child;
261 int child_pos, new_n_subtrees;
264 _dbus_verbose (" creating subtree %s\n",
268 child = _dbus_object_subtree_new (path[0],
273 new_n_subtrees = subtree->n_subtrees + 1;
274 if (new_n_subtrees > subtree->max_subtrees)
276 int new_max_subtrees;
277 DBusObjectSubtree **new_subtrees;
279 new_max_subtrees = subtree->max_subtrees == 0 ? 1 : 2 * subtree->max_subtrees;
280 new_subtrees = dbus_realloc (subtree->subtrees,
281 new_max_subtrees * sizeof (DBusObjectSubtree*));
282 if (new_subtrees == NULL)
284 _dbus_object_subtree_unref (child);
287 subtree->subtrees = new_subtrees;
288 subtree->max_subtrees = new_max_subtrees;
291 /* The binary search failed, so i == j points to the
292 place the child should be inserted. */
294 _dbus_assert (child_pos < new_n_subtrees &&
295 new_n_subtrees <= subtree->max_subtrees);
296 if (child_pos + 1 < new_n_subtrees)
298 memmove (&subtree->subtrees[child_pos+1],
299 &subtree->subtrees[child_pos],
300 (new_n_subtrees - child_pos - 1) *
301 sizeof subtree->subtrees[0]);
303 subtree->subtrees[child_pos] = child;
306 *index_in_parent = child_pos;
307 subtree->n_subtrees = new_n_subtrees;
308 child->parent = subtree;
310 return find_subtree_recurse (child,
311 &path[1], create_if_not_found,
312 index_in_parent, exact_match);
316 if (exact_match != NULL)
317 *exact_match = FALSE;
318 return (return_deepest_match && subtree->invoke_as_fallback) ? subtree : NULL;
322 #ifdef DBUS_ENABLE_EMBEDDED_TESTS
323 static DBusObjectSubtree*
324 find_subtree (DBusObjectTree *tree,
326 int *index_in_parent)
328 DBusObjectSubtree *subtree;
331 _dbus_verbose ("Looking for exact registered subtree\n");
334 subtree = find_subtree_recurse (tree->root, path, FALSE, index_in_parent, NULL);
336 if (subtree && subtree->message_function == NULL)
343 static DBusObjectSubtree*
344 lookup_subtree (DBusObjectTree *tree,
348 _dbus_verbose ("Looking for subtree\n");
350 return find_subtree_recurse (tree->root, path, FALSE, NULL, NULL);
353 static DBusObjectSubtree*
354 find_handler (DBusObjectTree *tree,
356 dbus_bool_t *exact_match)
359 _dbus_verbose ("Looking for deepest handler\n");
361 _dbus_assert (exact_match != NULL);
363 *exact_match = FALSE; /* ensure always initialized */
365 return find_subtree_recurse (tree->root, path, FALSE, NULL, exact_match);
368 static DBusObjectSubtree*
369 ensure_subtree (DBusObjectTree *tree,
373 _dbus_verbose ("Ensuring subtree\n");
375 return find_subtree_recurse (tree->root, path, TRUE, NULL, NULL);
378 static char *flatten_path (const char **path);
381 * Registers a new subtree in the global object tree.
383 * @param tree the global object tree
384 * @param fallback #TRUE to handle messages to children of this path
385 * @param path NULL-terminated array of path elements giving path to subtree
386 * @param vtable the vtable used to traverse this subtree
387 * @param user_data user data to pass to methods in the vtable
388 * @param error address where an error can be returned
389 * @returns #FALSE if an error (#DBUS_ERROR_NO_MEMORY or
390 * #DBUS_ERROR_OBJECT_PATH_IN_USE) is reported
393 _dbus_object_tree_register (DBusObjectTree *tree,
394 dbus_bool_t fallback,
396 const DBusObjectPathVTable *vtable,
400 DBusObjectSubtree *subtree;
402 _dbus_assert (tree != NULL);
403 _dbus_assert (vtable->message_function != NULL);
404 _dbus_assert (path != NULL);
406 subtree = ensure_subtree (tree, path);
409 _DBUS_SET_OOM (error);
413 if (subtree->message_function != NULL)
417 char *complete_path = flatten_path (path);
419 dbus_set_error (error, DBUS_ERROR_OBJECT_PATH_IN_USE,
420 "A handler is already registered for %s",
421 complete_path ? complete_path
422 : "(cannot represent path: out of memory!)");
424 dbus_free (complete_path);
430 subtree->message_function = vtable->message_function;
431 subtree->unregister_function = vtable->unregister_function;
432 subtree->user_data = user_data;
433 subtree->invoke_as_fallback = fallback != FALSE;
439 * Attempts to unregister the given subtree. If the subtree is registered,
440 * stores its unregister function and user data for later use and returns
441 * #TRUE. If subtree is not registered, simply returns #FALSE. Does not free
442 * subtree or remove it from the object tree.
444 * @param subtree the subtree to unregister
445 * @param unregister_function_out stores subtree's unregister_function
446 * @param user_data_out stores subtree's user_data
447 * @return #FALSE if the subtree was not registered, #TRUE on success
450 unregister_subtree (DBusObjectSubtree *subtree,
451 DBusObjectPathUnregisterFunction *unregister_function_out,
452 void **user_data_out)
454 _dbus_assert (subtree != NULL);
455 _dbus_assert (unregister_function_out != NULL);
456 _dbus_assert (user_data_out != NULL);
458 /* Confirm subtree is registered */
459 if (subtree->message_function != NULL)
461 subtree->message_function = NULL;
463 *unregister_function_out = subtree->unregister_function;
464 *user_data_out = subtree->user_data;
466 subtree->unregister_function = NULL;
467 subtree->user_data = NULL;
473 /* Assert that this unregistered subtree is either the root node or has
474 children, otherwise we have a dangling path which should never
476 _dbus_assert (subtree->parent == NULL || subtree->n_subtrees > 0);
478 /* The subtree is not registered */
484 * Attempts to remove a child subtree from its parent. If removal is
485 * successful, also frees the child. Returns #TRUE on success, #FALSE
486 * otherwise. A #FALSE return value tells unregister_and_free_path_recurse to
487 * stop attempting to remove ancestors, i.e., that no ancestors of the
488 * specified child are eligible for removal.
490 * @param parent parent from which to remove child
491 * @param child_index parent->subtrees index of child to remove
492 * @return #TRUE if removal and free succeed, #FALSE otherwise
495 attempt_child_removal (DBusObjectSubtree *parent,
498 /* Candidate for removal */
499 DBusObjectSubtree* candidate;
501 _dbus_assert (parent != NULL);
502 _dbus_assert (child_index >= 0 && child_index < parent->n_subtrees);
504 candidate = parent->subtrees[child_index];
505 _dbus_assert (candidate != NULL);
507 if (candidate->n_subtrees == 0 && candidate->message_function == NULL)
509 /* The candidate node is childless and is not a registered
512 /* ... remove it from its parent... */
513 /* Assumes a 0-byte memmove is OK */
514 memmove (&parent->subtrees[child_index],
515 &parent->subtrees[child_index + 1],
516 (parent->n_subtrees - child_index - 1)
517 * sizeof (parent->subtrees[0]));
518 parent->n_subtrees -= 1;
520 /* ... and free it */
521 candidate->parent = NULL;
522 _dbus_object_subtree_unref (candidate);
530 * Searches the object tree for a registered subtree node at the given path.
531 * If a registered node is found, it is removed from the tree and freed, and
532 * TRUE is returned. If a registered subtree node is not found at the given
533 * path, the tree is not modified and FALSE is returned.
535 * The found node's unregister_function and user_data are returned in the
536 * corresponding _out arguments. The caller should define these variables and
537 * pass their addresses as arguments.
539 * Likewise, the caller should define and set to TRUE a boolean variable, then
540 * pass its address as the continue_removal_attempts argument.
542 * Once a matching registered node is found, removed and freed, the recursive
543 * return path is traversed. Along the way, eligible ancestor nodes are
544 * removed and freed. An ancestor node is eligible for removal if and only if
545 * 1) it has no children, i.e., it has become childless and 2) it is not itself
546 * a registered handler.
548 * For example, suppose /A/B and /A/C are registered paths, and that these are
549 * the only paths in the tree. If B is removed and freed, C is still reachable
550 * through A, so A cannot be removed and freed. If C is subsequently removed
551 * and freed, then A becomes a childless node and it becomes eligible for
552 * removal, and will be removed and freed.
554 * Similarly, suppose /A is a registered path, and /A/B is also a registered
555 * path, and that these are the only paths in the tree. If B is removed and
556 * freed, then even though A has become childless, it can't be freed because it
557 * refers to a path that is still registered.
559 * @param subtree subtree from which to start the search, root for initial call
560 * @param path path to subtree (same as _dbus_object_tree_unregister_and_unlock)
561 * @param continue_removal_attempts pointer to a bool, #TRUE for initial call
562 * @param unregister_function_out returns the found node's unregister_function
563 * @param user_data_out returns the found node's user_data
564 * @returns #TRUE if a registered node was found at path, #FALSE otherwise
567 unregister_and_free_path_recurse
568 (DBusObjectSubtree *subtree,
570 dbus_bool_t *continue_removal_attempts,
571 DBusObjectPathUnregisterFunction *unregister_function_out,
572 void **user_data_out)
576 _dbus_assert (continue_removal_attempts != NULL);
577 _dbus_assert (*continue_removal_attempts);
578 _dbus_assert (unregister_function_out != NULL);
579 _dbus_assert (user_data_out != NULL);
582 return unregister_subtree (subtree, unregister_function_out, user_data_out);
585 j = subtree->n_subtrees;
591 v = strcmp (path[0], subtree->subtrees[k]->name);
596 freed = unregister_and_free_path_recurse (subtree->subtrees[k],
598 continue_removal_attempts,
599 unregister_function_out,
601 if (freed && *continue_removal_attempts)
602 *continue_removal_attempts = attempt_child_removal (subtree, k);
618 * Unregisters an object subtree that was registered with the
621 * @param tree the global object tree
622 * @param path path to the subtree (same as the one passed to _dbus_object_tree_register())
625 _dbus_object_tree_unregister_and_unlock (DBusObjectTree *tree,
628 dbus_bool_t found_subtree;
629 dbus_bool_t continue_removal_attempts;
630 DBusObjectPathUnregisterFunction unregister_function;
632 DBusConnection *connection;
634 _dbus_assert (tree != NULL);
635 _dbus_assert (path != NULL);
637 continue_removal_attempts = TRUE;
638 unregister_function = NULL;
641 found_subtree = unregister_and_free_path_recurse (tree->root,
643 &continue_removal_attempts,
644 &unregister_function,
647 #ifndef DBUS_DISABLE_CHECKS
648 if (found_subtree == FALSE)
650 _dbus_warn ("Attempted to unregister path (path[0] = %s path[1] = %s) which isn't registered",
651 path[0] ? path[0] : "null",
652 (path[0] && path[1]) ? path[1] : "null");
656 _dbus_assert (found_subtree == TRUE);
660 connection = tree->connection;
662 /* Unlock and call application code */
663 #ifdef DBUS_ENABLE_EMBEDDED_TESTS
667 _dbus_connection_ref_unlocked (connection);
668 _dbus_verbose ("unlock\n");
669 _dbus_connection_unlock (connection);
672 if (unregister_function)
673 (* unregister_function) (connection, user_data);
675 #ifdef DBUS_ENABLE_EMBEDDED_TESTS
678 dbus_connection_unref (connection);
682 free_subtree_recurse (DBusConnection *connection,
683 DBusObjectSubtree *subtree)
685 /* Delete them from the end, for slightly
686 * more robustness against odd reentrancy.
688 while (subtree->n_subtrees > 0)
690 DBusObjectSubtree *child;
692 child = subtree->subtrees[subtree->n_subtrees - 1];
693 subtree->subtrees[subtree->n_subtrees - 1] = NULL;
694 subtree->n_subtrees -= 1;
695 child->parent = NULL;
697 free_subtree_recurse (connection, child);
700 /* Call application code */
701 if (subtree->unregister_function)
702 (* subtree->unregister_function) (connection,
705 subtree->message_function = NULL;
706 subtree->unregister_function = NULL;
707 subtree->user_data = NULL;
709 /* Now free ourselves */
710 _dbus_object_subtree_unref (subtree);
714 * Free all the handlers in the tree. Lock on tree's connection
717 * @param tree the object tree
720 _dbus_object_tree_free_all_unlocked (DBusObjectTree *tree)
723 free_subtree_recurse (tree->connection,
729 _dbus_object_tree_list_registered_unlocked (DBusObjectTree *tree,
730 const char **parent_path,
731 char ***child_entries)
733 DBusObjectSubtree *subtree;
736 _dbus_assert (parent_path != NULL);
737 _dbus_assert (child_entries != NULL);
739 *child_entries = NULL;
741 subtree = lookup_subtree (tree, parent_path);
744 retval = dbus_new0 (char *, 1);
749 retval = dbus_new0 (char*, subtree->n_subtrees + 1);
753 while (i < subtree->n_subtrees)
755 retval[i] = _dbus_strdup (subtree->subtrees[i]->name);
756 if (retval[i] == NULL)
758 dbus_free_string_array (retval);
768 *child_entries = retval;
769 return retval != NULL;
772 static DBusHandlerResult
773 handle_default_introspect_and_unlock (DBusObjectTree *tree,
774 DBusMessage *message,
778 DBusHandlerResult result;
782 DBusMessageIter iter;
783 const char *v_STRING;
784 dbus_bool_t already_unlocked;
786 /* We have the connection lock here */
788 already_unlocked = FALSE;
790 _dbus_verbose (" considering default Introspect() handler...\n");
794 if (!dbus_message_is_method_call (message,
795 DBUS_INTERFACE_INTROSPECTABLE,
798 #ifdef DBUS_ENABLE_EMBEDDED_TESTS
799 if (tree->connection)
802 _dbus_verbose ("unlock\n");
803 _dbus_connection_unlock (tree->connection);
806 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
809 _dbus_verbose (" using default Introspect() handler!\n");
811 if (!_dbus_string_init (&xml))
813 #ifdef DBUS_ENABLE_EMBEDDED_TESTS
814 if (tree->connection)
817 _dbus_verbose ("unlock\n");
818 _dbus_connection_unlock (tree->connection);
821 return DBUS_HANDLER_RESULT_NEED_MEMORY;
824 result = DBUS_HANDLER_RESULT_NEED_MEMORY;
827 if (!_dbus_object_tree_list_registered_unlocked (tree, path, &children))
830 if (!_dbus_string_append (&xml, DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE))
833 if (!_dbus_string_append (&xml, "<node>\n"))
837 while (children[i] != NULL)
839 if (!_dbus_string_append_printf (&xml, " <node name=\"%s\"/>\n",
846 if (!_dbus_string_append (&xml, "</node>\n"))
849 reply = dbus_message_new_method_return (message);
853 dbus_message_iter_init_append (reply, &iter);
854 v_STRING = _dbus_string_get_const_data (&xml);
855 if (!dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &v_STRING))
858 #ifdef DBUS_ENABLE_EMBEDDED_TESTS
859 if (tree->connection)
862 already_unlocked = TRUE;
864 if (!_dbus_connection_send_and_unlock (tree->connection, reply, NULL))
868 result = DBUS_HANDLER_RESULT_HANDLED;
871 #ifdef DBUS_ENABLE_EMBEDDED_TESTS
872 if (tree->connection)
875 if (!already_unlocked)
877 _dbus_verbose ("unlock\n");
878 _dbus_connection_unlock (tree->connection);
882 _dbus_string_free (&xml);
883 dbus_free_string_array (children);
885 dbus_message_unref (reply);
891 * Tries to dispatch a message by directing it to handler for the
892 * object path listed in the message header, if any. Messages are
893 * dispatched first to the registered handler that matches the largest
894 * number of path elements; that is, message to /foo/bar/baz would go
895 * to the handler for /foo/bar before the one for /foo.
897 * @todo thread problems
899 * @param tree the global object tree
900 * @param message the message to dispatch
901 * @param found_object return location for the object
902 * @returns whether message was handled successfully
905 _dbus_object_tree_dispatch_and_unlock (DBusObjectTree *tree,
906 DBusMessage *message,
907 dbus_bool_t *found_object)
910 dbus_bool_t exact_match;
913 DBusHandlerResult result;
914 DBusObjectSubtree *subtree;
917 _dbus_verbose ("Dispatch of message by object path\n");
921 if (!dbus_message_get_path_decomposed (message, &path))
923 #ifdef DBUS_ENABLE_EMBEDDED_TESTS
924 if (tree->connection)
927 _dbus_verbose ("unlock\n");
928 _dbus_connection_unlock (tree->connection);
931 _dbus_verbose ("No memory to get decomposed path\n");
933 return DBUS_HANDLER_RESULT_NEED_MEMORY;
938 #ifdef DBUS_ENABLE_EMBEDDED_TESTS
939 if (tree->connection)
942 _dbus_verbose ("unlock\n");
943 _dbus_connection_unlock (tree->connection);
946 _dbus_verbose ("No path field in message\n");
947 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
950 /* Find the deepest path that covers the path in the message */
951 subtree = find_handler (tree, (const char**) path, &exact_match);
954 *found_object = !!subtree;
956 /* Build a list of all paths that cover the path in the message */
960 while (subtree != NULL)
962 if (subtree->message_function != NULL && (exact_match || subtree->invoke_as_fallback))
964 _dbus_object_subtree_ref (subtree);
966 /* run deepest paths first */
967 if (!_dbus_list_append (&list, subtree))
969 result = DBUS_HANDLER_RESULT_NEED_MEMORY;
970 _dbus_object_subtree_unref (subtree);
971 goto free_and_return;
976 subtree = subtree->parent;
979 _dbus_verbose ("%d handlers in the path tree for this message\n",
980 _dbus_list_get_length (&list));
982 /* Invoke each handler in the list */
984 result = DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
986 link = _dbus_list_get_first_link (&list);
989 DBusList *next = _dbus_list_get_next_link (&list, link);
990 subtree = link->data;
992 /* message_function is NULL if we're unregistered
995 if (subtree->message_function)
997 DBusObjectPathMessageFunction message_function;
1000 message_function = subtree->message_function;
1001 user_data = subtree->user_data;
1004 _dbus_verbose (" (invoking a handler)\n");
1007 #ifdef DBUS_ENABLE_EMBEDDED_TESTS
1008 if (tree->connection)
1011 _dbus_verbose ("unlock\n");
1012 _dbus_connection_unlock (tree->connection);
1015 /* FIXME you could unregister the subtree in another thread
1016 * before we invoke the callback, and I can't figure out a
1017 * good way to solve this.
1020 result = (* message_function) (tree->connection,
1024 #ifdef DBUS_ENABLE_EMBEDDED_TESTS
1025 if (tree->connection)
1027 _dbus_connection_lock (tree->connection);
1029 if (result != DBUS_HANDLER_RESULT_NOT_YET_HANDLED)
1030 goto free_and_return;
1038 if (result == DBUS_HANDLER_RESULT_NOT_YET_HANDLED)
1040 /* This hardcoded default handler does a minimal Introspect()
1042 result = handle_default_introspect_and_unlock (tree, message,
1043 (const char**) path);
1047 #ifdef DBUS_ENABLE_EMBEDDED_TESTS
1048 if (tree->connection)
1051 _dbus_verbose ("unlock\n");
1052 _dbus_connection_unlock (tree->connection);
1056 while (list != NULL)
1058 link = _dbus_list_get_first_link (&list);
1059 _dbus_object_subtree_unref (link->data);
1060 _dbus_list_remove_link (&list, link);
1063 dbus_free_string_array (path);
1069 * Looks up the data passed to _dbus_object_tree_register() for a
1070 * handler at the given path.
1072 * @param tree the global object tree
1073 * @param path NULL-terminated array of path elements giving path to subtree
1074 * @returns the object's user_data or #NULL if none found
1077 _dbus_object_tree_get_user_data_unlocked (DBusObjectTree *tree,
1080 dbus_bool_t exact_match;
1081 DBusObjectSubtree *subtree;
1083 _dbus_assert (tree != NULL);
1084 _dbus_assert (path != NULL);
1086 /* Find the deepest path that covers the path in the message */
1087 subtree = find_handler (tree, (const char**) path, &exact_match);
1089 if ((subtree == NULL) || !exact_match)
1091 _dbus_verbose ("No object at specified path found\n");
1095 return subtree->user_data;
1099 * Allocates a subtree object.
1101 * @param name name to duplicate.
1102 * @returns newly-allocated subtree
1104 static DBusObjectSubtree*
1105 allocate_subtree_object (const char *name)
1108 DBusObjectSubtree *subtree;
1109 const size_t front_padding = _DBUS_STRUCT_OFFSET (DBusObjectSubtree, name);
1111 _dbus_assert (name != NULL);
1113 len = strlen (name);
1115 subtree = dbus_malloc0 (MAX (front_padding + (len + 1), sizeof (DBusObjectSubtree)));
1117 if (subtree == NULL)
1120 memcpy (subtree->name, name, len + 1);
1125 static DBusObjectSubtree*
1126 _dbus_object_subtree_new (const char *name,
1127 const DBusObjectPathVTable *vtable,
1130 DBusObjectSubtree *subtree;
1132 subtree = allocate_subtree_object (name);
1133 if (subtree == NULL)
1136 _dbus_assert (name != NULL);
1138 subtree->parent = NULL;
1142 subtree->message_function = vtable->message_function;
1143 subtree->unregister_function = vtable->unregister_function;
1147 subtree->message_function = NULL;
1148 subtree->unregister_function = NULL;
1151 subtree->user_data = user_data;
1152 _dbus_atomic_inc (&subtree->refcount);
1153 subtree->subtrees = NULL;
1154 subtree->n_subtrees = 0;
1155 subtree->max_subtrees = 0;
1156 subtree->invoke_as_fallback = FALSE;
1164 static DBusObjectSubtree *
1165 _dbus_object_subtree_ref (DBusObjectSubtree *subtree)
1167 #ifdef DBUS_DISABLE_ASSERT
1168 _dbus_atomic_inc (&subtree->refcount);
1170 dbus_int32_t old_value;
1172 old_value = _dbus_atomic_inc (&subtree->refcount);
1173 _dbus_assert (old_value > 0);
1180 _dbus_object_subtree_unref (DBusObjectSubtree *subtree)
1182 dbus_int32_t old_value;
1184 old_value = _dbus_atomic_dec (&subtree->refcount);
1185 _dbus_assert (old_value > 0);
1189 _dbus_assert (subtree->unregister_function == NULL);
1190 _dbus_assert (subtree->message_function == NULL);
1192 dbus_free (subtree->subtrees);
1193 dbus_free (subtree);
1198 * Lists the registered fallback handlers and object path handlers at
1199 * the given parent_path. The returned array should be freed with
1200 * dbus_free_string_array().
1202 * @param tree the object tree
1203 * @param parent_path the path to list the child handlers of
1204 * @param child_entries returns #NULL-terminated array of children
1205 * @returns #FALSE if no memory to allocate the child entries
1208 _dbus_object_tree_list_registered_and_unlock (DBusObjectTree *tree,
1209 const char **parent_path,
1210 char ***child_entries)
1214 result = _dbus_object_tree_list_registered_unlocked (tree,
1218 #ifdef DBUS_ENABLE_EMBEDDED_TESTS
1219 if (tree->connection)
1222 _dbus_verbose ("unlock\n");
1223 _dbus_connection_unlock (tree->connection);
1230 /** Set to 1 to get a bunch of spew about disassembling the path string */
1231 #define VERBOSE_DECOMPOSE 0
1234 * Decompose an object path. A path of just "/" is
1235 * represented as an empty vector of strings.
1236 * The path need not be nul terminated.
1238 * @param data the path data
1239 * @param len the length of the path string
1240 * @param path address to store new object path
1241 * @param path_len length of stored path
1244 _dbus_decompose_path (const char* data,
1253 _dbus_assert (data != NULL);
1254 _dbus_assert (path != NULL);
1256 #if VERBOSE_DECOMPOSE
1257 _dbus_verbose ("Decomposing path \"%s\"\n",
1262 if (len > 1) /* if path is not just "/" */
1267 _dbus_assert (data[i] != '\0');
1274 retval = dbus_new0 (char*, n_components + 1);
1280 if (n_components == 0)
1284 while (comp < n_components)
1286 _dbus_assert (i < len);
1292 while (j < len && data[j] != '/')
1295 /* Now [i, j) is the path component */
1296 _dbus_assert (i < j);
1297 _dbus_assert (data[i] != '/');
1298 _dbus_assert (j == len || data[j] == '/');
1300 #if VERBOSE_DECOMPOSE
1301 _dbus_verbose (" (component in [%d,%d))\n",
1305 retval[comp] = _dbus_memdup (&data[i], j - i + 1);
1306 if (retval[comp] == NULL)
1308 dbus_free_string_array (retval);
1311 retval[comp][j-i] = '\0';
1312 #if VERBOSE_DECOMPOSE
1313 _dbus_verbose (" (component %d = \"%s\")\n",
1314 comp, retval[comp]);
1320 _dbus_assert (i == len);
1324 *path_len = n_components;
1332 flatten_path (const char **path)
1337 if (!_dbus_string_init (&str))
1340 if (path[0] == NULL)
1342 if (!_dbus_string_append_byte (&str, '/'))
1352 if (!_dbus_string_append_byte (&str, '/'))
1355 if (!_dbus_string_append (&str, path[i]))
1362 if (!_dbus_string_steal_data (&str, &s))
1365 _dbus_string_free (&str);
1370 _dbus_string_free (&str);
1375 #ifdef DBUS_ENABLE_EMBEDDED_TESTS
1377 #ifndef DOXYGEN_SHOULD_SKIP_THIS
1379 #include "dbus-test.h"
1389 /* Returns TRUE if container is a parent of child
1391 static StrComparison
1392 path_contains (const char **container,
1398 while (child[i] != NULL)
1402 if (container[i] == NULL)
1403 return STR_PREFIX; /* container ran out, child continues;
1404 * thus the container is a parent of the
1408 _dbus_assert (container[i] != NULL);
1409 _dbus_assert (child[i] != NULL);
1411 v = strcmp (container[i], child[i]);
1414 return STR_DIFFERENT; /* they overlap until here and then are different,
1421 /* Child ran out; if container also did, they are equal;
1422 * otherwise, the child is a parent of the container.
1424 if (container[i] == NULL)
1427 return STR_DIFFERENT;
1432 spew_subtree_recurse (DBusObjectSubtree *subtree,
1440 _dbus_verbose (" ");
1444 _dbus_verbose ("%s (%d children)\n",
1445 subtree->name, subtree->n_subtrees);
1448 while (i < subtree->n_subtrees)
1450 spew_subtree_recurse (subtree->subtrees[i], indent + 2);
1457 spew_tree (DBusObjectTree *tree)
1459 spew_subtree_recurse (tree->root, 0);
1464 * Callback data used in tests
1468 const char **path; /**< Path */
1469 dbus_bool_t handler_fallback; /**< true if the handler may be called as fallback */
1470 dbus_bool_t message_handled; /**< Gets set to true if message handler called */
1471 dbus_bool_t handler_unregistered; /**< gets set to true if handler is unregistered */
1476 test_unregister_function (DBusConnection *connection,
1479 TreeTestData *ttd = user_data;
1481 ttd->handler_unregistered = TRUE;
1484 static DBusHandlerResult
1485 test_message_function (DBusConnection *connection,
1486 DBusMessage *message,
1489 TreeTestData *ttd = user_data;
1491 ttd->message_handled = TRUE;
1493 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1497 do_register (DBusObjectTree *tree,
1499 dbus_bool_t fallback,
1501 TreeTestData *tree_test_data)
1503 DBusObjectPathVTable vtable = { test_unregister_function,
1504 test_message_function, NULL };
1506 tree_test_data[i].message_handled = FALSE;
1507 tree_test_data[i].handler_unregistered = FALSE;
1508 tree_test_data[i].handler_fallback = fallback;
1509 tree_test_data[i].path = path;
1511 if (!_dbus_object_tree_register (tree, fallback, path,
1517 _dbus_assert (_dbus_object_tree_get_user_data_unlocked (tree, path) ==
1518 &tree_test_data[i]);
1524 do_test_dispatch (DBusObjectTree *tree,
1527 TreeTestData *tree_test_data,
1530 DBusMessage *message;
1532 DBusHandlerResult result;
1537 flat = flatten_path (path);
1541 message = dbus_message_new_method_call (NULL,
1543 "org.freedesktop.TestInterface",
1546 if (message == NULL)
1550 while (j < n_test_data)
1552 tree_test_data[j].message_handled = FALSE;
1556 result = _dbus_object_tree_dispatch_and_unlock (tree, message, NULL);
1557 if (result == DBUS_HANDLER_RESULT_NEED_MEMORY)
1560 _dbus_assert (tree_test_data[i].message_handled);
1563 while (j < n_test_data)
1565 if (tree_test_data[j].message_handled)
1567 if (tree_test_data[j].handler_fallback)
1568 _dbus_assert (path_contains (tree_test_data[j].path,
1569 path) != STR_DIFFERENT);
1571 _dbus_assert (path_contains (tree_test_data[j].path, path) == STR_EQUAL);
1575 if (tree_test_data[j].handler_fallback)
1576 _dbus_assert (path_contains (tree_test_data[j].path,
1577 path) == STR_DIFFERENT);
1579 _dbus_assert (path_contains (tree_test_data[j].path, path) != STR_EQUAL);
1585 dbus_message_unref (message);
1591 dbus_message_unref (message);
1598 const char *result[20];
1599 } DecomposePathTest;
1601 static DecomposePathTest decompose_tests[] = {
1602 { "/foo", { "foo", NULL } },
1603 { "/foo/bar", { "foo", "bar", NULL } },
1605 { "/a/b", { "a", "b", NULL } },
1606 { "/a/b/c", { "a", "b", "c", NULL } },
1607 { "/a/b/c/d", { "a", "b", "c", "d", NULL } },
1608 { "/foo/bar/q", { "foo", "bar", "q", NULL } },
1609 { "/foo/bar/this/is/longer", { "foo", "bar", "this", "is", "longer", NULL } }
1612 /* Return TRUE on success, FALSE on OOM, die with an assertion failure
1615 run_decompose_tests (void)
1620 while (i < _DBUS_N_ELEMENTS (decompose_tests))
1626 if (!_dbus_decompose_path (decompose_tests[i].path,
1627 strlen (decompose_tests[i].path),
1628 &result, &result_len))
1631 expected_len = _dbus_string_array_length (decompose_tests[i].result);
1633 if (result_len != (int) _dbus_string_array_length ((const char**)result) ||
1634 expected_len != result_len ||
1635 path_contains (decompose_tests[i].result,
1636 (const char**) result) != STR_EQUAL)
1638 int real_len = _dbus_string_array_length ((const char**)result);
1639 _dbus_warn ("Expected decompose of %s to have len %d, returned %d, appears to have %d",
1640 decompose_tests[i].path, expected_len, result_len,
1642 _dbus_warn ("Decompose resulted in elements: { ");
1644 while (i < real_len)
1646 _dbus_warn ("\"%s\"%s", result[i],
1647 (i + 1) == real_len ? "" : ", ");
1651 _dbus_assert_not_reached ("path decompose failed");
1654 dbus_free_string_array (result);
1662 static DBusObjectSubtree*
1663 find_subtree_registered_or_unregistered (DBusObjectTree *tree,
1667 _dbus_verbose ("Looking for exact subtree, registered or unregistered\n");
1670 return find_subtree_recurse (tree->root, path, FALSE, NULL, NULL);
1673 /* Returns TRUE if the right thing happens, but the right thing might
1676 object_tree_test_iteration (void *data)
1678 const char *path0[] = { NULL };
1679 const char *path1[] = { "foo", NULL };
1680 const char *path2[] = { "foo", "bar", NULL };
1681 const char *path3[] = { "foo", "bar", "baz", NULL };
1682 const char *path4[] = { "foo", "bar", "boo", NULL };
1683 const char *path5[] = { "blah", NULL };
1684 const char *path6[] = { "blah", "boof", NULL };
1685 const char *path7[] = { "blah", "boof", "this", "is", "really", "long", NULL };
1686 const char *path8[] = { "childless", NULL };
1687 const char *path9[] = { "blah", "a", NULL };
1688 const char *path10[] = { "blah", "b", NULL };
1689 const char *path11[] = { "blah", "c", NULL };
1690 const char *path12[] = { "blah", "a", "d", NULL };
1691 const char *path13[] = { "blah", "b", "d", NULL };
1692 const char *path14[] = { "blah", "c", "d", NULL };
1693 DBusObjectPathVTable test_vtable = { NULL, test_message_function, NULL };
1694 DBusObjectTree *tree;
1695 TreeTestData tree_test_data[9];
1697 dbus_bool_t exact_match;
1699 if (!run_decompose_tests ())
1700 return TRUE; /* OOM is OK */
1704 tree = _dbus_object_tree_new (NULL);
1708 if (!do_register (tree, path0, TRUE, 0, tree_test_data))
1711 _dbus_assert (find_subtree (tree, path0, NULL));
1712 _dbus_assert (!find_subtree (tree, path1, NULL));
1713 _dbus_assert (!find_subtree (tree, path2, NULL));
1714 _dbus_assert (!find_subtree (tree, path3, NULL));
1715 _dbus_assert (!find_subtree (tree, path4, NULL));
1716 _dbus_assert (!find_subtree (tree, path5, NULL));
1717 _dbus_assert (!find_subtree (tree, path6, NULL));
1718 _dbus_assert (!find_subtree (tree, path7, NULL));
1719 _dbus_assert (!find_subtree (tree, path8, NULL));
1721 _dbus_assert (find_handler (tree, path0, &exact_match) && exact_match);
1722 _dbus_assert (find_handler (tree, path1, &exact_match) == tree->root && !exact_match);
1723 _dbus_assert (find_handler (tree, path2, &exact_match) == tree->root && !exact_match);
1724 _dbus_assert (find_handler (tree, path3, &exact_match) == tree->root && !exact_match);
1725 _dbus_assert (find_handler (tree, path4, &exact_match) == tree->root && !exact_match);
1726 _dbus_assert (find_handler (tree, path5, &exact_match) == tree->root && !exact_match);
1727 _dbus_assert (find_handler (tree, path6, &exact_match) == tree->root && !exact_match);
1728 _dbus_assert (find_handler (tree, path7, &exact_match) == tree->root && !exact_match);
1729 _dbus_assert (find_handler (tree, path8, &exact_match) == tree->root && !exact_match);
1731 if (!do_register (tree, path1, TRUE, 1, tree_test_data))
1734 _dbus_assert (find_subtree (tree, path0, NULL));
1735 _dbus_assert (find_subtree (tree, path1, NULL));
1736 _dbus_assert (!find_subtree (tree, path2, NULL));
1737 _dbus_assert (!find_subtree (tree, path3, NULL));
1738 _dbus_assert (!find_subtree (tree, path4, NULL));
1739 _dbus_assert (!find_subtree (tree, path5, NULL));
1740 _dbus_assert (!find_subtree (tree, path6, NULL));
1741 _dbus_assert (!find_subtree (tree, path7, NULL));
1742 _dbus_assert (!find_subtree (tree, path8, NULL));
1744 _dbus_assert (find_handler (tree, path0, &exact_match) && exact_match);
1745 _dbus_assert (find_handler (tree, path1, &exact_match) && exact_match);
1746 _dbus_assert (find_handler (tree, path2, &exact_match) && !exact_match);
1747 _dbus_assert (find_handler (tree, path3, &exact_match) && !exact_match);
1748 _dbus_assert (find_handler (tree, path4, &exact_match) && !exact_match);
1749 _dbus_assert (find_handler (tree, path5, &exact_match) == tree->root && !exact_match);
1750 _dbus_assert (find_handler (tree, path6, &exact_match) == tree->root && !exact_match);
1751 _dbus_assert (find_handler (tree, path7, &exact_match) == tree->root && !exact_match);
1752 _dbus_assert (find_handler (tree, path8, &exact_match) == tree->root && !exact_match);
1754 if (!do_register (tree, path2, TRUE, 2, tree_test_data))
1757 _dbus_assert (find_subtree (tree, path1, NULL));
1758 _dbus_assert (find_subtree (tree, path2, NULL));
1759 _dbus_assert (!find_subtree (tree, path3, NULL));
1760 _dbus_assert (!find_subtree (tree, path4, NULL));
1761 _dbus_assert (!find_subtree (tree, path5, NULL));
1762 _dbus_assert (!find_subtree (tree, path6, NULL));
1763 _dbus_assert (!find_subtree (tree, path7, NULL));
1764 _dbus_assert (!find_subtree (tree, path8, NULL));
1766 if (!do_register (tree, path3, TRUE, 3, tree_test_data))
1769 _dbus_assert (find_subtree (tree, path0, NULL));
1770 _dbus_assert (find_subtree (tree, path1, NULL));
1771 _dbus_assert (find_subtree (tree, path2, NULL));
1772 _dbus_assert (find_subtree (tree, path3, NULL));
1773 _dbus_assert (!find_subtree (tree, path4, NULL));
1774 _dbus_assert (!find_subtree (tree, path5, NULL));
1775 _dbus_assert (!find_subtree (tree, path6, NULL));
1776 _dbus_assert (!find_subtree (tree, path7, NULL));
1777 _dbus_assert (!find_subtree (tree, path8, NULL));
1779 if (!do_register (tree, path4, TRUE, 4, tree_test_data))
1782 _dbus_assert (find_subtree (tree, path0, NULL));
1783 _dbus_assert (find_subtree (tree, path1, NULL));
1784 _dbus_assert (find_subtree (tree, path2, NULL));
1785 _dbus_assert (find_subtree (tree, path3, NULL));
1786 _dbus_assert (find_subtree (tree, path4, NULL));
1787 _dbus_assert (!find_subtree (tree, path5, NULL));
1788 _dbus_assert (!find_subtree (tree, path6, NULL));
1789 _dbus_assert (!find_subtree (tree, path7, NULL));
1790 _dbus_assert (!find_subtree (tree, path8, NULL));
1792 if (!do_register (tree, path5, TRUE, 5, tree_test_data))
1795 _dbus_assert (find_subtree (tree, path0, NULL));
1796 _dbus_assert (find_subtree (tree, path1, NULL));
1797 _dbus_assert (find_subtree (tree, path2, NULL));
1798 _dbus_assert (find_subtree (tree, path3, NULL));
1799 _dbus_assert (find_subtree (tree, path4, NULL));
1800 _dbus_assert (find_subtree (tree, path5, NULL));
1801 _dbus_assert (!find_subtree (tree, path6, NULL));
1802 _dbus_assert (!find_subtree (tree, path7, NULL));
1803 _dbus_assert (!find_subtree (tree, path8, NULL));
1805 _dbus_assert (find_handler (tree, path0, &exact_match) == tree->root && exact_match);
1806 _dbus_assert (find_handler (tree, path1, &exact_match) != tree->root && exact_match);
1807 _dbus_assert (find_handler (tree, path2, &exact_match) != tree->root && exact_match);
1808 _dbus_assert (find_handler (tree, path3, &exact_match) != tree->root && exact_match);
1809 _dbus_assert (find_handler (tree, path4, &exact_match) != tree->root && exact_match);
1810 _dbus_assert (find_handler (tree, path5, &exact_match) != tree->root && exact_match);
1811 _dbus_assert (find_handler (tree, path6, &exact_match) != tree->root && !exact_match);
1812 _dbus_assert (find_handler (tree, path7, &exact_match) != tree->root && !exact_match);
1813 _dbus_assert (find_handler (tree, path8, &exact_match) == tree->root && !exact_match);
1815 if (!do_register (tree, path6, TRUE, 6, tree_test_data))
1818 _dbus_assert (find_subtree (tree, path0, NULL));
1819 _dbus_assert (find_subtree (tree, path1, NULL));
1820 _dbus_assert (find_subtree (tree, path2, NULL));
1821 _dbus_assert (find_subtree (tree, path3, NULL));
1822 _dbus_assert (find_subtree (tree, path4, NULL));
1823 _dbus_assert (find_subtree (tree, path5, NULL));
1824 _dbus_assert (find_subtree (tree, path6, NULL));
1825 _dbus_assert (!find_subtree (tree, path7, NULL));
1826 _dbus_assert (!find_subtree (tree, path8, NULL));
1828 if (!do_register (tree, path7, TRUE, 7, tree_test_data))
1831 _dbus_assert (find_subtree (tree, path0, NULL));
1832 _dbus_assert (find_subtree (tree, path1, NULL));
1833 _dbus_assert (find_subtree (tree, path2, NULL));
1834 _dbus_assert (find_subtree (tree, path3, NULL));
1835 _dbus_assert (find_subtree (tree, path4, NULL));
1836 _dbus_assert (find_subtree (tree, path5, NULL));
1837 _dbus_assert (find_subtree (tree, path6, NULL));
1838 _dbus_assert (find_subtree (tree, path7, NULL));
1839 _dbus_assert (!find_subtree (tree, path8, NULL));
1841 if (!do_register (tree, path8, TRUE, 8, tree_test_data))
1844 _dbus_assert (find_subtree (tree, path0, NULL));
1845 _dbus_assert (find_subtree (tree, path1, NULL));
1846 _dbus_assert (find_subtree (tree, path2, NULL));
1847 _dbus_assert (find_subtree (tree, path3, NULL));
1848 _dbus_assert (find_subtree (tree, path4, NULL));
1849 _dbus_assert (find_subtree (tree, path5, NULL));
1850 _dbus_assert (find_subtree (tree, path6, NULL));
1851 _dbus_assert (find_subtree (tree, path7, NULL));
1852 _dbus_assert (find_subtree (tree, path8, NULL));
1854 _dbus_assert (find_handler (tree, path0, &exact_match) == tree->root && exact_match);
1855 _dbus_assert (find_handler (tree, path1, &exact_match) != tree->root && exact_match);
1856 _dbus_assert (find_handler (tree, path2, &exact_match) != tree->root && exact_match);
1857 _dbus_assert (find_handler (tree, path3, &exact_match) != tree->root && exact_match);
1858 _dbus_assert (find_handler (tree, path4, &exact_match) != tree->root && exact_match);
1859 _dbus_assert (find_handler (tree, path5, &exact_match) != tree->root && exact_match);
1860 _dbus_assert (find_handler (tree, path6, &exact_match) != tree->root && exact_match);
1861 _dbus_assert (find_handler (tree, path7, &exact_match) != tree->root && exact_match);
1862 _dbus_assert (find_handler (tree, path8, &exact_match) != tree->root && exact_match);
1864 /* test the list_registered function */
1867 const char *root[] = { NULL };
1868 char **child_entries;
1871 _dbus_object_tree_list_registered_unlocked (tree, path1, &child_entries);
1872 if (child_entries != NULL)
1874 nb = _dbus_string_array_length ((const char**)child_entries);
1875 _dbus_assert (nb == 1);
1876 dbus_free_string_array (child_entries);
1879 _dbus_object_tree_list_registered_unlocked (tree, path2, &child_entries);
1880 if (child_entries != NULL)
1882 nb = _dbus_string_array_length ((const char**)child_entries);
1883 _dbus_assert (nb == 2);
1884 dbus_free_string_array (child_entries);
1887 _dbus_object_tree_list_registered_unlocked (tree, path8, &child_entries);
1888 if (child_entries != NULL)
1890 nb = _dbus_string_array_length ((const char**)child_entries);
1891 _dbus_assert (nb == 0);
1892 dbus_free_string_array (child_entries);
1895 _dbus_object_tree_list_registered_unlocked (tree, root, &child_entries);
1896 if (child_entries != NULL)
1898 nb = _dbus_string_array_length ((const char**)child_entries);
1899 _dbus_assert (nb == 3);
1900 dbus_free_string_array (child_entries);
1904 /* Check that destroying tree calls unregister funcs */
1905 _dbus_object_tree_unref (tree);
1908 while (i < (int) _DBUS_N_ELEMENTS (tree_test_data))
1910 _dbus_assert (tree_test_data[i].handler_unregistered);
1911 _dbus_assert (!tree_test_data[i].message_handled);
1915 /* Now start again and try the individual unregister function */
1916 tree = _dbus_object_tree_new (NULL);
1920 if (!do_register (tree, path0, TRUE, 0, tree_test_data))
1922 if (!do_register (tree, path1, TRUE, 1, tree_test_data))
1924 if (!do_register (tree, path2, TRUE, 2, tree_test_data))
1926 if (!do_register (tree, path3, TRUE, 3, tree_test_data))
1928 if (!do_register (tree, path4, TRUE, 4, tree_test_data))
1930 if (!do_register (tree, path5, TRUE, 5, tree_test_data))
1932 if (!do_register (tree, path6, TRUE, 6, tree_test_data))
1934 if (!do_register (tree, path7, TRUE, 7, tree_test_data))
1936 if (!do_register (tree, path8, TRUE, 8, tree_test_data))
1939 _dbus_object_tree_unregister_and_unlock (tree, path0);
1940 _dbus_assert (_dbus_object_tree_get_user_data_unlocked (tree, path0) == NULL);
1942 _dbus_assert (!find_subtree (tree, path0, NULL));
1943 _dbus_assert (find_subtree (tree, path1, NULL));
1944 _dbus_assert (find_subtree (tree, path2, NULL));
1945 _dbus_assert (find_subtree (tree, path3, NULL));
1946 _dbus_assert (find_subtree (tree, path4, NULL));
1947 _dbus_assert (find_subtree (tree, path5, NULL));
1948 _dbus_assert (find_subtree (tree, path6, NULL));
1949 _dbus_assert (find_subtree (tree, path7, NULL));
1950 _dbus_assert (find_subtree (tree, path8, NULL));
1952 _dbus_object_tree_unregister_and_unlock (tree, path1);
1953 _dbus_assert (_dbus_object_tree_get_user_data_unlocked (tree, path1) == NULL);
1955 _dbus_assert (!find_subtree (tree, path0, NULL));
1956 _dbus_assert (!find_subtree (tree, path1, NULL));
1957 _dbus_assert (find_subtree (tree, path2, NULL));
1958 _dbus_assert (find_subtree (tree, path3, NULL));
1959 _dbus_assert (find_subtree (tree, path4, NULL));
1960 _dbus_assert (find_subtree (tree, path5, NULL));
1961 _dbus_assert (find_subtree (tree, path6, NULL));
1962 _dbus_assert (find_subtree (tree, path7, NULL));
1963 _dbus_assert (find_subtree (tree, path8, NULL));
1965 _dbus_object_tree_unregister_and_unlock (tree, path2);
1966 _dbus_assert (_dbus_object_tree_get_user_data_unlocked (tree, path2) == NULL);
1968 _dbus_assert (!find_subtree (tree, path0, NULL));
1969 _dbus_assert (!find_subtree (tree, path1, NULL));
1970 _dbus_assert (!find_subtree (tree, path2, NULL));
1971 _dbus_assert (find_subtree (tree, path3, NULL));
1972 _dbus_assert (find_subtree (tree, path4, NULL));
1973 _dbus_assert (find_subtree (tree, path5, NULL));
1974 _dbus_assert (find_subtree (tree, path6, NULL));
1975 _dbus_assert (find_subtree (tree, path7, NULL));
1976 _dbus_assert (find_subtree (tree, path8, NULL));
1978 _dbus_object_tree_unregister_and_unlock (tree, path3);
1979 _dbus_assert (_dbus_object_tree_get_user_data_unlocked (tree, path3) == NULL);
1981 _dbus_assert (!find_subtree (tree, path0, NULL));
1982 _dbus_assert (!find_subtree (tree, path1, NULL));
1983 _dbus_assert (!find_subtree (tree, path2, NULL));
1984 _dbus_assert (!find_subtree (tree, path3, NULL));
1985 _dbus_assert (find_subtree (tree, path4, NULL));
1986 _dbus_assert (find_subtree (tree, path5, NULL));
1987 _dbus_assert (find_subtree (tree, path6, NULL));
1988 _dbus_assert (find_subtree (tree, path7, NULL));
1989 _dbus_assert (find_subtree (tree, path8, NULL));
1991 _dbus_object_tree_unregister_and_unlock (tree, path4);
1992 _dbus_assert (_dbus_object_tree_get_user_data_unlocked (tree, path4) == NULL);
1994 _dbus_assert (!find_subtree (tree, path0, NULL));
1995 _dbus_assert (!find_subtree (tree, path1, NULL));
1996 _dbus_assert (!find_subtree (tree, path2, NULL));
1997 _dbus_assert (!find_subtree (tree, path3, NULL));
1998 _dbus_assert (!find_subtree (tree, path4, NULL));
1999 _dbus_assert (find_subtree (tree, path5, NULL));
2000 _dbus_assert (find_subtree (tree, path6, NULL));
2001 _dbus_assert (find_subtree (tree, path7, NULL));
2002 _dbus_assert (find_subtree (tree, path8, NULL));
2004 _dbus_object_tree_unregister_and_unlock (tree, path5);
2005 _dbus_assert (_dbus_object_tree_get_user_data_unlocked (tree, path5) == NULL);
2007 _dbus_assert (!find_subtree (tree, path0, NULL));
2008 _dbus_assert (!find_subtree (tree, path1, NULL));
2009 _dbus_assert (!find_subtree (tree, path2, NULL));
2010 _dbus_assert (!find_subtree (tree, path3, NULL));
2011 _dbus_assert (!find_subtree (tree, path4, NULL));
2012 _dbus_assert (!find_subtree (tree, path5, NULL));
2013 _dbus_assert (find_subtree (tree, path6, NULL));
2014 _dbus_assert (find_subtree (tree, path7, NULL));
2015 _dbus_assert (find_subtree (tree, path8, NULL));
2017 _dbus_object_tree_unregister_and_unlock (tree, path6);
2018 _dbus_assert (_dbus_object_tree_get_user_data_unlocked (tree, path6) == NULL);
2020 _dbus_assert (!find_subtree (tree, path0, NULL));
2021 _dbus_assert (!find_subtree (tree, path1, NULL));
2022 _dbus_assert (!find_subtree (tree, path2, NULL));
2023 _dbus_assert (!find_subtree (tree, path3, NULL));
2024 _dbus_assert (!find_subtree (tree, path4, NULL));
2025 _dbus_assert (!find_subtree (tree, path5, NULL));
2026 _dbus_assert (!find_subtree (tree, path6, NULL));
2027 _dbus_assert (find_subtree (tree, path7, NULL));
2028 _dbus_assert (find_subtree (tree, path8, NULL));
2030 _dbus_object_tree_unregister_and_unlock (tree, path7);
2031 _dbus_assert (_dbus_object_tree_get_user_data_unlocked (tree, path7) == NULL);
2033 _dbus_assert (!find_subtree (tree, path0, NULL));
2034 _dbus_assert (!find_subtree (tree, path1, NULL));
2035 _dbus_assert (!find_subtree (tree, path2, NULL));
2036 _dbus_assert (!find_subtree (tree, path3, NULL));
2037 _dbus_assert (!find_subtree (tree, path4, NULL));
2038 _dbus_assert (!find_subtree (tree, path5, NULL));
2039 _dbus_assert (!find_subtree (tree, path6, NULL));
2040 _dbus_assert (!find_subtree (tree, path7, NULL));
2041 _dbus_assert (find_subtree (tree, path8, NULL));
2043 _dbus_object_tree_unregister_and_unlock (tree, path8);
2044 _dbus_assert (_dbus_object_tree_get_user_data_unlocked (tree, path8) == NULL);
2046 _dbus_assert (!find_subtree (tree, path0, NULL));
2047 _dbus_assert (!find_subtree (tree, path1, NULL));
2048 _dbus_assert (!find_subtree (tree, path2, NULL));
2049 _dbus_assert (!find_subtree (tree, path3, NULL));
2050 _dbus_assert (!find_subtree (tree, path4, NULL));
2051 _dbus_assert (!find_subtree (tree, path5, NULL));
2052 _dbus_assert (!find_subtree (tree, path6, NULL));
2053 _dbus_assert (!find_subtree (tree, path7, NULL));
2054 _dbus_assert (!find_subtree (tree, path8, NULL));
2057 while (i < (int) _DBUS_N_ELEMENTS (tree_test_data))
2059 _dbus_assert (tree_test_data[i].handler_unregistered);
2060 _dbus_assert (!tree_test_data[i].message_handled);
2064 /* Test removal of newly-childless unregistered nodes */
2065 if (!do_register (tree, path2, TRUE, 2, tree_test_data))
2068 _dbus_object_tree_unregister_and_unlock (tree, path2);
2069 _dbus_assert (!find_subtree_registered_or_unregistered (tree, path2));
2070 _dbus_assert (!find_subtree_registered_or_unregistered (tree, path1));
2071 _dbus_assert (find_subtree_registered_or_unregistered (tree, path0));
2073 /* Test that unregistered parents cannot be freed out from under their
2075 if (!do_register (tree, path2, TRUE, 2, tree_test_data))
2078 _dbus_assert (!find_subtree (tree, path1, NULL));
2079 _dbus_assert (find_subtree_registered_or_unregistered (tree, path1));
2080 _dbus_assert (find_subtree_registered_or_unregistered (tree, path0));
2083 /* This triggers the "Attempted to unregister path ..." warning message */
2084 _dbus_object_tree_unregister_and_unlock (tree, path1);
2086 _dbus_assert (find_subtree (tree, path2, NULL));
2087 _dbus_assert (!find_subtree (tree, path1, NULL));
2088 _dbus_assert (find_subtree_registered_or_unregistered (tree, path1));
2089 _dbus_assert (find_subtree_registered_or_unregistered (tree, path0));
2091 _dbus_object_tree_unregister_and_unlock (tree, path2);
2092 _dbus_assert (!find_subtree (tree, path2, NULL));
2093 _dbus_assert (!find_subtree_registered_or_unregistered (tree, path2));
2094 _dbus_assert (!find_subtree_registered_or_unregistered (tree, path1));
2095 _dbus_assert (find_subtree_registered_or_unregistered (tree, path0));
2097 /* Test that registered parents cannot be freed out from under their
2098 children, and that if they are unregistered before their children, they
2099 are still freed when their children are unregistered */
2100 if (!do_register (tree, path1, TRUE, 1, tree_test_data))
2102 if (!do_register (tree, path2, TRUE, 2, tree_test_data))
2105 _dbus_assert (find_subtree (tree, path1, NULL));
2106 _dbus_assert (find_subtree (tree, path2, NULL));
2108 _dbus_object_tree_unregister_and_unlock (tree, path1);
2109 _dbus_assert (!find_subtree (tree, path1, NULL));
2110 _dbus_assert (find_subtree (tree, path2, NULL));
2111 _dbus_assert (find_subtree_registered_or_unregistered (tree, path1));
2112 _dbus_assert (find_subtree_registered_or_unregistered (tree, path0));
2114 _dbus_object_tree_unregister_and_unlock (tree, path2);
2115 _dbus_assert (!find_subtree (tree, path1, NULL));
2116 _dbus_assert (!find_subtree_registered_or_unregistered (tree, path1));
2117 _dbus_assert (!find_subtree (tree, path2, NULL));
2118 _dbus_assert (!find_subtree_registered_or_unregistered (tree, path2));
2119 _dbus_assert (find_subtree_registered_or_unregistered (tree, path0));
2121 /* Test with NULL unregister_function and user_data */
2122 if (!_dbus_object_tree_register (tree, TRUE, path2,
2128 _dbus_assert (_dbus_object_tree_get_user_data_unlocked (tree, path2) == NULL);
2129 _dbus_object_tree_unregister_and_unlock (tree, path2);
2130 _dbus_assert (!find_subtree (tree, path2, NULL));
2131 _dbus_assert (!find_subtree_registered_or_unregistered (tree, path2));
2132 _dbus_assert (!find_subtree_registered_or_unregistered (tree, path1));
2133 _dbus_assert (find_subtree_registered_or_unregistered (tree, path0));
2135 /* Test freeing a long path */
2136 if (!do_register (tree, path3, TRUE, 3, tree_test_data))
2139 _dbus_object_tree_unregister_and_unlock (tree, path3);
2140 _dbus_assert (!find_subtree (tree, path3, NULL));
2141 _dbus_assert (!find_subtree_registered_or_unregistered (tree, path3));
2142 _dbus_assert (!find_subtree_registered_or_unregistered (tree, path2));
2143 _dbus_assert (!find_subtree_registered_or_unregistered (tree, path1));
2144 _dbus_assert (find_subtree_registered_or_unregistered (tree, path0));
2146 /* Test freeing multiple children from the same path */
2147 if (!do_register (tree, path3, TRUE, 3, tree_test_data))
2149 if (!do_register (tree, path4, TRUE, 4, tree_test_data))
2152 _dbus_assert (find_subtree (tree, path3, NULL));
2153 _dbus_assert (find_subtree (tree, path4, NULL));
2155 _dbus_object_tree_unregister_and_unlock (tree, path3);
2156 _dbus_assert (!find_subtree (tree, path3, NULL));
2157 _dbus_assert (!find_subtree_registered_or_unregistered (tree, path3));
2158 _dbus_assert (find_subtree (tree, path4, NULL));
2159 _dbus_assert (find_subtree_registered_or_unregistered (tree, path4));
2160 _dbus_assert (find_subtree_registered_or_unregistered (tree, path2));
2161 _dbus_assert (find_subtree_registered_or_unregistered (tree, path1));
2163 _dbus_object_tree_unregister_and_unlock (tree, path4);
2164 _dbus_assert (!find_subtree (tree, path4, NULL));
2165 _dbus_assert (!find_subtree_registered_or_unregistered (tree, path4));
2166 _dbus_assert (!find_subtree (tree, path3, NULL));
2167 _dbus_assert (!find_subtree_registered_or_unregistered (tree, path3));
2168 _dbus_assert (!find_subtree_registered_or_unregistered (tree, path2));
2169 _dbus_assert (!find_subtree_registered_or_unregistered (tree, path1));
2171 /* Test subtree removal */
2172 if (!_dbus_object_tree_register (tree, TRUE, path12,
2178 _dbus_assert (find_subtree (tree, path12, NULL));
2180 if (!_dbus_object_tree_register (tree, TRUE, path13,
2186 _dbus_assert (find_subtree (tree, path13, NULL));
2188 if (!_dbus_object_tree_register (tree, TRUE, path14,
2194 _dbus_assert (find_subtree (tree, path14, NULL));
2196 _dbus_object_tree_unregister_and_unlock (tree, path12);
2198 _dbus_assert (!find_subtree_registered_or_unregistered (tree, path12));
2199 _dbus_assert (find_subtree (tree, path13, NULL));
2200 _dbus_assert (find_subtree (tree, path14, NULL));
2201 _dbus_assert (!find_subtree_registered_or_unregistered (tree, path9));
2202 _dbus_assert (find_subtree_registered_or_unregistered (tree, path5));
2204 if (!_dbus_object_tree_register (tree, TRUE, path12,
2210 _dbus_assert (find_subtree (tree, path12, NULL));
2212 _dbus_object_tree_unregister_and_unlock (tree, path13);
2214 _dbus_assert (find_subtree (tree, path12, NULL));
2215 _dbus_assert (!find_subtree_registered_or_unregistered (tree, path13));
2216 _dbus_assert (find_subtree (tree, path14, NULL));
2217 _dbus_assert (!find_subtree_registered_or_unregistered (tree, path10));
2218 _dbus_assert (find_subtree_registered_or_unregistered (tree, path5));
2220 if (!_dbus_object_tree_register (tree, TRUE, path13,
2226 _dbus_assert (find_subtree (tree, path13, NULL));
2228 _dbus_object_tree_unregister_and_unlock (tree, path14);
2230 _dbus_assert (find_subtree (tree, path12, NULL));
2231 _dbus_assert (find_subtree (tree, path13, NULL));
2232 _dbus_assert (!find_subtree_registered_or_unregistered (tree, path14));
2233 _dbus_assert (!find_subtree_registered_or_unregistered (tree, path11));
2234 _dbus_assert (find_subtree_registered_or_unregistered (tree, path5));
2236 _dbus_object_tree_unregister_and_unlock (tree, path12);
2238 _dbus_assert (!find_subtree_registered_or_unregistered (tree, path12));
2239 _dbus_assert (!find_subtree_registered_or_unregistered (tree, path9));
2240 _dbus_assert (find_subtree_registered_or_unregistered (tree, path5));
2242 _dbus_object_tree_unregister_and_unlock (tree, path13);
2244 _dbus_assert (!find_subtree_registered_or_unregistered (tree, path13));
2245 _dbus_assert (!find_subtree_registered_or_unregistered (tree, path10));
2246 _dbus_assert (!find_subtree_registered_or_unregistered (tree, path5));
2249 /* Test attempting to unregister non-existent paths. These trigger
2250 "Attempted to unregister path ..." warning messages */
2251 _dbus_object_tree_unregister_and_unlock (tree, path0);
2252 _dbus_object_tree_unregister_and_unlock (tree, path1);
2253 _dbus_object_tree_unregister_and_unlock (tree, path2);
2254 _dbus_object_tree_unregister_and_unlock (tree, path3);
2255 _dbus_object_tree_unregister_and_unlock (tree, path4);
2258 /* Register it all again, and test dispatch */
2260 if (!do_register (tree, path0, TRUE, 0, tree_test_data))
2262 if (!do_register (tree, path1, FALSE, 1, tree_test_data))
2264 if (!do_register (tree, path2, TRUE, 2, tree_test_data))
2266 if (!do_register (tree, path3, TRUE, 3, tree_test_data))
2268 if (!do_register (tree, path4, TRUE, 4, tree_test_data))
2270 if (!do_register (tree, path5, TRUE, 5, tree_test_data))
2272 if (!do_register (tree, path6, FALSE, 6, tree_test_data))
2274 if (!do_register (tree, path7, TRUE, 7, tree_test_data))
2276 if (!do_register (tree, path8, TRUE, 8, tree_test_data))
2283 if (!do_test_dispatch (tree, path0, 0, tree_test_data, _DBUS_N_ELEMENTS (tree_test_data)))
2285 if (!do_test_dispatch (tree, path1, 1, tree_test_data, _DBUS_N_ELEMENTS (tree_test_data)))
2287 if (!do_test_dispatch (tree, path2, 2, tree_test_data, _DBUS_N_ELEMENTS (tree_test_data)))
2289 if (!do_test_dispatch (tree, path3, 3, tree_test_data, _DBUS_N_ELEMENTS (tree_test_data)))
2291 if (!do_test_dispatch (tree, path4, 4, tree_test_data, _DBUS_N_ELEMENTS (tree_test_data)))
2293 if (!do_test_dispatch (tree, path5, 5, tree_test_data, _DBUS_N_ELEMENTS (tree_test_data)))
2295 if (!do_test_dispatch (tree, path6, 6, tree_test_data, _DBUS_N_ELEMENTS (tree_test_data)))
2297 if (!do_test_dispatch (tree, path7, 7, tree_test_data, _DBUS_N_ELEMENTS (tree_test_data)))
2299 if (!do_test_dispatch (tree, path8, 8, tree_test_data, _DBUS_N_ELEMENTS (tree_test_data)))
2306 _dbus_object_tree_ref (tree);
2307 _dbus_object_tree_unref (tree);
2308 _dbus_object_tree_unref (tree);
2315 * @ingroup DBusObjectTree
2316 * Unit test for DBusObjectTree
2317 * @returns #TRUE on success.
2320 _dbus_object_tree_test (void)
2322 return _dbus_test_oom_handling ("object tree",
2323 object_tree_test_iteration,
2327 #endif /* !DOXYGEN_SHOULD_SKIP_THIS */
2329 #endif /* DBUS_ENABLE_EMBEDDED_TESTS */