D-Bus  1.6.12
dbus-object-tree.c
1 /* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
2 /* dbus-object-tree.c DBusObjectTree (internals of DBusConnection)
3  *
4  * Copyright (C) 2003, 2005 Red Hat Inc.
5  *
6  * Licensed under the Academic Free License version 2.1
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or
11  * (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21  *
22  */
23 
24 #include <config.h>
25 #include "dbus-object-tree.h"
26 #include "dbus-connection-internal.h"
27 #include "dbus-internals.h"
28 #include "dbus-hash.h"
29 #include "dbus-protocol.h"
30 #include "dbus-string.h"
31 #include <string.h>
32 #include <stdlib.h>
33 
47 
48 static DBusObjectSubtree* _dbus_object_subtree_new (const char *name,
49  const DBusObjectPathVTable *vtable,
50  void *user_data);
51 static DBusObjectSubtree* _dbus_object_subtree_ref (DBusObjectSubtree *subtree);
52 static void _dbus_object_subtree_unref (DBusObjectSubtree *subtree);
53 
58 {
59  int refcount;
63 };
64 
71 {
76  void *user_data;
78  int n_subtrees;
80  unsigned int invoke_as_fallback : 1;
81  char name[1];
82 };
83 
93 {
94  DBusObjectTree *tree;
95 
96  /* the connection passed in here isn't fully constructed,
97  * so don't do anything more than store a pointer to
98  * it
99  */
100 
101  tree = dbus_new0 (DBusObjectTree, 1);
102  if (tree == NULL)
103  goto oom;
104 
105  tree->refcount = 1;
106  tree->connection = connection;
107  tree->root = _dbus_object_subtree_new ("/", NULL, NULL);
108  if (tree->root == NULL)
109  goto oom;
110  tree->root->invoke_as_fallback = TRUE;
111 
112  return tree;
113 
114  oom:
115  if (tree)
116  {
117  dbus_free (tree);
118  }
119 
120  return NULL;
121 }
122 
130 {
131  _dbus_assert (tree->refcount > 0);
132 
133  tree->refcount += 1;
134 
135  return tree;
136 }
137 
142 void
144 {
145  _dbus_assert (tree->refcount > 0);
146 
147  tree->refcount -= 1;
148 
149  if (tree->refcount == 0)
150  {
152 
153  dbus_free (tree);
154  }
155 }
156 
160 #define VERBOSE_FIND 0
161 
162 static DBusObjectSubtree*
163 find_subtree_recurse (DBusObjectSubtree *subtree,
164  const char **path,
165  dbus_bool_t create_if_not_found,
166  int *index_in_parent,
167  dbus_bool_t *exact_match)
168 {
169  int i, j;
170  dbus_bool_t return_deepest_match;
171 
172  return_deepest_match = exact_match != NULL;
173 
174  _dbus_assert (!(return_deepest_match && create_if_not_found));
175 
176  if (path[0] == NULL)
177  {
178 #if VERBOSE_FIND
179  _dbus_verbose (" path exhausted, returning %s\n",
180  subtree->name);
181 #endif
182  if (exact_match != NULL)
183  *exact_match = TRUE;
184  return subtree;
185  }
186 
187 #if VERBOSE_FIND
188  _dbus_verbose (" searching children of %s for %s\n",
189  subtree->name, path[0]);
190 #endif
191 
192  i = 0;
193  j = subtree->n_subtrees;
194  while (i < j)
195  {
196  int k, v;
197 
198  k = (i + j) / 2;
199  v = strcmp (path[0], subtree->subtrees[k]->name);
200 
201 #if VERBOSE_FIND
202  _dbus_verbose (" %s cmp %s = %d\n",
203  path[0], subtree->subtrees[k]->name,
204  v);
205 #endif
206 
207  if (v == 0)
208  {
209  if (index_in_parent)
210  {
211 #if VERBOSE_FIND
212  _dbus_verbose (" storing parent index %d\n", k);
213 #endif
214  *index_in_parent = k;
215  }
216 
217  if (return_deepest_match)
218  {
219  DBusObjectSubtree *next;
220 
221  next = find_subtree_recurse (subtree->subtrees[k],
222  &path[1], create_if_not_found,
223  index_in_parent, exact_match);
224  if (next == NULL &&
225  subtree->invoke_as_fallback)
226  {
227 #if VERBOSE_FIND
228  _dbus_verbose (" no deeper match found, returning %s\n",
229  subtree->name);
230 #endif
231  if (exact_match != NULL)
232  *exact_match = FALSE;
233  return subtree;
234  }
235  else
236  return next;
237  }
238  else
239  return find_subtree_recurse (subtree->subtrees[k],
240  &path[1], create_if_not_found,
241  index_in_parent, exact_match);
242  }
243  else if (v < 0)
244  {
245  j = k;
246  }
247  else
248  {
249  i = k + 1;
250  }
251  }
252 
253 #if VERBOSE_FIND
254  _dbus_verbose (" no match found, current tree %s, create_if_not_found = %d\n",
255  subtree->name, create_if_not_found);
256 #endif
257 
258  if (create_if_not_found)
259  {
260  DBusObjectSubtree* child;
261  int child_pos, new_n_subtrees;
262 
263 #if VERBOSE_FIND
264  _dbus_verbose (" creating subtree %s\n",
265  path[0]);
266 #endif
267 
268  child = _dbus_object_subtree_new (path[0],
269  NULL, NULL);
270  if (child == NULL)
271  return NULL;
272 
273  new_n_subtrees = subtree->n_subtrees + 1;
274  if (new_n_subtrees > subtree->max_subtrees)
275  {
276  int new_max_subtrees;
277  DBusObjectSubtree **new_subtrees;
278 
279  new_max_subtrees = subtree->max_subtrees == 0 ? 1 : 2 * subtree->max_subtrees;
280  new_subtrees = dbus_realloc (subtree->subtrees,
281  new_max_subtrees * sizeof (DBusObjectSubtree*));
282  if (new_subtrees == NULL)
283  {
284  _dbus_object_subtree_unref (child);
285  return NULL;
286  }
287  subtree->subtrees = new_subtrees;
288  subtree->max_subtrees = new_max_subtrees;
289  }
290 
291  /* The binary search failed, so i == j points to the
292  place the child should be inserted. */
293  child_pos = i;
294  _dbus_assert (child_pos < new_n_subtrees &&
295  new_n_subtrees <= subtree->max_subtrees);
296  if (child_pos + 1 < new_n_subtrees)
297  {
298  memmove (&subtree->subtrees[child_pos+1],
299  &subtree->subtrees[child_pos],
300  (new_n_subtrees - child_pos - 1) *
301  sizeof subtree->subtrees[0]);
302  }
303  subtree->subtrees[child_pos] = child;
304 
305  if (index_in_parent)
306  *index_in_parent = child_pos;
307  subtree->n_subtrees = new_n_subtrees;
308  child->parent = subtree;
309 
310  return find_subtree_recurse (child,
311  &path[1], create_if_not_found,
312  index_in_parent, exact_match);
313  }
314  else
315  {
316  if (exact_match != NULL)
317  *exact_match = FALSE;
318  return (return_deepest_match && subtree->invoke_as_fallback) ? subtree : NULL;
319  }
320 }
321 
322 static DBusObjectSubtree*
323 find_subtree (DBusObjectTree *tree,
324  const char **path,
325  int *index_in_parent)
326 {
327  DBusObjectSubtree *subtree;
328 
329 #if VERBOSE_FIND
330  _dbus_verbose ("Looking for exact registered subtree\n");
331 #endif
332 
333  subtree = find_subtree_recurse (tree->root, path, FALSE, index_in_parent, NULL);
334 
335  if (subtree && subtree->message_function == NULL)
336  return NULL;
337  else
338  return subtree;
339 }
340 
341 static DBusObjectSubtree*
342 lookup_subtree (DBusObjectTree *tree,
343  const char **path)
344 {
345 #if VERBOSE_FIND
346  _dbus_verbose ("Looking for subtree\n");
347 #endif
348  return find_subtree_recurse (tree->root, path, FALSE, NULL, NULL);
349 }
350 
351 static DBusObjectSubtree*
352 find_handler (DBusObjectTree *tree,
353  const char **path,
354  dbus_bool_t *exact_match)
355 {
356 #if VERBOSE_FIND
357  _dbus_verbose ("Looking for deepest handler\n");
358 #endif
359  _dbus_assert (exact_match != NULL);
360 
361  *exact_match = FALSE; /* ensure always initialized */
362 
363  return find_subtree_recurse (tree->root, path, FALSE, NULL, exact_match);
364 }
365 
366 static DBusObjectSubtree*
367 ensure_subtree (DBusObjectTree *tree,
368  const char **path)
369 {
370 #if VERBOSE_FIND
371  _dbus_verbose ("Ensuring subtree\n");
372 #endif
373  return find_subtree_recurse (tree->root, path, TRUE, NULL, NULL);
374 }
375 
376 static char *flatten_path (const char **path);
377 
392  dbus_bool_t fallback,
393  const char **path,
394  const DBusObjectPathVTable *vtable,
395  void *user_data,
396  DBusError *error)
397 {
398  DBusObjectSubtree *subtree;
399 
400  _dbus_assert (tree != NULL);
401  _dbus_assert (vtable->message_function != NULL);
402  _dbus_assert (path != NULL);
403 
404  subtree = ensure_subtree (tree, path);
405  if (subtree == NULL)
406  {
407  _DBUS_SET_OOM (error);
408  return FALSE;
409  }
410 
411  if (subtree->message_function != NULL)
412  {
413  if (error != NULL)
414  {
415  char *complete_path = flatten_path (path);
416 
418  "A handler is already registered for %s",
419  complete_path ? complete_path
420  : "(cannot represent path: out of memory!)");
421 
422  dbus_free (complete_path);
423  }
424 
425  return FALSE;
426  }
427 
428  subtree->message_function = vtable->message_function;
429  subtree->unregister_function = vtable->unregister_function;
430  subtree->user_data = user_data;
431  subtree->invoke_as_fallback = fallback != FALSE;
432 
433  return TRUE;
434 }
435 
443 void
445  const char **path)
446 {
447  int i;
448  DBusObjectSubtree *subtree;
449  DBusObjectPathUnregisterFunction unregister_function;
450  void *user_data;
451  DBusConnection *connection;
452 
453  _dbus_assert (path != NULL);
454 
455  unregister_function = NULL;
456  user_data = NULL;
457 
458  subtree = find_subtree (tree, path, &i);
459 
460 #ifndef DBUS_DISABLE_CHECKS
461  if (subtree == NULL)
462  {
463  _dbus_warn ("Attempted to unregister path (path[0] = %s path[1] = %s) which isn't registered\n",
464  path[0] ? path[0] : "null",
465  path[1] ? path[1] : "null");
466  goto unlock;
467  }
468 #else
469  _dbus_assert (subtree != NULL);
470 #endif
471 
472  _dbus_assert (subtree->parent == NULL ||
473  (i >= 0 && subtree->parent->subtrees[i] == subtree));
474 
475  subtree->message_function = NULL;
476 
477  unregister_function = subtree->unregister_function;
478  user_data = subtree->user_data;
479 
480  subtree->unregister_function = NULL;
481  subtree->user_data = NULL;
482 
483  /* If we have no subtrees of our own, remove from
484  * our parent (FIXME could also be more aggressive
485  * and remove our parent if it becomes empty)
486  */
487  if (subtree->parent && subtree->n_subtrees == 0)
488  {
489  /* assumes a 0-byte memmove is OK */
490  memmove (&subtree->parent->subtrees[i],
491  &subtree->parent->subtrees[i+1],
492  (subtree->parent->n_subtrees - i - 1) *
493  sizeof (subtree->parent->subtrees[0]));
494  subtree->parent->n_subtrees -= 1;
495 
496  subtree->parent = NULL;
497 
498  _dbus_object_subtree_unref (subtree);
499  }
500  subtree = NULL;
501 
502 unlock:
503  connection = tree->connection;
504 
505  /* Unlock and call application code */
506 #ifdef DBUS_BUILD_TESTS
507  if (connection)
508 #endif
509  {
510  _dbus_connection_ref_unlocked (connection);
511  _dbus_verbose ("unlock\n");
512  _dbus_connection_unlock (connection);
513  }
514 
515  if (unregister_function)
516  (* unregister_function) (connection, user_data);
517 
518 #ifdef DBUS_BUILD_TESTS
519  if (connection)
520 #endif
521  dbus_connection_unref (connection);
522 }
523 
524 static void
525 free_subtree_recurse (DBusConnection *connection,
526  DBusObjectSubtree *subtree)
527 {
528  /* Delete them from the end, for slightly
529  * more robustness against odd reentrancy.
530  */
531  while (subtree->n_subtrees > 0)
532  {
533  DBusObjectSubtree *child;
534 
535  child = subtree->subtrees[subtree->n_subtrees - 1];
536  subtree->subtrees[subtree->n_subtrees - 1] = NULL;
537  subtree->n_subtrees -= 1;
538  child->parent = NULL;
539 
540  free_subtree_recurse (connection, child);
541  }
542 
543  /* Call application code */
544  if (subtree->unregister_function)
545  (* subtree->unregister_function) (connection,
546  subtree->user_data);
547 
548  subtree->message_function = NULL;
549  subtree->unregister_function = NULL;
550  subtree->user_data = NULL;
551 
552  /* Now free ourselves */
553  _dbus_object_subtree_unref (subtree);
554 }
555 
562 void
564 {
565  if (tree->root)
566  free_subtree_recurse (tree->connection,
567  tree->root);
568  tree->root = NULL;
569 }
570 
571 static dbus_bool_t
572 _dbus_object_tree_list_registered_unlocked (DBusObjectTree *tree,
573  const char **parent_path,
574  char ***child_entries)
575 {
576  DBusObjectSubtree *subtree;
577  char **retval;
578 
579  _dbus_assert (parent_path != NULL);
580  _dbus_assert (child_entries != NULL);
581 
582  *child_entries = NULL;
583 
584  subtree = lookup_subtree (tree, parent_path);
585  if (subtree == NULL)
586  {
587  retval = dbus_new0 (char *, 1);
588  }
589  else
590  {
591  int i;
592  retval = dbus_new0 (char*, subtree->n_subtrees + 1);
593  if (retval == NULL)
594  goto out;
595  i = 0;
596  while (i < subtree->n_subtrees)
597  {
598  retval[i] = _dbus_strdup (subtree->subtrees[i]->name);
599  if (retval[i] == NULL)
600  {
601  dbus_free_string_array (retval);
602  retval = NULL;
603  goto out;
604  }
605  ++i;
606  }
607  }
608 
609  out:
610 
611  *child_entries = retval;
612  return retval != NULL;
613 }
614 
615 static DBusHandlerResult
616 handle_default_introspect_and_unlock (DBusObjectTree *tree,
617  DBusMessage *message,
618  const char **path)
619 {
620  DBusString xml;
621  DBusHandlerResult result;
622  char **children;
623  int i;
624  DBusMessage *reply;
625  DBusMessageIter iter;
626  const char *v_STRING;
627  dbus_bool_t already_unlocked;
628 
629  /* We have the connection lock here */
630 
631  already_unlocked = FALSE;
632 
633  _dbus_verbose (" considering default Introspect() handler...\n");
634 
635  reply = NULL;
636 
637  if (!dbus_message_is_method_call (message,
639  "Introspect"))
640  {
641 #ifdef DBUS_BUILD_TESTS
642  if (tree->connection)
643 #endif
644  {
645  _dbus_verbose ("unlock\n");
647  }
648 
650  }
651 
652  _dbus_verbose (" using default Introspect() handler!\n");
653 
654  if (!_dbus_string_init (&xml))
655  {
656 #ifdef DBUS_BUILD_TESTS
657  if (tree->connection)
658 #endif
659  {
660  _dbus_verbose ("unlock\n");
662  }
663 
665  }
666 
668 
669  children = NULL;
670  if (!_dbus_object_tree_list_registered_unlocked (tree, path, &children))
671  goto out;
672 
674  goto out;
675 
676  if (!_dbus_string_append (&xml, "<node>\n"))
677  goto out;
678 
679  i = 0;
680  while (children[i] != NULL)
681  {
682  if (!_dbus_string_append_printf (&xml, " <node name=\"%s\"/>\n",
683  children[i]))
684  goto out;
685 
686  ++i;
687  }
688 
689  if (!_dbus_string_append (&xml, "</node>\n"))
690  goto out;
691 
692  reply = dbus_message_new_method_return (message);
693  if (reply == NULL)
694  goto out;
695 
696  dbus_message_iter_init_append (reply, &iter);
697  v_STRING = _dbus_string_get_const_data (&xml);
698  if (!dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &v_STRING))
699  goto out;
700 
701 #ifdef DBUS_BUILD_TESTS
702  if (tree->connection)
703 #endif
704  {
705  already_unlocked = TRUE;
706 
707  if (!_dbus_connection_send_and_unlock (tree->connection, reply, NULL))
708  goto out;
709  }
710 
712 
713  out:
714 #ifdef DBUS_BUILD_TESTS
715  if (tree->connection)
716 #endif
717  {
718  if (!already_unlocked)
719  {
720  _dbus_verbose ("unlock\n");
722  }
723  }
724 
725  _dbus_string_free (&xml);
726  dbus_free_string_array (children);
727  if (reply)
728  dbus_message_unref (reply);
729 
730  return result;
731 }
732 
748  DBusMessage *message,
749  dbus_bool_t *found_object)
750 {
751  char **path;
752  dbus_bool_t exact_match;
753  DBusList *list;
754  DBusList *link;
755  DBusHandlerResult result;
756  DBusObjectSubtree *subtree;
757 
758 #if 0
759  _dbus_verbose ("Dispatch of message by object path\n");
760 #endif
761 
762  path = NULL;
763  if (!dbus_message_get_path_decomposed (message, &path))
764  {
765 #ifdef DBUS_BUILD_TESTS
766  if (tree->connection)
767 #endif
768  {
769  _dbus_verbose ("unlock\n");
771  }
772 
773  _dbus_verbose ("No memory to get decomposed path\n");
774 
776  }
777 
778  if (path == NULL)
779  {
780 #ifdef DBUS_BUILD_TESTS
781  if (tree->connection)
782 #endif
783  {
784  _dbus_verbose ("unlock\n");
786  }
787 
788  _dbus_verbose ("No path field in message\n");
790  }
791 
792  /* Find the deepest path that covers the path in the message */
793  subtree = find_handler (tree, (const char**) path, &exact_match);
794 
795  if (found_object)
796  *found_object = !!subtree;
797 
798  /* Build a list of all paths that cover the path in the message */
799 
800  list = NULL;
801 
802  while (subtree != NULL)
803  {
804  if (subtree->message_function != NULL && (exact_match || subtree->invoke_as_fallback))
805  {
806  _dbus_object_subtree_ref (subtree);
807 
808  /* run deepest paths first */
809  if (!_dbus_list_append (&list, subtree))
810  {
812  _dbus_object_subtree_unref (subtree);
813  goto free_and_return;
814  }
815  }
816 
817  exact_match = FALSE;
818  subtree = subtree->parent;
819  }
820 
821  _dbus_verbose ("%d handlers in the path tree for this message\n",
822  _dbus_list_get_length (&list));
823 
824  /* Invoke each handler in the list */
825 
827 
828  link = _dbus_list_get_first_link (&list);
829  while (link != NULL)
830  {
831  DBusList *next = _dbus_list_get_next_link (&list, link);
832  subtree = link->data;
833 
834  /* message_function is NULL if we're unregistered
835  * due to reentrancy
836  */
837  if (subtree->message_function)
838  {
839  DBusObjectPathMessageFunction message_function;
840  void *user_data;
841 
842  message_function = subtree->message_function;
843  user_data = subtree->user_data;
844 
845 #if 0
846  _dbus_verbose (" (invoking a handler)\n");
847 #endif
848 
849 #ifdef DBUS_BUILD_TESTS
850  if (tree->connection)
851 #endif
852  {
853  _dbus_verbose ("unlock\n");
855  }
856 
857  /* FIXME you could unregister the subtree in another thread
858  * before we invoke the callback, and I can't figure out a
859  * good way to solve this.
860  */
861 
862  result = (* message_function) (tree->connection,
863  message,
864  user_data);
865 
866 #ifdef DBUS_BUILD_TESTS
867  if (tree->connection)
868 #endif
870 
872  goto free_and_return;
873  }
874 
875  link = next;
876  }
877 
878  free_and_return:
879 
881  {
882  /* This hardcoded default handler does a minimal Introspect()
883  */
884  result = handle_default_introspect_and_unlock (tree, message,
885  (const char**) path);
886  }
887  else
888  {
889 #ifdef DBUS_BUILD_TESTS
890  if (tree->connection)
891 #endif
892  {
893  _dbus_verbose ("unlock\n");
895  }
896  }
897 
898  while (list != NULL)
899  {
900  link = _dbus_list_get_first_link (&list);
901  _dbus_object_subtree_unref (link->data);
902  _dbus_list_remove_link (&list, link);
903  }
904 
905  dbus_free_string_array (path);
906 
907  return result;
908 }
909 
918 void*
920  const char **path)
921 {
922  dbus_bool_t exact_match;
923  DBusObjectSubtree *subtree;
924 
925  _dbus_assert (tree != NULL);
926  _dbus_assert (path != NULL);
927 
928  /* Find the deepest path that covers the path in the message */
929  subtree = find_handler (tree, (const char**) path, &exact_match);
930 
931  if ((subtree == NULL) || !exact_match)
932  {
933  _dbus_verbose ("No object at specified path found\n");
934  return NULL;
935  }
936 
937  return subtree->user_data;
938 }
939 
946 static DBusObjectSubtree*
947 allocate_subtree_object (const char *name)
948 {
949  int len;
950  DBusObjectSubtree *subtree;
951  const size_t front_padding = _DBUS_STRUCT_OFFSET (DBusObjectSubtree, name);
952 
953  _dbus_assert (name != NULL);
954 
955  len = strlen (name);
956 
957  subtree = dbus_malloc0 (MAX (front_padding + (len + 1), sizeof (DBusObjectSubtree)));
958 
959  if (subtree == NULL)
960  return NULL;
961 
962  memcpy (subtree->name, name, len + 1);
963 
964  return subtree;
965 }
966 
967 static DBusObjectSubtree*
968 _dbus_object_subtree_new (const char *name,
969  const DBusObjectPathVTable *vtable,
970  void *user_data)
971 {
972  DBusObjectSubtree *subtree;
973 
974  subtree = allocate_subtree_object (name);
975  if (subtree == NULL)
976  goto oom;
977 
978  _dbus_assert (name != NULL);
979 
980  subtree->parent = NULL;
981 
982  if (vtable)
983  {
984  subtree->message_function = vtable->message_function;
985  subtree->unregister_function = vtable->unregister_function;
986  }
987  else
988  {
989  subtree->message_function = NULL;
990  subtree->unregister_function = NULL;
991  }
992 
993  subtree->user_data = user_data;
994  _dbus_atomic_inc (&subtree->refcount);
995  subtree->subtrees = NULL;
996  subtree->n_subtrees = 0;
997  subtree->max_subtrees = 0;
998  subtree->invoke_as_fallback = FALSE;
999 
1000  return subtree;
1001 
1002  oom:
1003  return NULL;
1004 }
1005 
1006 static DBusObjectSubtree *
1007 _dbus_object_subtree_ref (DBusObjectSubtree *subtree)
1008 {
1009 #ifdef DBUS_DISABLE_ASSERT
1010  _dbus_atomic_inc (&subtree->refcount);
1011 #else
1012  dbus_int32_t old_value;
1013 
1014  old_value = _dbus_atomic_inc (&subtree->refcount);
1015  _dbus_assert (old_value > 0);
1016 #endif
1017 
1018  return subtree;
1019 }
1020 
1021 static void
1022 _dbus_object_subtree_unref (DBusObjectSubtree *subtree)
1023 {
1024  dbus_int32_t old_value;
1025 
1026  old_value = _dbus_atomic_dec (&subtree->refcount);
1027  _dbus_assert (old_value > 0);
1028 
1029  if (old_value == 1)
1030  {
1031  _dbus_assert (subtree->unregister_function == NULL);
1032  _dbus_assert (subtree->message_function == NULL);
1033 
1034  dbus_free (subtree->subtrees);
1035  dbus_free (subtree);
1036  }
1037 }
1038 
1051  const char **parent_path,
1052  char ***child_entries)
1053 {
1054  dbus_bool_t result;
1055 
1056  result = _dbus_object_tree_list_registered_unlocked (tree,
1057  parent_path,
1058  child_entries);
1059 
1060 #ifdef DBUS_BUILD_TESTS
1061  if (tree->connection)
1062 #endif
1063  {
1064  _dbus_verbose ("unlock\n");
1066  }
1067 
1068  return result;
1069 }
1070 
1071 
1073 #define VERBOSE_DECOMPOSE 0
1074 
1086 _dbus_decompose_path (const char* data,
1087  int len,
1088  char ***path,
1089  int *path_len)
1090 {
1091  char **retval;
1092  int n_components;
1093  int i, j, comp;
1094 
1095  _dbus_assert (data != NULL);
1096  _dbus_assert (path != NULL);
1097 
1098 #if VERBOSE_DECOMPOSE
1099  _dbus_verbose ("Decomposing path \"%s\"\n",
1100  data);
1101 #endif
1102 
1103  n_components = 0;
1104  if (len > 1) /* if path is not just "/" */
1105  {
1106  i = 0;
1107  while (i < len)
1108  {
1109  _dbus_assert (data[i] != '\0');
1110  if (data[i] == '/')
1111  n_components += 1;
1112  ++i;
1113  }
1114  }
1115 
1116  retval = dbus_new0 (char*, n_components + 1);
1117 
1118  if (retval == NULL)
1119  return FALSE;
1120 
1121  comp = 0;
1122  if (n_components == 0)
1123  i = 1;
1124  else
1125  i = 0;
1126  while (comp < n_components)
1127  {
1128  _dbus_assert (i < len);
1129 
1130  if (data[i] == '/')
1131  ++i;
1132  j = i;
1133 
1134  while (j < len && data[j] != '/')
1135  ++j;
1136 
1137  /* Now [i, j) is the path component */
1138  _dbus_assert (i < j);
1139  _dbus_assert (data[i] != '/');
1140  _dbus_assert (j == len || data[j] == '/');
1141 
1142 #if VERBOSE_DECOMPOSE
1143  _dbus_verbose (" (component in [%d,%d))\n",
1144  i, j);
1145 #endif
1146 
1147  retval[comp] = _dbus_memdup (&data[i], j - i + 1);
1148  if (retval[comp] == NULL)
1149  {
1150  dbus_free_string_array (retval);
1151  return FALSE;
1152  }
1153  retval[comp][j-i] = '\0';
1154 #if VERBOSE_DECOMPOSE
1155  _dbus_verbose (" (component %d = \"%s\")\n",
1156  comp, retval[comp]);
1157 #endif
1158 
1159  ++comp;
1160  i = j;
1161  }
1162  _dbus_assert (i == len);
1163 
1164  *path = retval;
1165  if (path_len)
1166  *path_len = n_components;
1167 
1168  return TRUE;
1169 }
1170 
1173 static char*
1174 flatten_path (const char **path)
1175 {
1176  DBusString str;
1177  char *s;
1178 
1179  if (!_dbus_string_init (&str))
1180  return NULL;
1181 
1182  if (path[0] == NULL)
1183  {
1184  if (!_dbus_string_append_byte (&str, '/'))
1185  goto nomem;
1186  }
1187  else
1188  {
1189  int i;
1190 
1191  i = 0;
1192  while (path[i])
1193  {
1194  if (!_dbus_string_append_byte (&str, '/'))
1195  goto nomem;
1196 
1197  if (!_dbus_string_append (&str, path[i]))
1198  goto nomem;
1199 
1200  ++i;
1201  }
1202  }
1203 
1204  if (!_dbus_string_steal_data (&str, &s))
1205  goto nomem;
1206 
1207  _dbus_string_free (&str);
1208 
1209  return s;
1210 
1211  nomem:
1212  _dbus_string_free (&str);
1213  return NULL;
1214 }
1215 
1216 
1217 #ifdef DBUS_BUILD_TESTS
1218 
1219 #ifndef DOXYGEN_SHOULD_SKIP_THIS
1220 
1221 #include "dbus-test.h"
1222 #include <stdio.h>
1223 
1224 typedef enum
1225 {
1226  STR_EQUAL,
1227  STR_PREFIX,
1228  STR_DIFFERENT
1229 } StrComparison;
1230 
1231 /* Returns TRUE if container is a parent of child
1232  */
1233 static StrComparison
1234 path_contains (const char **container,
1235  const char **child)
1236 {
1237  int i;
1238 
1239  i = 0;
1240  while (child[i] != NULL)
1241  {
1242  int v;
1243 
1244  if (container[i] == NULL)
1245  return STR_PREFIX; /* container ran out, child continues;
1246  * thus the container is a parent of the
1247  * child.
1248  */
1249 
1250  _dbus_assert (container[i] != NULL);
1251  _dbus_assert (child[i] != NULL);
1252 
1253  v = strcmp (container[i], child[i]);
1254 
1255  if (v != 0)
1256  return STR_DIFFERENT; /* they overlap until here and then are different,
1257  * not overlapping
1258  */
1259 
1260  ++i;
1261  }
1262 
1263  /* Child ran out; if container also did, they are equal;
1264  * otherwise, the child is a parent of the container.
1265  */
1266  if (container[i] == NULL)
1267  return STR_EQUAL;
1268  else
1269  return STR_DIFFERENT;
1270 }
1271 
1272 #if 0
1273 static void
1274 spew_subtree_recurse (DBusObjectSubtree *subtree,
1275  int indent)
1276 {
1277  int i;
1278 
1279  i = 0;
1280  while (i < indent)
1281  {
1282  _dbus_verbose (" ");
1283  ++i;
1284  }
1285 
1286  _dbus_verbose ("%s (%d children)\n",
1287  subtree->name, subtree->n_subtrees);
1288 
1289  i = 0;
1290  while (i < subtree->n_subtrees)
1291  {
1292  spew_subtree_recurse (subtree->subtrees[i], indent + 2);
1293 
1294  ++i;
1295  }
1296 }
1297 
1298 static void
1299 spew_tree (DBusObjectTree *tree)
1300 {
1301  spew_subtree_recurse (tree->root, 0);
1302 }
1303 #endif
1304 
1308 typedef struct
1309 {
1310  const char **path;
1311  dbus_bool_t handler_fallback;
1312  dbus_bool_t message_handled;
1313  dbus_bool_t handler_unregistered;
1314 } TreeTestData;
1315 
1316 
1317 static void
1318 test_unregister_function (DBusConnection *connection,
1319  void *user_data)
1320 {
1321  TreeTestData *ttd = user_data;
1322 
1323  ttd->handler_unregistered = TRUE;
1324 }
1325 
1326 static DBusHandlerResult
1327 test_message_function (DBusConnection *connection,
1328  DBusMessage *message,
1329  void *user_data)
1330 {
1331  TreeTestData *ttd = user_data;
1332 
1333  ttd->message_handled = TRUE;
1334 
1336 }
1337 
1338 static dbus_bool_t
1339 do_register (DBusObjectTree *tree,
1340  const char **path,
1341  dbus_bool_t fallback,
1342  int i,
1343  TreeTestData *tree_test_data)
1344 {
1345  DBusObjectPathVTable vtable = { test_unregister_function,
1346  test_message_function, NULL };
1347 
1348  tree_test_data[i].message_handled = FALSE;
1349  tree_test_data[i].handler_unregistered = FALSE;
1350  tree_test_data[i].handler_fallback = fallback;
1351  tree_test_data[i].path = path;
1352 
1353  if (!_dbus_object_tree_register (tree, fallback, path,
1354  &vtable,
1355  &tree_test_data[i],
1356  NULL))
1357  return FALSE;
1358 
1360  &tree_test_data[i]);
1361 
1362  return TRUE;
1363 }
1364 
1365 static dbus_bool_t
1366 do_test_dispatch (DBusObjectTree *tree,
1367  const char **path,
1368  int i,
1369  TreeTestData *tree_test_data,
1370  int n_test_data)
1371 {
1372  DBusMessage *message;
1373  int j;
1374  DBusHandlerResult result;
1375  char *flat;
1376 
1377  message = NULL;
1378 
1379  flat = flatten_path (path);
1380  if (flat == NULL)
1381  goto oom;
1382 
1384  flat,
1385  "org.freedesktop.TestInterface",
1386  "Foo");
1387  dbus_free (flat);
1388  if (message == NULL)
1389  goto oom;
1390 
1391  j = 0;
1392  while (j < n_test_data)
1393  {
1394  tree_test_data[j].message_handled = FALSE;
1395  ++j;
1396  }
1397 
1398  result = _dbus_object_tree_dispatch_and_unlock (tree, message, NULL);
1399  if (result == DBUS_HANDLER_RESULT_NEED_MEMORY)
1400  goto oom;
1401 
1402  _dbus_assert (tree_test_data[i].message_handled);
1403 
1404  j = 0;
1405  while (j < n_test_data)
1406  {
1407  if (tree_test_data[j].message_handled)
1408  {
1409  if (tree_test_data[j].handler_fallback)
1410  _dbus_assert (path_contains (tree_test_data[j].path,
1411  path) != STR_DIFFERENT);
1412  else
1413  _dbus_assert (path_contains (tree_test_data[j].path, path) == STR_EQUAL);
1414  }
1415  else
1416  {
1417  if (tree_test_data[j].handler_fallback)
1418  _dbus_assert (path_contains (tree_test_data[j].path,
1419  path) == STR_DIFFERENT);
1420  else
1421  _dbus_assert (path_contains (tree_test_data[j].path, path) != STR_EQUAL);
1422  }
1423 
1424  ++j;
1425  }
1426 
1427  dbus_message_unref (message);
1428 
1429  return TRUE;
1430 
1431  oom:
1432  if (message)
1433  dbus_message_unref (message);
1434  return FALSE;
1435 }
1436 
1437 static size_t
1438 string_array_length (const char **array)
1439 {
1440  size_t i;
1441  for (i = 0; array[i]; i++) ;
1442  return i;
1443 }
1444 
1445 typedef struct
1446 {
1447  const char *path;
1448  const char *result[20];
1449 } DecomposePathTest;
1450 
1451 static DecomposePathTest decompose_tests[] = {
1452  { "/foo", { "foo", NULL } },
1453  { "/foo/bar", { "foo", "bar", NULL } },
1454  { "/", { NULL } },
1455  { "/a/b", { "a", "b", NULL } },
1456  { "/a/b/c", { "a", "b", "c", NULL } },
1457  { "/a/b/c/d", { "a", "b", "c", "d", NULL } },
1458  { "/foo/bar/q", { "foo", "bar", "q", NULL } },
1459  { "/foo/bar/this/is/longer", { "foo", "bar", "this", "is", "longer", NULL } }
1460 };
1461 
1462 static dbus_bool_t
1463 run_decompose_tests (void)
1464 {
1465  int i;
1466 
1467  i = 0;
1468  while (i < _DBUS_N_ELEMENTS (decompose_tests))
1469  {
1470  char **result;
1471  int result_len;
1472  int expected_len;
1473 
1474  if (!_dbus_decompose_path (decompose_tests[i].path,
1475  strlen (decompose_tests[i].path),
1476  &result, &result_len))
1477  return FALSE;
1478 
1479  expected_len = string_array_length (decompose_tests[i].result);
1480 
1481  if (result_len != (int) string_array_length ((const char**)result) ||
1482  expected_len != result_len ||
1483  path_contains (decompose_tests[i].result,
1484  (const char**) result) != STR_EQUAL)
1485  {
1486  int real_len = string_array_length ((const char**)result);
1487  _dbus_warn ("Expected decompose of %s to have len %d, returned %d, appears to have %d\n",
1488  decompose_tests[i].path, expected_len, result_len,
1489  real_len);
1490  _dbus_warn ("Decompose resulted in elements: { ");
1491  i = 0;
1492  while (i < real_len)
1493  {
1494  _dbus_warn ("\"%s\"%s", result[i],
1495  (i + 1) == real_len ? "" : ", ");
1496  ++i;
1497  }
1498  _dbus_warn ("}\n");
1499  _dbus_assert_not_reached ("path decompose failed\n");
1500  }
1501 
1502  dbus_free_string_array (result);
1503 
1504  ++i;
1505  }
1506 
1507  return TRUE;
1508 }
1509 
1510 static dbus_bool_t
1511 object_tree_test_iteration (void *data)
1512 {
1513  const char *path0[] = { NULL };
1514  const char *path1[] = { "foo", NULL };
1515  const char *path2[] = { "foo", "bar", NULL };
1516  const char *path3[] = { "foo", "bar", "baz", NULL };
1517  const char *path4[] = { "foo", "bar", "boo", NULL };
1518  const char *path5[] = { "blah", NULL };
1519  const char *path6[] = { "blah", "boof", NULL };
1520  const char *path7[] = { "blah", "boof", "this", "is", "really", "long", NULL };
1521  const char *path8[] = { "childless", NULL };
1522  DBusObjectTree *tree;
1523  TreeTestData tree_test_data[9];
1524  int i;
1525  dbus_bool_t exact_match;
1526 
1527  if (!run_decompose_tests ())
1528  return FALSE;
1529 
1530  tree = NULL;
1531 
1532  tree = _dbus_object_tree_new (NULL);
1533  if (tree == NULL)
1534  goto out;
1535 
1536  if (!do_register (tree, path0, TRUE, 0, tree_test_data))
1537  goto out;
1538 
1539  _dbus_assert (find_subtree (tree, path0, NULL));
1540  _dbus_assert (!find_subtree (tree, path1, NULL));
1541  _dbus_assert (!find_subtree (tree, path2, NULL));
1542  _dbus_assert (!find_subtree (tree, path3, NULL));
1543  _dbus_assert (!find_subtree (tree, path4, NULL));
1544  _dbus_assert (!find_subtree (tree, path5, NULL));
1545  _dbus_assert (!find_subtree (tree, path6, NULL));
1546  _dbus_assert (!find_subtree (tree, path7, NULL));
1547  _dbus_assert (!find_subtree (tree, path8, NULL));
1548 
1549  _dbus_assert (find_handler (tree, path0, &exact_match) && exact_match);
1550  _dbus_assert (find_handler (tree, path1, &exact_match) == tree->root && !exact_match);
1551  _dbus_assert (find_handler (tree, path2, &exact_match) == tree->root && !exact_match);
1552  _dbus_assert (find_handler (tree, path3, &exact_match) == tree->root && !exact_match);
1553  _dbus_assert (find_handler (tree, path4, &exact_match) == tree->root && !exact_match);
1554  _dbus_assert (find_handler (tree, path5, &exact_match) == tree->root && !exact_match);
1555  _dbus_assert (find_handler (tree, path6, &exact_match) == tree->root && !exact_match);
1556  _dbus_assert (find_handler (tree, path7, &exact_match) == tree->root && !exact_match);
1557  _dbus_assert (find_handler (tree, path8, &exact_match) == tree->root && !exact_match);
1558 
1559  if (!do_register (tree, path1, TRUE, 1, tree_test_data))
1560  goto out;
1561 
1562  _dbus_assert (find_subtree (tree, path0, NULL));
1563  _dbus_assert (find_subtree (tree, path1, NULL));
1564  _dbus_assert (!find_subtree (tree, path2, NULL));
1565  _dbus_assert (!find_subtree (tree, path3, NULL));
1566  _dbus_assert (!find_subtree (tree, path4, NULL));
1567  _dbus_assert (!find_subtree (tree, path5, NULL));
1568  _dbus_assert (!find_subtree (tree, path6, NULL));
1569  _dbus_assert (!find_subtree (tree, path7, NULL));
1570  _dbus_assert (!find_subtree (tree, path8, NULL));
1571 
1572  _dbus_assert (find_handler (tree, path0, &exact_match) && exact_match);
1573  _dbus_assert (find_handler (tree, path1, &exact_match) && exact_match);
1574  _dbus_assert (find_handler (tree, path2, &exact_match) && !exact_match);
1575  _dbus_assert (find_handler (tree, path3, &exact_match) && !exact_match);
1576  _dbus_assert (find_handler (tree, path4, &exact_match) && !exact_match);
1577  _dbus_assert (find_handler (tree, path5, &exact_match) == tree->root && !exact_match);
1578  _dbus_assert (find_handler (tree, path6, &exact_match) == tree->root && !exact_match);
1579  _dbus_assert (find_handler (tree, path7, &exact_match) == tree->root && !exact_match);
1580  _dbus_assert (find_handler (tree, path8, &exact_match) == tree->root && !exact_match);
1581 
1582  if (!do_register (tree, path2, TRUE, 2, tree_test_data))
1583  goto out;
1584 
1585  _dbus_assert (find_subtree (tree, path1, NULL));
1586  _dbus_assert (find_subtree (tree, path2, NULL));
1587  _dbus_assert (!find_subtree (tree, path3, NULL));
1588  _dbus_assert (!find_subtree (tree, path4, NULL));
1589  _dbus_assert (!find_subtree (tree, path5, NULL));
1590  _dbus_assert (!find_subtree (tree, path6, NULL));
1591  _dbus_assert (!find_subtree (tree, path7, NULL));
1592  _dbus_assert (!find_subtree (tree, path8, NULL));
1593 
1594  if (!do_register (tree, path3, TRUE, 3, tree_test_data))
1595  goto out;
1596 
1597  _dbus_assert (find_subtree (tree, path0, NULL));
1598  _dbus_assert (find_subtree (tree, path1, NULL));
1599  _dbus_assert (find_subtree (tree, path2, NULL));
1600  _dbus_assert (find_subtree (tree, path3, NULL));
1601  _dbus_assert (!find_subtree (tree, path4, NULL));
1602  _dbus_assert (!find_subtree (tree, path5, NULL));
1603  _dbus_assert (!find_subtree (tree, path6, NULL));
1604  _dbus_assert (!find_subtree (tree, path7, NULL));
1605  _dbus_assert (!find_subtree (tree, path8, NULL));
1606 
1607  if (!do_register (tree, path4, TRUE, 4, tree_test_data))
1608  goto out;
1609 
1610  _dbus_assert (find_subtree (tree, path0, NULL));
1611  _dbus_assert (find_subtree (tree, path1, NULL));
1612  _dbus_assert (find_subtree (tree, path2, NULL));
1613  _dbus_assert (find_subtree (tree, path3, NULL));
1614  _dbus_assert (find_subtree (tree, path4, NULL));
1615  _dbus_assert (!find_subtree (tree, path5, NULL));
1616  _dbus_assert (!find_subtree (tree, path6, NULL));
1617  _dbus_assert (!find_subtree (tree, path7, NULL));
1618  _dbus_assert (!find_subtree (tree, path8, NULL));
1619 
1620  if (!do_register (tree, path5, TRUE, 5, tree_test_data))
1621  goto out;
1622 
1623  _dbus_assert (find_subtree (tree, path0, NULL));
1624  _dbus_assert (find_subtree (tree, path1, NULL));
1625  _dbus_assert (find_subtree (tree, path2, NULL));
1626  _dbus_assert (find_subtree (tree, path3, NULL));
1627  _dbus_assert (find_subtree (tree, path4, NULL));
1628  _dbus_assert (find_subtree (tree, path5, NULL));
1629  _dbus_assert (!find_subtree (tree, path6, NULL));
1630  _dbus_assert (!find_subtree (tree, path7, NULL));
1631  _dbus_assert (!find_subtree (tree, path8, NULL));
1632 
1633  _dbus_assert (find_handler (tree, path0, &exact_match) == tree->root && exact_match);
1634  _dbus_assert (find_handler (tree, path1, &exact_match) != tree->root && exact_match);
1635  _dbus_assert (find_handler (tree, path2, &exact_match) != tree->root && exact_match);
1636  _dbus_assert (find_handler (tree, path3, &exact_match) != tree->root && exact_match);
1637  _dbus_assert (find_handler (tree, path4, &exact_match) != tree->root && exact_match);
1638  _dbus_assert (find_handler (tree, path5, &exact_match) != tree->root && exact_match);
1639  _dbus_assert (find_handler (tree, path6, &exact_match) != tree->root && !exact_match);
1640  _dbus_assert (find_handler (tree, path7, &exact_match) != tree->root && !exact_match);
1641  _dbus_assert (find_handler (tree, path8, &exact_match) == tree->root && !exact_match);
1642 
1643  if (!do_register (tree, path6, TRUE, 6, tree_test_data))
1644  goto out;
1645 
1646  _dbus_assert (find_subtree (tree, path0, NULL));
1647  _dbus_assert (find_subtree (tree, path1, NULL));
1648  _dbus_assert (find_subtree (tree, path2, NULL));
1649  _dbus_assert (find_subtree (tree, path3, NULL));
1650  _dbus_assert (find_subtree (tree, path4, NULL));
1651  _dbus_assert (find_subtree (tree, path5, NULL));
1652  _dbus_assert (find_subtree (tree, path6, NULL));
1653  _dbus_assert (!find_subtree (tree, path7, NULL));
1654  _dbus_assert (!find_subtree (tree, path8, NULL));
1655 
1656  if (!do_register (tree, path7, TRUE, 7, tree_test_data))
1657  goto out;
1658 
1659  _dbus_assert (find_subtree (tree, path0, NULL));
1660  _dbus_assert (find_subtree (tree, path1, NULL));
1661  _dbus_assert (find_subtree (tree, path2, NULL));
1662  _dbus_assert (find_subtree (tree, path3, NULL));
1663  _dbus_assert (find_subtree (tree, path4, NULL));
1664  _dbus_assert (find_subtree (tree, path5, NULL));
1665  _dbus_assert (find_subtree (tree, path6, NULL));
1666  _dbus_assert (find_subtree (tree, path7, NULL));
1667  _dbus_assert (!find_subtree (tree, path8, NULL));
1668 
1669  if (!do_register (tree, path8, TRUE, 8, tree_test_data))
1670  goto out;
1671 
1672  _dbus_assert (find_subtree (tree, path0, NULL));
1673  _dbus_assert (find_subtree (tree, path1, NULL));
1674  _dbus_assert (find_subtree (tree, path2, NULL));
1675  _dbus_assert (find_subtree (tree, path3, NULL));
1676  _dbus_assert (find_subtree (tree, path4, NULL));
1677  _dbus_assert (find_subtree (tree, path5, NULL));
1678  _dbus_assert (find_subtree (tree, path6, NULL));
1679  _dbus_assert (find_subtree (tree, path7, NULL));
1680  _dbus_assert (find_subtree (tree, path8, NULL));
1681 
1682  _dbus_assert (find_handler (tree, path0, &exact_match) == tree->root && exact_match);
1683  _dbus_assert (find_handler (tree, path1, &exact_match) != tree->root && exact_match);
1684  _dbus_assert (find_handler (tree, path2, &exact_match) != tree->root && exact_match);
1685  _dbus_assert (find_handler (tree, path3, &exact_match) != tree->root && exact_match);
1686  _dbus_assert (find_handler (tree, path4, &exact_match) != tree->root && exact_match);
1687  _dbus_assert (find_handler (tree, path5, &exact_match) != tree->root && exact_match);
1688  _dbus_assert (find_handler (tree, path6, &exact_match) != tree->root && exact_match);
1689  _dbus_assert (find_handler (tree, path7, &exact_match) != tree->root && exact_match);
1690  _dbus_assert (find_handler (tree, path8, &exact_match) != tree->root && exact_match);
1691 
1692  /* test the list_registered function */
1693 
1694  {
1695  const char *root[] = { NULL };
1696  char **child_entries;
1697  int nb;
1698 
1699  _dbus_object_tree_list_registered_unlocked (tree, path1, &child_entries);
1700  if (child_entries != NULL)
1701  {
1702  nb = string_array_length ((const char**)child_entries);
1703  _dbus_assert (nb == 1);
1704  dbus_free_string_array (child_entries);
1705  }
1706 
1707  _dbus_object_tree_list_registered_unlocked (tree, path2, &child_entries);
1708  if (child_entries != NULL)
1709  {
1710  nb = string_array_length ((const char**)child_entries);
1711  _dbus_assert (nb == 2);
1712  dbus_free_string_array (child_entries);
1713  }
1714 
1715  _dbus_object_tree_list_registered_unlocked (tree, path8, &child_entries);
1716  if (child_entries != NULL)
1717  {
1718  nb = string_array_length ((const char**)child_entries);
1719  _dbus_assert (nb == 0);
1720  dbus_free_string_array (child_entries);
1721  }
1722 
1723  _dbus_object_tree_list_registered_unlocked (tree, root, &child_entries);
1724  if (child_entries != NULL)
1725  {
1726  nb = string_array_length ((const char**)child_entries);
1727  _dbus_assert (nb == 3);
1728  dbus_free_string_array (child_entries);
1729  }
1730  }
1731 
1732  /* Check that destroying tree calls unregister funcs */
1733  _dbus_object_tree_unref (tree);
1734 
1735  i = 0;
1736  while (i < (int) _DBUS_N_ELEMENTS (tree_test_data))
1737  {
1738  _dbus_assert (tree_test_data[i].handler_unregistered);
1739  _dbus_assert (!tree_test_data[i].message_handled);
1740  ++i;
1741  }
1742 
1743  /* Now start again and try the individual unregister function */
1744  tree = _dbus_object_tree_new (NULL);
1745  if (tree == NULL)
1746  goto out;
1747 
1748  if (!do_register (tree, path0, TRUE, 0, tree_test_data))
1749  goto out;
1750  if (!do_register (tree, path1, TRUE, 1, tree_test_data))
1751  goto out;
1752  if (!do_register (tree, path2, TRUE, 2, tree_test_data))
1753  goto out;
1754  if (!do_register (tree, path3, TRUE, 3, tree_test_data))
1755  goto out;
1756  if (!do_register (tree, path4, TRUE, 4, tree_test_data))
1757  goto out;
1758  if (!do_register (tree, path5, TRUE, 5, tree_test_data))
1759  goto out;
1760  if (!do_register (tree, path6, TRUE, 6, tree_test_data))
1761  goto out;
1762  if (!do_register (tree, path7, TRUE, 7, tree_test_data))
1763  goto out;
1764  if (!do_register (tree, path8, TRUE, 8, tree_test_data))
1765  goto out;
1766 
1769 
1770  _dbus_assert (!find_subtree (tree, path0, NULL));
1771  _dbus_assert (find_subtree (tree, path1, NULL));
1772  _dbus_assert (find_subtree (tree, path2, NULL));
1773  _dbus_assert (find_subtree (tree, path3, NULL));
1774  _dbus_assert (find_subtree (tree, path4, NULL));
1775  _dbus_assert (find_subtree (tree, path5, NULL));
1776  _dbus_assert (find_subtree (tree, path6, NULL));
1777  _dbus_assert (find_subtree (tree, path7, NULL));
1778  _dbus_assert (find_subtree (tree, path8, NULL));
1779 
1782 
1783  _dbus_assert (!find_subtree (tree, path0, NULL));
1784  _dbus_assert (!find_subtree (tree, path1, NULL));
1785  _dbus_assert (find_subtree (tree, path2, NULL));
1786  _dbus_assert (find_subtree (tree, path3, NULL));
1787  _dbus_assert (find_subtree (tree, path4, NULL));
1788  _dbus_assert (find_subtree (tree, path5, NULL));
1789  _dbus_assert (find_subtree (tree, path6, NULL));
1790  _dbus_assert (find_subtree (tree, path7, NULL));
1791  _dbus_assert (find_subtree (tree, path8, NULL));
1792 
1795 
1796  _dbus_assert (!find_subtree (tree, path0, NULL));
1797  _dbus_assert (!find_subtree (tree, path1, NULL));
1798  _dbus_assert (!find_subtree (tree, path2, NULL));
1799  _dbus_assert (find_subtree (tree, path3, NULL));
1800  _dbus_assert (find_subtree (tree, path4, NULL));
1801  _dbus_assert (find_subtree (tree, path5, NULL));
1802  _dbus_assert (find_subtree (tree, path6, NULL));
1803  _dbus_assert (find_subtree (tree, path7, NULL));
1804  _dbus_assert (find_subtree (tree, path8, NULL));
1805 
1808 
1809  _dbus_assert (!find_subtree (tree, path0, NULL));
1810  _dbus_assert (!find_subtree (tree, path1, NULL));
1811  _dbus_assert (!find_subtree (tree, path2, NULL));
1812  _dbus_assert (!find_subtree (tree, path3, NULL));
1813  _dbus_assert (find_subtree (tree, path4, NULL));
1814  _dbus_assert (find_subtree (tree, path5, NULL));
1815  _dbus_assert (find_subtree (tree, path6, NULL));
1816  _dbus_assert (find_subtree (tree, path7, NULL));
1817  _dbus_assert (find_subtree (tree, path8, NULL));
1818 
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 
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 
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 
1860 
1861  _dbus_assert (!find_subtree (tree, path0, NULL));
1862  _dbus_assert (!find_subtree (tree, path1, NULL));
1863  _dbus_assert (!find_subtree (tree, path2, NULL));
1864  _dbus_assert (!find_subtree (tree, path3, NULL));
1865  _dbus_assert (!find_subtree (tree, path4, NULL));
1866  _dbus_assert (!find_subtree (tree, path5, NULL));
1867  _dbus_assert (!find_subtree (tree, path6, NULL));
1868  _dbus_assert (!find_subtree (tree, path7, NULL));
1869  _dbus_assert (find_subtree (tree, path8, NULL));
1870 
1873 
1874  _dbus_assert (!find_subtree (tree, path0, NULL));
1875  _dbus_assert (!find_subtree (tree, path1, NULL));
1876  _dbus_assert (!find_subtree (tree, path2, NULL));
1877  _dbus_assert (!find_subtree (tree, path3, NULL));
1878  _dbus_assert (!find_subtree (tree, path4, NULL));
1879  _dbus_assert (!find_subtree (tree, path5, NULL));
1880  _dbus_assert (!find_subtree (tree, path6, NULL));
1881  _dbus_assert (!find_subtree (tree, path7, NULL));
1882  _dbus_assert (!find_subtree (tree, path8, NULL));
1883 
1884  i = 0;
1885  while (i < (int) _DBUS_N_ELEMENTS (tree_test_data))
1886  {
1887  _dbus_assert (tree_test_data[i].handler_unregistered);
1888  _dbus_assert (!tree_test_data[i].message_handled);
1889  ++i;
1890  }
1891 
1892  /* Register it all again, and test dispatch */
1893 
1894  if (!do_register (tree, path0, TRUE, 0, tree_test_data))
1895  goto out;
1896  if (!do_register (tree, path1, FALSE, 1, tree_test_data))
1897  goto out;
1898  if (!do_register (tree, path2, TRUE, 2, tree_test_data))
1899  goto out;
1900  if (!do_register (tree, path3, TRUE, 3, tree_test_data))
1901  goto out;
1902  if (!do_register (tree, path4, TRUE, 4, tree_test_data))
1903  goto out;
1904  if (!do_register (tree, path5, TRUE, 5, tree_test_data))
1905  goto out;
1906  if (!do_register (tree, path6, FALSE, 6, tree_test_data))
1907  goto out;
1908  if (!do_register (tree, path7, TRUE, 7, tree_test_data))
1909  goto out;
1910  if (!do_register (tree, path8, TRUE, 8, tree_test_data))
1911  goto out;
1912 
1913 #if 0
1914  spew_tree (tree);
1915 #endif
1916 
1917  if (!do_test_dispatch (tree, path0, 0, tree_test_data, _DBUS_N_ELEMENTS (tree_test_data)))
1918  goto out;
1919  if (!do_test_dispatch (tree, path1, 1, tree_test_data, _DBUS_N_ELEMENTS (tree_test_data)))
1920  goto out;
1921  if (!do_test_dispatch (tree, path2, 2, tree_test_data, _DBUS_N_ELEMENTS (tree_test_data)))
1922  goto out;
1923  if (!do_test_dispatch (tree, path3, 3, tree_test_data, _DBUS_N_ELEMENTS (tree_test_data)))
1924  goto out;
1925  if (!do_test_dispatch (tree, path4, 4, tree_test_data, _DBUS_N_ELEMENTS (tree_test_data)))
1926  goto out;
1927  if (!do_test_dispatch (tree, path5, 5, tree_test_data, _DBUS_N_ELEMENTS (tree_test_data)))
1928  goto out;
1929  if (!do_test_dispatch (tree, path6, 6, tree_test_data, _DBUS_N_ELEMENTS (tree_test_data)))
1930  goto out;
1931  if (!do_test_dispatch (tree, path7, 7, tree_test_data, _DBUS_N_ELEMENTS (tree_test_data)))
1932  goto out;
1933  if (!do_test_dispatch (tree, path8, 8, tree_test_data, _DBUS_N_ELEMENTS (tree_test_data)))
1934  goto out;
1935 
1936  out:
1937  if (tree)
1938  {
1939  /* test ref */
1940  _dbus_object_tree_ref (tree);
1941  _dbus_object_tree_unref (tree);
1942  _dbus_object_tree_unref (tree);
1943  }
1944 
1945  return TRUE;
1946 }
1947 
1954 _dbus_object_tree_test (void)
1955 {
1956  _dbus_test_oom_handling ("object tree",
1957  object_tree_test_iteration,
1958  NULL);
1959 
1960  return TRUE;
1961 }
1962 
1963 #endif /* !DOXYGEN_SHOULD_SKIP_THIS */
1964 
1965 #endif /* DBUS_BUILD_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:913
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:229
int max_subtrees
Number of allocated entries in subtrees.
#define NULL
A null pointer, defined appropriately for C or C++.
#define DBUS_INTERFACE_INTROSPECTABLE
The interface supported by introspectable objects.
Definition: dbus-shared.h:90
void _dbus_object_tree_free_all_unlocked(DBusObjectTree *tree)
Free all the handlers in the tree.
void * dbus_realloc(void *memory, size_t bytes)
Resizes a block of memory previously allocated by dbus_malloc() or dbus_malloc0().
Definition: dbus-memory.c:600
void dbus_free(void *memory)
Frees a block of memory previously allocated by dbus_malloc() or dbus_malloc0().
Definition: dbus-memory.c:700
DBusConnection * connection
Connection this tree belongs to.
void _dbus_connection_lock(DBusConnection *connection)
Acquires the connection lock.
void _dbus_list_remove_link(DBusList **list, DBusList *link)
Removes a link from the list.
Definition: dbus-list.c:516
#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:90
dbus_int32_t _dbus_atomic_dec(DBusAtomic *atomic)
Atomically decrement an integer.
Virtual table that must be implemented to handle a portion of the object path hierarchy.
Internals of DBusMessage.
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.
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:259
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:1111
DBusObjectSubtree ** subtrees
Child nodes.
Object representing an exception.
Definition: dbus-errors.h:48
void dbus_set_error(DBusError *error, const char *name, const char *format,...)
Assigns an error name and message to a DBusError.
Definition: dbus-errors.c:354
DBusObjectPathMessageFunction message_function
Function to handle messages.
void * user_data
Data for functions.
dbus_bool_t _dbus_connection_send_and_unlock(DBusConnection *connection, DBusMessage *message, dbus_uint32_t *client_serial)
Like dbus_connection_send(), but assumes the connection is already locked on function entry...
dbus_int32_t _dbus_atomic_inc(DBusAtomic *atomic)
Atomically increments an integer.
#define _DBUS_N_ELEMENTS(array)
Computes the number of elements in a fixed-size array using sizeof().
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:1154
DBusObjectSubtree * parent
Parent node.
void _dbus_string_free(DBusString *str)
Frees a string created by _dbus_string_init().
Definition: dbus-string.c:242
#define TRUE
Expands to &quot;1&quot;.
#define _dbus_assert_not_reached(explanation)
Aborts with an error message if called.
dbus_bool_t dbus_message_is_method_call(DBusMessage *message, const char *interface, const char *method)
Checks whether the message is a method call with the given interface and member fields.
void * _dbus_object_tree_get_user_data_unlocked(DBusObjectTree *tree, const char **path)
Looks up the data passed to _dbus_object_tree_register() for a handler at the given path...
dbus_bool_t _dbus_object_tree_register(DBusObjectTree *tree, dbus_bool_t fallback, const char **path, const DBusObjectPathVTable *vtable, void *user_data, DBusError *error)
Registers a new subtree in the global object tree.
DBusHandlerResult(* DBusObjectPathMessageFunction)(DBusConnection *connection, DBusMessage *message, void *user_data)
Called when a message is sent to a registered object path.
int refcount
Reference count.
DBusObjectTree * _dbus_object_tree_new(DBusConnection *connection)
Creates a new object tree, representing a mapping from paths to handler vtables.
A node in a linked list.
Definition: dbus-list.h:34
void dbus_free_string_array(char **str_array)
Frees a NULL-terminated array of strings.
Definition: dbus-memory.c:748
DBusAtomic refcount
Reference count.
int _dbus_list_get_length(DBusList **list)
Gets the length of a list.
Definition: dbus-list.c:719
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:556
#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:530
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:619
void dbus_connection_unref(DBusConnection *connection)
Decrements the reference count of a DBusConnection, and finalizes it if the count reaches zero...
void _dbus_object_tree_unref(DBusObjectTree *tree)
Decrement the reference count.
DBusConnection * _dbus_connection_ref_unlocked(DBusConnection *connection)
Increments the reference count of a DBusConnection.
Message has had its effect - no need to run more handlers.
Definition: dbus-shared.h:68
int dbus_int32_t
A 32-bit signed integer on all platforms.
char * _dbus_strdup(const char *str)
Duplicates a string.
void _dbus_connection_unlock(DBusConnection *connection)
Releases the connection lock.
const char * _dbus_string_get_const_data(const DBusString *str)
Gets the raw character buffer from a const string.
Definition: dbus-string.c:446
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_call(const char *destination, const char *path, const char *interface, const char *method)
Constructs a new message to invoke a method on a remote object.
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).