D-Bus  1.16.2
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  * SPDX-License-Identifier: AFL-2.1 OR GPL-2.0-or-later
7  *
8  * Licensed under the Academic Free License version 2.1
9  *
10  * This program is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation; either version 2 of the License, or
13  * (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program; if not, write to the Free Software
22  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
23  *
24  */
25 
26 #include <config.h>
27 #include "dbus-object-tree.h"
28 #include "dbus-connection-internal.h"
29 #include "dbus-internals.h"
30 #include "dbus-hash.h"
31 #include "dbus-protocol.h"
32 #include "dbus-string.h"
33 #include <dbus/dbus-test-tap.h>
34 #include <string.h>
35 #include <stdlib.h>
36 
50 
51 static DBusObjectSubtree* _dbus_object_subtree_new (const char *name,
52  const DBusObjectPathVTable *vtable,
53  void *user_data);
54 static DBusObjectSubtree* _dbus_object_subtree_ref (DBusObjectSubtree *subtree);
55 static void _dbus_object_subtree_unref (DBusObjectSubtree *subtree);
56 
61 {
62  int refcount;
66 };
67 
74 {
79  void *user_data;
81  int n_subtrees;
83  unsigned int invoke_as_fallback : 1;
84  char name[1];
85 };
86 
96 {
97  DBusObjectTree *tree;
98 
99  /* the connection passed in here isn't fully constructed,
100  * so don't do anything more than store a pointer to
101  * it
102  */
103 
104  tree = dbus_new0 (DBusObjectTree, 1);
105  if (tree == NULL)
106  goto oom;
107 
108  tree->refcount = 1;
109  tree->connection = connection;
110  tree->root = _dbus_object_subtree_new ("/", NULL, NULL);
111  if (tree->root == NULL)
112  goto oom;
113  tree->root->invoke_as_fallback = TRUE;
114 
115  return tree;
116 
117  oom:
118  if (tree)
119  {
120  dbus_free (tree);
121  }
122 
123  return NULL;
124 }
125 
133 {
134  _dbus_assert (tree->refcount > 0);
135 
136  tree->refcount += 1;
137 
138  return tree;
139 }
140 
145 void
147 {
148  _dbus_assert (tree->refcount > 0);
149 
150  tree->refcount -= 1;
151 
152  if (tree->refcount == 0)
153  {
155 
156  dbus_free (tree);
157  }
158 }
159 
163 #define VERBOSE_FIND 0
164 
165 static DBusObjectSubtree*
166 find_subtree_recurse (DBusObjectSubtree *subtree,
167  const char **path,
168  dbus_bool_t create_if_not_found,
169  int *index_in_parent,
170  dbus_bool_t *exact_match)
171 {
172  int i, j;
173  dbus_bool_t return_deepest_match;
174 
175  return_deepest_match = exact_match != NULL;
176 
177  _dbus_assert (!(return_deepest_match && create_if_not_found));
178 
179  if (path[0] == NULL)
180  {
181 #if VERBOSE_FIND
182  _dbus_verbose (" path exhausted, returning %s\n",
183  subtree->name);
184 #endif
185  if (exact_match != NULL)
186  *exact_match = TRUE;
187  return subtree;
188  }
189 
190 #if VERBOSE_FIND
191  _dbus_verbose (" searching children of %s for %s\n",
192  subtree->name, path[0]);
193 #endif
194 
195  i = 0;
196  j = subtree->n_subtrees;
197  while (i < j)
198  {
199  int k, v;
200 
201  k = (i + j) / 2;
202  v = strcmp (path[0], subtree->subtrees[k]->name);
203 
204 #if VERBOSE_FIND
205  _dbus_verbose (" %s cmp %s = %d\n",
206  path[0], subtree->subtrees[k]->name,
207  v);
208 #endif
209 
210  if (v == 0)
211  {
212  if (index_in_parent)
213  {
214 #if VERBOSE_FIND
215  _dbus_verbose (" storing parent index %d\n", k);
216 #endif
217  *index_in_parent = k;
218  }
219 
220  if (return_deepest_match)
221  {
222  DBusObjectSubtree *next;
223 
224  next = find_subtree_recurse (subtree->subtrees[k],
225  &path[1], create_if_not_found,
226  index_in_parent, exact_match);
227  if (next == NULL &&
228  subtree->invoke_as_fallback)
229  {
230 #if VERBOSE_FIND
231  _dbus_verbose (" no deeper match found, returning %s\n",
232  subtree->name);
233 #endif
234  if (exact_match != NULL)
235  *exact_match = FALSE;
236  return subtree;
237  }
238  else
239  return next;
240  }
241  else
242  return find_subtree_recurse (subtree->subtrees[k],
243  &path[1], create_if_not_found,
244  index_in_parent, exact_match);
245  }
246  else if (v < 0)
247  {
248  j = k;
249  }
250  else
251  {
252  i = k + 1;
253  }
254  }
255 
256 #if VERBOSE_FIND
257  _dbus_verbose (" no match found, current tree %s, create_if_not_found = %d\n",
258  subtree->name, create_if_not_found);
259 #endif
260 
261  if (create_if_not_found)
262  {
263  DBusObjectSubtree* child;
264  int child_pos, new_n_subtrees;
265 
266 #if VERBOSE_FIND
267  _dbus_verbose (" creating subtree %s\n",
268  path[0]);
269 #endif
270 
271  child = _dbus_object_subtree_new (path[0],
272  NULL, NULL);
273  if (child == NULL)
274  return NULL;
275 
276  new_n_subtrees = subtree->n_subtrees + 1;
277  if (new_n_subtrees > subtree->max_subtrees)
278  {
279  int new_max_subtrees;
280  DBusObjectSubtree **new_subtrees;
281 
282  new_max_subtrees = subtree->max_subtrees == 0 ? 1 : 2 * subtree->max_subtrees;
283  new_subtrees = dbus_realloc (subtree->subtrees,
284  new_max_subtrees * sizeof (DBusObjectSubtree*));
285  if (new_subtrees == NULL)
286  {
287  _dbus_object_subtree_unref (child);
288  return NULL;
289  }
290  subtree->subtrees = new_subtrees;
291  subtree->max_subtrees = new_max_subtrees;
292  }
293 
294  /* The binary search failed, so i == j points to the
295  place the child should be inserted. */
296  child_pos = i;
297  _dbus_assert (child_pos < new_n_subtrees &&
298  new_n_subtrees <= subtree->max_subtrees);
299  if (child_pos + 1 < new_n_subtrees)
300  {
301  memmove (&subtree->subtrees[child_pos+1],
302  &subtree->subtrees[child_pos],
303  (new_n_subtrees - child_pos - 1) *
304  sizeof subtree->subtrees[0]);
305  }
306  subtree->subtrees[child_pos] = child;
307 
308  if (index_in_parent)
309  *index_in_parent = child_pos;
310  subtree->n_subtrees = new_n_subtrees;
311  child->parent = subtree;
312 
313  return find_subtree_recurse (child,
314  &path[1], create_if_not_found,
315  index_in_parent, exact_match);
316  }
317  else
318  {
319  if (exact_match != NULL)
320  *exact_match = FALSE;
321  return (return_deepest_match && subtree->invoke_as_fallback) ? subtree : NULL;
322  }
323 }
324 
325 #ifdef DBUS_ENABLE_EMBEDDED_TESTS
326 static DBusObjectSubtree*
327 find_subtree (DBusObjectTree *tree,
328  const char **path,
329  int *index_in_parent)
330 {
331  DBusObjectSubtree *subtree;
332 
333 #if VERBOSE_FIND
334  _dbus_verbose ("Looking for exact registered subtree\n");
335 #endif
336 
337  subtree = find_subtree_recurse (tree->root, path, FALSE, index_in_parent, NULL);
338 
339  if (subtree && subtree->message_function == NULL)
340  return NULL;
341  else
342  return subtree;
343 }
344 #endif
345 
346 static DBusObjectSubtree*
347 lookup_subtree (DBusObjectTree *tree,
348  const char **path)
349 {
350 #if VERBOSE_FIND
351  _dbus_verbose ("Looking for subtree\n");
352 #endif
353  return find_subtree_recurse (tree->root, path, FALSE, NULL, NULL);
354 }
355 
356 static DBusObjectSubtree*
357 find_handler (DBusObjectTree *tree,
358  const char **path,
359  dbus_bool_t *exact_match)
360 {
361 #if VERBOSE_FIND
362  _dbus_verbose ("Looking for deepest handler\n");
363 #endif
364  _dbus_assert (exact_match != NULL);
365 
366  *exact_match = FALSE; /* ensure always initialized */
367 
368  return find_subtree_recurse (tree->root, path, FALSE, NULL, exact_match);
369 }
370 
371 static DBusObjectSubtree*
372 ensure_subtree (DBusObjectTree *tree,
373  const char **path)
374 {
375 #if VERBOSE_FIND
376  _dbus_verbose ("Ensuring subtree\n");
377 #endif
378  return find_subtree_recurse (tree->root, path, TRUE, NULL, NULL);
379 }
380 
381 static char *flatten_path (const char **path);
382 
397  dbus_bool_t fallback,
398  const char **path,
399  const DBusObjectPathVTable *vtable,
400  void *user_data,
401  DBusError *error)
402 {
403  DBusObjectSubtree *subtree;
404 
405  _dbus_assert (tree != NULL);
406  _dbus_assert (vtable->message_function != NULL);
407  _dbus_assert (path != NULL);
408 
409  subtree = ensure_subtree (tree, path);
410  if (subtree == NULL)
411  {
412  _DBUS_SET_OOM (error);
413  return FALSE;
414  }
415 
416  if (subtree->message_function != NULL)
417  {
418  if (error != NULL)
419  {
420  char *complete_path = flatten_path (path);
421 
423  "A handler is already registered for %s",
424  complete_path ? complete_path
425  : "(cannot represent path: out of memory!)");
426 
427  dbus_free (complete_path);
428  }
429 
430  return FALSE;
431  }
432 
433  subtree->message_function = vtable->message_function;
434  subtree->unregister_function = vtable->unregister_function;
435  subtree->user_data = user_data;
436  subtree->invoke_as_fallback = fallback != FALSE;
437 
438  return TRUE;
439 }
440 
452 static dbus_bool_t
453 unregister_subtree (DBusObjectSubtree *subtree,
454  DBusObjectPathUnregisterFunction *unregister_function_out,
455  void **user_data_out)
456 {
457  _dbus_assert (subtree != NULL);
458  _dbus_assert (unregister_function_out != NULL);
459  _dbus_assert (user_data_out != NULL);
460 
461  /* Confirm subtree is registered */
462  if (subtree->message_function != NULL)
463  {
464  subtree->message_function = NULL;
465 
466  *unregister_function_out = subtree->unregister_function;
467  *user_data_out = subtree->user_data;
468 
469  subtree->unregister_function = NULL;
470  subtree->user_data = NULL;
471 
472  return TRUE;
473  }
474  else
475  {
476  /* Assert that this unregistered subtree is either the root node or has
477  children, otherwise we have a dangling path which should never
478  happen */
479  _dbus_assert (subtree->parent == NULL || subtree->n_subtrees > 0);
480 
481  /* The subtree is not registered */
482  return FALSE;
483  }
484 }
485 
497 static dbus_bool_t
498 attempt_child_removal (DBusObjectSubtree *parent,
499  int child_index)
500 {
501  /* Candidate for removal */
502  DBusObjectSubtree* candidate;
503 
504  _dbus_assert (parent != NULL);
505  _dbus_assert (child_index >= 0 && child_index < parent->n_subtrees);
506 
507  candidate = parent->subtrees[child_index];
508  _dbus_assert (candidate != NULL);
509 
510  if (candidate->n_subtrees == 0 && candidate->message_function == NULL)
511  {
512  /* The candidate node is childless and is not a registered
513  path, so... */
514 
515  /* ... remove it from its parent... */
516  /* Assumes a 0-byte memmove is OK */
517  memmove (&parent->subtrees[child_index],
518  &parent->subtrees[child_index + 1],
519  (parent->n_subtrees - child_index - 1)
520  * sizeof (parent->subtrees[0]));
521  parent->n_subtrees -= 1;
522 
523  /* ... and free it */
524  candidate->parent = NULL;
525  _dbus_object_subtree_unref (candidate);
526 
527  return TRUE;
528  }
529  return FALSE;
530 }
531 
569 static dbus_bool_t
570 unregister_and_free_path_recurse
571 (DBusObjectSubtree *subtree,
572  const char **path,
573  dbus_bool_t *continue_removal_attempts,
574  DBusObjectPathUnregisterFunction *unregister_function_out,
575  void **user_data_out)
576 {
577  int i, j;
578 
579  _dbus_assert (continue_removal_attempts != NULL);
580  _dbus_assert (*continue_removal_attempts);
581  _dbus_assert (unregister_function_out != NULL);
582  _dbus_assert (user_data_out != NULL);
583 
584  if (path[0] == NULL)
585  return unregister_subtree (subtree, unregister_function_out, user_data_out);
586 
587  i = 0;
588  j = subtree->n_subtrees;
589  while (i < j)
590  {
591  int k, v;
592 
593  k = (i + j) / 2;
594  v = strcmp (path[0], subtree->subtrees[k]->name);
595 
596  if (v == 0)
597  {
598  dbus_bool_t freed;
599  freed = unregister_and_free_path_recurse (subtree->subtrees[k],
600  &path[1],
601  continue_removal_attempts,
602  unregister_function_out,
603  user_data_out);
604  if (freed && *continue_removal_attempts)
605  *continue_removal_attempts = attempt_child_removal (subtree, k);
606  return freed;
607  }
608  else if (v < 0)
609  {
610  j = k;
611  }
612  else
613  {
614  i = k + 1;
615  }
616  }
617  return FALSE;
618 }
619 
627 void
629  const char **path)
630 {
631  dbus_bool_t found_subtree;
632  dbus_bool_t continue_removal_attempts;
633  DBusObjectPathUnregisterFunction unregister_function;
634  void *user_data;
635  DBusConnection *connection;
636 
637  _dbus_assert (tree != NULL);
638  _dbus_assert (path != NULL);
639 
640  continue_removal_attempts = TRUE;
641  unregister_function = NULL;
642  user_data = NULL;
643 
644  found_subtree = unregister_and_free_path_recurse (tree->root,
645  path,
646  &continue_removal_attempts,
647  &unregister_function,
648  &user_data);
649 
650 #ifndef DBUS_DISABLE_CHECKS
651  if (found_subtree == FALSE)
652  {
653  _dbus_warn ("Attempted to unregister path (path[0] = %s path[1] = %s) which isn't registered",
654  path[0] ? path[0] : "null",
655  (path[0] && path[1]) ? path[1] : "null");
656  goto unlock;
657  }
658 #else
659  _dbus_assert (found_subtree == TRUE);
660 #endif
661 
662 unlock:
663  connection = tree->connection;
664 
665  /* Unlock and call application code */
666 #ifdef DBUS_ENABLE_EMBEDDED_TESTS
667  if (connection)
668 #endif
669  {
670  _dbus_connection_ref_unlocked (connection);
671  _dbus_verbose ("unlock\n");
672  _dbus_connection_unlock (connection);
673  }
674 
675  if (unregister_function)
676  (* unregister_function) (connection, user_data);
677 
678 #ifdef DBUS_ENABLE_EMBEDDED_TESTS
679  if (connection)
680 #endif
681  dbus_connection_unref (connection);
682 }
683 
684 static void
685 free_subtree_recurse (DBusConnection *connection,
686  DBusObjectSubtree *subtree)
687 {
688  /* Delete them from the end, for slightly
689  * more robustness against odd reentrancy.
690  */
691  while (subtree->n_subtrees > 0)
692  {
693  DBusObjectSubtree *child;
694 
695  child = subtree->subtrees[subtree->n_subtrees - 1];
696  subtree->subtrees[subtree->n_subtrees - 1] = NULL;
697  subtree->n_subtrees -= 1;
698  child->parent = NULL;
699 
700  free_subtree_recurse (connection, child);
701  }
702 
703  /* Call application code */
704  if (subtree->unregister_function)
705  (* subtree->unregister_function) (connection,
706  subtree->user_data);
707 
708  subtree->message_function = NULL;
709  subtree->unregister_function = NULL;
710  subtree->user_data = NULL;
711 
712  /* Now free ourselves */
713  _dbus_object_subtree_unref (subtree);
714 }
715 
722 void
724 {
725  if (tree->root)
726  free_subtree_recurse (tree->connection,
727  tree->root);
728  tree->root = NULL;
729 }
730 
731 static dbus_bool_t
732 _dbus_object_tree_list_registered_unlocked (DBusObjectTree *tree,
733  const char **parent_path,
734  char ***child_entries)
735 {
736  DBusObjectSubtree *subtree;
737  char **retval;
738 
739  _dbus_assert (parent_path != NULL);
740  _dbus_assert (child_entries != NULL);
741 
742  *child_entries = NULL;
743 
744  subtree = lookup_subtree (tree, parent_path);
745  if (subtree == NULL)
746  {
747  retval = dbus_new0 (char *, 1);
748  }
749  else
750  {
751  int i;
752  retval = dbus_new0 (char*, subtree->n_subtrees + 1);
753  if (retval == NULL)
754  goto out;
755  i = 0;
756  while (i < subtree->n_subtrees)
757  {
758  retval[i] = _dbus_strdup (subtree->subtrees[i]->name);
759  if (retval[i] == NULL)
760  {
761  dbus_free_string_array (retval);
762  retval = NULL;
763  goto out;
764  }
765  ++i;
766  }
767  }
768 
769  out:
770 
771  *child_entries = retval;
772  return retval != NULL;
773 }
774 
775 static DBusHandlerResult
776 handle_default_introspect_and_unlock (DBusObjectTree *tree,
777  DBusMessage *message,
778  const char **path)
779 {
780  DBusString xml;
781  DBusHandlerResult result;
782  char **children;
783  int i;
784  DBusMessage *reply;
785  DBusMessageIter iter;
786  const char *v_STRING;
787  dbus_bool_t already_unlocked;
788 
789  /* We have the connection lock here */
790 
791  already_unlocked = FALSE;
792 
793  _dbus_verbose (" considering default Introspect() handler...\n");
794 
795  reply = NULL;
796 
797  if (!dbus_message_is_method_call (message,
799  "Introspect"))
800  {
801 #ifdef DBUS_ENABLE_EMBEDDED_TESTS
802  if (tree->connection)
803 #endif
804  {
805  _dbus_verbose ("unlock\n");
807  }
808 
810  }
811 
812  _dbus_verbose (" using default Introspect() handler!\n");
813 
814  if (!_dbus_string_init (&xml))
815  {
816 #ifdef DBUS_ENABLE_EMBEDDED_TESTS
817  if (tree->connection)
818 #endif
819  {
820  _dbus_verbose ("unlock\n");
822  }
823 
825  }
826 
828 
829  children = NULL;
830  if (!_dbus_object_tree_list_registered_unlocked (tree, path, &children))
831  goto out;
832 
834  goto out;
835 
836  if (!_dbus_string_append (&xml, "<node>\n"))
837  goto out;
838 
839  i = 0;
840  while (children[i] != NULL)
841  {
842  if (!_dbus_string_append_printf (&xml, " <node name=\"%s\"/>\n",
843  children[i]))
844  goto out;
845 
846  ++i;
847  }
848 
849  if (!_dbus_string_append (&xml, "</node>\n"))
850  goto out;
851 
852  reply = dbus_message_new_method_return (message);
853  if (reply == NULL)
854  goto out;
855 
856  dbus_message_iter_init_append (reply, &iter);
857  v_STRING = _dbus_string_get_const_data (&xml);
858  if (!dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &v_STRING))
859  goto out;
860 
861 #ifdef DBUS_ENABLE_EMBEDDED_TESTS
862  if (tree->connection)
863 #endif
864  {
865  already_unlocked = TRUE;
866 
867  if (!_dbus_connection_send_and_unlock (tree->connection, reply, NULL))
868  goto out;
869  }
870 
872 
873  out:
874 #ifdef DBUS_ENABLE_EMBEDDED_TESTS
875  if (tree->connection)
876 #endif
877  {
878  if (!already_unlocked)
879  {
880  _dbus_verbose ("unlock\n");
882  }
883  }
884 
885  _dbus_string_free (&xml);
886  dbus_free_string_array (children);
887  if (reply)
888  dbus_message_unref (reply);
889 
890  return result;
891 }
892 
909  DBusMessage *message,
910  dbus_bool_t *found_object)
911 {
912  char **path;
913  dbus_bool_t exact_match;
914  DBusList *list;
915  DBusList *link;
916  DBusHandlerResult result;
917  DBusObjectSubtree *subtree;
918 
919 #if 0
920  _dbus_verbose ("Dispatch of message by object path\n");
921 #endif
922 
923  path = NULL;
924  if (!dbus_message_get_path_decomposed (message, &path))
925  {
926 #ifdef DBUS_ENABLE_EMBEDDED_TESTS
927  if (tree->connection)
928 #endif
929  {
930  _dbus_verbose ("unlock\n");
932  }
933 
934  _dbus_verbose ("No memory to get decomposed path\n");
935 
937  }
938 
939  if (path == NULL)
940  {
941 #ifdef DBUS_ENABLE_EMBEDDED_TESTS
942  if (tree->connection)
943 #endif
944  {
945  _dbus_verbose ("unlock\n");
947  }
948 
949  _dbus_verbose ("No path field in message\n");
951  }
952 
953  /* Find the deepest path that covers the path in the message */
954  subtree = find_handler (tree, (const char**) path, &exact_match);
955 
956  if (found_object)
957  *found_object = !!subtree;
958 
959  /* Build a list of all paths that cover the path in the message */
960 
961  list = NULL;
962 
963  while (subtree != NULL)
964  {
965  if (subtree->message_function != NULL && (exact_match || subtree->invoke_as_fallback))
966  {
967  _dbus_object_subtree_ref (subtree);
968 
969  /* run deepest paths first */
970  if (!_dbus_list_append (&list, subtree))
971  {
973  _dbus_object_subtree_unref (subtree);
974  goto free_and_return;
975  }
976  }
977 
978  exact_match = FALSE;
979  subtree = subtree->parent;
980  }
981 
982  _dbus_verbose ("%d handlers in the path tree for this message\n",
983  _dbus_list_get_length (&list));
984 
985  /* Invoke each handler in the list */
986 
988 
989  link = _dbus_list_get_first_link (&list);
990  while (link != NULL)
991  {
992  DBusList *next = _dbus_list_get_next_link (&list, link);
993  subtree = link->data;
994 
995  /* message_function is NULL if we're unregistered
996  * due to reentrancy
997  */
998  if (subtree->message_function)
999  {
1000  DBusObjectPathMessageFunction message_function;
1001  void *user_data;
1002 
1003  message_function = subtree->message_function;
1004  user_data = subtree->user_data;
1005 
1006 #if 0
1007  _dbus_verbose (" (invoking a handler)\n");
1008 #endif
1009 
1010 #ifdef DBUS_ENABLE_EMBEDDED_TESTS
1011  if (tree->connection)
1012 #endif
1013  {
1014  _dbus_verbose ("unlock\n");
1016  }
1017 
1018  /* FIXME you could unregister the subtree in another thread
1019  * before we invoke the callback, and I can't figure out a
1020  * good way to solve this.
1021  */
1022 
1023  result = (* message_function) (tree->connection,
1024  message,
1025  user_data);
1026 
1027 #ifdef DBUS_ENABLE_EMBEDDED_TESTS
1028  if (tree->connection)
1029 #endif
1031 
1033  goto free_and_return;
1034  }
1035 
1036  link = next;
1037  }
1038 
1039  free_and_return:
1040 
1042  {
1043  /* This hardcoded default handler does a minimal Introspect()
1044  */
1045  result = handle_default_introspect_and_unlock (tree, message,
1046  (const char**) path);
1047  }
1048  else
1049  {
1050 #ifdef DBUS_ENABLE_EMBEDDED_TESTS
1051  if (tree->connection)
1052 #endif
1053  {
1054  _dbus_verbose ("unlock\n");
1056  }
1057  }
1058 
1059  while (list != NULL)
1060  {
1061  link = _dbus_list_get_first_link (&list);
1062  _dbus_object_subtree_unref (link->data);
1063  _dbus_list_remove_link (&list, link);
1064  }
1065 
1066  dbus_free_string_array (path);
1067 
1068  return result;
1069 }
1070 
1079 void*
1081  const char **path)
1082 {
1083  dbus_bool_t exact_match;
1084  DBusObjectSubtree *subtree;
1085 
1086  _dbus_assert (tree != NULL);
1087  _dbus_assert (path != NULL);
1088 
1089  /* Find the deepest path that covers the path in the message */
1090  subtree = find_handler (tree, (const char**) path, &exact_match);
1091 
1092  if ((subtree == NULL) || !exact_match)
1093  {
1094  _dbus_verbose ("No object at specified path found\n");
1095  return NULL;
1096  }
1097 
1098  return subtree->user_data;
1099 }
1100 
1107 static DBusObjectSubtree*
1108 allocate_subtree_object (const char *name)
1109 {
1110  int len;
1111  DBusObjectSubtree *subtree;
1112  const size_t front_padding = _DBUS_STRUCT_OFFSET (DBusObjectSubtree, name);
1113 
1114  _dbus_assert (name != NULL);
1115 
1116  len = strlen (name);
1117 
1118  subtree = dbus_malloc0 (MAX (front_padding + (len + 1), sizeof (DBusObjectSubtree)));
1119 
1120  if (subtree == NULL)
1121  return NULL;
1122 
1123  memcpy (subtree->name, name, len + 1);
1124 
1125  return subtree;
1126 }
1127 
1128 static DBusObjectSubtree*
1129 _dbus_object_subtree_new (const char *name,
1130  const DBusObjectPathVTable *vtable,
1131  void *user_data)
1132 {
1133  DBusObjectSubtree *subtree;
1134 
1135  subtree = allocate_subtree_object (name);
1136  if (subtree == NULL)
1137  goto oom;
1138 
1139  _dbus_assert (name != NULL);
1140 
1141  subtree->parent = NULL;
1142 
1143  if (vtable)
1144  {
1145  subtree->message_function = vtable->message_function;
1146  subtree->unregister_function = vtable->unregister_function;
1147  }
1148  else
1149  {
1150  subtree->message_function = NULL;
1151  subtree->unregister_function = NULL;
1152  }
1153 
1154  subtree->user_data = user_data;
1155  _dbus_atomic_inc (&subtree->refcount);
1156  subtree->subtrees = NULL;
1157  subtree->n_subtrees = 0;
1158  subtree->max_subtrees = 0;
1159  subtree->invoke_as_fallback = FALSE;
1160 
1161  return subtree;
1162 
1163  oom:
1164  return NULL;
1165 }
1166 
1167 static DBusObjectSubtree *
1168 _dbus_object_subtree_ref (DBusObjectSubtree *subtree)
1169 {
1170 #ifdef DBUS_DISABLE_ASSERT
1171  _dbus_atomic_inc (&subtree->refcount);
1172 #else
1173  dbus_int32_t old_value;
1174 
1175  old_value = _dbus_atomic_inc (&subtree->refcount);
1176  _dbus_assert (old_value > 0);
1177 #endif
1178 
1179  return subtree;
1180 }
1181 
1182 static void
1183 _dbus_object_subtree_unref (DBusObjectSubtree *subtree)
1184 {
1185  dbus_int32_t old_value;
1186 
1187  old_value = _dbus_atomic_dec (&subtree->refcount);
1188  _dbus_assert (old_value > 0);
1189 
1190  if (old_value == 1)
1191  {
1192  _dbus_assert (subtree->unregister_function == NULL);
1193  _dbus_assert (subtree->message_function == NULL);
1194 
1195  dbus_free (subtree->subtrees);
1196  dbus_free (subtree);
1197  }
1198 }
1199 
1212  const char **parent_path,
1213  char ***child_entries)
1214 {
1215  dbus_bool_t result;
1216 
1217  result = _dbus_object_tree_list_registered_unlocked (tree,
1218  parent_path,
1219  child_entries);
1220 
1221 #ifdef DBUS_ENABLE_EMBEDDED_TESTS
1222  if (tree->connection)
1223 #endif
1224  {
1225  _dbus_verbose ("unlock\n");
1227  }
1228 
1229  return result;
1230 }
1231 
1232 
1234 #define VERBOSE_DECOMPOSE 0
1235 
1247 _dbus_decompose_path (const char* data,
1248  int len,
1249  char ***path,
1250  int *path_len)
1251 {
1252  char **retval;
1253  int n_components;
1254  int i, j, comp;
1255 
1256  _dbus_assert (data != NULL);
1257  _dbus_assert (path != NULL);
1258 
1259 #if VERBOSE_DECOMPOSE
1260  _dbus_verbose ("Decomposing path \"%s\"\n",
1261  data);
1262 #endif
1263 
1264  n_components = 0;
1265  if (len > 1) /* if path is not just "/" */
1266  {
1267  i = 0;
1268  while (i < len)
1269  {
1270  _dbus_assert (data[i] != '\0');
1271  if (data[i] == '/')
1272  n_components += 1;
1273  ++i;
1274  }
1275  }
1276 
1277  retval = dbus_new0 (char*, n_components + 1);
1278 
1279  if (retval == NULL)
1280  return FALSE;
1281 
1282  comp = 0;
1283  if (n_components == 0)
1284  i = 1;
1285  else
1286  i = 0;
1287  while (comp < n_components)
1288  {
1289  _dbus_assert (i < len);
1290 
1291  if (data[i] == '/')
1292  ++i;
1293  j = i;
1294 
1295  while (j < len && data[j] != '/')
1296  ++j;
1297 
1298  /* Now [i, j) is the path component */
1299  _dbus_assert (i < j);
1300  _dbus_assert (data[i] != '/');
1301  _dbus_assert (j == len || data[j] == '/');
1302 
1303 #if VERBOSE_DECOMPOSE
1304  _dbus_verbose (" (component in [%d,%d))\n",
1305  i, j);
1306 #endif
1307 
1308  retval[comp] = _dbus_memdup (&data[i], j - i + 1);
1309  if (retval[comp] == NULL)
1310  {
1311  dbus_free_string_array (retval);
1312  return FALSE;
1313  }
1314  retval[comp][j-i] = '\0';
1315 #if VERBOSE_DECOMPOSE
1316  _dbus_verbose (" (component %d = \"%s\")\n",
1317  comp, retval[comp]);
1318 #endif
1319 
1320  ++comp;
1321  i = j;
1322  }
1323  _dbus_assert (i == len);
1324 
1325  *path = retval;
1326  if (path_len)
1327  *path_len = n_components;
1328 
1329  return TRUE;
1330 }
1331 
1334 static char*
1335 flatten_path (const char **path)
1336 {
1337  DBusString str;
1338  char *s;
1339 
1340  if (!_dbus_string_init (&str))
1341  return NULL;
1342 
1343  if (path[0] == NULL)
1344  {
1345  if (!_dbus_string_append_byte (&str, '/'))
1346  goto nomem;
1347  }
1348  else
1349  {
1350  int i;
1351 
1352  i = 0;
1353  while (path[i])
1354  {
1355  if (!_dbus_string_append_byte (&str, '/'))
1356  goto nomem;
1357 
1358  if (!_dbus_string_append (&str, path[i]))
1359  goto nomem;
1360 
1361  ++i;
1362  }
1363  }
1364 
1365  if (!_dbus_string_steal_data (&str, &s))
1366  goto nomem;
1367 
1368  _dbus_string_free (&str);
1369 
1370  return s;
1371 
1372  nomem:
1373  _dbus_string_free (&str);
1374  return NULL;
1375 }
1376 
1377 
1378 #ifdef DBUS_ENABLE_EMBEDDED_TESTS
1379 
1380 #ifndef DOXYGEN_SHOULD_SKIP_THIS
1381 
1382 #include "dbus-test.h"
1383 #include <stdio.h>
1384 
1385 typedef enum
1386 {
1387  STR_EQUAL,
1388  STR_PREFIX,
1389  STR_DIFFERENT
1390 } StrComparison;
1391 
1392 /* Returns TRUE if container is a parent of child
1393  */
1394 static StrComparison
1395 path_contains (const char **container,
1396  const char **child)
1397 {
1398  int i;
1399 
1400  i = 0;
1401  while (child[i] != NULL)
1402  {
1403  int v;
1404 
1405  if (container[i] == NULL)
1406  return STR_PREFIX; /* container ran out, child continues;
1407  * thus the container is a parent of the
1408  * child.
1409  */
1410 
1411  _dbus_assert (container[i] != NULL);
1412  _dbus_assert (child[i] != NULL);
1413 
1414  v = strcmp (container[i], child[i]);
1415 
1416  if (v != 0)
1417  return STR_DIFFERENT; /* they overlap until here and then are different,
1418  * not overlapping
1419  */
1420 
1421  ++i;
1422  }
1423 
1424  /* Child ran out; if container also did, they are equal;
1425  * otherwise, the child is a parent of the container.
1426  */
1427  if (container[i] == NULL)
1428  return STR_EQUAL;
1429  else
1430  return STR_DIFFERENT;
1431 }
1432 
1433 #if 0
1434 static void
1435 spew_subtree_recurse (DBusObjectSubtree *subtree,
1436  int indent)
1437 {
1438  int i;
1439 
1440  i = 0;
1441  while (i < indent)
1442  {
1443  _dbus_verbose (" ");
1444  ++i;
1445  }
1446 
1447  _dbus_verbose ("%s (%d children)\n",
1448  subtree->name, subtree->n_subtrees);
1449 
1450  i = 0;
1451  while (i < subtree->n_subtrees)
1452  {
1453  spew_subtree_recurse (subtree->subtrees[i], indent + 2);
1454 
1455  ++i;
1456  }
1457 }
1458 
1459 static void
1460 spew_tree (DBusObjectTree *tree)
1461 {
1462  spew_subtree_recurse (tree->root, 0);
1463 }
1464 #endif
1465 
1469 typedef struct
1470 {
1471  const char **path;
1472  dbus_bool_t handler_fallback;
1473  dbus_bool_t message_handled;
1474  dbus_bool_t handler_unregistered;
1475 } TreeTestData;
1476 
1477 
1478 static void
1479 test_unregister_function (DBusConnection *connection,
1480  void *user_data)
1481 {
1482  TreeTestData *ttd = user_data;
1483 
1484  ttd->handler_unregistered = TRUE;
1485 }
1486 
1487 static DBusHandlerResult
1488 test_message_function (DBusConnection *connection,
1489  DBusMessage *message,
1490  void *user_data)
1491 {
1492  TreeTestData *ttd = user_data;
1493 
1494  ttd->message_handled = TRUE;
1495 
1497 }
1498 
1499 static dbus_bool_t
1500 do_register (DBusObjectTree *tree,
1501  const char **path,
1502  dbus_bool_t fallback,
1503  int i,
1504  TreeTestData *tree_test_data)
1505 {
1506  DBusObjectPathVTable vtable = { test_unregister_function,
1507  test_message_function, NULL };
1508 
1509  tree_test_data[i].message_handled = FALSE;
1510  tree_test_data[i].handler_unregistered = FALSE;
1511  tree_test_data[i].handler_fallback = fallback;
1512  tree_test_data[i].path = path;
1513 
1514  if (!_dbus_object_tree_register (tree, fallback, path,
1515  &vtable,
1516  &tree_test_data[i],
1517  NULL))
1518  return FALSE;
1519 
1521  &tree_test_data[i]);
1522 
1523  return TRUE;
1524 }
1525 
1526 static dbus_bool_t
1527 do_test_dispatch (DBusObjectTree *tree,
1528  const char **path,
1529  int i,
1530  TreeTestData *tree_test_data,
1531  int n_test_data)
1532 {
1533  DBusMessage *message;
1534  int j;
1535  DBusHandlerResult result;
1536  char *flat;
1537 
1538  message = NULL;
1539 
1540  flat = flatten_path (path);
1541  if (flat == NULL)
1542  goto oom;
1543 
1545  flat,
1546  "org.freedesktop.TestInterface",
1547  "Foo");
1548  dbus_free (flat);
1549  if (message == NULL)
1550  goto oom;
1551 
1552  j = 0;
1553  while (j < n_test_data)
1554  {
1555  tree_test_data[j].message_handled = FALSE;
1556  ++j;
1557  }
1558 
1559  result = _dbus_object_tree_dispatch_and_unlock (tree, message, NULL);
1560  if (result == DBUS_HANDLER_RESULT_NEED_MEMORY)
1561  goto oom;
1562 
1563  _dbus_assert (tree_test_data[i].message_handled);
1564 
1565  j = 0;
1566  while (j < n_test_data)
1567  {
1568  if (tree_test_data[j].message_handled)
1569  {
1570  if (tree_test_data[j].handler_fallback)
1571  _dbus_assert (path_contains (tree_test_data[j].path,
1572  path) != STR_DIFFERENT);
1573  else
1574  _dbus_assert (path_contains (tree_test_data[j].path, path) == STR_EQUAL);
1575  }
1576  else
1577  {
1578  if (tree_test_data[j].handler_fallback)
1579  _dbus_assert (path_contains (tree_test_data[j].path,
1580  path) == STR_DIFFERENT);
1581  else
1582  _dbus_assert (path_contains (tree_test_data[j].path, path) != STR_EQUAL);
1583  }
1584 
1585  ++j;
1586  }
1587 
1588  dbus_message_unref (message);
1589 
1590  return TRUE;
1591 
1592  oom:
1593  if (message)
1594  dbus_message_unref (message);
1595  return FALSE;
1596 }
1597 
1598 typedef struct
1599 {
1600  const char *path;
1601  const char *result[20];
1602 } DecomposePathTest;
1603 
1604 static DecomposePathTest decompose_tests[] = {
1605  { "/foo", { "foo", NULL } },
1606  { "/foo/bar", { "foo", "bar", NULL } },
1607  { "/", { NULL } },
1608  { "/a/b", { "a", "b", NULL } },
1609  { "/a/b/c", { "a", "b", "c", NULL } },
1610  { "/a/b/c/d", { "a", "b", "c", "d", NULL } },
1611  { "/foo/bar/q", { "foo", "bar", "q", NULL } },
1612  { "/foo/bar/this/is/longer", { "foo", "bar", "this", "is", "longer", NULL } }
1613 };
1614 
1615 /* Return TRUE on success, FALSE on OOM, die with an assertion failure
1616  * on failure. */
1617 static dbus_bool_t
1618 run_decompose_tests (void)
1619 {
1620  int i;
1621 
1622  i = 0;
1623  while (i < _DBUS_N_ELEMENTS (decompose_tests))
1624  {
1625  char **result;
1626  int result_len;
1627  int expected_len;
1628 
1629  if (!_dbus_decompose_path (decompose_tests[i].path,
1630  strlen (decompose_tests[i].path),
1631  &result, &result_len))
1632  return FALSE;
1633 
1634  expected_len = _dbus_string_array_length (decompose_tests[i].result);
1635 
1636  if (result_len != (int) _dbus_string_array_length ((const char**)result) ||
1637  expected_len != result_len ||
1638  path_contains (decompose_tests[i].result,
1639  (const char**) result) != STR_EQUAL)
1640  {
1641  int real_len = _dbus_string_array_length ((const char**)result);
1642  _dbus_warn ("Expected decompose of %s to have len %d, returned %d, appears to have %d",
1643  decompose_tests[i].path, expected_len, result_len,
1644  real_len);
1645  _dbus_warn ("Decompose resulted in elements: { ");
1646  i = 0;
1647  while (i < real_len)
1648  {
1649  _dbus_warn ("\"%s\"%s", result[i],
1650  (i + 1) == real_len ? "" : ", ");
1651  ++i;
1652  }
1653  _dbus_warn ("}");
1654  _dbus_test_fatal ("path decompose failed");
1655  }
1656 
1657  dbus_free_string_array (result);
1658 
1659  ++i;
1660  }
1661 
1662  return TRUE;
1663 }
1664 
1665 static DBusObjectSubtree*
1666 find_subtree_registered_or_unregistered (DBusObjectTree *tree,
1667  const char **path)
1668 {
1669 #if VERBOSE_FIND
1670  _dbus_verbose ("Looking for exact subtree, registered or unregistered\n");
1671 #endif
1672 
1673  return find_subtree_recurse (tree->root, path, FALSE, NULL, NULL);
1674 }
1675 
1676 /* Returns TRUE if the right thing happens, but the right thing might
1677  * be OOM. */
1678 static dbus_bool_t
1679 object_tree_test_iteration (void *data,
1680  dbus_bool_t have_memory)
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 TRUE; /* OOM is OK */
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 = _dbus_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 = _dbus_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 = _dbus_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 = _dbus_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 (const char *test_data_dir _DBUS_GNUC_UNUSED)
2325 {
2326  return _dbus_test_oom_handling ("object tree",
2327  object_tree_test_iteration,
2328  NULL);
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:980
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:339
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:97
void _dbus_object_tree_free_all_unlocked(DBusObjectTree *tree)
Free all the handlers in the tree.
void dbus_free(void *memory)
Frees a block of memory previously allocated by dbus_malloc() or dbus_malloc0().
Definition: dbus-memory.c:710
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:530
#define DBUS_TYPE_STRING
Type code marking a UTF-8 encoded, nul-terminated Unicode string.
DBusObjectPathMessageFunction message_function
Function to handle messages.
void * data
Data stored at this element.
Definition: dbus-list.h:40
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:71
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:182
DBusHandlerResult
Results that a message handler can return.
Definition: dbus-shared.h:68
DBusMessageIter struct; contains no public fields.
Definition: dbus-message.h:63
#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:121
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:60
dbus_uint32_t dbus_bool_t
A boolean, valid values are TRUE and FALSE.
Definition: dbus-types.h:37
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:273
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:1147
DBusObjectSubtree ** subtrees
Child nodes.
Object representing an exception.
Definition: dbus-errors.h:50
size_t _dbus_string_array_length(const char **array)
Returns the size of a string array.
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:356
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:1190
DBusObjectSubtree * parent
Parent node.
void _dbus_string_free(DBusString *str)
Frees a string created by _dbus_string_init(), and fills it with the same contents as #_DBUS_STRING_I...
Definition: dbus-string.c:278
#define TRUE
Expands to "1".
#define _dbus_assert(condition)
Aborts with an error message if the condition is false.
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:36
void dbus_free_string_array(char **str_array)
Frees a NULL-terminated array of strings.
Definition: dbus-memory.c:758
DBusAtomic refcount
Reference count.
int _dbus_list_get_length(DBusList **list)
Gets the length of a list.
Definition: dbus-list.c:760
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:597
#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:540
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:686
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.
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:610
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:70
int dbus_int32_t
A 32-bit signed integer on all platforms.
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:72
DBusMessage * dbus_message_new_method_return(DBusMessage *method_call)
Constructs a message that is a reply to a method call.