D-Bus 1.13.18

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