D-Bus: dbus-object-tree.c Source File

D-Bus 1.10.22

dbus-object-tree.c
1 /* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
2 /* dbus-object-tree.c DBusObjectTree (internals of DBusConnection)
3 *
4 * Copyright (C) 2003, 2005 Red Hat Inc.
5 *
6 * Licensed under the Academic Free License version 2.1
7 *
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.
12 *
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.
17 *
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
21 *
22 */
23
24 #include <config.h>
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"
31 #include <string.h>
32 #include <stdlib.h>
33
46 typedef struct DBusObjectSubtree DBusObjectSubtree;
47
48 static DBusObjectSubtree* _dbus_object_subtree_new (const char *name,
49 const DBusObjectPathVTable *vtable,
50 void *user_data);
51 static DBusObjectSubtree* _dbus_object_subtree_ref (DBusObjectSubtree *subtree);
52 static void _dbus_object_subtree_unref (DBusObjectSubtree *subtree);
53
57 struct DBusObjectTree
58 {
59 int refcount;
60 DBusConnection *connection;
62 DBusObjectSubtree *root;
63 };
64
70 struct DBusObjectSubtree
71 {
72 DBusAtomic refcount;
73 DBusObjectSubtree *parent;
74 DBusObjectPathUnregisterFunction unregister_function;
75 DBusObjectPathMessageFunction message_function;
76 void *user_data;
77 DBusObjectSubtree **subtrees;
78 int n_subtrees;
79 int max_subtrees;
80 unsigned int invoke_as_fallback : 1;
81 char name[1];
82 };
83
91 DBusObjectTree*
92 _dbus_object_tree_new (DBusConnection *connection)
93 {
94 DBusObjectTree *tree;
95
96 /* the connection passed in here isn't fully constructed,
97 * so don't do anything more than store a pointer to
98 * it
99 */
100
101 tree = dbus_new0 (DBusObjectTree, 1);
102 if (tree == NULL)
103 goto oom;
104
105 tree->refcount = 1;
106 tree->connection = connection;
107 tree->root = _dbus_object_subtree_new ("/", NULL, NULL);
108 if (tree->root == NULL)
109 goto oom;
110 tree->root->invoke_as_fallback = TRUE;
111
112 return tree;
113
114 oom:
115 if (tree)
116 {
117 dbus_free (tree);
118 }
119
120 return NULL;
121 }
122
128 DBusObjectTree *
129 _dbus_object_tree_ref (DBusObjectTree *tree)
130 {
131 _dbus_assert (tree->refcount > 0);
132
133 tree->refcount += 1;
134
135 return tree;
136 }
137
142 void
143 _dbus_object_tree_unref (DBusObjectTree *tree)
144 {
145 _dbus_assert (tree->refcount > 0);
146
147 tree->refcount -= 1;
148
149 if (tree->refcount == 0)
150 {
151 _dbus_object_tree_free_all_unlocked (tree);
152
153 dbus_free (tree);
154 }
155 }
156
160 #define VERBOSE_FIND 0
161
162 static DBusObjectSubtree*
163 find_subtree_recurse (DBusObjectSubtree *subtree,
164 const char **path,
165 dbus_bool_t create_if_not_found,
166 int *index_in_parent,
167 dbus_bool_t *exact_match)
168 {
169 int i, j;
170 dbus_bool_t return_deepest_match;
171
172 return_deepest_match = exact_match != NULL;
173
174 _dbus_assert (!(return_deepest_match && create_if_not_found));
175
176 if (path[0] == NULL)
177 {
178 #if VERBOSE_FIND
179 _dbus_verbose (" path exhausted, returning %s\n",
180 subtree->name);
181 #endif
182 if (exact_match != NULL)
183 *exact_match = TRUE;
184 return subtree;
185 }
186
187 #if VERBOSE_FIND
188 _dbus_verbose (" searching children of %s for %s\n",
189 subtree->name, path[0]);
190 #endif
191
192 i = 0;
193 j = subtree->n_subtrees;
194 while (i < j)
195 {
196 int k, v;
197
198 k = (i + j) / 2;
199 v = strcmp (path[0], subtree->subtrees[k]->name);
200
201 #if VERBOSE_FIND
202 _dbus_verbose (" %s cmp %s = %d\n",
203 path[0], subtree->subtrees[k]->name,
204 v);
205 #endif
206
207 if (v == 0)
208 {
209 if (index_in_parent)
210 {
211 #if VERBOSE_FIND
212 _dbus_verbose (" storing parent index %d\n", k);
213 #endif
214 *index_in_parent = k;
215 }
216
217 if (return_deepest_match)
218 {
219 DBusObjectSubtree *next;
220
221 next = find_subtree_recurse (subtree->subtrees[k],
222 &path[1], create_if_not_found,
223 index_in_parent, exact_match);
224 if (next == NULL &&
225 subtree->invoke_as_fallback)
226 {
227 #if VERBOSE_FIND
228 _dbus_verbose (" no deeper match found, returning %s\n",
229 subtree->name);
230 #endif
231 if (exact_match != NULL)
232 *exact_match = FALSE;
233 return subtree;
234 }
235 else
236 return next;
237 }
238 else
239 return find_subtree_recurse (subtree->subtrees[k],
240 &path[1], create_if_not_found,
241 index_in_parent, exact_match);
242 }
243 else if (v < 0)
244 {
245 j = k;
246 }
247 else
248 {
249 i = k + 1;
250 }
251 }
252
253 #if VERBOSE_FIND
254 _dbus_verbose (" no match found, current tree %s, create_if_not_found = %d\n",
255 subtree->name, create_if_not_found);
256 #endif
257
258 if (create_if_not_found)
259 {
260 DBusObjectSubtree* child;
261 int child_pos, new_n_subtrees;
262
263 #if VERBOSE_FIND
264 _dbus_verbose (" creating subtree %s\n",
265 path[0]);
266 #endif
267
268 child = _dbus_object_subtree_new (path[0],
269 NULL, NULL);
270 if (child == NULL)
271 return NULL;
272
273 new_n_subtrees = subtree->n_subtrees + 1;
274 if (new_n_subtrees > subtree->max_subtrees)
275 {
276 int new_max_subtrees;
277 DBusObjectSubtree **new_subtrees;
278
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)
283 {
284 _dbus_object_subtree_unref (child);
285 return NULL;
286 }
287 subtree->subtrees = new_subtrees;
288 subtree->max_subtrees = new_max_subtrees;
289 }
290
291 /* The binary search failed, so i == j points to the
292 place the child should be inserted. */
293 child_pos = i;
294 _dbus_assert (child_pos < new_n_subtrees &&
295 new_n_subtrees <= subtree->max_subtrees);
296 if (child_pos + 1 < new_n_subtrees)
297 {
298 memmove (&subtree->subtrees[child_pos+1],
299 &subtree->subtrees[child_pos],
300 (new_n_subtrees - child_pos - 1) *
301 sizeof subtree->subtrees[0]);
302 }
303 subtree->subtrees[child_pos] = child;
304
305 if (index_in_parent)
306 *index_in_parent = child_pos;
307 subtree->n_subtrees = new_n_subtrees;
308 child->parent = subtree;
309
310 return find_subtree_recurse (child,
311 &path[1], create_if_not_found,
312 index_in_parent, exact_match);
313 }
314 else
315 {
316 if (exact_match != NULL)
317 *exact_match = FALSE;
318 return (return_deepest_match && subtree->invoke_as_fallback) ? subtree : NULL;
319 }
320 }
321
322 #ifdef DBUS_ENABLE_EMBEDDED_TESTS
323 static DBusObjectSubtree*
324 find_subtree (DBusObjectTree *tree,
325 const char **path,
326 int *index_in_parent)
327 {
328 DBusObjectSubtree *subtree;
329
330 #if VERBOSE_FIND
331 _dbus_verbose ("Looking for exact registered subtree\n");
332 #endif
333
334 subtree = find_subtree_recurse (tree->root, path, FALSE, index_in_parent, NULL);
335
336 if (subtree && subtree->message_function == NULL)
337 return NULL;
338 else
339 return subtree;
340 }
341 #endif
342
343 static DBusObjectSubtree*
344 lookup_subtree (DBusObjectTree *tree,
345 const char **path)
346 {
347 #if VERBOSE_FIND
348 _dbus_verbose ("Looking for subtree\n");
349 #endif
350 return find_subtree_recurse (tree->root, path, FALSE, NULL, NULL);
351 }
352
353 static DBusObjectSubtree*
354 find_handler (DBusObjectTree *tree,
355 const char **path,
356 dbus_bool_t *exact_match)
357 {
358 #if VERBOSE_FIND
359 _dbus_verbose ("Looking for deepest handler\n");
360 #endif
361 _dbus_assert (exact_match != NULL);
362
363 *exact_match = FALSE; /* ensure always initialized */
364
365 return find_subtree_recurse (tree->root, path, FALSE, NULL, exact_match);
366 }
367
368 static DBusObjectSubtree*
369 ensure_subtree (DBusObjectTree *tree,
370 const char **path)
371 {
372 #if VERBOSE_FIND
373 _dbus_verbose ("Ensuring subtree\n");
374 #endif
375 return find_subtree_recurse (tree->root, path, TRUE, NULL, NULL);
376 }
377
378 static char *flatten_path (const char **path);
379
392 dbus_bool_t
393 _dbus_object_tree_register (DBusObjectTree *tree,
394 dbus_bool_t fallback,
395 const char **path,
396 const DBusObjectPathVTable *vtable,
397 void *user_data,
398 DBusError *error)
399 {
400 DBusObjectSubtree *subtree;
401
402 _dbus_assert (tree != NULL);
403 _dbus_assert (vtable->message_function != NULL);
404 _dbus_assert (path != NULL);
405
406 subtree = ensure_subtree (tree, path);
407 if (subtree == NULL)
408 {
409 _DBUS_SET_OOM (error);
410 return FALSE;
411 }
412
413 if (subtree->message_function != NULL)
414 {
415 if (error != NULL)
416 {
417 char *complete_path = flatten_path (path);
418
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!)");
423
424 dbus_free (complete_path);
425 }
426
427 return FALSE;
428 }
429
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;
434
435 return TRUE;
436 }
437
449 static dbus_bool_t
450 unregister_subtree (DBusObjectSubtree *subtree,
451 DBusObjectPathUnregisterFunction *unregister_function_out,
452 void **user_data_out)
453 {
454 _dbus_assert (subtree != NULL);
455 _dbus_assert (unregister_function_out != NULL);
456 _dbus_assert (user_data_out != NULL);
457
458 /* Confirm subtree is registered */
459 if (subtree->message_function != NULL)
460 {
461 subtree->message_function = NULL;
462
463 *unregister_function_out = subtree->unregister_function;
464 *user_data_out = subtree->user_data;
465
466 subtree->unregister_function = NULL;
467 subtree->user_data = NULL;
468
469 return TRUE;
470 }
471 else
472 {
473 /* Assert that this unregistered subtree is either the root node or has
474 children, otherwise we have a dangling path which should never
475 happen */
476 _dbus_assert (subtree->parent == NULL || subtree->n_subtrees > 0);
477
478 /* The subtree is not registered */
479 return FALSE;
480 }
481 }
482
494 static dbus_bool_t
495 attempt_child_removal (DBusObjectSubtree *parent,
496 int child_index)
497 {
498 /* Candidate for removal */
499 DBusObjectSubtree* candidate;
500
501 _dbus_assert (parent != NULL);
502 _dbus_assert (child_index >= 0 && child_index < parent->n_subtrees);
503
504 candidate = parent->subtrees[child_index];
505 _dbus_assert (candidate != NULL);
506
507 if (candidate->n_subtrees == 0 && candidate->message_function == NULL)
508 {
509 /* The candidate node is childless and is not a registered
510 path, so... */
511
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;
519
520 /* ... and free it */
521 candidate->parent = NULL;
522 _dbus_object_subtree_unref (candidate);
523
524 return TRUE;
525 }
526 return FALSE;
527 }
528
566 static dbus_bool_t
567 unregister_and_free_path_recurse
568 (DBusObjectSubtree *subtree,
569 const char **path,
570 dbus_bool_t *continue_removal_attempts,
571 DBusObjectPathUnregisterFunction *unregister_function_out,
572 void **user_data_out)
573 {
574 int i, j;
575
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);
580
581 if (path[0] == NULL)
582 return unregister_subtree (subtree, unregister_function_out, user_data_out);
583
584 i = 0;
585 j = subtree->n_subtrees;
586 while (i < j)
587 {
588 int k, v;
589
590 k = (i + j) / 2;
591 v = strcmp (path[0], subtree->subtrees[k]->name);
592
593 if (v == 0)
594 {
595 dbus_bool_t freed;
596 freed = unregister_and_free_path_recurse (subtree->subtrees[k],
597 &path[1],
598 continue_removal_attempts,
599 unregister_function_out,
600 user_data_out);
601 if (freed && *continue_removal_attempts)
602 *continue_removal_attempts = attempt_child_removal (subtree, k);
603 return freed;
604 }
605 else if (v < 0)
606 {
607 j = k;
608 }
609 else
610 {
611 i = k + 1;
612 }
613 }
614 return FALSE;
615 }
616
624 void
625 _dbus_object_tree_unregister_and_unlock (DBusObjectTree *tree,
626 const char **path)
627 {
628 dbus_bool_t found_subtree;
629 dbus_bool_t continue_removal_attempts;
630 DBusObjectPathUnregisterFunction unregister_function;
631 void *user_data;
632 DBusConnection *connection;
633
634 _dbus_assert (tree != NULL);
635 _dbus_assert (path != NULL);
636
637 continue_removal_attempts = TRUE;
638 unregister_function = NULL;
639 user_data = NULL;
640
641 found_subtree = unregister_and_free_path_recurse (tree->root,
642 path,
643 &continue_removal_attempts,
644 &unregister_function,
645 &user_data);
646
647 #ifndef DBUS_DISABLE_CHECKS
648 if (found_subtree == FALSE)
649 {
650 _dbus_warn ("Attempted to unregister path (path[0] = %s path[1] = %s) which isn't registered\n",
651 path[0] ? path[0] : "null",
652 (path[0] && path[1]) ? path[1] : "null");
653 goto unlock;
654 }
655 #else
656 _dbus_assert (found_subtree == TRUE);
657 #endif
658
659 unlock:
660 connection = tree->connection;
661
662 /* Unlock and call application code */
663 #ifdef DBUS_ENABLE_EMBEDDED_TESTS
664 if (connection)
665 #endif
666 {
667 _dbus_connection_ref_unlocked (connection);
668 _dbus_verbose ("unlock\n");
669 _dbus_connection_unlock (connection);
670 }
671
672 if (unregister_function)
673 (* unregister_function) (connection, user_data);
674
675 #ifdef DBUS_ENABLE_EMBEDDED_TESTS
676 if (connection)
677 #endif
678 dbus_connection_unref (connection);
679 }
680
681 static void
682 free_subtree_recurse (DBusConnection *connection,
683 DBusObjectSubtree *subtree)
684 {
685 /* Delete them from the end, for slightly
686 * more robustness against odd reentrancy.
687 */
688 while (subtree->n_subtrees > 0)
689 {
690 DBusObjectSubtree *child;
691
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;
696
697 free_subtree_recurse (connection, child);
698 }
699
700 /* Call application code */
701 if (subtree->unregister_function)
702 (* subtree->unregister_function) (connection,
703 subtree->user_data);
704
705 subtree->message_function = NULL;
706 subtree->unregister_function = NULL;
707 subtree->user_data = NULL;
708
709 /* Now free ourselves */
710 _dbus_object_subtree_unref (subtree);
711 }
712
719 void
720 _dbus_object_tree_free_all_unlocked (DBusObjectTree *tree)
721 {
722 if (tree->root)
723 free_subtree_recurse (tree->connection,
724 tree->root);
725 tree->root = NULL;
726 }
727
728 static dbus_bool_t
729 _dbus_object_tree_list_registered_unlocked (DBusObjectTree *tree,
730 const char **parent_path,
731 char ***child_entries)
732 {
733 DBusObjectSubtree *subtree;
734 char **retval;
735
736 _dbus_assert (parent_path != NULL);
737 _dbus_assert (child_entries != NULL);
738
739 *child_entries = NULL;
740
741 subtree = lookup_subtree (tree, parent_path);
742 if (subtree == NULL)
743 {
744 retval = dbus_new0 (char *, 1);
745 }
746 else
747 {
748 int i;
749 retval = dbus_new0 (char*, subtree->n_subtrees + 1);
750 if (retval == NULL)
751 goto out;
752 i = 0;
753 while (i < subtree->n_subtrees)
754 {
755 retval[i] = _dbus_strdup (subtree->subtrees[i]->name);
756 if (retval[i] == NULL)
757 {
758 dbus_free_string_array (retval);
759 retval = NULL;
760 goto out;
761 }
762 ++i;
763 }
764 }
765
766 out:
767
768 *child_entries = retval;
769 return retval != NULL;
770 }
771
772 static DBusHandlerResult
773 handle_default_introspect_and_unlock (DBusObjectTree *tree,
774 DBusMessage *message,
775 const char **path)
776 {
777 DBusString xml;
778 DBusHandlerResult result;
779 char **children;
780 int i;
781 DBusMessage *reply;
782 DBusMessageIter iter;
783 const char *v_STRING;
784 dbus_bool_t already_unlocked;
785
786 /* We have the connection lock here */
787
788 already_unlocked = FALSE;
789
790 _dbus_verbose (" considering default Introspect() handler...\n");
791
792 reply = NULL;
793
794 if (!dbus_message_is_method_call (message,
795 DBUS_INTERFACE_INTROSPECTABLE,
796 "Introspect"))
797 {
798 #ifdef DBUS_ENABLE_EMBEDDED_TESTS
799 if (tree->connection)
800 #endif
801 {
802 _dbus_verbose ("unlock\n");
803 _dbus_connection_unlock (tree->connection);
804 }
805
806 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
807 }
808
809 _dbus_verbose (" using default Introspect() handler!\n");
810
811 if (!_dbus_string_init (&xml))
812 {
813 #ifdef DBUS_ENABLE_EMBEDDED_TESTS
814 if (tree->connection)
815 #endif
816 {
817 _dbus_verbose ("unlock\n");
818 _dbus_connection_unlock (tree->connection);
819 }
820
821 return DBUS_HANDLER_RESULT_NEED_MEMORY;
822 }
823
824 result = DBUS_HANDLER_RESULT_NEED_MEMORY;
825
826 children = NULL;
827 if (!_dbus_object_tree_list_registered_unlocked (tree, path, &children))
828 goto out;
829
830 if (!_dbus_string_append (&xml, DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE))
831 goto out;
832
833 if (!_dbus_string_append (&xml, "<node>\n"))
834 goto out;
835
836 i = 0;
837 while (children[i] != NULL)
838 {
839 if (!_dbus_string_append_printf (&xml, " <node name=\"%s\"/>\n",
840 children[i]))
841 goto out;
842
843 ++i;
844 }
845
846 if (!_dbus_string_append (&xml, "</node>\n"))
847 goto out;
848
849 reply = dbus_message_new_method_return (message);
850 if (reply == NULL)
851 goto out;
852
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))
856 goto out;
857
858 #ifdef DBUS_ENABLE_EMBEDDED_TESTS
859 if (tree->connection)
860 #endif
861 {
862 already_unlocked = TRUE;
863
864 if (!_dbus_connection_send_and_unlock (tree->connection, reply, NULL))
865 goto out;
866 }
867
868 result = DBUS_HANDLER_RESULT_HANDLED;
869
870 out:
871 #ifdef DBUS_ENABLE_EMBEDDED_TESTS
872 if (tree->connection)
873 #endif
874 {
875 if (!already_unlocked)
876 {
877 _dbus_verbose ("unlock\n");
878 _dbus_connection_unlock (tree->connection);
879 }
880 }
881
882 _dbus_string_free (&xml);
883 dbus_free_string_array (children);
884 if (reply)
885 dbus_message_unref (reply);
886
887 return result;
888 }
889
904 DBusHandlerResult
905 _dbus_object_tree_dispatch_and_unlock (DBusObjectTree *tree,
906 DBusMessage *message,
907 dbus_bool_t *found_object)
908 {
909 char **path;
910 dbus_bool_t exact_match;
911 DBusList *list;
912 DBusList *link;
913 DBusHandlerResult result;
914 DBusObjectSubtree *subtree;
915
916 #if 0
917 _dbus_verbose ("Dispatch of message by object path\n");
918 #endif
919
920 path = NULL;
921 if (!dbus_message_get_path_decomposed (message, &path))
922 {
923 #ifdef DBUS_ENABLE_EMBEDDED_TESTS
924 if (tree->connection)
925 #endif
926 {
927 _dbus_verbose ("unlock\n");
928 _dbus_connection_unlock (tree->connection);
929 }
930
931 _dbus_verbose ("No memory to get decomposed path\n");
932
933 return DBUS_HANDLER_RESULT_NEED_MEMORY;
934 }
935
936 if (path == NULL)
937 {
938 #ifdef DBUS_ENABLE_EMBEDDED_TESTS
939 if (tree->connection)
940 #endif
941 {
942 _dbus_verbose ("unlock\n");
943 _dbus_connection_unlock (tree->connection);
944 }
945
946 _dbus_verbose ("No path field in message\n");
947 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
948 }
949
950 /* Find the deepest path that covers the path in the message */
951 subtree = find_handler (tree, (const char**) path, &exact_match);
952
953 if (found_object)
954 *found_object = !!subtree;
955
956 /* Build a list of all paths that cover the path in the message */
957
958 list = NULL;
959
960 while (subtree != NULL)
961 {
962 if (subtree->message_function != NULL && (exact_match || subtree->invoke_as_fallback))
963 {
964 _dbus_object_subtree_ref (subtree);
965
966 /* run deepest paths first */
967 if (!_dbus_list_append (&list, subtree))
968 {
969 result = DBUS_HANDLER_RESULT_NEED_MEMORY;
970 _dbus_object_subtree_unref (subtree);
971 goto free_and_return;
972 }
973 }
974
975 exact_match = FALSE;
976 subtree = subtree->parent;
977 }
978
979 _dbus_verbose ("%d handlers in the path tree for this message\n",
980 _dbus_list_get_length (&list));
981
982 /* Invoke each handler in the list */
983
984 result = DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
985
986 link = _dbus_list_get_first_link (&list);
987 while (link != NULL)
988 {
989 DBusList *next = _dbus_list_get_next_link (&list, link);
990 subtree = link->data;
991
992 /* message_function is NULL if we're unregistered
993 * due to reentrancy
994 */
995 if (subtree->message_function)
996 {
997 DBusObjectPathMessageFunction message_function;
998 void *user_data;
999
1000 message_function = subtree->message_function;
1001 user_data = subtree->user_data;
1002
1003 #if 0
1004 _dbus_verbose (" (invoking a handler)\n");
1005 #endif
1006
1007 #ifdef DBUS_ENABLE_EMBEDDED_TESTS
1008 if (tree->connection)
1009 #endif
1010 {
1011 _dbus_verbose ("unlock\n");
1012 _dbus_connection_unlock (tree->connection);
1013 }
1014
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.
1018 */
1019
1020 result = (* message_function) (tree->connection,
1021 message,
1022 user_data);
1023
1024 #ifdef DBUS_ENABLE_EMBEDDED_TESTS
1025 if (tree->connection)
1026 #endif
1027 _dbus_connection_lock (tree->connection);
1028
1029 if (result != DBUS_HANDLER_RESULT_NOT_YET_HANDLED)
1030 goto free_and_return;
1031 }
1032
1033 link = next;
1034 }
1035
1036 free_and_return:
1037
1038 if (result == DBUS_HANDLER_RESULT_NOT_YET_HANDLED)
1039 {
1040 /* This hardcoded default handler does a minimal Introspect()
1041 */
1042 result = handle_default_introspect_and_unlock (tree, message,
1043 (const char**) path);
1044 }
1045 else
1046 {
1047 #ifdef DBUS_ENABLE_EMBEDDED_TESTS
1048 if (tree->connection)
1049 #endif
1050 {
1051 _dbus_verbose ("unlock\n");
1052 _dbus_connection_unlock (tree->connection);
1053 }
1054 }
1055
1056 while (list != NULL)
1057 {
1058 link = _dbus_list_get_first_link (&list);
1059 _dbus_object_subtree_unref (link->data);
1060 _dbus_list_remove_link (&list, link);
1061 }
1062
1063 dbus_free_string_array (path);
1064
1065 return result;
1066 }
1067
1076 void*
1077 _dbus_object_tree_get_user_data_unlocked (DBusObjectTree *tree,
1078 const char **path)
1079 {
1080 dbus_bool_t exact_match;
1081 DBusObjectSubtree *subtree;
1082
1083 _dbus_assert (tree != NULL);
1084 _dbus_assert (path != NULL);
1085
1086 /* Find the deepest path that covers the path in the message */
1087 subtree = find_handler (tree, (const char**) path, &exact_match);
1088
1089 if ((subtree == NULL) || !exact_match)
1090 {
1091 _dbus_verbose ("No object at specified path found\n");
1092 return NULL;
1093 }
1094
1095 return subtree->user_data;
1096 }
1097
1104 static DBusObjectSubtree*
1105 allocate_subtree_object (const char *name)
1106 {
1107 int len;
1108 DBusObjectSubtree *subtree;
1109 const size_t front_padding = _DBUS_STRUCT_OFFSET (DBusObjectSubtree, name);
1110
1111 _dbus_assert (name != NULL);
1112
1113 len = strlen (name);
1114
1115 subtree = dbus_malloc0 (MAX (front_padding + (len + 1), sizeof (DBusObjectSubtree)));
1116
1117 if (subtree == NULL)
1118 return NULL;
1119
1120 memcpy (subtree->name, name, len + 1);
1121
1122 return subtree;
1123 }
1124
1125 static DBusObjectSubtree*
1126 _dbus_object_subtree_new (const char *name,
1127 const DBusObjectPathVTable *vtable,
1128 void *user_data)
1129 {
1130 DBusObjectSubtree *subtree;
1131
1132 subtree = allocate_subtree_object (name);
1133 if (subtree == NULL)
1134 goto oom;
1135
1136 _dbus_assert (name != NULL);
1137
1138 subtree->parent = NULL;
1139
1140 if (vtable)
1141 {
1142 subtree->message_function = vtable->message_function;
1143 subtree->unregister_function = vtable->unregister_function;
1144 }
1145 else
1146 {
1147 subtree->message_function = NULL;
1148 subtree->unregister_function = NULL;
1149 }
1150
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;
1157
1158 return subtree;
1159
1160 oom:
1161 return NULL;
1162 }
1163
1164 static DBusObjectSubtree *
1165 _dbus_object_subtree_ref (DBusObjectSubtree *subtree)
1166 {
1167 #ifdef DBUS_DISABLE_ASSERT
1168 _dbus_atomic_inc (&subtree->refcount);
1169 #else
1170 dbus_int32_t old_value;
1171
1172 old_value = _dbus_atomic_inc (&subtree->refcount);
1173 _dbus_assert (old_value > 0);
1174 #endif
1175
1176 return subtree;
1177 }
1178
1179 static void
1180 _dbus_object_subtree_unref (DBusObjectSubtree *subtree)
1181 {
1182 dbus_int32_t old_value;
1183
1184 old_value = _dbus_atomic_dec (&subtree->refcount);
1185 _dbus_assert (old_value > 0);
1186
1187 if (old_value == 1)
1188 {
1189 _dbus_assert (subtree->unregister_function == NULL);
1190 _dbus_assert (subtree->message_function == NULL);
1191
1192 dbus_free (subtree->subtrees);
1193 dbus_free (subtree);
1194 }
1195 }
1196
1207 dbus_bool_t
1208 _dbus_object_tree_list_registered_and_unlock (DBusObjectTree *tree,
1209 const char **parent_path,
1210 char ***child_entries)
1211 {
1212 dbus_bool_t result;
1213
1214 result = _dbus_object_tree_list_registered_unlocked (tree,
1215 parent_path,
1216 child_entries);
1217
1218 #ifdef DBUS_ENABLE_EMBEDDED_TESTS
1219 if (tree->connection)
1220 #endif
1221 {
1222 _dbus_verbose ("unlock\n");
1223 _dbus_connection_unlock (tree->connection);
1224 }
1225
1226 return result;
1227 }
1228
1229
1231 #define VERBOSE_DECOMPOSE 0
1232
1243 dbus_bool_t
1244 _dbus_decompose_path (const char* data,
1245 int len,
1246 char ***path,
1247 int *path_len)
1248 {
1249 char **retval;
1250 int n_components;
1251 int i, j, comp;
1252
1253 _dbus_assert (data != NULL);
1254 _dbus_assert (path != NULL);
1255
1256 #if VERBOSE_DECOMPOSE
1257 _dbus_verbose ("Decomposing path \"%s\"\n",
1258 data);
1259 #endif
1260
1261 n_components = 0;
1262 if (len > 1) /* if path is not just "/" */
1263 {
1264 i = 0;
1265 while (i < len)
1266 {
1267 _dbus_assert (data[i] != '\0');
1268 if (data[i] == '/')
1269 n_components += 1;
1270 ++i;
1271 }
1272 }
1273
1274 retval = dbus_new0 (char*, n_components + 1);
1275
1276 if (retval == NULL)
1277 return FALSE;
1278
1279 comp = 0;
1280 if (n_components == 0)
1281 i = 1;
1282 else
1283 i = 0;
1284 while (comp < n_components)
1285 {
1286 _dbus_assert (i < len);
1287
1288 if (data[i] == '/')
1289 ++i;
1290 j = i;
1291
1292 while (j < len && data[j] != '/')
1293 ++j;
1294
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] == '/');
1299
1300 #if VERBOSE_DECOMPOSE
1301 _dbus_verbose (" (component in [%d,%d))\n",
1302 i, j);
1303 #endif
1304
1305 retval[comp] = _dbus_memdup (&data[i], j - i + 1);
1306 if (retval[comp] == NULL)
1307 {
1308 dbus_free_string_array (retval);
1309 return FALSE;
1310 }
1311 retval[comp][j-i] = '\0';
1312 #if VERBOSE_DECOMPOSE
1313 _dbus_verbose (" (component %d = \"%s\")\n",
1314 comp, retval[comp]);
1315 #endif
1316
1317 ++comp;
1318 i = j;
1319 }
1320 _dbus_assert (i == len);
1321
1322 *path = retval;
1323 if (path_len)
1324 *path_len = n_components;
1325
1326 return TRUE;
1327 }
1328
1331 static char*
1332 flatten_path (const char **path)
1333 {
1334 DBusString str;
1335 char *s;
1336
1337 if (!_dbus_string_init (&str))
1338 return NULL;
1339
1340 if (path[0] == NULL)
1341 {
1342 if (!_dbus_string_append_byte (&str, '/'))
1343 goto nomem;
1344 }
1345 else
1346 {
1347 int i;
1348
1349 i = 0;
1350 while (path[i])
1351 {
1352 if (!_dbus_string_append_byte (&str, '/'))
1353 goto nomem;
1354
1355 if (!_dbus_string_append (&str, path[i]))
1356 goto nomem;
1357
1358 ++i;
1359 }
1360 }
1361
1362 if (!_dbus_string_steal_data (&str, &s))
1363 goto nomem;
1364
1365 _dbus_string_free (&str);
1366
1367 return s;
1368
1369 nomem:
1370 _dbus_string_free (&str);
1371 return NULL;
1372 }
1373
1374
1375 #ifdef DBUS_ENABLE_EMBEDDED_TESTS
1376
1377 #ifndef DOXYGEN_SHOULD_SKIP_THIS
1378
1379 #include "dbus-test.h"
1380 #include <stdio.h>
1381
1382 typedef enum
1383 {
1384 STR_EQUAL,
1385 STR_PREFIX,
1386 STR_DIFFERENT
1387 } StrComparison;
1388
1389 /* Returns TRUE if container is a parent of child
1390 */
1391 static StrComparison
1392 path_contains (const char **container,
1393 const char **child)
1394 {
1395 int i;
1396
1397 i = 0;
1398 while (child[i] != NULL)
1399 {
1400 int v;
1401
1402 if (container[i] == NULL)
1403 return STR_PREFIX; /* container ran out, child continues;
1404 * thus the container is a parent of the
1405 * child.
1406 */
1407
1408 _dbus_assert (container[i] != NULL);
1409 _dbus_assert (child[i] != NULL);
1410
1411 v = strcmp (container[i], child[i]);
1412
1413 if (v != 0)
1414 return STR_DIFFERENT; /* they overlap until here and then are different,
1415 * not overlapping
1416 */
1417
1418 ++i;
1419 }
1420
1421 /* Child ran out; if container also did, they are equal;
1422 * otherwise, the child is a parent of the container.
1423 */
1424 if (container[i] == NULL)
1425 return STR_EQUAL;
1426 else
1427 return STR_DIFFERENT;
1428 }
1429
1430 #if 0
1431 static void
1432 spew_subtree_recurse (DBusObjectSubtree *subtree,
1433 int indent)
1434 {
1435 int i;
1436
1437 i = 0;
1438 while (i < indent)
1439 {
1440 _dbus_verbose (" ");
1441 ++i;
1442 }
1443
1444 _dbus_verbose ("%s (%d children)\n",
1445 subtree->name, subtree->n_subtrees);
1446
1447 i = 0;
1448 while (i < subtree->n_subtrees)
1449 {
1450 spew_subtree_recurse (subtree->subtrees[i], indent + 2);
1451
1452 ++i;
1453 }
1454 }
1455
1456 static void
1457 spew_tree (DBusObjectTree *tree)
1458 {
1459 spew_subtree_recurse (tree->root, 0);
1460 }
1461 #endif
1462
1466 typedef struct
1467 {
1468 const char **path;
1469 dbus_bool_t handler_fallback;
1470 dbus_bool_t message_handled;
1471 dbus_bool_t handler_unregistered;
1472 } TreeTestData;
1473
1474
1475 static void
1476 test_unregister_function (DBusConnection *connection,
1477 void *user_data)
1478 {
1479 TreeTestData *ttd = user_data;
1480
1481 ttd->handler_unregistered = TRUE;
1482 }
1483
1484 static DBusHandlerResult
1485 test_message_function (DBusConnection *connection,
1486 DBusMessage *message,
1487 void *user_data)
1488 {
1489 TreeTestData *ttd = user_data;
1490
1491 ttd->message_handled = TRUE;
1492
1493 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1494 }
1495
1496 static dbus_bool_t
1497 do_register (DBusObjectTree *tree,
1498 const char **path,
1499 dbus_bool_t fallback,
1500 int i,
1501 TreeTestData *tree_test_data)
1502 {
1503 DBusObjectPathVTable vtable = { test_unregister_function,
1504 test_message_function, NULL };
1505
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;
1510
1511 if (!_dbus_object_tree_register (tree, fallback, path,
1512 &vtable,
1513 &tree_test_data[i],
1514 NULL))
1515 return FALSE;
1516
1517 _dbus_assert (_dbus_object_tree_get_user_data_unlocked (tree, path) ==
1518 &tree_test_data[i]);
1519
1520 return TRUE;
1521 }
1522
1523 static dbus_bool_t
1524 do_test_dispatch (DBusObjectTree *tree,
1525 const char **path,
1526 int i,
1527 TreeTestData *tree_test_data,
1528 int n_test_data)
1529 {
1530 DBusMessage *message;
1531 int j;
1532 DBusHandlerResult result;
1533 char *flat;
1534
1535 message = NULL;
1536
1537 flat = flatten_path (path);
1538 if (flat == NULL)
1539 goto oom;
1540
1541 message = dbus_message_new_method_call (NULL,
1542 flat,
1543 "org.freedesktop.TestInterface",
1544 "Foo");
1545 dbus_free (flat);
1546 if (message == NULL)
1547 goto oom;
1548
1549 j = 0;
1550 while (j < n_test_data)
1551 {
1552 tree_test_data[j].message_handled = FALSE;
1553 ++j;
1554 }
1555
1556 result = _dbus_object_tree_dispatch_and_unlock (tree, message, NULL);
1557 if (result == DBUS_HANDLER_RESULT_NEED_MEMORY)
1558 goto oom;
1559
1560 _dbus_assert (tree_test_data[i].message_handled);
1561
1562 j = 0;
1563 while (j < n_test_data)
1564 {
1565 if (tree_test_data[j].message_handled)
1566 {
1567 if (tree_test_data[j].handler_fallback)
1568 _dbus_assert (path_contains (tree_test_data[j].path,
1569 path) != STR_DIFFERENT);
1570 else
1571 _dbus_assert (path_contains (tree_test_data[j].path, path) == STR_EQUAL);
1572 }
1573 else
1574 {
1575 if (tree_test_data[j].handler_fallback)
1576 _dbus_assert (path_contains (tree_test_data[j].path,
1577 path) == STR_DIFFERENT);
1578 else
1579 _dbus_assert (path_contains (tree_test_data[j].path, path) != STR_EQUAL);
1580 }
1581
1582 ++j;
1583 }
1584
1585 dbus_message_unref (message);
1586
1587 return TRUE;
1588
1589 oom:
1590 if (message)
1591 dbus_message_unref (message);
1592 return FALSE;
1593 }
1594
1595 static size_t
1596 string_array_length (const char **array)
1597 {
1598 size_t i;
1599 for (i = 0; array[i]; i++) ;
1600 return i;
1601 }
1602
1603 typedef struct
1604 {
1605 const char *path;
1606 const char *result[20];
1607 } DecomposePathTest;
1608
1609 static DecomposePathTest decompose_tests[] = {
1610 { "/foo", { "foo", NULL } },
1611 { "/foo/bar", { "foo", "bar", NULL } },
1612 { "/", { NULL } },
1613 { "/a/b", { "a", "b", NULL } },
1614 { "/a/b/c", { "a", "b", "c", NULL } },
1615 { "/a/b/c/d", { "a", "b", "c", "d", NULL } },
1616 { "/foo/bar/q", { "foo", "bar", "q", NULL } },
1617 { "/foo/bar/this/is/longer", { "foo", "bar", "this", "is", "longer", NULL } }
1618 };
1619
1620 static dbus_bool_t
1621 run_decompose_tests (void)
1622 {
1623 int i;
1624
1625 i = 0;
1626 while (i < _DBUS_N_ELEMENTS (decompose_tests))
1627 {
1628 char **result;
1629 int result_len;
1630 int expected_len;
1631
1632 if (!_dbus_decompose_path (decompose_tests[i].path,
1633 strlen (decompose_tests[i].path),
1634 &result, &result_len))
1635 return FALSE;
1636
1637 expected_len = string_array_length (decompose_tests[i].result);
1638
1639 if (result_len != (int) string_array_length ((const char**)result) ||
1640 expected_len != result_len ||
1641 path_contains (decompose_tests[i].result,
1642 (const char**) result) != STR_EQUAL)
1643 {
1644 int real_len = string_array_length ((const char**)result);
1645 _dbus_warn ("Expected decompose of %s to have len %d, returned %d, appears to have %d\n",
1646 decompose_tests[i].path, expected_len, result_len,
1647 real_len);
1648 _dbus_warn ("Decompose resulted in elements: { ");
1649 i = 0;
1650 while (i < real_len)
1651 {
1652 _dbus_warn ("\"%s\"%s", result[i],
1653 (i + 1) == real_len ? "" : ", ");
1654 ++i;
1655 }
1656 _dbus_warn ("}\n");
1657 _dbus_assert_not_reached ("path decompose failed\n");
1658 }
1659
1660 dbus_free_string_array (result);
1661
1662 ++i;
1663 }
1664
1665 return TRUE;
1666 }
1667
1668 static DBusObjectSubtree*
1669 find_subtree_registered_or_unregistered (DBusObjectTree *tree,
1670 const char **path)
1671 {
1672 #if VERBOSE_FIND
1673 _dbus_verbose ("Looking for exact subtree, registered or unregistered\n");
1674 #endif
1675
1676 return find_subtree_recurse (tree->root, path, FALSE, NULL, NULL);
1677 }
1678
1679 static dbus_bool_t
1680 object_tree_test_iteration (void *data)
1681 {
1682 const char *path0[] = { NULL };
1683 const char *path1[] = { "foo", NULL };
1684 const char *path2[] = { "foo", "bar", NULL };
1685 const char *path3[] = { "foo", "bar", "baz", NULL };
1686 const char *path4[] = { "foo", "bar", "boo", NULL };
1687 const char *path5[] = { "blah", NULL };
1688 const char *path6[] = { "blah", "boof", NULL };
1689 const char *path7[] = { "blah", "boof", "this", "is", "really", "long", NULL };
1690 const char *path8[] = { "childless", NULL };
1691 const char *path9[] = { "blah", "a", NULL };
1692 const char *path10[] = { "blah", "b", NULL };
1693 const char *path11[] = { "blah", "c", NULL };
1694 const char *path12[] = { "blah", "a", "d", NULL };
1695 const char *path13[] = { "blah", "b", "d", NULL };
1696 const char *path14[] = { "blah", "c", "d", NULL };
1697 DBusObjectPathVTable test_vtable = { NULL, test_message_function, NULL };
1698 DBusObjectTree *tree;
1699 TreeTestData tree_test_data[9];
1700 int i;
1701 dbus_bool_t exact_match;
1702
1703 if (!run_decompose_tests ())
1704 return FALSE;
1705
1706 tree = NULL;
1707
1708 tree = _dbus_object_tree_new (NULL);
1709 if (tree == NULL)
1710 goto out;
1711
1712 if (!do_register (tree, path0, TRUE, 0, tree_test_data))
1713 goto out;
1714
1715 _dbus_assert (find_subtree (tree, path0, NULL));
1716 _dbus_assert (!find_subtree (tree, path1, NULL));
1717 _dbus_assert (!find_subtree (tree, path2, NULL));
1718 _dbus_assert (!find_subtree (tree, path3, NULL));
1719 _dbus_assert (!find_subtree (tree, path4, NULL));
1720 _dbus_assert (!find_subtree (tree, path5, NULL));
1721 _dbus_assert (!find_subtree (tree, path6, NULL));
1722 _dbus_assert (!find_subtree (tree, path7, NULL));
1723 _dbus_assert (!find_subtree (tree, path8, NULL));
1724
1725 _dbus_assert (find_handler (tree, path0, &exact_match) && exact_match);
1726 _dbus_assert (find_handler (tree, path1, &exact_match) == tree->root && !exact_match);
1727 _dbus_assert (find_handler (tree, path2, &exact_match) == tree->root && !exact_match);
1728 _dbus_assert (find_handler (tree, path3, &exact_match) == tree->root && !exact_match);
1729 _dbus_assert (find_handler (tree, path4, &exact_match) == tree->root && !exact_match);
1730 _dbus_assert (find_handler (tree, path5, &exact_match) == tree->root && !exact_match);
1731 _dbus_assert (find_handler (tree, path6, &exact_match) == tree->root && !exact_match);
1732 _dbus_assert (find_handler (tree, path7, &exact_match) == tree->root && !exact_match);
1733 _dbus_assert (find_handler (tree, path8, &exact_match) == tree->root && !exact_match);
1734
1735 if (!do_register (tree, path1, TRUE, 1, tree_test_data))
1736 goto out;
1737
1738 _dbus_assert (find_subtree (tree, path0, NULL));
1739 _dbus_assert (find_subtree (tree, path1, NULL));
1740 _dbus_assert (!find_subtree (tree, path2, NULL));
1741 _dbus_assert (!find_subtree (tree, path3, NULL));
1742 _dbus_assert (!find_subtree (tree, path4, NULL));
1743 _dbus_assert (!find_subtree (tree, path5, NULL));
1744 _dbus_assert (!find_subtree (tree, path6, NULL));
1745 _dbus_assert (!find_subtree (tree, path7, NULL));
1746 _dbus_assert (!find_subtree (tree, path8, NULL));
1747
1748 _dbus_assert (find_handler (tree, path0, &exact_match) && exact_match);
1749 _dbus_assert (find_handler (tree, path1, &exact_match) && exact_match);
1750 _dbus_assert (find_handler (tree, path2, &exact_match) && !exact_match);
1751 _dbus_assert (find_handler (tree, path3, &exact_match) && !exact_match);
1752 _dbus_assert (find_handler (tree, path4, &exact_match) && !exact_match);
1753 _dbus_assert (find_handler (tree, path5, &exact_match) == tree->root && !exact_match);
1754 _dbus_assert (find_handler (tree, path6, &exact_match) == tree->root && !exact_match);
1755 _dbus_assert (find_handler (tree, path7, &exact_match) == tree->root && !exact_match);
1756 _dbus_assert (find_handler (tree, path8, &exact_match) == tree->root && !exact_match);
1757
1758 if (!do_register (tree, path2, TRUE, 2, tree_test_data))
1759 goto out;
1760
1761 _dbus_assert (find_subtree (tree, path1, NULL));
1762 _dbus_assert (find_subtree (tree, path2, NULL));
1763 _dbus_assert (!find_subtree (tree, path3, NULL));
1764 _dbus_assert (!find_subtree (tree, path4, NULL));
1765 _dbus_assert (!find_subtree (tree, path5, NULL));
1766 _dbus_assert (!find_subtree (tree, path6, NULL));
1767 _dbus_assert (!find_subtree (tree, path7, NULL));
1768 _dbus_assert (!find_subtree (tree, path8, NULL));
1769
1770 if (!do_register (tree, path3, TRUE, 3, tree_test_data))
1771 goto out;
1772
1773 _dbus_assert (find_subtree (tree, path0, NULL));
1774 _dbus_assert (find_subtree (tree, path1, NULL));
1775 _dbus_assert (find_subtree (tree, path2, NULL));
1776 _dbus_assert (find_subtree (tree, path3, NULL));
1777 _dbus_assert (!find_subtree (tree, path4, NULL));
1778 _dbus_assert (!find_subtree (tree, path5, NULL));
1779 _dbus_assert (!find_subtree (tree, path6, NULL));
1780 _dbus_assert (!find_subtree (tree, path7, NULL));
1781 _dbus_assert (!find_subtree (tree, path8, NULL));
1782
1783 if (!do_register (tree, path4, TRUE, 4, tree_test_data))
1784 goto out;
1785
1786 _dbus_assert (find_subtree (tree, path0, NULL));
1787 _dbus_assert (find_subtree (tree, path1, NULL));
1788 _dbus_assert (find_subtree (tree, path2, NULL));
1789 _dbus_assert (find_subtree (tree, path3, NULL));
1790 _dbus_assert (find_subtree (tree, path4, NULL));
1791 _dbus_assert (!find_subtree (tree, path5, NULL));
1792 _dbus_assert (!find_subtree (tree, path6, NULL));
1793 _dbus_assert (!find_subtree (tree, path7, NULL));
1794 _dbus_assert (!find_subtree (tree, path8, NULL));
1795
1796 if (!do_register (tree, path5, TRUE, 5, tree_test_data))
1797 goto out;
1798
1799 _dbus_assert (find_subtree (tree, path0, NULL));
1800 _dbus_assert (find_subtree (tree, path1, NULL));
1801 _dbus_assert (find_subtree (tree, path2, NULL));
1802 _dbus_assert (find_subtree (tree, path3, NULL));
1803 _dbus_assert (find_subtree (tree, path4, NULL));
1804 _dbus_assert (find_subtree (tree, path5, NULL));
1805 _dbus_assert (!find_subtree (tree, path6, NULL));
1806 _dbus_assert (!find_subtree (tree, path7, NULL));
1807 _dbus_assert (!find_subtree (tree, path8, NULL));
1808
1809 _dbus_assert (find_handler (tree, path0, &exact_match) == tree->root && exact_match);
1810 _dbus_assert (find_handler (tree, path1, &exact_match) != tree->root && exact_match);
1811 _dbus_assert (find_handler (tree, path2, &exact_match) != tree->root && exact_match);
1812 _dbus_assert (find_handler (tree, path3, &exact_match) != tree->root && exact_match);
1813 _dbus_assert (find_handler (tree, path4, &exact_match) != tree->root && exact_match);
1814 _dbus_assert (find_handler (tree, path5, &exact_match) != tree->root && exact_match);
1815 _dbus_assert (find_handler (tree, path6, &exact_match) != tree->root && !exact_match);
1816 _dbus_assert (find_handler (tree, path7, &exact_match) != tree->root && !exact_match);
1817 _dbus_assert (find_handler (tree, path8, &exact_match) == tree->root && !exact_match);
1818
1819 if (!do_register (tree, path6, TRUE, 6, tree_test_data))
1820 goto out;
1821
1822 _dbus_assert (find_subtree (tree, path0, NULL));
1823 _dbus_assert (find_subtree (tree, path1, NULL));
1824 _dbus_assert (find_subtree (tree, path2, NULL));
1825 _dbus_assert (find_subtree (tree, path3, NULL));
1826 _dbus_assert (find_subtree (tree, path4, NULL));
1827 _dbus_assert (find_subtree (tree, path5, NULL));
1828 _dbus_assert (find_subtree (tree, path6, NULL));
1829 _dbus_assert (!find_subtree (tree, path7, NULL));
1830 _dbus_assert (!find_subtree (tree, path8, NULL));
1831
1832 if (!do_register (tree, path7, TRUE, 7, tree_test_data))
1833 goto out;
1834
1835 _dbus_assert (find_subtree (tree, path0, NULL));
1836 _dbus_assert (find_subtree (tree, path1, NULL));
1837 _dbus_assert (find_subtree (tree, path2, NULL));
1838 _dbus_assert (find_subtree (tree, path3, NULL));
1839 _dbus_assert (find_subtree (tree, path4, NULL));
1840 _dbus_assert (find_subtree (tree, path5, NULL));
1841 _dbus_assert (find_subtree (tree, path6, NULL));
1842 _dbus_assert (find_subtree (tree, path7, NULL));
1843 _dbus_assert (!find_subtree (tree, path8, NULL));
1844
1845 if (!do_register (tree, path8, TRUE, 8, tree_test_data))
1846 goto out;
1847
1848 _dbus_assert (find_subtree (tree, path0, NULL));
1849 _dbus_assert (find_subtree (tree, path1, NULL));
1850 _dbus_assert (find_subtree (tree, path2, NULL));
1851 _dbus_assert (find_subtree (tree, path3, NULL));
1852 _dbus_assert (find_subtree (tree, path4, NULL));
1853 _dbus_assert (find_subtree (tree, path5, NULL));
1854 _dbus_assert (find_subtree (tree, path6, NULL));
1855 _dbus_assert (find_subtree (tree, path7, NULL));
1856 _dbus_assert (find_subtree (tree, path8, NULL));
1857
1858 _dbus_assert (find_handler (tree, path0, &exact_match) == tree->root && exact_match);
1859 _dbus_assert (find_handler (tree, path1, &exact_match) != tree->root && exact_match);
1860 _dbus_assert (find_handler (tree, path2, &exact_match) != tree->root && exact_match);
1861 _dbus_assert (find_handler (tree, path3, &exact_match) != tree->root && exact_match);
1862 _dbus_assert (find_handler (tree, path4, &exact_match) != tree->root && exact_match);
1863 _dbus_assert (find_handler (tree, path5, &exact_match) != tree->root && exact_match);
1864 _dbus_assert (find_handler (tree, path6, &exact_match) != tree->root && exact_match);
1865 _dbus_assert (find_handler (tree, path7, &exact_match) != tree->root && exact_match);
1866 _dbus_assert (find_handler (tree, path8, &exact_match) != tree->root && exact_match);
1867
1868 /* test the list_registered function */
1869
1870 {
1871 const char *root[] = { NULL };
1872 char **child_entries;
1873 int nb;
1874
1875 _dbus_object_tree_list_registered_unlocked (tree, path1, &child_entries);
1876 if (child_entries != NULL)
1877 {
1878 nb = string_array_length ((const char**)child_entries);
1879 _dbus_assert (nb == 1);
1880 dbus_free_string_array (child_entries);
1881 }
1882
1883 _dbus_object_tree_list_registered_unlocked (tree, path2, &child_entries);
1884 if (child_entries != NULL)
1885 {
1886 nb = string_array_length ((const char**)child_entries);
1887 _dbus_assert (nb == 2);
1888 dbus_free_string_array (child_entries);
1889 }
1890
1891 _dbus_object_tree_list_registered_unlocked (tree, path8, &child_entries);
1892 if (child_entries != NULL)
1893 {
1894 nb = string_array_length ((const char**)child_entries);
1895 _dbus_assert (nb == 0);
1896 dbus_free_string_array (child_entries);
1897 }
1898
1899 _dbus_object_tree_list_registered_unlocked (tree, root, &child_entries);
1900 if (child_entries != NULL)
1901 {
1902 nb = string_array_length ((const char**)child_entries);
1903 _dbus_assert (nb == 3);
1904 dbus_free_string_array (child_entries);
1905 }
1906 }
1907
1908 /* Check that destroying tree calls unregister funcs */
1909 _dbus_object_tree_unref (tree);
1910
1911 i = 0;
1912 while (i < (int) _DBUS_N_ELEMENTS (tree_test_data))
1913 {
1914 _dbus_assert (tree_test_data[i].handler_unregistered);
1915 _dbus_assert (!tree_test_data[i].message_handled);
1916 ++i;
1917 }
1918
1919 /* Now start again and try the individual unregister function */
1920 tree = _dbus_object_tree_new (NULL);
1921 if (tree == NULL)
1922 goto out;
1923
1924 if (!do_register (tree, path0, TRUE, 0, tree_test_data))
1925 goto out;
1926 if (!do_register (tree, path1, TRUE, 1, tree_test_data))
1927 goto out;
1928 if (!do_register (tree, path2, TRUE, 2, tree_test_data))
1929 goto out;
1930 if (!do_register (tree, path3, TRUE, 3, tree_test_data))
1931 goto out;
1932 if (!do_register (tree, path4, TRUE, 4, tree_test_data))
1933 goto out;
1934 if (!do_register (tree, path5, TRUE, 5, tree_test_data))
1935 goto out;
1936 if (!do_register (tree, path6, TRUE, 6, tree_test_data))
1937 goto out;
1938 if (!do_register (tree, path7, TRUE, 7, tree_test_data))
1939 goto out;
1940 if (!do_register (tree, path8, TRUE, 8, tree_test_data))
1941 goto out;
1942
1943 _dbus_object_tree_unregister_and_unlock (tree, path0);
1944 _dbus_assert (_dbus_object_tree_get_user_data_unlocked (tree, path0) == NULL);
1945
1946 _dbus_assert (!find_subtree (tree, path0, NULL));
1947 _dbus_assert (find_subtree (tree, path1, NULL));
1948 _dbus_assert (find_subtree (tree, path2, NULL));
1949 _dbus_assert (find_subtree (tree, path3, NULL));
1950 _dbus_assert (find_subtree (tree, path4, NULL));
1951 _dbus_assert (find_subtree (tree, path5, NULL));
1952 _dbus_assert (find_subtree (tree, path6, NULL));
1953 _dbus_assert (find_subtree (tree, path7, NULL));
1954 _dbus_assert (find_subtree (tree, path8, NULL));
1955
1956 _dbus_object_tree_unregister_and_unlock (tree, path1);
1957 _dbus_assert (_dbus_object_tree_get_user_data_unlocked (tree, path1) == NULL);
1958
1959 _dbus_assert (!find_subtree (tree, path0, NULL));
1960 _dbus_assert (!find_subtree (tree, path1, NULL));
1961 _dbus_assert (find_subtree (tree, path2, NULL));
1962 _dbus_assert (find_subtree (tree, path3, NULL));
1963 _dbus_assert (find_subtree (tree, path4, NULL));
1964 _dbus_assert (find_subtree (tree, path5, NULL));
1965 _dbus_assert (find_subtree (tree, path6, NULL));
1966 _dbus_assert (find_subtree (tree, path7, NULL));
1967 _dbus_assert (find_subtree (tree, path8, NULL));
1968
1969 _dbus_object_tree_unregister_and_unlock (tree, path2);
1970 _dbus_assert (_dbus_object_tree_get_user_data_unlocked (tree, path2) == NULL);
1971
1972 _dbus_assert (!find_subtree (tree, path0, NULL));
1973 _dbus_assert (!find_subtree (tree, path1, NULL));
1974 _dbus_assert (!find_subtree (tree, path2, NULL));
1975 _dbus_assert (find_subtree (tree, path3, NULL));
1976 _dbus_assert (find_subtree (tree, path4, NULL));
1977 _dbus_assert (find_subtree (tree, path5, NULL));
1978 _dbus_assert (find_subtree (tree, path6, NULL));
1979 _dbus_assert (find_subtree (tree, path7, NULL));
1980 _dbus_assert (find_subtree (tree, path8, NULL));
1981
1982 _dbus_object_tree_unregister_and_unlock (tree, path3);
1983 _dbus_assert (_dbus_object_tree_get_user_data_unlocked (tree, path3) == NULL);
1984
1985 _dbus_assert (!find_subtree (tree, path0, NULL));
1986 _dbus_assert (!find_subtree (tree, path1, NULL));
1987 _dbus_assert (!find_subtree (tree, path2, NULL));
1988 _dbus_assert (!find_subtree (tree, path3, NULL));
1989 _dbus_assert (find_subtree (tree, path4, NULL));
1990 _dbus_assert (find_subtree (tree, path5, NULL));
1991 _dbus_assert (find_subtree (tree, path6, NULL));
1992 _dbus_assert (find_subtree (tree, path7, NULL));
1993 _dbus_assert (find_subtree (tree, path8, NULL));
1994
1995 _dbus_object_tree_unregister_and_unlock (tree, path4);
1996 _dbus_assert (_dbus_object_tree_get_user_data_unlocked (tree, path4) == NULL);
1997
1998 _dbus_assert (!find_subtree (tree, path0, NULL));
1999 _dbus_assert (!find_subtree (tree, path1, NULL));
2000 _dbus_assert (!find_subtree (tree, path2, NULL));
2001 _dbus_assert (!find_subtree (tree, path3, NULL));
2002 _dbus_assert (!find_subtree (tree, path4, NULL));
2003 _dbus_assert (find_subtree (tree, path5, NULL));
2004 _dbus_assert (find_subtree (tree, path6, NULL));
2005 _dbus_assert (find_subtree (tree, path7, NULL));
2006 _dbus_assert (find_subtree (tree, path8, NULL));
2007
2008 _dbus_object_tree_unregister_and_unlock (tree, path5);
2009 _dbus_assert (_dbus_object_tree_get_user_data_unlocked (tree, path5) == NULL);
2010
2011 _dbus_assert (!find_subtree (tree, path0, NULL));
2012 _dbus_assert (!find_subtree (tree, path1, NULL));
2013 _dbus_assert (!find_subtree (tree, path2, NULL));
2014 _dbus_assert (!find_subtree (tree, path3, NULL));
2015 _dbus_assert (!find_subtree (tree, path4, NULL));
2016 _dbus_assert (!find_subtree (tree, path5, NULL));
2017 _dbus_assert (find_subtree (tree, path6, NULL));
2018 _dbus_assert (find_subtree (tree, path7, NULL));
2019 _dbus_assert (find_subtree (tree, path8, NULL));
2020
2021 _dbus_object_tree_unregister_and_unlock (tree, path6);
2022 _dbus_assert (_dbus_object_tree_get_user_data_unlocked (tree, path6) == NULL);
2023
2024 _dbus_assert (!find_subtree (tree, path0, NULL));
2025 _dbus_assert (!find_subtree (tree, path1, NULL));
2026 _dbus_assert (!find_subtree (tree, path2, NULL));
2027 _dbus_assert (!find_subtree (tree, path3, NULL));
2028 _dbus_assert (!find_subtree (tree, path4, NULL));
2029 _dbus_assert (!find_subtree (tree, path5, NULL));
2030 _dbus_assert (!find_subtree (tree, path6, NULL));
2031 _dbus_assert (find_subtree (tree, path7, NULL));
2032 _dbus_assert (find_subtree (tree, path8, NULL));
2033
2034 _dbus_object_tree_unregister_and_unlock (tree, path7);
2035 _dbus_assert (_dbus_object_tree_get_user_data_unlocked (tree, path7) == NULL);
2036
2037 _dbus_assert (!find_subtree (tree, path0, NULL));
2038 _dbus_assert (!find_subtree (tree, path1, NULL));
2039 _dbus_assert (!find_subtree (tree, path2, NULL));
2040 _dbus_assert (!find_subtree (tree, path3, NULL));
2041 _dbus_assert (!find_subtree (tree, path4, NULL));
2042 _dbus_assert (!find_subtree (tree, path5, NULL));
2043 _dbus_assert (!find_subtree (tree, path6, NULL));
2044 _dbus_assert (!find_subtree (tree, path7, NULL));
2045 _dbus_assert (find_subtree (tree, path8, NULL));
2046
2047 _dbus_object_tree_unregister_and_unlock (tree, path8);
2048 _dbus_assert (_dbus_object_tree_get_user_data_unlocked (tree, path8) == NULL);
2049
2050 _dbus_assert (!find_subtree (tree, path0, NULL));
2051 _dbus_assert (!find_subtree (tree, path1, NULL));
2052 _dbus_assert (!find_subtree (tree, path2, NULL));
2053 _dbus_assert (!find_subtree (tree, path3, NULL));
2054 _dbus_assert (!find_subtree (tree, path4, NULL));
2055 _dbus_assert (!find_subtree (tree, path5, NULL));
2056 _dbus_assert (!find_subtree (tree, path6, NULL));
2057 _dbus_assert (!find_subtree (tree, path7, NULL));
2058 _dbus_assert (!find_subtree (tree, path8, NULL));
2059
2060 i = 0;
2061 while (i < (int) _DBUS_N_ELEMENTS (tree_test_data))
2062 {
2063 _dbus_assert (tree_test_data[i].handler_unregistered);
2064 _dbus_assert (!tree_test_data[i].message_handled);
2065 ++i;
2066 }
2067
2068 /* Test removal of newly-childless unregistered nodes */
2069 if (!do_register (tree, path2, TRUE, 2, tree_test_data))
2070 goto out;
2071
2072 _dbus_object_tree_unregister_and_unlock (tree, path2);
2073 _dbus_assert (!find_subtree_registered_or_unregistered (tree, path2));
2074 _dbus_assert (!find_subtree_registered_or_unregistered (tree, path1));
2075 _dbus_assert (find_subtree_registered_or_unregistered (tree, path0));
2076
2077 /* Test that unregistered parents cannot be freed out from under their
2078 children */
2079 if (!do_register (tree, path2, TRUE, 2, tree_test_data))
2080 goto out;
2081
2082 _dbus_assert (!find_subtree (tree, path1, NULL));
2083 _dbus_assert (find_subtree_registered_or_unregistered (tree, path1));
2084 _dbus_assert (find_subtree_registered_or_unregistered (tree, path0));
2085
2086 #if 0
2087 /* This triggers the "Attempted to unregister path ..." warning message */
2088 _dbus_object_tree_unregister_and_unlock (tree, path1);
2089 #endif
2090 _dbus_assert (find_subtree (tree, path2, NULL));
2091 _dbus_assert (!find_subtree (tree, path1, NULL));
2092 _dbus_assert (find_subtree_registered_or_unregistered (tree, path1));
2093 _dbus_assert (find_subtree_registered_or_unregistered (tree, path0));
2094
2095 _dbus_object_tree_unregister_and_unlock (tree, path2);
2096 _dbus_assert (!find_subtree (tree, path2, NULL));
2097 _dbus_assert (!find_subtree_registered_or_unregistered (tree, path2));
2098 _dbus_assert (!find_subtree_registered_or_unregistered (tree, path1));
2099 _dbus_assert (find_subtree_registered_or_unregistered (tree, path0));
2100
2101 /* Test that registered parents cannot be freed out from under their
2102 children, and that if they are unregistered before their children, they
2103 are still freed when their children are unregistered */
2104 if (!do_register (tree, path1, TRUE, 1, tree_test_data))
2105 goto out;
2106 if (!do_register (tree, path2, TRUE, 2, tree_test_data))
2107 goto out;
2108
2109 _dbus_assert (find_subtree (tree, path1, NULL));
2110 _dbus_assert (find_subtree (tree, path2, NULL));
2111
2112 _dbus_object_tree_unregister_and_unlock (tree, path1);
2113 _dbus_assert (!find_subtree (tree, path1, NULL));
2114 _dbus_assert (find_subtree (tree, path2, NULL));
2115 _dbus_assert (find_subtree_registered_or_unregistered (tree, path1));
2116 _dbus_assert (find_subtree_registered_or_unregistered (tree, path0));
2117
2118 _dbus_object_tree_unregister_and_unlock (tree, path2);
2119 _dbus_assert (!find_subtree (tree, path1, NULL));
2120 _dbus_assert (!find_subtree_registered_or_unregistered (tree, path1));
2121 _dbus_assert (!find_subtree (tree, path2, NULL));
2122 _dbus_assert (!find_subtree_registered_or_unregistered (tree, path2));
2123 _dbus_assert (find_subtree_registered_or_unregistered (tree, path0));
2124
2125 /* Test with NULL unregister_function and user_data */
2126 if (!_dbus_object_tree_register (tree, TRUE, path2,
2127 &test_vtable,
2128 NULL,
2129 NULL))
2130 goto out;
2131
2132 _dbus_assert (_dbus_object_tree_get_user_data_unlocked (tree, path2) == NULL);
2133 _dbus_object_tree_unregister_and_unlock (tree, path2);
2134 _dbus_assert (!find_subtree (tree, path2, NULL));
2135 _dbus_assert (!find_subtree_registered_or_unregistered (tree, path2));
2136 _dbus_assert (!find_subtree_registered_or_unregistered (tree, path1));
2137 _dbus_assert (find_subtree_registered_or_unregistered (tree, path0));
2138
2139 /* Test freeing a long path */
2140 if (!do_register (tree, path3, TRUE, 3, tree_test_data))
2141 goto out;
2142
2143 _dbus_object_tree_unregister_and_unlock (tree, path3);
2144 _dbus_assert (!find_subtree (tree, path3, NULL));
2145 _dbus_assert (!find_subtree_registered_or_unregistered (tree, path3));
2146 _dbus_assert (!find_subtree_registered_or_unregistered (tree, path2));
2147 _dbus_assert (!find_subtree_registered_or_unregistered (tree, path1));
2148 _dbus_assert (find_subtree_registered_or_unregistered (tree, path0));
2149
2150 /* Test freeing multiple children from the same path */
2151 if (!do_register (tree, path3, TRUE, 3, tree_test_data))
2152 goto out;
2153 if (!do_register (tree, path4, TRUE, 4, tree_test_data))
2154 goto out;
2155
2156 _dbus_assert (find_subtree (tree, path3, NULL));
2157 _dbus_assert (find_subtree (tree, path4, NULL));
2158
2159 _dbus_object_tree_unregister_and_unlock (tree, path3);
2160 _dbus_assert (!find_subtree (tree, path3, NULL));
2161 _dbus_assert (!find_subtree_registered_or_unregistered (tree, path3));
2162 _dbus_assert (find_subtree (tree, path4, NULL));
2163 _dbus_assert (find_subtree_registered_or_unregistered (tree, path4));
2164 _dbus_assert (find_subtree_registered_or_unregistered (tree, path2));
2165 _dbus_assert (find_subtree_registered_or_unregistered (tree, path1));
2166
2167 _dbus_object_tree_unregister_and_unlock (tree, path4);
2168 _dbus_assert (!find_subtree (tree, path4, NULL));
2169 _dbus_assert (!find_subtree_registered_or_unregistered (tree, path4));
2170 _dbus_assert (!find_subtree (tree, path3, NULL));
2171 _dbus_assert (!find_subtree_registered_or_unregistered (tree, path3));
2172 _dbus_assert (!find_subtree_registered_or_unregistered (tree, path2));
2173 _dbus_assert (!find_subtree_registered_or_unregistered (tree, path1));
2174
2175 /* Test subtree removal */
2176 if (!_dbus_object_tree_register (tree, TRUE, path12,
2177 &test_vtable,
2178 NULL,
2179 NULL))
2180 goto out;
2181
2182 _dbus_assert (find_subtree (tree, path12, NULL));
2183
2184 if (!_dbus_object_tree_register (tree, TRUE, path13,
2185 &test_vtable,
2186 NULL,
2187 NULL))
2188 goto out;
2189
2190 _dbus_assert (find_subtree (tree, path13, NULL));
2191
2192 if (!_dbus_object_tree_register (tree, TRUE, path14,
2193 &test_vtable,
2194 NULL,
2195 NULL))
2196 goto out;
2197
2198 _dbus_assert (find_subtree (tree, path14, NULL));
2199
2200 _dbus_object_tree_unregister_and_unlock (tree, path12);
2201
2202 _dbus_assert (!find_subtree_registered_or_unregistered (tree, path12));
2203 _dbus_assert (find_subtree (tree, path13, NULL));
2204 _dbus_assert (find_subtree (tree, path14, NULL));
2205 _dbus_assert (!find_subtree_registered_or_unregistered (tree, path9));
2206 _dbus_assert (find_subtree_registered_or_unregistered (tree, path5));
2207
2208 if (!_dbus_object_tree_register (tree, TRUE, path12,
2209 &test_vtable,
2210 NULL,
2211 NULL))
2212 goto out;
2213
2214 _dbus_assert (find_subtree (tree, path12, NULL));
2215
2216 _dbus_object_tree_unregister_and_unlock (tree, path13);
2217
2218 _dbus_assert (find_subtree (tree, path12, NULL));
2219 _dbus_assert (!find_subtree_registered_or_unregistered (tree, path13));
2220 _dbus_assert (find_subtree (tree, path14, NULL));
2221 _dbus_assert (!find_subtree_registered_or_unregistered (tree, path10));
2222 _dbus_assert (find_subtree_registered_or_unregistered (tree, path5));
2223
2224 if (!_dbus_object_tree_register (tree, TRUE, path13,
2225 &test_vtable,
2226 NULL,
2227 NULL))
2228 goto out;
2229
2230 _dbus_assert (find_subtree (tree, path13, NULL));
2231
2232 _dbus_object_tree_unregister_and_unlock (tree, path14);
2233
2234 _dbus_assert (find_subtree (tree, path12, NULL));
2235 _dbus_assert (find_subtree (tree, path13, NULL));
2236 _dbus_assert (!find_subtree_registered_or_unregistered (tree, path14));
2237 _dbus_assert (!find_subtree_registered_or_unregistered (tree, path11));
2238 _dbus_assert (find_subtree_registered_or_unregistered (tree, path5));
2239
2240 _dbus_object_tree_unregister_and_unlock (tree, path12);
2241
2242 _dbus_assert (!find_subtree_registered_or_unregistered (tree, path12));
2243 _dbus_assert (!find_subtree_registered_or_unregistered (tree, path9));
2244 _dbus_assert (find_subtree_registered_or_unregistered (tree, path5));
2245
2246 _dbus_object_tree_unregister_and_unlock (tree, path13);
2247
2248 _dbus_assert (!find_subtree_registered_or_unregistered (tree, path13));
2249 _dbus_assert (!find_subtree_registered_or_unregistered (tree, path10));
2250 _dbus_assert (!find_subtree_registered_or_unregistered (tree, path5));
2251
2252 #if 0
2253 /* Test attempting to unregister non-existent paths. These trigger
2254 "Attempted to unregister path ..." warning messages */
2255 _dbus_object_tree_unregister_and_unlock (tree, path0);
2256 _dbus_object_tree_unregister_and_unlock (tree, path1);
2257 _dbus_object_tree_unregister_and_unlock (tree, path2);
2258 _dbus_object_tree_unregister_and_unlock (tree, path3);
2259 _dbus_object_tree_unregister_and_unlock (tree, path4);
2260 #endif
2261
2262 /* Register it all again, and test dispatch */
2263
2264 if (!do_register (tree, path0, TRUE, 0, tree_test_data))
2265 goto out;
2266 if (!do_register (tree, path1, FALSE, 1, tree_test_data))
2267 goto out;
2268 if (!do_register (tree, path2, TRUE, 2, tree_test_data))
2269 goto out;
2270 if (!do_register (tree, path3, TRUE, 3, tree_test_data))
2271 goto out;
2272 if (!do_register (tree, path4, TRUE, 4, tree_test_data))
2273 goto out;
2274 if (!do_register (tree, path5, TRUE, 5, tree_test_data))
2275 goto out;
2276 if (!do_register (tree, path6, FALSE, 6, tree_test_data))
2277 goto out;
2278 if (!do_register (tree, path7, TRUE, 7, tree_test_data))
2279 goto out;
2280 if (!do_register (tree, path8, TRUE, 8, tree_test_data))
2281 goto out;
2282
2283 #if 0
2284 spew_tree (tree);
2285 #endif
2286
2287 if (!do_test_dispatch (tree, path0, 0, tree_test_data, _DBUS_N_ELEMENTS (tree_test_data)))
2288 goto out;
2289 if (!do_test_dispatch (tree, path1, 1, tree_test_data, _DBUS_N_ELEMENTS (tree_test_data)))
2290 goto out;
2291 if (!do_test_dispatch (tree, path2, 2, tree_test_data, _DBUS_N_ELEMENTS (tree_test_data)))
2292 goto out;
2293 if (!do_test_dispatch (tree, path3, 3, tree_test_data, _DBUS_N_ELEMENTS (tree_test_data)))
2294 goto out;
2295 if (!do_test_dispatch (tree, path4, 4, tree_test_data, _DBUS_N_ELEMENTS (tree_test_data)))
2296 goto out;
2297 if (!do_test_dispatch (tree, path5, 5, tree_test_data, _DBUS_N_ELEMENTS (tree_test_data)))
2298 goto out;
2299 if (!do_test_dispatch (tree, path6, 6, tree_test_data, _DBUS_N_ELEMENTS (tree_test_data)))
2300 goto out;
2301 if (!do_test_dispatch (tree, path7, 7, tree_test_data, _DBUS_N_ELEMENTS (tree_test_data)))
2302 goto out;
2303 if (!do_test_dispatch (tree, path8, 8, tree_test_data, _DBUS_N_ELEMENTS (tree_test_data)))
2304 goto out;
2305
2306 out:
2307 if (tree)
2308 {
2309 /* test ref */
2310 _dbus_object_tree_ref (tree);
2311 _dbus_object_tree_unref (tree);
2312 _dbus_object_tree_unref (tree);
2313 }
2314
2315 return TRUE;
2316 }
2317
2323 dbus_bool_t
2324 _dbus_object_tree_test (void)
2325 {
2326 _dbus_test_oom_handling ("object tree",
2327 object_tree_test_iteration,
2328 NULL);
2329
2330 return TRUE;
2331 }
2332
2333 #endif /* !DOXYGEN_SHOULD_SKIP_THIS */
2334
2335 #endif /* DBUS_ENABLE_EMBEDDED_TESTS */
_dbus_string_append
dbus_bool_t _dbus_string_append(DBusString *str, const char *buffer)
Appends a nul-terminated C-style string to a DBusString.
Definition: dbus-string.c:935
_dbus_object_tree_dispatch_and_unlock
DBusHandlerResult _dbus_object_tree_dispatch_and_unlock(DBusObjectTree *tree, DBusMessage *message, dbus_bool_t *found_object)
Tries to dispatch a message by directing it to handler for the object path listed in the message head...
Definition: dbus-object-tree.c:905
DBusAtomic
An atomic integer safe to increment or decrement from multiple threads.
Definition: dbus-sysdeps.h:279
DBusObjectSubtree::max_subtrees
int max_subtrees
Number of allocated entries in subtrees.
Definition: dbus-object-tree.c:79
NULL
#define NULL
A null pointer, defined appropriately for C or C++.
dbus_message_is_method_call
dbus_bool_t dbus_message_is_method_call(DBusMessage *message, const char *iface, const char *method)
Checks whether the message is a method call with the given interface and member fields.
Definition: dbus-message.c:3693
DBUS_INTERFACE_INTROSPECTABLE
#define DBUS_INTERFACE_INTROSPECTABLE
The interface supported by introspectable objects.
Definition: dbus-shared.h:95
_dbus_object_tree_free_all_unlocked
void _dbus_object_tree_free_all_unlocked(DBusObjectTree *tree)
Free all the handlers in the tree.
Definition: dbus-object-tree.c:720
dbus_realloc
void * dbus_realloc(void *memory, size_t bytes)
Resizes a block of memory previously allocated by dbus_malloc() or dbus_malloc0().
Definition: dbus-memory.c:601
dbus_free
void dbus_free(void *memory)
Frees a block of memory previously allocated by dbus_malloc() or dbus_malloc0().
Definition: dbus-memory.c:701
DBusObjectTree::connection
DBusConnection * connection
Connection this tree belongs to.
Definition: dbus-object-tree.c:60
_dbus_connection_lock
DBUS_PRIVATE_EXPORT void _dbus_connection_lock(DBusConnection *connection)
Acquires the connection lock.
Definition: dbus-connection.c:388
_dbus_list_remove_link
void _dbus_list_remove_link(DBusList **list, DBusList *link)
Removes a link from the list.
Definition: dbus-list.c:527
DBUS_TYPE_STRING
#define DBUS_TYPE_STRING
Type code marking a UTF-8 encoded, nul-terminated Unicode string.
Definition: dbus-protocol.h:102
DBusObjectSubtree::message_function
DBusObjectPathMessageFunction message_function
Function to handle messages.
Definition: dbus-object-tree.c:75
_dbus_assert
#define _dbus_assert(condition)
Aborts with an error message if the condition is false.
Definition: dbus-internals.h:148
DBusList::data
void * data
Data stored at this element.
Definition: dbus-list.h:38
DBusObjectSubtree::unregister_function
DBusObjectPathUnregisterFunction unregister_function
Function to call on unregister.
Definition: dbus-object-tree.c:74
DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE
#define DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE
XML document type declaration of the introspection format version 1.0.
Definition: dbus-protocol.h:468
DBusObjectSubtree::invoke_as_fallback
unsigned int invoke_as_fallback
Whether to invoke message_function when child nodes don&#39;t handle the message.
Definition: dbus-object-tree.c:80
DBUS_HANDLER_RESULT_NOT_YET_HANDLED
Message has not had any effect - see if other handlers want it.
Definition: dbus-shared.h:69
dbus_message_iter_init_append
void dbus_message_iter_init_append(DBusMessage *message, DBusMessageIter *iter)
Initializes a DBusMessageIter for appending arguments to the end of a message.
Definition: dbus-message.c:2499
DBusObjectSubtree
Struct representing a single registered subtree handler, or node that&#39;s a parent of a registered subt...
Definition: dbus-object-tree.c:70
_dbus_object_tree_unregister_and_unlock
void _dbus_object_tree_unregister_and_unlock(DBusObjectTree *tree, const char **path)
Unregisters an object subtree that was registered with the same path.
Definition: dbus-object-tree.c:625
DBusObjectSubtree::name
char name[1]
Allocated as large as necessary.
Definition: dbus-object-tree.c:81
DBusConnection
Implementation details of DBusConnection.
Definition: dbus-connection.c:256
DBusObjectTree::root
DBusObjectSubtree * root
Root of the tree ("/" node)
Definition: dbus-object-tree.c:62
_dbus_string_init
dbus_bool_t _dbus_string_init(DBusString *str)
Initializes a string.
Definition: dbus-string.c:175
DBusHandlerResult
DBusHandlerResult
Results that a message handler can return.
Definition: dbus-shared.h:66
DBusMessageIter
DBusMessageIter struct; contains no public fields.
Definition: dbus-message.h:51
_dbus_list_get_next_link
#define _dbus_list_get_next_link(list, link)
Gets the next link in the list, or NULL if there are no more links.
Definition: dbus-list.h:116
DBusObjectPathVTable
Virtual table that must be implemented to handle a portion of the object path hierarchy.
Definition: dbus-connection.h:384
DBusMessage
Internals of DBusMessage.
Definition: dbus-message-private.h:99
DBusObjectPathUnregisterFunction
void(* DBusObjectPathUnregisterFunction)(DBusConnection *connection, void *user_data)
Called when a DBusObjectPathVTable is unregistered (or its connection is freed).
Definition: dbus-connection.h:367
DBusObjectSubtree::n_subtrees
int n_subtrees
Number of child nodes.
Definition: dbus-object-tree.c:78
DBusObjectPathVTable::unregister_function
DBusObjectPathUnregisterFunction unregister_function
Function to unregister this handler.
Definition: dbus-connection.h:386
DBUS_ERROR_OBJECT_PATH_IN_USE
#define DBUS_ERROR_OBJECT_PATH_IN_USE
There&#39;s already an object with the requested object path.
Definition: dbus-protocol.h:450
dbus_new0
#define dbus_new0(type, count)
Safe macro for using dbus_malloc0().
Definition: dbus-memory.h:59
DBusString
Definition: dbus-string.h:42
dbus_bool_t
dbus_uint32_t dbus_bool_t
A boolean, valid values are TRUE and FALSE.
Definition: dbus-types.h:35
_dbus_object_tree_list_registered_and_unlock
dbus_bool_t _dbus_object_tree_list_registered_and_unlock(DBusObjectTree *tree, const char **parent_path, char ***child_entries)
Lists the registered fallback handlers and object path handlers at the given parent_path.
Definition: dbus-object-tree.c:1208
dbus_message_get_path_decomposed
dbus_bool_t dbus_message_get_path_decomposed(DBusMessage *message, char ***path)
Gets the object path this message is being sent to (for DBUS_MESSAGE_TYPE_METHOD_CALL) or being emitt...
Definition: dbus-message.c:3255
DBusObjectTree
Internals of DBusObjectTree.
Definition: dbus-object-tree.c:57
_dbus_warn
void _dbus_warn(const char *format,...)
Prints a warning message to stderr.
Definition: dbus-internals.c:230
_dbus_atomic_inc
dbus_int32_t _dbus_atomic_inc(DBusAtomic *atomic)
Atomically increments an integer.
Definition: dbus-sysdeps-unix.c:2753
_dbus_object_tree_ref
DBusObjectTree * _dbus_object_tree_ref(DBusObjectTree *tree)
Increment the reference count.
Definition: dbus-object-tree.c:129
_dbus_list_append
dbus_bool_t _dbus_list_append(DBusList **list, void *data)
Appends a value to the list.
Definition: dbus-list.c:270
_dbus_decompose_path
dbus_bool_t _dbus_decompose_path(const char *data, int len, char ***path, int *path_len)
Decompose an object path.
Definition: dbus-object-tree.c:1244
_dbus_memdup
void * _dbus_memdup(const void *mem, size_t n_bytes)
Duplicates a block of memory.
Definition: dbus-internals.c:565
_dbus_string_append_printf
dbus_bool_t _dbus_string_append_printf(DBusString *str, const char *format,...)
Appends a printf-style formatted string to the DBusString.
Definition: dbus-string.c:1114
DBusObjectSubtree::subtrees
DBusObjectSubtree ** subtrees
Child nodes.
Definition: dbus-object-tree.c:77
DBusError
Object representing an exception.
Definition: dbus-errors.h:48
dbus_set_error
void dbus_set_error(DBusError *error, const char *name, const char *format,...)
Assigns an error name and message to a DBusError.
Definition: dbus-errors.c:354
DBusObjectPathVTable::message_function
DBusObjectPathMessageFunction message_function
Function to handle messages.
Definition: dbus-connection.h:387
DBusObjectSubtree::user_data
void * user_data
Data for functions.
Definition: dbus-object-tree.c:76
_dbus_connection_send_and_unlock
dbus_bool_t _dbus_connection_send_and_unlock(DBusConnection *connection, DBusMessage *message, dbus_uint32_t *client_serial)
Like dbus_connection_send(), but assumes the connection is already locked on function entry...
Definition: dbus-connection.c:2098
_DBUS_N_ELEMENTS
#define _DBUS_N_ELEMENTS(array)
Computes the number of elements in a fixed-size array using sizeof().
Definition: dbus-internals.h:189
dbus_message_new_method_call
DBusMessage * dbus_message_new_method_call(const char *destination, const char *path, const char *iface, const char *method)
Constructs a new message to invoke a method on a remote object.
Definition: dbus-message.c:1360
_dbus_string_append_byte
dbus_bool_t _dbus_string_append_byte(DBusString *str, unsigned char byte)
Appends a single byte to the string, returning FALSE if not enough memory.
Definition: dbus-string.c:1157
DBusObjectSubtree::parent
DBusObjectSubtree * parent
Parent node.
Definition: dbus-object-tree.c:73
_dbus_string_free
void _dbus_string_free(DBusString *str)
Frees a string created by _dbus_string_init().
Definition: dbus-string.c:259
TRUE
#define TRUE
Expands to "1".
_dbus_assert_not_reached
#define _dbus_assert_not_reached(explanation)
Aborts with an error message if called.
Definition: dbus-internals.h:159
_dbus_object_tree_get_user_data_unlocked
void * _dbus_object_tree_get_user_data_unlocked(DBusObjectTree *tree, const char **path)
Looks up the data passed to _dbus_object_tree_register() for a handler at the given path...
Definition: dbus-object-tree.c:1077
_dbus_object_tree_register
dbus_bool_t _dbus_object_tree_register(DBusObjectTree *tree, dbus_bool_t fallback, const char **path, const DBusObjectPathVTable *vtable, void *user_data, DBusError *error)
Registers a new subtree in the global object tree.
Definition: dbus-object-tree.c:393
DBusObjectPathMessageFunction
DBusHandlerResult(* DBusObjectPathMessageFunction)(DBusConnection *connection, DBusMessage *message, void *user_data)
Called when a message is sent to a registered object path.
Definition: dbus-connection.h:374
DBusObjectTree::refcount
int refcount
Reference count.
Definition: dbus-object-tree.c:59
_dbus_object_tree_new
DBusObjectTree * _dbus_object_tree_new(DBusConnection *connection)
Creates a new object tree, representing a mapping from paths to handler vtables.
Definition: dbus-object-tree.c:92
_dbus_atomic_dec
dbus_int32_t _dbus_atomic_dec(DBusAtomic *atomic)
Atomically decrement an integer.
Definition: dbus-sysdeps-unix.c:2776
DBusList
A node in a linked list.
Definition: dbus-list.h:34
dbus_free_string_array
void dbus_free_string_array(char **str_array)
Frees a NULL-terminated array of strings.
Definition: dbus-memory.c:749
DBusObjectSubtree::refcount
DBusAtomic refcount
Reference count.
Definition: dbus-object-tree.c:72
_dbus_list_get_length
int _dbus_list_get_length(DBusList **list)
Gets the length of a list.
Definition: dbus-list.c:730
dbus_message_iter_append_basic
dbus_bool_t dbus_message_iter_append_basic(DBusMessageIter *iter, int type, const void *value)
Appends a basic-typed value to the message.
Definition: dbus-message.c:2734
_dbus_list_get_first_link
DBusList * _dbus_list_get_first_link(DBusList **list)
Gets the first link in the list.
Definition: dbus-list.c:567
FALSE
#define FALSE
Expands to "0".
dbus_malloc0
void * dbus_malloc0(size_t bytes)
Allocates the given number of bytes, as with standard malloc(), but all bytes are initialized to zero...
Definition: dbus-memory.c:531
_dbus_string_steal_data
dbus_bool_t _dbus_string_steal_data(DBusString *str, char **data_return)
Like _dbus_string_get_data(), but removes the gotten data from the original string.
Definition: dbus-string.c:641
dbus_connection_unref
void dbus_connection_unref(DBusConnection *connection)
Decrements the reference count of a DBusConnection, and finalizes it if the count reaches zero...
Definition: dbus-connection.c:2819
_dbus_object_tree_unref
void _dbus_object_tree_unref(DBusObjectTree *tree)
Decrement the reference count.
Definition: dbus-object-tree.c:143
_dbus_connection_ref_unlocked
DBUS_PRIVATE_EXPORT DBusConnection * _dbus_connection_ref_unlocked(DBusConnection *connection)
Increments the reference count of a DBusConnection.
Definition: dbus-connection.c:1419
DBUS_HANDLER_RESULT_HANDLED
Message has had its effect - no need to run more handlers.
Definition: dbus-shared.h:68
_dbus_strdup
char * _dbus_strdup(const char *str)
Duplicates a string.
Definition: dbus-internals.c:537
_dbus_connection_unlock
DBUS_PRIVATE_EXPORT void _dbus_connection_unlock(DBusConnection *connection)
Releases the connection lock.
Definition: dbus-connection.c:399
dbus_message_unref
void dbus_message_unref(DBusMessage *message)
Decrements the reference count of a DBusMessage, freeing the message if the count reaches 0...
Definition: dbus-message.c:1717
DBUS_HANDLER_RESULT_NEED_MEMORY
Need more memory in order to return DBUS_HANDLER_RESULT_HANDLED or DBUS_HANDLER_RESULT_NOT_YET_HANDLE...
Definition: dbus-shared.h:70
dbus_message_new_method_return
DBusMessage * dbus_message_new_method_return(DBusMessage *method_call)
Constructs a message that is a reply to a method call.
Definition: dbus-message.c:1400