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

D-Bus 1.8.16

- Main Page
- Related Pages
- Modules
- Data Structures
- Files

- File List

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 static DBusObjectSubtree*
323 find_subtree (DBusObjectTree *tree,
324 const char **path,
325 int *index_in_parent)
326 {
327 DBusObjectSubtree *subtree;
328
329 #if VERBOSE_FIND
330 _dbus_verbose ("Looking for exact registered subtree\n");
331 #endif
332
333 subtree = find_subtree_recurse (tree->root, path, FALSE, index_in_parent, NULL);
334
335 if (subtree && subtree->message_function == NULL)
336 return NULL;
337 else
338 return subtree;
339 }
340
341 static DBusObjectSubtree*
342 lookup_subtree (DBusObjectTree *tree,
343 const char **path)
344 {
345 #if VERBOSE_FIND
346 _dbus_verbose ("Looking for subtree\n");
347 #endif
348 return find_subtree_recurse (tree->root, path, FALSE, NULL, NULL);
349 }
350
351 static DBusObjectSubtree*
352 find_handler (DBusObjectTree *tree,
353 const char **path,
354 dbus_bool_t *exact_match)
355 {
356 #if VERBOSE_FIND
357 _dbus_verbose ("Looking for deepest handler\n");
358 #endif
359 _dbus_assert (exact_match != NULL);
360
361 *exact_match = FALSE; /* ensure always initialized */
362
363 return find_subtree_recurse (tree->root, path, FALSE, NULL, exact_match);
364 }
365
366 static DBusObjectSubtree*
367 ensure_subtree (DBusObjectTree *tree,
368 const char **path)
369 {
370 #if VERBOSE_FIND
371 _dbus_verbose ("Ensuring subtree\n");
372 #endif
373 return find_subtree_recurse (tree->root, path, TRUE, NULL, NULL);
374 }
375
376 static char *flatten_path (const char **path);
377
390 dbus_bool_t
391 _dbus_object_tree_register (DBusObjectTree *tree,
392 dbus_bool_t fallback,
393 const char **path,
394 const DBusObjectPathVTable *vtable,
395 void *user_data,
396 DBusError *error)
397 {
398 DBusObjectSubtree *subtree;
399
400 _dbus_assert (tree != NULL);
401 _dbus_assert (vtable->message_function != NULL);
402 _dbus_assert (path != NULL);
403
404 subtree = ensure_subtree (tree, path);
405 if (subtree == NULL)
406 {
407 _DBUS_SET_OOM (error);
408 return FALSE;
409 }
410
411 if (subtree->message_function != NULL)
412 {
413 if (error != NULL)
414 {
415 char *complete_path = flatten_path (path);
416
417 dbus_set_error (error, DBUS_ERROR_OBJECT_PATH_IN_USE,
418 "A handler is already registered for %s",
419 complete_path ? complete_path
420 : "(cannot represent path: out of memory!)");
421
422 dbus_free (complete_path);
423 }
424
425 return FALSE;
426 }
427
428 subtree->message_function = vtable->message_function;
429 subtree->unregister_function = vtable->unregister_function;
430 subtree->user_data = user_data;
431 subtree->invoke_as_fallback = fallback != FALSE;
432
433 return TRUE;
434 }
435
447 static dbus_bool_t
448 unregister_subtree (DBusObjectSubtree *subtree,
449 DBusObjectPathUnregisterFunction *unregister_function_out,
450 void **user_data_out)
451 {
452 _dbus_assert (subtree != NULL);
453 _dbus_assert (unregister_function_out != NULL);
454 _dbus_assert (user_data_out != NULL);
455
456 /* Confirm subtree is registered */
457 if (subtree->message_function != NULL)
458 {
459 subtree->message_function = NULL;
460
461 *unregister_function_out = subtree->unregister_function;
462 *user_data_out = subtree->user_data;
463
464 subtree->unregister_function = NULL;
465 subtree->user_data = NULL;
466
467 return TRUE;
468 }
469 else
470 {
471 /* Assert that this unregistered subtree is either the root node or has
472 children, otherwise we have a dangling path which should never
473 happen */
474 _dbus_assert (subtree->parent == NULL || subtree->n_subtrees > 0);
475
476 /* The subtree is not registered */
477 return FALSE;
478 }
479 }
480
492 static dbus_bool_t
493 attempt_child_removal (DBusObjectSubtree *parent,
494 int child_index)
495 {
496 /* Candidate for removal */
497 DBusObjectSubtree* candidate;
498
499 _dbus_assert (parent != NULL);
500 _dbus_assert (child_index >= 0 && child_index < parent->n_subtrees);
501
502 candidate = parent->subtrees[child_index];
503 _dbus_assert (candidate != NULL);
504
505 if (candidate->n_subtrees == 0 && candidate->message_function == NULL)
506 {
507 /* The candidate node is childless and is not a registered
508 path, so... */
509
510 /* ... remove it from its parent... */
511 /* Assumes a 0-byte memmove is OK */
512 memmove (&parent->subtrees[child_index],
513 &parent->subtrees[child_index + 1],
514 (parent->n_subtrees - child_index - 1)
515 * sizeof (parent->subtrees[0]));
516 parent->n_subtrees -= 1;
517
518 /* ... and free it */
519 candidate->parent = NULL;
520 _dbus_object_subtree_unref (candidate);
521
522 return TRUE;
523 }
524 return FALSE;
525 }
526
564 static dbus_bool_t
565 unregister_and_free_path_recurse
566 (DBusObjectSubtree *subtree,
567 const char **path,
568 dbus_bool_t *continue_removal_attempts,
569 DBusObjectPathUnregisterFunction *unregister_function_out,
570 void **user_data_out)
571 {
572 int i, j;
573
574 _dbus_assert (continue_removal_attempts != NULL);
575 _dbus_assert (*continue_removal_attempts);
576 _dbus_assert (unregister_function_out != NULL);
577 _dbus_assert (user_data_out != NULL);
578
579 if (path[0] == NULL)
580 return unregister_subtree (subtree, unregister_function_out, user_data_out);
581
582 i = 0;
583 j = subtree->n_subtrees;
584 while (i < j)
585 {
586 int k, v;
587
588 k = (i + j) / 2;
589 v = strcmp (path[0], subtree->subtrees[k]->name);
590
591 if (v == 0)
592 {
593 dbus_bool_t freed;
594 freed = unregister_and_free_path_recurse (subtree->subtrees[k],
595 &path[1],
596 continue_removal_attempts,
597 unregister_function_out,
598 user_data_out);
599 if (freed && *continue_removal_attempts)
600 *continue_removal_attempts = attempt_child_removal (subtree, k);
601 return freed;
602 }
603 else if (v < 0)
604 {
605 j = k;
606 }
607 else
608 {
609 i = k + 1;
610 }
611 }
612 return FALSE;
613 }
614
622 void
623 _dbus_object_tree_unregister_and_unlock (DBusObjectTree *tree,
624 const char **path)
625 {
626 dbus_bool_t found_subtree;
627 dbus_bool_t continue_removal_attempts;
628 DBusObjectPathUnregisterFunction unregister_function;
629 void *user_data;
630 DBusConnection *connection;
631
632 _dbus_assert (tree != NULL);
633 _dbus_assert (path != NULL);
634
635 continue_removal_attempts = TRUE;
636 unregister_function = NULL;
637 user_data = NULL;
638
639 found_subtree = unregister_and_free_path_recurse (tree->root,
640 path,
641 &continue_removal_attempts,
642 &unregister_function,
643 &user_data);
644
645 #ifndef DBUS_DISABLE_CHECKS
646 if (found_subtree == FALSE)
647 {
648 _dbus_warn ("Attempted to unregister path (path[0] = %s path[1] = %s) which isn't registered\n",
649 path[0] ? path[0] : "null",
650 (path[0] && path[1]) ? path[1] : "null");
651 goto unlock;
652 }
653 #else
654 _dbus_assert (found_subtree == TRUE);
655 #endif
656
657 unlock:
658 connection = tree->connection;
659
660 /* Unlock and call application code */
661 #ifdef DBUS_ENABLE_EMBEDDED_TESTS
662 if (connection)
663 #endif
664 {
665 _dbus_connection_ref_unlocked (connection);
666 _dbus_verbose ("unlock\n");
667 _dbus_connection_unlock (connection);
668 }
669
670 if (unregister_function)
671 (* unregister_function) (connection, user_data);
672
673 #ifdef DBUS_ENABLE_EMBEDDED_TESTS
674 if (connection)
675 #endif
676 dbus_connection_unref (connection);
677 }
678
679 static void
680 free_subtree_recurse (DBusConnection *connection,
681 DBusObjectSubtree *subtree)
682 {
683 /* Delete them from the end, for slightly
684 * more robustness against odd reentrancy.
685 */
686 while (subtree->n_subtrees > 0)
687 {
688 DBusObjectSubtree *child;
689
690 child = subtree->subtrees[subtree->n_subtrees - 1];
691 subtree->subtrees[subtree->n_subtrees - 1] = NULL;
692 subtree->n_subtrees -= 1;
693 child->parent = NULL;
694
695 free_subtree_recurse (connection, child);
696 }
697
698 /* Call application code */
699 if (subtree->unregister_function)
700 (* subtree->unregister_function) (connection,
701 subtree->user_data);
702
703 subtree->message_function = NULL;
704 subtree->unregister_function = NULL;
705 subtree->user_data = NULL;
706
707 /* Now free ourselves */
708 _dbus_object_subtree_unref (subtree);
709 }
710
717 void
718 _dbus_object_tree_free_all_unlocked (DBusObjectTree *tree)
719 {
720 if (tree->root)
721 free_subtree_recurse (tree->connection,
722 tree->root);
723 tree->root = NULL;
724 }
725
726 static dbus_bool_t
727 _dbus_object_tree_list_registered_unlocked (DBusObjectTree *tree,
728 const char **parent_path,
729 char ***child_entries)
730 {
731 DBusObjectSubtree *subtree;
732 char **retval;
733
734 _dbus_assert (parent_path != NULL);
735 _dbus_assert (child_entries != NULL);
736
737 *child_entries = NULL;
738
739 subtree = lookup_subtree (tree, parent_path);
740 if (subtree == NULL)
741 {
742 retval = dbus_new0 (char *, 1);
743 }
744 else
745 {
746 int i;
747 retval = dbus_new0 (char*, subtree->n_subtrees + 1);
748 if (retval == NULL)
749 goto out;
750 i = 0;
751 while (i < subtree->n_subtrees)
752 {
753 retval[i] = _dbus_strdup (subtree->subtrees[i]->name);
754 if (retval[i] == NULL)
755 {
756 dbus_free_string_array (retval);
757 retval = NULL;
758 goto out;
759 }
760 ++i;
761 }
762 }
763
764 out:
765
766 *child_entries = retval;
767 return retval != NULL;
768 }
769
770 static DBusHandlerResult
771 handle_default_introspect_and_unlock (DBusObjectTree *tree,
772 DBusMessage *message,
773 const char **path)
774 {
775 DBusString xml;
776 DBusHandlerResult result;
777 char **children;
778 int i;
779 DBusMessage *reply;
780 DBusMessageIter iter;
781 const char *v_STRING;
782 dbus_bool_t already_unlocked;
783
784 /* We have the connection lock here */
785
786 already_unlocked = FALSE;
787
788 _dbus_verbose (" considering default Introspect() handler...\n");
789
790 reply = NULL;
791
792 if (!dbus_message_is_method_call (message,
793 DBUS_INTERFACE_INTROSPECTABLE,
794 "Introspect"))
795 {
796 #ifdef DBUS_ENABLE_EMBEDDED_TESTS
797 if (tree->connection)
798 #endif
799 {
800 _dbus_verbose ("unlock\n");
801 _dbus_connection_unlock (tree->connection);
802 }
803
804 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
805 }
806
807 _dbus_verbose (" using default Introspect() handler!\n");
808
809 if (!_dbus_string_init (&xml))
810 {
811 #ifdef DBUS_ENABLE_EMBEDDED_TESTS
812 if (tree->connection)
813 #endif
814 {
815 _dbus_verbose ("unlock\n");
816 _dbus_connection_unlock (tree->connection);
817 }
818
819 return DBUS_HANDLER_RESULT_NEED_MEMORY;
820 }
821
822 result = DBUS_HANDLER_RESULT_NEED_MEMORY;
823
824 children = NULL;
825 if (!_dbus_object_tree_list_registered_unlocked (tree, path, &children))
826 goto out;
827
828 if (!_dbus_string_append (&xml, DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE))
829 goto out;
830
831 if (!_dbus_string_append (&xml, "<node>\n"))
832 goto out;
833
834 i = 0;
835 while (children[i] != NULL)
836 {
837 if (!_dbus_string_append_printf (&xml, " <node name=\"%s\"/>\n",
838 children[i]))
839 goto out;
840
841 ++i;
842 }
843
844 if (!_dbus_string_append (&xml, "</node>\n"))
845 goto out;
846
847 reply = dbus_message_new_method_return (message);
848 if (reply == NULL)
849 goto out;
850
851 dbus_message_iter_init_append (reply, &iter);
852 v_STRING = _dbus_string_get_const_data (&xml);
853 if (!dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &v_STRING))
854 goto out;
855
856 #ifdef DBUS_ENABLE_EMBEDDED_TESTS
857 if (tree->connection)
858 #endif
859 {
860 already_unlocked = TRUE;
861
862 if (!_dbus_connection_send_and_unlock (tree->connection, reply, NULL))
863 goto out;
864 }
865
866 result = DBUS_HANDLER_RESULT_HANDLED;
867
868 out:
869 #ifdef DBUS_ENABLE_EMBEDDED_TESTS
870 if (tree->connection)
871 #endif
872 {
873 if (!already_unlocked)
874 {
875 _dbus_verbose ("unlock\n");
876 _dbus_connection_unlock (tree->connection);
877 }
878 }
879
880 _dbus_string_free (&xml);
881 dbus_free_string_array (children);
882 if (reply)
883 dbus_message_unref (reply);
884
885 return result;
886 }
887
902 DBusHandlerResult
903 _dbus_object_tree_dispatch_and_unlock (DBusObjectTree *tree,
904 DBusMessage *message,
905 dbus_bool_t *found_object)
906 {
907 char **path;
908 dbus_bool_t exact_match;
909 DBusList *list;
910 DBusList *link;
911 DBusHandlerResult result;
912 DBusObjectSubtree *subtree;
913
914 #if 0
915 _dbus_verbose ("Dispatch of message by object path\n");
916 #endif
917
918 path = NULL;
919 if (!dbus_message_get_path_decomposed (message, &path))
920 {
921 #ifdef DBUS_ENABLE_EMBEDDED_TESTS
922 if (tree->connection)
923 #endif
924 {
925 _dbus_verbose ("unlock\n");
926 _dbus_connection_unlock (tree->connection);
927 }
928
929 _dbus_verbose ("No memory to get decomposed path\n");
930
931 return DBUS_HANDLER_RESULT_NEED_MEMORY;
932 }
933
934 if (path == NULL)
935 {
936 #ifdef DBUS_ENABLE_EMBEDDED_TESTS
937 if (tree->connection)
938 #endif
939 {
940 _dbus_verbose ("unlock\n");
941 _dbus_connection_unlock (tree->connection);
942 }
943
944 _dbus_verbose ("No path field in message\n");
945 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
946 }
947
948 /* Find the deepest path that covers the path in the message */
949 subtree = find_handler (tree, (const char**) path, &exact_match);
950
951 if (found_object)
952 *found_object = !!subtree;
953
954 /* Build a list of all paths that cover the path in the message */
955
956 list = NULL;
957
958 while (subtree != NULL)
959 {
960 if (subtree->message_function != NULL && (exact_match || subtree->invoke_as_fallback))
961 {
962 _dbus_object_subtree_ref (subtree);
963
964 /* run deepest paths first */
965 if (!_dbus_list_append (&list, subtree))
966 {
967 result = DBUS_HANDLER_RESULT_NEED_MEMORY;
968 _dbus_object_subtree_unref (subtree);
969 goto free_and_return;
970 }
971 }
972
973 exact_match = FALSE;
974 subtree = subtree->parent;
975 }
976
977 _dbus_verbose ("%d handlers in the path tree for this message\n",
978 _dbus_list_get_length (&list));
979
980 /* Invoke each handler in the list */
981
982 result = DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
983
984 link = _dbus_list_get_first_link (&list);
985 while (link != NULL)
986 {
987 DBusList *next = _dbus_list_get_next_link (&list, link);
988 subtree = link->data;
989
990 /* message_function is NULL if we're unregistered
991 * due to reentrancy
992 */
993 if (subtree->message_function)
994 {
995 DBusObjectPathMessageFunction message_function;
996 void *user_data;
997
998 message_function = subtree->message_function;
999 user_data = subtree->user_data;
1000
1001 #if 0
1002 _dbus_verbose (" (invoking a handler)\n");
1003 #endif
1004
1005 #ifdef DBUS_ENABLE_EMBEDDED_TESTS
1006 if (tree->connection)
1007 #endif
1008 {
1009 _dbus_verbose ("unlock\n");
1010 _dbus_connection_unlock (tree->connection);
1011 }
1012
1013 /* FIXME you could unregister the subtree in another thread
1014 * before we invoke the callback, and I can't figure out a
1015 * good way to solve this.
1016 */
1017
1018 result = (* message_function) (tree->connection,
1019 message,
1020 user_data);
1021
1022 #ifdef DBUS_ENABLE_EMBEDDED_TESTS
1023 if (tree->connection)
1024 #endif
1025 _dbus_connection_lock (tree->connection);
1026
1027 if (result != DBUS_HANDLER_RESULT_NOT_YET_HANDLED)
1028 goto free_and_return;
1029 }
1030
1031 link = next;
1032 }
1033
1034 free_and_return:
1035
1036 if (result == DBUS_HANDLER_RESULT_NOT_YET_HANDLED)
1037 {
1038 /* This hardcoded default handler does a minimal Introspect()
1039 */
1040 result = handle_default_introspect_and_unlock (tree, message,
1041 (const char**) path);
1042 }
1043 else
1044 {
1045 #ifdef DBUS_ENABLE_EMBEDDED_TESTS
1046 if (tree->connection)
1047 #endif
1048 {
1049 _dbus_verbose ("unlock\n");
1050 _dbus_connection_unlock (tree->connection);
1051 }
1052 }
1053
1054 while (list != NULL)
1055 {
1056 link = _dbus_list_get_first_link (&list);
1057 _dbus_object_subtree_unref (link->data);
1058 _dbus_list_remove_link (&list, link);
1059 }
1060
1061 dbus_free_string_array (path);
1062
1063 return result;
1064 }
1065
1074 void*
1075 _dbus_object_tree_get_user_data_unlocked (DBusObjectTree *tree,
1076 const char **path)
1077 {
1078 dbus_bool_t exact_match;
1079 DBusObjectSubtree *subtree;
1080
1081 _dbus_assert (tree != NULL);
1082 _dbus_assert (path != NULL);
1083
1084 /* Find the deepest path that covers the path in the message */
1085 subtree = find_handler (tree, (const char**) path, &exact_match);
1086
1087 if ((subtree == NULL) || !exact_match)
1088 {
1089 _dbus_verbose ("No object at specified path found\n");
1090 return NULL;
1091 }
1092
1093 return subtree->user_data;
1094 }
1095
1102 static DBusObjectSubtree*
1103 allocate_subtree_object (const char *name)
1104 {
1105 int len;
1106 DBusObjectSubtree *subtree;
1107 const size_t front_padding = _DBUS_STRUCT_OFFSET (DBusObjectSubtree, name);
1108
1109 _dbus_assert (name != NULL);
1110
1111 len = strlen (name);
1112
1113 subtree = dbus_malloc0 (MAX (front_padding + (len + 1), sizeof (DBusObjectSubtree)));
1114
1115 if (subtree == NULL)
1116 return NULL;
1117
1118 memcpy (subtree->name, name, len + 1);
1119
1120 return subtree;
1121 }
1122
1123 static DBusObjectSubtree*
1124 _dbus_object_subtree_new (const char *name,
1125 const DBusObjectPathVTable *vtable,
1126 void *user_data)
1127 {
1128 DBusObjectSubtree *subtree;
1129
1130 subtree = allocate_subtree_object (name);
1131 if (subtree == NULL)
1132 goto oom;
1133
1134 _dbus_assert (name != NULL);
1135
1136 subtree->parent = NULL;
1137
1138 if (vtable)
1139 {
1140 subtree->message_function = vtable->message_function;
1141 subtree->unregister_function = vtable->unregister_function;
1142 }
1143 else
1144 {
1145 subtree->message_function = NULL;
1146 subtree->unregister_function = NULL;
1147 }
1148
1149 subtree->user_data = user_data;
1150 _dbus_atomic_inc (&subtree->refcount);
1151 subtree->subtrees = NULL;
1152 subtree->n_subtrees = 0;
1153 subtree->max_subtrees = 0;
1154 subtree->invoke_as_fallback = FALSE;
1155
1156 return subtree;
1157
1158 oom:
1159 return NULL;
1160 }
1161
1162 static DBusObjectSubtree *
1163 _dbus_object_subtree_ref (DBusObjectSubtree *subtree)
1164 {
1165 #ifdef DBUS_DISABLE_ASSERT
1166 _dbus_atomic_inc (&subtree->refcount);
1167 #else
1168 dbus_int32_t old_value;
1169
1170 old_value = _dbus_atomic_inc (&subtree->refcount);
1171 _dbus_assert (old_value > 0);
1172 #endif
1173
1174 return subtree;
1175 }
1176
1177 static void
1178 _dbus_object_subtree_unref (DBusObjectSubtree *subtree)
1179 {
1180 dbus_int32_t old_value;
1181
1182 old_value = _dbus_atomic_dec (&subtree->refcount);
1183 _dbus_assert (old_value > 0);
1184
1185 if (old_value == 1)
1186 {
1187 _dbus_assert (subtree->unregister_function == NULL);
1188 _dbus_assert (subtree->message_function == NULL);
1189
1190 dbus_free (subtree->subtrees);
1191 dbus_free (subtree);
1192 }
1193 }
1194
1205 dbus_bool_t
1206 _dbus_object_tree_list_registered_and_unlock (DBusObjectTree *tree,
1207 const char **parent_path,
1208 char ***child_entries)
1209 {
1210 dbus_bool_t result;
1211
1212 result = _dbus_object_tree_list_registered_unlocked (tree,
1213 parent_path,
1214 child_entries);
1215
1216 #ifdef DBUS_ENABLE_EMBEDDED_TESTS
1217 if (tree->connection)
1218 #endif
1219 {
1220 _dbus_verbose ("unlock\n");
1221 _dbus_connection_unlock (tree->connection);
1222 }
1223
1224 return result;
1225 }
1226
1227
1229 #define VERBOSE_DECOMPOSE 0
1230
1241 dbus_bool_t
1242 _dbus_decompose_path (const char* data,
1243 int len,
1244 char ***path,
1245 int *path_len)
1246 {
1247 char **retval;
1248 int n_components;
1249 int i, j, comp;
1250
1251 _dbus_assert (data != NULL);
1252 _dbus_assert (path != NULL);
1253
1254 #if VERBOSE_DECOMPOSE
1255 _dbus_verbose ("Decomposing path \"%s\"\n",
1256 data);
1257 #endif
1258
1259 n_components = 0;
1260 if (len > 1) /* if path is not just "/" */
1261 {
1262 i = 0;
1263 while (i < len)
1264 {
1265 _dbus_assert (data[i] != '\0');
1266 if (data[i] == '/')
1267 n_components += 1;
1268 ++i;
1269 }
1270 }
1271
1272 retval = dbus_new0 (char*, n_components + 1);
1273
1274 if (retval == NULL)
1275 return FALSE;
1276
1277 comp = 0;
1278 if (n_components == 0)
1279 i = 1;
1280 else
1281 i = 0;
1282 while (comp < n_components)
1283 {
1284 _dbus_assert (i < len);
1285
1286 if (data[i] == '/')
1287 ++i;
1288 j = i;
1289
1290 while (j < len && data[j] != '/')
1291 ++j;
1292
1293 /* Now [i, j) is the path component */
1294 _dbus_assert (i < j);
1295 _dbus_assert (data[i] != '/');
1296 _dbus_assert (j == len || data[j] == '/');
1297
1298 #if VERBOSE_DECOMPOSE
1299 _dbus_verbose (" (component in [%d,%d))\n",
1300 i, j);
1301 #endif
1302
1303 retval[comp] = _dbus_memdup (&data[i], j - i + 1);
1304 if (retval[comp] == NULL)
1305 {
1306 dbus_free_string_array (retval);
1307 return FALSE;
1308 }
1309 retval[comp][j-i] = '\0';
1310 #if VERBOSE_DECOMPOSE
1311 _dbus_verbose (" (component %d = \"%s\")\n",
1312 comp, retval[comp]);
1313 #endif
1314
1315 ++comp;
1316 i = j;
1317 }
1318 _dbus_assert (i == len);
1319
1320 *path = retval;
1321 if (path_len)
1322 *path_len = n_components;
1323
1324 return TRUE;
1325 }
1326
1329 static char*
1330 flatten_path (const char **path)
1331 {
1332 DBusString str;
1333 char *s;
1334
1335 if (!_dbus_string_init (&str))
1336 return NULL;
1337
1338 if (path[0] == NULL)
1339 {
1340 if (!_dbus_string_append_byte (&str, '/'))
1341 goto nomem;
1342 }
1343 else
1344 {
1345 int i;
1346
1347 i = 0;
1348 while (path[i])
1349 {
1350 if (!_dbus_string_append_byte (&str, '/'))
1351 goto nomem;
1352
1353 if (!_dbus_string_append (&str, path[i]))
1354 goto nomem;
1355
1356 ++i;
1357 }
1358 }
1359
1360 if (!_dbus_string_steal_data (&str, &s))
1361 goto nomem;
1362
1363 _dbus_string_free (&str);
1364
1365 return s;
1366
1367 nomem:
1368 _dbus_string_free (&str);
1369 return NULL;
1370 }
1371
1372
1373 #ifdef DBUS_ENABLE_EMBEDDED_TESTS
1374
1375 #ifndef DOXYGEN_SHOULD_SKIP_THIS
1376
1377 #include "dbus-test.h"
1378 #include <stdio.h>
1379
1380 typedef enum
1381 {
1382 STR_EQUAL,
1383 STR_PREFIX,
1384 STR_DIFFERENT
1385 } StrComparison;
1386
1387 /* Returns TRUE if container is a parent of child
1388 */
1389 static StrComparison
1390 path_contains (const char **container,
1391 const char **child)
1392 {
1393 int i;
1394
1395 i = 0;
1396 while (child[i] != NULL)
1397 {
1398 int v;
1399
1400 if (container[i] == NULL)
1401 return STR_PREFIX; /* container ran out, child continues;
1402 * thus the container is a parent of the
1403 * child.
1404 */
1405
1406 _dbus_assert (container[i] != NULL);
1407 _dbus_assert (child[i] != NULL);
1408
1409 v = strcmp (container[i], child[i]);
1410
1411 if (v != 0)
1412 return STR_DIFFERENT; /* they overlap until here and then are different,
1413 * not overlapping
1414 */
1415
1416 ++i;
1417 }
1418
1419 /* Child ran out; if container also did, they are equal;
1420 * otherwise, the child is a parent of the container.
1421 */
1422 if (container[i] == NULL)
1423 return STR_EQUAL;
1424 else
1425 return STR_DIFFERENT;
1426 }
1427
1428 #if 0
1429 static void
1430 spew_subtree_recurse (DBusObjectSubtree *subtree,
1431 int indent)
1432 {
1433 int i;
1434
1435 i = 0;
1436 while (i < indent)
1437 {
1438 _dbus_verbose (" ");
1439 ++i;
1440 }
1441
1442 _dbus_verbose ("%s (%d children)\n",
1443 subtree->name, subtree->n_subtrees);
1444
1445 i = 0;
1446 while (i < subtree->n_subtrees)
1447 {
1448 spew_subtree_recurse (subtree->subtrees[i], indent + 2);
1449
1450 ++i;
1451 }
1452 }
1453
1454 static void
1455 spew_tree (DBusObjectTree *tree)
1456 {
1457 spew_subtree_recurse (tree->root, 0);
1458 }
1459 #endif
1460
1464 typedef struct
1465 {
1466 const char **path;
1467 dbus_bool_t handler_fallback;
1468 dbus_bool_t message_handled;
1469 dbus_bool_t handler_unregistered;
1470 } TreeTestData;
1471
1472
1473 static void
1474 test_unregister_function (DBusConnection *connection,
1475 void *user_data)
1476 {
1477 TreeTestData *ttd = user_data;
1478
1479 ttd->handler_unregistered = TRUE;
1480 }
1481
1482 static DBusHandlerResult
1483 test_message_function (DBusConnection *connection,
1484 DBusMessage *message,
1485 void *user_data)
1486 {
1487 TreeTestData *ttd = user_data;
1488
1489 ttd->message_handled = TRUE;
1490
1491 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1492 }
1493
1494 static dbus_bool_t
1495 do_register (DBusObjectTree *tree,
1496 const char **path,
1497 dbus_bool_t fallback,
1498 int i,
1499 TreeTestData *tree_test_data)
1500 {
1501 DBusObjectPathVTable vtable = { test_unregister_function,
1502 test_message_function, NULL };
1503
1504 tree_test_data[i].message_handled = FALSE;
1505 tree_test_data[i].handler_unregistered = FALSE;
1506 tree_test_data[i].handler_fallback = fallback;
1507 tree_test_data[i].path = path;
1508
1509 if (!_dbus_object_tree_register (tree, fallback, path,
1510 &vtable,
1511 &tree_test_data[i],
1512 NULL))
1513 return FALSE;
1514
1515 _dbus_assert (_dbus_object_tree_get_user_data_unlocked (tree, path) ==
1516 &tree_test_data[i]);
1517
1518 return TRUE;
1519 }
1520
1521 static dbus_bool_t
1522 do_test_dispatch (DBusObjectTree *tree,
1523 const char **path,
1524 int i,
1525 TreeTestData *tree_test_data,
1526 int n_test_data)
1527 {
1528 DBusMessage *message;
1529 int j;
1530 DBusHandlerResult result;
1531 char *flat;
1532
1533 message = NULL;
1534
1535 flat = flatten_path (path);
1536 if (flat == NULL)
1537 goto oom;
1538
1539 message = dbus_message_new_method_call (NULL,
1540 flat,
1541 "org.freedesktop.TestInterface",
1542 "Foo");
1543 dbus_free (flat);
1544 if (message == NULL)
1545 goto oom;
1546
1547 j = 0;
1548 while (j < n_test_data)
1549 {
1550 tree_test_data[j].message_handled = FALSE;
1551 ++j;
1552 }
1553
1554 result = _dbus_object_tree_dispatch_and_unlock (tree, message, NULL);
1555 if (result == DBUS_HANDLER_RESULT_NEED_MEMORY)
1556 goto oom;
1557
1558 _dbus_assert (tree_test_data[i].message_handled);
1559
1560 j = 0;
1561 while (j < n_test_data)
1562 {
1563 if (tree_test_data[j].message_handled)
1564 {
1565 if (tree_test_data[j].handler_fallback)
1566 _dbus_assert (path_contains (tree_test_data[j].path,
1567 path) != STR_DIFFERENT);
1568 else
1569 _dbus_assert (path_contains (tree_test_data[j].path, path) == STR_EQUAL);
1570 }
1571 else
1572 {
1573 if (tree_test_data[j].handler_fallback)
1574 _dbus_assert (path_contains (tree_test_data[j].path,
1575 path) == STR_DIFFERENT);
1576 else
1577 _dbus_assert (path_contains (tree_test_data[j].path, path) != STR_EQUAL);
1578 }
1579
1580 ++j;
1581 }
1582
1583 dbus_message_unref (message);
1584
1585 return TRUE;
1586
1587 oom:
1588 if (message)
1589 dbus_message_unref (message);
1590 return FALSE;
1591 }
1592
1593 static size_t
1594 string_array_length (const char **array)
1595 {
1596 size_t i;
1597 for (i = 0; array[i]; i++) ;
1598 return i;
1599 }
1600
1601 typedef struct
1602 {
1603 const char *path;
1604 const char *result[20];
1605 } DecomposePathTest;
1606
1607 static DecomposePathTest decompose_tests[] = {
1608 { "/foo", { "foo", NULL } },
1609 { "/foo/bar", { "foo", "bar", NULL } },
1610 { "/", { NULL } },
1611 { "/a/b", { "a", "b", NULL } },
1612 { "/a/b/c", { "a", "b", "c", NULL } },
1613 { "/a/b/c/d", { "a", "b", "c", "d", NULL } },
1614 { "/foo/bar/q", { "foo", "bar", "q", NULL } },
1615 { "/foo/bar/this/is/longer", { "foo", "bar", "this", "is", "longer", NULL } }
1616 };
1617
1618 static dbus_bool_t
1619 run_decompose_tests (void)
1620 {
1621 int i;
1622
1623 i = 0;
1624 while (i < _DBUS_N_ELEMENTS (decompose_tests))
1625 {
1626 char **result;
1627 int result_len;
1628 int expected_len;
1629
1630 if (!_dbus_decompose_path (decompose_tests[i].path,
1631 strlen (decompose_tests[i].path),
1632 &result, &result_len))
1633 return FALSE;
1634
1635 expected_len = string_array_length (decompose_tests[i].result);
1636
1637 if (result_len != (int) string_array_length ((const char**)result) ||
1638 expected_len != result_len ||
1639 path_contains (decompose_tests[i].result,
1640 (const char**) result) != STR_EQUAL)
1641 {
1642 int real_len = string_array_length ((const char**)result);
1643 _dbus_warn ("Expected decompose of %s to have len %d, returned %d, appears to have %d\n",
1644 decompose_tests[i].path, expected_len, result_len,
1645 real_len);
1646 _dbus_warn ("Decompose resulted in elements: { ");
1647 i = 0;
1648 while (i < real_len)
1649 {
1650 _dbus_warn ("\"%s\"%s", result[i],
1651 (i + 1) == real_len ? "" : ", ");
1652 ++i;
1653 }
1654 _dbus_warn ("}\n");
1655 _dbus_assert_not_reached ("path decompose failed\n");
1656 }
1657
1658 dbus_free_string_array (result);
1659
1660 ++i;
1661 }
1662
1663 return TRUE;
1664 }
1665
1666 static DBusObjectSubtree*
1667 find_subtree_registered_or_unregistered (DBusObjectTree *tree,
1668 const char **path)
1669 {
1670 #if VERBOSE_FIND
1671 _dbus_verbose ("Looking for exact subtree, registered or unregistered\n");
1672 #endif
1673
1674 return find_subtree_recurse (tree->root, path, FALSE, NULL, NULL);
1675 }
1676
1677 static dbus_bool_t
1678 object_tree_test_iteration (void *data)
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 FALSE;
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 = 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 = 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 = 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 = 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 (void)
2323 {
2324 _dbus_test_oom_handling ("object tree",
2325 object_tree_test_iteration,
2326 NULL);
2327
2328 return TRUE;
2329 }
2330
2331 #endif /* !DOXYGEN_SHOULD_SKIP_THIS */
2332
2333 #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:918
_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:903
DBusAtomic
An atomic integer safe to increment or decrement from multiple threads.
Definition: dbus-sysdeps.h:227
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:3602
DBUS_INTERFACE_INTROSPECTABLE
#define DBUS_INTERFACE_INTROSPECTABLE
The interface supported by introspectable objects.
Definition: dbus-shared.h:90
_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:718
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
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:135
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:459
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: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:2421
DBusObjectSubtree
Struct representing a single registered subtree handler, or node that'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:623
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:90
_dbus_atomic_dec
dbus_int32_t _dbus_atomic_dec(DBusAtomic *atomic)
Atomically decrement an integer.
Definition: dbus-sysdeps-unix.c:2523
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's already an object with the requested object path.
Definition: dbus-protocol.h:445
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:1206
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:3164
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_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:1242
_dbus_memdup
void * _dbus_memdup(const void *mem, size_t n_bytes)
Duplicates a block of memory.
Definition: dbus-internals.c:555
_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:1096
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_atomic_inc
dbus_int32_t _dbus_atomic_inc(DBusAtomic *atomic)
Atomically increments an integer.
Definition: dbus-sysdeps-unix.c:2500
_DBUS_N_ELEMENTS
#define _DBUS_N_ELEMENTS(array)
Computes the number of elements in a fixed-size array using sizeof().
Definition: dbus-internals.h:174
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:1333
_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:1139
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:242
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:145
_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:1075
_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:391
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
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:2656
_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:624
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:2817
_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
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:527
_dbus_connection_unlock
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:1690
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:1373