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