D-Bus  1.8.16
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 
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 
58 {
59  int refcount;
63 };
64 
71 {
76  void *user_data;
78  int n_subtrees;
80  unsigned int invoke_as_fallback : 1;
81  char name[1];
82 };
83 
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 
130 {
131  _dbus_assert (tree->refcount > 0);
132 
133  tree->refcount += 1;
134 
135  return tree;
136 }
137 
142 void
144 {
145  _dbus_assert (tree->refcount > 0);
146 
147  tree->refcount -= 1;
148 
149  if (tree->refcount == 0)
150  {
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 
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 
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
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
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,
794  "Introspect"))
795  {
796 #ifdef DBUS_ENABLE_EMBEDDED_TESTS
797  if (tree->connection)
798 #endif
799  {
800  _dbus_verbose ("unlock\n");
802  }
803 
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");
817  }
818 
820  }
821 
823 
824  children = NULL;
825  if (!_dbus_object_tree_list_registered_unlocked (tree, path, &children))
826  goto out;
827 
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 
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");
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 
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");
927  }
928 
929  _dbus_verbose ("No memory to get decomposed path\n");
930 
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");
942  }
943 
944  _dbus_verbose ("No path field in message\n");
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  {
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 
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");
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
1026 
1028  goto free_and_return;
1029  }
1030 
1031  link = next;
1032  }
1033 
1034  free_and_return:
1035 
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");
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*
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 
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");
1222  }
1223 
1224  return result;
1225 }
1226 
1227 
1229 #define VERBOSE_DECOMPOSE 0
1230 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 */
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 */
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 
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_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
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...
An atomic integer safe to increment or decrement from multiple threads.
Definition: dbus-sysdeps.h:227
int max_subtrees
Number of allocated entries in subtrees.
#define NULL
A null pointer, defined appropriately for C or C++.
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.
#define DBUS_INTERFACE_INTROSPECTABLE
The interface supported by introspectable objects.
Definition: dbus-shared.h:90
void _dbus_object_tree_free_all_unlocked(DBusObjectTree *tree)
Free all the handlers in the tree.
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
void dbus_free(void *memory)
Frees a block of memory previously allocated by dbus_malloc() or dbus_malloc0().
Definition: dbus-memory.c:701
DBusConnection * connection
Connection this tree belongs to.
void _dbus_connection_lock(DBusConnection *connection)
Acquires the connection lock.
void _dbus_list_remove_link(DBusList **list, DBusList *link)
Removes a link from the list.
Definition: dbus-list.c:527
#define DBUS_TYPE_STRING
Type code marking a UTF-8 encoded, nul-terminated Unicode string.
DBusObjectPathMessageFunction message_function
Function to handle messages.
#define _dbus_assert(condition)
Aborts with an error message if the condition is false.
void * data
Data stored at this element.
Definition: dbus-list.h:38
DBusObjectPathUnregisterFunction unregister_function
Function to call on unregister.
#define DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE
XML document type declaration of the introspection format version 1.0.
unsigned int invoke_as_fallback
Whether to invoke message_function when child nodes don't handle the message.
Message has not had any effect - see if other handlers want it.
Definition: dbus-shared.h:69
void dbus_message_iter_init_append(DBusMessage *message, DBusMessageIter *iter)
Initializes a DBusMessageIter for appending arguments to the end of a message.
Struct representing a single registered subtree handler, or node that's a parent of a registered subt...
void _dbus_object_tree_unregister_and_unlock(DBusObjectTree *tree, const char **path)
Unregisters an object subtree that was registered with the same path.
char name[1]
Allocated as large as necessary.
Implementation details of DBusConnection.
DBusObjectSubtree * root
Root of the tree ("/" node)
dbus_bool_t _dbus_string_init(DBusString *str)
Initializes a string.
Definition: dbus-string.c:175
DBusHandlerResult
Results that a message handler can return.
Definition: dbus-shared.h:66
DBusMessageIter struct; contains no public fields.
Definition: dbus-message.h:51
#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_int32_t _dbus_atomic_dec(DBusAtomic *atomic)
Atomically decrement an integer.
Virtual table that must be implemented to handle a portion of the object path hierarchy.
Internals of DBusMessage.
void(* DBusObjectPathUnregisterFunction)(DBusConnection *connection, void *user_data)
Called when a DBusObjectPathVTable is unregistered (or its connection is freed).
int n_subtrees
Number of child nodes.
DBusObjectPathUnregisterFunction unregister_function
Function to unregister this handler.
#define DBUS_ERROR_OBJECT_PATH_IN_USE
There's already an object with the requested object path.
#define dbus_new0(type, count)
Safe macro for using dbus_malloc0().
Definition: dbus-memory.h:59
dbus_uint32_t dbus_bool_t
A boolean, valid values are TRUE and FALSE.
Definition: dbus-types.h:35
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.
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...
Internals of DBusObjectTree.
void _dbus_warn(const char *format,...)
Prints a warning message to stderr.
DBusObjectTree * _dbus_object_tree_ref(DBusObjectTree *tree)
Increment the reference count.
dbus_bool_t _dbus_list_append(DBusList **list, void *data)
Appends a value to the list.
Definition: dbus-list.c:270
dbus_bool_t _dbus_decompose_path(const char *data, int len, char ***path, int *path_len)
Decompose an object path.
void * _dbus_memdup(const void *mem, size_t n_bytes)
Duplicates a block of memory.
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
Child nodes.
Object representing an exception.
Definition: dbus-errors.h:48
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
DBusObjectPathMessageFunction message_function
Function to handle messages.
void * user_data
Data for functions.
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...
dbus_int32_t _dbus_atomic_inc(DBusAtomic *atomic)
Atomically increments an integer.
#define _DBUS_N_ELEMENTS(array)
Computes the number of elements in a fixed-size array using sizeof().
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.
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
Parent node.
void _dbus_string_free(DBusString *str)
Frees a string created by _dbus_string_init().
Definition: dbus-string.c:242
#define TRUE
Expands to "1".
#define _dbus_assert_not_reached(explanation)
Aborts with an error message if called.
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...
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.
DBusHandlerResult(* DBusObjectPathMessageFunction)(DBusConnection *connection, DBusMessage *message, void *user_data)
Called when a message is sent to a registered object path.
int refcount
Reference count.
DBusObjectTree * _dbus_object_tree_new(DBusConnection *connection)
Creates a new object tree, representing a mapping from paths to handler vtables.
A node in a linked list.
Definition: dbus-list.h:34
void dbus_free_string_array(char **str_array)
Frees a NULL-terminated array of strings.
Definition: dbus-memory.c:749
DBusAtomic refcount
Reference count.
int _dbus_list_get_length(DBusList **list)
Gets the length of a list.
Definition: dbus-list.c:730
dbus_bool_t dbus_message_iter_append_basic(DBusMessageIter *iter, int type, const void *value)
Appends a basic-typed value to the message.
DBusList * _dbus_list_get_first_link(DBusList **list)
Gets the first link in the list.
Definition: dbus-list.c:567
#define FALSE
Expands to "0".
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_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
void dbus_connection_unref(DBusConnection *connection)
Decrements the reference count of a DBusConnection, and finalizes it if the count reaches zero...
void _dbus_object_tree_unref(DBusObjectTree *tree)
Decrement the reference count.
DBusConnection * _dbus_connection_ref_unlocked(DBusConnection *connection)
Increments the reference count of a DBusConnection.
Message has had its effect - no need to run more handlers.
Definition: dbus-shared.h:68
int dbus_int32_t
A 32-bit signed integer on all platforms.
char * _dbus_strdup(const char *str)
Duplicates a string.
void _dbus_connection_unlock(DBusConnection *connection)
Releases the connection lock.
void dbus_message_unref(DBusMessage *message)
Decrements the reference count of a DBusMessage, freeing the message if the count reaches 0...
Need more memory in order to return DBUS_HANDLER_RESULT_HANDLED or DBUS_HANDLER_RESULT_NOT_YET_HANDLE...
Definition: dbus-shared.h:70
DBusMessage * dbus_message_new_method_return(DBusMessage *method_call)
Constructs a message that is a reply to a method call.