dbus-object-tree.c revision 248895207dc15914ac7970a6d1431308075dca1d
1/* -*- mode: C; c-file-style: "gnu" -*- */
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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
21 *
22 */
23#include "dbus-object-tree.h"
24#include "dbus-connection-internal.h"
25#include "dbus-internals.h"
26#include "dbus-hash.h"
27#include "dbus-protocol.h"
28#include "dbus-string.h"
29#include <string.h>
30#include <stdlib.h>
31
32/**
33 * @defgroup DBusObjectTree A hierarchy of objects with container-contained relationship
34 * @ingroup  DBusInternals
35 * @brief DBusObjectTree is used by DBusConnection to track the object tree
36 *
37 * Types and functions related to DBusObjectTree. These
38 * are all library-internal.
39 *
40 * @{
41 */
42
43/** Subnode of the object hierarchy */
44typedef struct DBusObjectSubtree DBusObjectSubtree;
45
46static DBusObjectSubtree* _dbus_object_subtree_new   (const char                  *name,
47                                                      const DBusObjectPathVTable  *vtable,
48                                                      void                        *user_data);
49static DBusObjectSubtree* _dbus_object_subtree_ref   (DBusObjectSubtree           *subtree);
50static void               _dbus_object_subtree_unref (DBusObjectSubtree           *subtree);
51
52/**
53 * Internals of DBusObjectTree
54 */
55struct DBusObjectTree
56{
57  int                 refcount;   /**< Reference count */
58  DBusConnection     *connection; /**< Connection this tree belongs to */
59
60  DBusObjectSubtree  *root;       /**< Root of the tree ("/" node) */
61};
62
63/**
64 * Struct representing a single registered subtree handler, or node
65 * that's a parent of a registered subtree handler. If
66 * message_function != NULL there's actually a handler at this node.
67 */
68struct DBusObjectSubtree
69{
70  DBusAtomic                         refcount;            /**< Reference count */
71  DBusObjectSubtree                 *parent;              /**< Parent node */
72  DBusObjectPathUnregisterFunction   unregister_function; /**< Function to call on unregister */
73  DBusObjectPathMessageFunction      message_function;    /**< Function to handle messages */
74  void                              *user_data;           /**< Data for functions */
75  DBusObjectSubtree                **subtrees;            /**< Child nodes */
76  int                                n_subtrees;          /**< Number of child nodes */
77  unsigned int                       subtrees_sorted : 1; /**< Whether children are sorted */
78  unsigned int                       invoke_as_fallback : 1; /**< Whether to invoke message_function when child nodes don't handle the message */
79  char                               name[1]; /**< Allocated as large as necessary */
80};
81
82/**
83 * Creates a new object tree, representing a mapping from paths
84 * to handler vtables.
85 *
86 * @param connection the connection this tree belongs to
87 * @returns the new tree or #NULL if no memory
88 */
89DBusObjectTree*
90_dbus_object_tree_new (DBusConnection *connection)
91{
92  DBusObjectTree *tree;
93
94  /* the connection passed in here isn't fully constructed,
95   * so don't do anything more than store a pointer to
96   * it
97   */
98
99  tree = dbus_new0 (DBusObjectTree, 1);
100  if (tree == NULL)
101    goto oom;
102
103  tree->refcount = 1;
104  tree->connection = connection;
105  tree->root = _dbus_object_subtree_new ("/", NULL, NULL);
106  if (tree->root == NULL)
107    goto oom;
108  tree->root->invoke_as_fallback = TRUE;
109
110  return tree;
111
112 oom:
113  if (tree)
114    {
115      dbus_free (tree);
116    }
117
118  return NULL;
119}
120
121/**
122 * Increment the reference count
123 * @param tree the object tree
124 * @returns the object tree
125 */
126DBusObjectTree *
127_dbus_object_tree_ref (DBusObjectTree *tree)
128{
129  _dbus_assert (tree->refcount > 0);
130
131  tree->refcount += 1;
132
133  return tree;
134}
135
136/**
137 * Decrement the reference count
138 * @param tree the object tree
139 */
140void
141_dbus_object_tree_unref (DBusObjectTree *tree)
142{
143  _dbus_assert (tree->refcount > 0);
144
145  tree->refcount -= 1;
146
147  if (tree->refcount == 0)
148    {
149      _dbus_object_tree_free_all_unlocked (tree);
150
151      dbus_free (tree);
152    }
153}
154
155static int
156subtree_cmp (DBusObjectSubtree *subtree_a,
157             DBusObjectSubtree *subtree_b)
158{
159  return strcmp (subtree_a->name, subtree_b->name);
160}
161
162static int
163subtree_qsort_cmp (const void *a,
164                   const void *b)
165{
166  DBusObjectSubtree **subtree_a_p = (void*) a;
167  DBusObjectSubtree **subtree_b_p = (void*) b;
168
169  return subtree_cmp (*subtree_a_p, *subtree_b_p);
170}
171
172static void
173ensure_sorted (DBusObjectSubtree *subtree)
174{
175  if (subtree->subtrees && !subtree->subtrees_sorted)
176    {
177      qsort (subtree->subtrees,
178             subtree->n_subtrees,
179             sizeof (DBusObjectSubtree*),
180             subtree_qsort_cmp);
181      subtree->subtrees_sorted = TRUE;
182    }
183}
184
185/** Set to 1 to get a bunch of debug spew about finding the
186 * subtree nodes
187 */
188#define VERBOSE_FIND 0
189
190static DBusObjectSubtree*
191find_subtree_recurse (DBusObjectSubtree  *subtree,
192                      const char        **path,
193                      dbus_bool_t         create_if_not_found,
194                      int                *index_in_parent,
195                      dbus_bool_t        *exact_match)
196{
197  int i;
198  dbus_bool_t return_deepest_match;
199
200  return_deepest_match = exact_match != NULL;
201
202  _dbus_assert (!(return_deepest_match && create_if_not_found));
203
204  if (path[0] == NULL)
205    {
206#if VERBOSE_FIND
207      _dbus_verbose ("  path exhausted, returning %s\n",
208                     subtree->name);
209#endif
210      if (exact_match != NULL)
211	*exact_match = TRUE;
212      return subtree;
213    }
214
215#if VERBOSE_FIND
216  _dbus_verbose ("  searching children of %s for %s\n",
217                 subtree->name, path[0]);
218#endif
219
220  ensure_sorted (subtree);
221
222  /* FIXME we should do a binary search here instead
223   * of O(n)
224   */
225
226  i = 0;
227  while (i < subtree->n_subtrees)
228    {
229      int v;
230
231      v = strcmp (path[0], subtree->subtrees[i]->name);
232
233#if VERBOSE_FIND
234      _dbus_verbose ("  %s cmp %s = %d\n",
235                     path[0], subtree->subtrees[i]->name,
236                     v);
237#endif
238
239      if (v == 0)
240        {
241          if (index_in_parent)
242            {
243#if VERBOSE_FIND
244              _dbus_verbose ("  storing parent index %d\n", i);
245#endif
246              *index_in_parent = i;
247            }
248
249          if (return_deepest_match)
250            {
251              DBusObjectSubtree *next;
252
253              next = find_subtree_recurse (subtree->subtrees[i],
254                                           &path[1], create_if_not_found,
255                                           index_in_parent, exact_match);
256              if (next == NULL &&
257                  subtree->invoke_as_fallback)
258                {
259#if VERBOSE_FIND
260                  _dbus_verbose ("  no deeper match found, returning %s\n",
261                                 subtree->name);
262#endif
263		  if (exact_match != NULL)
264		    *exact_match = FALSE;
265                  return subtree;
266                }
267              else
268                return next;
269            }
270          else
271            return find_subtree_recurse (subtree->subtrees[i],
272                                         &path[1], create_if_not_found,
273                                         index_in_parent, exact_match);
274        }
275      else if (v < 0)
276        {
277          goto not_found;
278        }
279
280      ++i;
281    }
282
283 not_found:
284#if VERBOSE_FIND
285  _dbus_verbose ("  no match found, current tree %s, create_if_not_found = %d\n",
286                 subtree->name, create_if_not_found);
287#endif
288
289  if (create_if_not_found)
290    {
291      DBusObjectSubtree* child;
292      DBusObjectSubtree **new_subtrees;
293      int new_n_subtrees;
294
295#if VERBOSE_FIND
296      _dbus_verbose ("  creating subtree %s\n",
297                     path[0]);
298#endif
299
300      child = _dbus_object_subtree_new (path[0],
301                                        NULL, NULL);
302      if (child == NULL)
303        return NULL;
304
305      /* FIXME we should do the "double alloc each time" standard thing */
306      new_n_subtrees = subtree->n_subtrees + 1;
307      new_subtrees = dbus_realloc (subtree->subtrees,
308                                   new_n_subtrees * sizeof (DBusObjectSubtree*));
309      if (new_subtrees == NULL)
310        {
311          child->unregister_function = NULL;
312          child->message_function = NULL;
313          _dbus_object_subtree_unref (child);
314          return NULL;
315        }
316
317      new_subtrees[subtree->n_subtrees] = child;
318      if (index_in_parent)
319        *index_in_parent = subtree->n_subtrees;
320      subtree->subtrees_sorted = FALSE;
321      subtree->n_subtrees = new_n_subtrees;
322      subtree->subtrees = new_subtrees;
323
324      child->parent = subtree;
325
326      return find_subtree_recurse (child,
327                                   &path[1], create_if_not_found,
328                                   index_in_parent, exact_match);
329    }
330  else
331    {
332      if (exact_match != NULL)
333	*exact_match = FALSE;
334      return (return_deepest_match && subtree->invoke_as_fallback) ? subtree : NULL;
335    }
336}
337
338static DBusObjectSubtree*
339find_subtree (DBusObjectTree *tree,
340              const char    **path,
341              int            *index_in_parent)
342{
343  DBusObjectSubtree *subtree;
344
345#if VERBOSE_FIND
346  _dbus_verbose ("Looking for exact registered subtree\n");
347#endif
348
349  subtree = find_subtree_recurse (tree->root, path, FALSE, index_in_parent, NULL);
350
351  if (subtree && subtree->message_function == NULL)
352    return NULL;
353  else
354    return subtree;
355}
356
357static DBusObjectSubtree*
358lookup_subtree (DBusObjectTree *tree,
359                const char    **path)
360{
361#if VERBOSE_FIND
362  _dbus_verbose ("Looking for subtree\n");
363#endif
364  return find_subtree_recurse (tree->root, path, FALSE, NULL, NULL);
365}
366
367static DBusObjectSubtree*
368find_handler (DBusObjectTree *tree,
369              const char    **path,
370              dbus_bool_t    *exact_match)
371{
372#if VERBOSE_FIND
373  _dbus_verbose ("Looking for deepest handler\n");
374#endif
375  _dbus_assert (exact_match != NULL);
376  return find_subtree_recurse (tree->root, path, FALSE, NULL, exact_match);
377}
378
379static DBusObjectSubtree*
380ensure_subtree (DBusObjectTree *tree,
381                const char    **path)
382{
383#if VERBOSE_FIND
384  _dbus_verbose ("Ensuring subtree\n");
385#endif
386  return find_subtree_recurse (tree->root, path, TRUE, NULL, NULL);
387}
388
389/**
390 * Registers a new subtree in the global object tree.
391 *
392 * @param tree the global object tree
393 * @param fallback #TRUE to handle messages to children of this path
394 * @param path NULL-terminated array of path elements giving path to subtree
395 * @param vtable the vtable used to traverse this subtree
396 * @param user_data user data to pass to methods in the vtable
397 * @returns #FALSE if not enough memory
398 */
399dbus_bool_t
400_dbus_object_tree_register (DBusObjectTree              *tree,
401                            dbus_bool_t                  fallback,
402                            const char                 **path,
403                            const DBusObjectPathVTable  *vtable,
404                            void                        *user_data)
405{
406  DBusObjectSubtree  *subtree;
407
408  _dbus_assert (tree != NULL);
409  _dbus_assert (vtable->message_function != NULL);
410  _dbus_assert (path != NULL);
411
412  subtree = ensure_subtree (tree, path);
413  if (subtree == NULL)
414    return FALSE;
415
416#ifndef DBUS_DISABLE_CHECKS
417  if (subtree->message_function != NULL)
418    {
419      _dbus_warn ("A handler is already registered for the path starting with path[0] = \"%s\"\n",
420                  path[0] ? path[0] : "null");
421      return FALSE;
422    }
423#else
424  _dbus_assert (subtree->message_function == NULL);
425#endif
426
427  subtree->message_function = vtable->message_function;
428  subtree->unregister_function = vtable->unregister_function;
429  subtree->user_data = user_data;
430  subtree->invoke_as_fallback = fallback != FALSE;
431
432  return TRUE;
433}
434
435/**
436 * Unregisters an object subtree that was registered with the
437 * same path.
438 *
439 * @param tree the global object tree
440 * @param path path to the subtree (same as the one passed to _dbus_object_tree_register())
441 */
442void
443_dbus_object_tree_unregister_and_unlock (DBusObjectTree          *tree,
444                                         const char             **path)
445{
446  int i;
447  DBusObjectSubtree *subtree;
448  DBusObjectPathUnregisterFunction unregister_function;
449  void *user_data;
450  DBusConnection *connection;
451
452  _dbus_assert (path != NULL);
453
454  subtree = find_subtree (tree, path, &i);
455
456#ifndef DBUS_DISABLE_CHECKS
457  if (subtree == NULL)
458    {
459      _dbus_warn ("Attempted to unregister path (path[0] = %s path[1] = %s) which isn't registered\n",
460                  path[0] ? path[0] : "null",
461                  path[1] ? path[1] : "null");
462      return;
463    }
464#else
465  _dbus_assert (subtree != NULL);
466#endif
467
468  _dbus_assert (subtree->parent == NULL ||
469                (i >= 0 && subtree->parent->subtrees[i] == subtree));
470
471  subtree->message_function = NULL;
472
473  unregister_function = subtree->unregister_function;
474  user_data = subtree->user_data;
475
476  subtree->unregister_function = NULL;
477  subtree->user_data = NULL;
478
479  /* If we have no subtrees of our own, remove from
480   * our parent (FIXME could also be more aggressive
481   * and remove our parent if it becomes empty)
482   */
483  if (subtree->parent && subtree->n_subtrees == 0)
484    {
485      /* assumes a 0-byte memmove is OK */
486      memmove (&subtree->parent->subtrees[i],
487               &subtree->parent->subtrees[i+1],
488               (subtree->parent->n_subtrees - i - 1) *
489               sizeof (subtree->parent->subtrees[0]));
490      subtree->parent->n_subtrees -= 1;
491
492      subtree->parent = NULL;
493
494      _dbus_object_subtree_unref (subtree);
495    }
496  subtree = NULL;
497
498  connection = tree->connection;
499
500  /* Unlock and call application code */
501#ifdef DBUS_BUILD_TESTS
502  if (connection)
503#endif
504    {
505      _dbus_connection_ref_unlocked (connection);
506      _dbus_verbose ("unlock %s\n", _DBUS_FUNCTION_NAME);
507      _dbus_connection_unlock (connection);
508    }
509
510  if (unregister_function)
511    (* unregister_function) (connection, user_data);
512
513#ifdef DBUS_BUILD_TESTS
514  if (connection)
515#endif
516    dbus_connection_unref (connection);
517}
518
519static void
520free_subtree_recurse (DBusConnection    *connection,
521                      DBusObjectSubtree *subtree)
522{
523  /* Delete them from the end, for slightly
524   * more robustness against odd reentrancy.
525   */
526  while (subtree->n_subtrees > 0)
527    {
528      DBusObjectSubtree *child;
529
530      child = subtree->subtrees[subtree->n_subtrees - 1];
531      subtree->subtrees[subtree->n_subtrees - 1] = NULL;
532      subtree->n_subtrees -= 1;
533      child->parent = NULL;
534
535      free_subtree_recurse (connection, child);
536    }
537
538  /* Call application code */
539  if (subtree->unregister_function)
540    (* subtree->unregister_function) (connection,
541				      subtree->user_data);
542
543  subtree->message_function = NULL;
544  subtree->unregister_function = NULL;
545  subtree->user_data = NULL;
546
547  /* Now free ourselves */
548  _dbus_object_subtree_unref (subtree);
549}
550
551/**
552 * Free all the handlers in the tree. Lock on tree's connection
553 * must not be held.
554 *
555 * @param tree the object tree
556 */
557void
558_dbus_object_tree_free_all_unlocked (DBusObjectTree *tree)
559{
560  if (tree->root)
561    free_subtree_recurse (tree->connection,
562                          tree->root);
563  tree->root = NULL;
564}
565
566static dbus_bool_t
567_dbus_object_tree_list_registered_unlocked (DBusObjectTree *tree,
568                                            const char    **parent_path,
569                                            char         ***child_entries)
570{
571  DBusObjectSubtree *subtree;
572  char **retval;
573
574  _dbus_assert (parent_path != NULL);
575  _dbus_assert (child_entries != NULL);
576
577  *child_entries = NULL;
578
579  subtree = lookup_subtree (tree, parent_path);
580  if (subtree == NULL)
581    {
582      retval = dbus_new0 (char *, 1);
583    }
584  else
585    {
586      int i;
587      retval = dbus_new0 (char*, subtree->n_subtrees + 1);
588      if (retval == NULL)
589        goto out;
590      i = 0;
591      while (i < subtree->n_subtrees)
592        {
593          retval[i] = _dbus_strdup (subtree->subtrees[i]->name);
594          if (retval[i] == NULL)
595            {
596              dbus_free_string_array (retval);
597              retval = NULL;
598              goto out;
599            }
600          ++i;
601        }
602    }
603
604 out:
605
606  *child_entries = retval;
607  return retval != NULL;
608}
609
610static DBusHandlerResult
611handle_default_introspect_and_unlock (DBusObjectTree          *tree,
612                                      DBusMessage             *message,
613                                      const char             **path)
614{
615  DBusString xml;
616  DBusHandlerResult result;
617  char **children;
618  int i;
619  DBusMessage *reply;
620  DBusMessageIter iter;
621  const char *v_STRING;
622  dbus_bool_t already_unlocked;
623
624  /* We have the connection lock here */
625
626  already_unlocked = FALSE;
627
628  _dbus_verbose (" considering default Introspect() handler...\n");
629
630  reply = NULL;
631
632  if (!dbus_message_is_method_call (message,
633                                    DBUS_INTERFACE_INTROSPECTABLE,
634                                    "Introspect"))
635    {
636#ifdef DBUS_BUILD_TESTS
637      if (tree->connection)
638#endif
639        {
640          _dbus_verbose ("unlock %s %d\n", _DBUS_FUNCTION_NAME, __LINE__);
641          _dbus_connection_unlock (tree->connection);
642        }
643
644      return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
645    }
646
647  _dbus_verbose (" using default Introspect() handler!\n");
648
649  if (!_dbus_string_init (&xml))
650    {
651#ifdef DBUS_BUILD_TESTS
652      if (tree->connection)
653#endif
654        {
655          _dbus_verbose ("unlock %s %d\n", _DBUS_FUNCTION_NAME, __LINE__);
656          _dbus_connection_unlock (tree->connection);
657        }
658
659      return DBUS_HANDLER_RESULT_NEED_MEMORY;
660    }
661
662  result = DBUS_HANDLER_RESULT_NEED_MEMORY;
663
664  children = NULL;
665  if (!_dbus_object_tree_list_registered_unlocked (tree, path, &children))
666    goto out;
667
668  if (!_dbus_string_append (&xml, DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE))
669    goto out;
670
671  if (!_dbus_string_append (&xml, "<node>\n"))
672    goto out;
673
674  i = 0;
675  while (children[i] != NULL)
676    {
677      if (!_dbus_string_append_printf (&xml, "  <node name=\"%s\"/>\n",
678                                       children[i]))
679        goto out;
680
681      ++i;
682    }
683
684  if (!_dbus_string_append (&xml, "</node>\n"))
685    goto out;
686
687  reply = dbus_message_new_method_return (message);
688  if (reply == NULL)
689    goto out;
690
691  dbus_message_iter_init_append (reply, &iter);
692  v_STRING = _dbus_string_get_const_data (&xml);
693  if (!dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &v_STRING))
694    goto out;
695
696#ifdef DBUS_BUILD_TESTS
697  if (tree->connection)
698#endif
699    {
700      already_unlocked = TRUE;
701
702      if (!_dbus_connection_send_and_unlock (tree->connection, reply, NULL))
703        goto out;
704    }
705
706  result = DBUS_HANDLER_RESULT_HANDLED;
707
708 out:
709#ifdef DBUS_BUILD_TESTS
710  if (tree->connection)
711#endif
712    {
713      if (!already_unlocked)
714        {
715          _dbus_verbose ("unlock %s %d\n", _DBUS_FUNCTION_NAME, __LINE__);
716          _dbus_connection_unlock (tree->connection);
717        }
718    }
719
720  _dbus_string_free (&xml);
721  dbus_free_string_array (children);
722  if (reply)
723    dbus_message_unref (reply);
724
725  return result;
726}
727
728/**
729 * Tries to dispatch a message by directing it to handler for the
730 * object path listed in the message header, if any. Messages are
731 * dispatched first to the registered handler that matches the largest
732 * number of path elements; that is, message to /foo/bar/baz would go
733 * to the handler for /foo/bar before the one for /foo.
734 *
735 * @todo thread problems
736 *
737 * @param tree the global object tree
738 * @param message the message to dispatch
739 * @returns whether message was handled successfully
740 */
741DBusHandlerResult
742_dbus_object_tree_dispatch_and_unlock (DBusObjectTree          *tree,
743                                       DBusMessage             *message)
744{
745  char **path;
746  dbus_bool_t exact_match;
747  DBusList *list;
748  DBusList *link;
749  DBusHandlerResult result;
750  DBusObjectSubtree *subtree;
751
752#if 0
753  _dbus_verbose ("Dispatch of message by object path\n");
754#endif
755
756  path = NULL;
757  if (!dbus_message_get_path_decomposed (message, &path))
758    {
759#ifdef DBUS_BUILD_TESTS
760      if (tree->connection)
761#endif
762        {
763          _dbus_verbose ("unlock %s\n", _DBUS_FUNCTION_NAME);
764          _dbus_connection_unlock (tree->connection);
765        }
766
767      _dbus_verbose ("No memory to get decomposed path\n");
768
769      return DBUS_HANDLER_RESULT_NEED_MEMORY;
770    }
771
772  if (path == NULL)
773    {
774#ifdef DBUS_BUILD_TESTS
775      if (tree->connection)
776#endif
777        {
778          _dbus_verbose ("unlock %s\n", _DBUS_FUNCTION_NAME);
779          _dbus_connection_unlock (tree->connection);
780        }
781
782      _dbus_verbose ("No path field in message\n");
783      return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
784    }
785
786  /* Find the deepest path that covers the path in the message */
787  subtree = find_handler (tree, (const char**) path, &exact_match);
788
789  /* Build a list of all paths that cover the path in the message */
790
791  list = NULL;
792
793  while (subtree != NULL)
794    {
795      if (subtree->message_function != NULL && (exact_match || subtree->invoke_as_fallback))
796        {
797          _dbus_object_subtree_ref (subtree);
798
799          /* run deepest paths first */
800          if (!_dbus_list_append (&list, subtree))
801            {
802              result = DBUS_HANDLER_RESULT_NEED_MEMORY;
803              _dbus_object_subtree_unref (subtree);
804              goto free_and_return;
805            }
806        }
807
808      exact_match = FALSE;
809      subtree = subtree->parent;
810    }
811
812  _dbus_verbose ("%d handlers in the path tree for this message\n",
813                 _dbus_list_get_length (&list));
814
815  /* Invoke each handler in the list */
816
817  result = DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
818
819  link = _dbus_list_get_first_link (&list);
820  while (link != NULL)
821    {
822      DBusList *next = _dbus_list_get_next_link (&list, link);
823      subtree = link->data;
824
825      /* message_function is NULL if we're unregistered
826       * due to reentrancy
827       */
828      if (subtree->message_function)
829        {
830          DBusObjectPathMessageFunction message_function;
831          void *user_data;
832
833          message_function = subtree->message_function;
834          user_data = subtree->user_data;
835
836#if 0
837          _dbus_verbose ("  (invoking a handler)\n");
838#endif
839
840#ifdef DBUS_BUILD_TESTS
841          if (tree->connection)
842#endif
843            {
844              _dbus_verbose ("unlock %s\n", _DBUS_FUNCTION_NAME);
845              _dbus_connection_unlock (tree->connection);
846            }
847
848          /* FIXME you could unregister the subtree in another thread
849           * before we invoke the callback, and I can't figure out a
850           * good way to solve this.
851           */
852
853          result = (* message_function) (tree->connection,
854                                         message,
855                                         user_data);
856
857#ifdef DBUS_BUILD_TESTS
858          if (tree->connection)
859#endif
860            _dbus_connection_lock (tree->connection);
861
862          if (result != DBUS_HANDLER_RESULT_NOT_YET_HANDLED)
863            goto free_and_return;
864        }
865
866      link = next;
867    }
868
869 free_and_return:
870
871  if (result == DBUS_HANDLER_RESULT_NOT_YET_HANDLED)
872    {
873      /* This hardcoded default handler does a minimal Introspect()
874       */
875      result = handle_default_introspect_and_unlock (tree, message,
876                                                     (const char**) path);
877    }
878  else
879    {
880#ifdef DBUS_BUILD_TESTS
881      if (tree->connection)
882#endif
883        {
884          _dbus_verbose ("unlock %s\n", _DBUS_FUNCTION_NAME);
885          _dbus_connection_unlock (tree->connection);
886        }
887    }
888
889  while (list != NULL)
890    {
891      link = _dbus_list_get_first_link (&list);
892      _dbus_object_subtree_unref (link->data);
893      _dbus_list_remove_link (&list, link);
894    }
895
896  dbus_free_string_array (path);
897
898  return result;
899}
900
901/**
902 * Allocates a subtree object.
903 *
904 * @param name name to duplicate.
905 * @returns newly-allocated subtree
906 */
907static DBusObjectSubtree*
908allocate_subtree_object (const char *name)
909{
910  int len;
911  DBusObjectSubtree *subtree;
912  const size_t front_padding = _DBUS_STRUCT_OFFSET (DBusObjectSubtree, name);
913
914  _dbus_assert (name != NULL);
915
916  len = strlen (name);
917
918  subtree = dbus_malloc (front_padding + (len + 1));
919
920  if (subtree == NULL)
921    return NULL;
922
923  memcpy (subtree->name, name, len + 1);
924
925  return subtree;
926}
927
928static DBusObjectSubtree*
929_dbus_object_subtree_new (const char                  *name,
930                          const DBusObjectPathVTable  *vtable,
931                          void                        *user_data)
932{
933  DBusObjectSubtree *subtree;
934
935  subtree = allocate_subtree_object (name);
936  if (subtree == NULL)
937    goto oom;
938
939  _dbus_assert (name != NULL);
940
941  subtree->parent = NULL;
942
943  if (vtable)
944    {
945      subtree->message_function = vtable->message_function;
946      subtree->unregister_function = vtable->unregister_function;
947    }
948  else
949    {
950      subtree->message_function = NULL;
951      subtree->unregister_function = NULL;
952    }
953
954  subtree->user_data = user_data;
955  subtree->refcount.value = 1;
956  subtree->subtrees = NULL;
957  subtree->n_subtrees = 0;
958  subtree->subtrees_sorted = TRUE;
959  subtree->invoke_as_fallback = FALSE;
960
961  return subtree;
962
963 oom:
964  if (subtree)
965    {
966      dbus_free (subtree);
967    }
968
969  return NULL;
970}
971
972static DBusObjectSubtree *
973_dbus_object_subtree_ref (DBusObjectSubtree *subtree)
974{
975  _dbus_assert (subtree->refcount.value > 0);
976  _dbus_atomic_inc (&subtree->refcount);
977
978  return subtree;
979}
980
981static void
982_dbus_object_subtree_unref (DBusObjectSubtree *subtree)
983{
984  _dbus_assert (subtree->refcount.value > 0);
985
986  if (_dbus_atomic_dec (&subtree->refcount) == 1)
987    {
988      _dbus_assert (subtree->unregister_function == NULL);
989      _dbus_assert (subtree->message_function == NULL);
990
991      dbus_free (subtree->subtrees);
992      dbus_free (subtree);
993    }
994}
995
996/**
997 * Lists the registered fallback handlers and object path handlers at
998 * the given parent_path. The returned array should be freed with
999 * dbus_free_string_array().
1000 *
1001 * @param tree the object tree
1002 * @param parent_path the path to list the child handlers of
1003 * @param child_entries returns #NULL-terminated array of children
1004 * @returns #FALSE if no memory to allocate the child entries
1005 */
1006dbus_bool_t
1007_dbus_object_tree_list_registered_and_unlock (DBusObjectTree *tree,
1008                                              const char    **parent_path,
1009                                              char         ***child_entries)
1010{
1011  dbus_bool_t result;
1012
1013  result = _dbus_object_tree_list_registered_unlocked (tree,
1014                                                       parent_path,
1015                                                       child_entries);
1016
1017#ifdef DBUS_BUILD_TESTS
1018  if (tree->connection)
1019#endif
1020    {
1021      _dbus_verbose ("unlock %s\n", _DBUS_FUNCTION_NAME);
1022      _dbus_connection_unlock (tree->connection);
1023    }
1024
1025  return result;
1026}
1027
1028
1029/** Set to 1 to get a bunch of spew about disassembling the path string */
1030#define VERBOSE_DECOMPOSE 0
1031
1032/**
1033 * Decompose an object path.  A path of just "/" is
1034 * represented as an empty vector of strings.
1035 * The path need not be nul terminated.
1036 *
1037 * @param data the path data
1038 * @param len  the length of the path string
1039 * @param path address to store new object path
1040 * @param path_len length of stored path
1041 */
1042dbus_bool_t
1043_dbus_decompose_path (const char*     data,
1044                      int             len,
1045                      char         ***path,
1046                      int            *path_len)
1047{
1048  char **retval;
1049  int n_components;
1050  int i, j, comp;
1051
1052  _dbus_assert (data != NULL);
1053
1054#if VERBOSE_DECOMPOSE
1055  _dbus_verbose ("Decomposing path \"%s\"\n",
1056                 data);
1057#endif
1058
1059  n_components = 0;
1060  if (len > 1) /* if path is not just "/" */
1061    {
1062      i = 0;
1063      while (i < len)
1064        {
1065          if (data[i] == '/')
1066            n_components += 1;
1067          ++i;
1068        }
1069    }
1070
1071  retval = dbus_new0 (char*, n_components + 1);
1072
1073  if (retval == NULL)
1074    return FALSE;
1075
1076  comp = 0;
1077  if (n_components == 0)
1078    i = 1;
1079  else
1080    i = 0;
1081  while (comp < n_components)
1082    {
1083      _dbus_assert (i < len);
1084
1085      if (data[i] == '/')
1086        ++i;
1087      j = i;
1088
1089      while (j < len && data[j] != '/')
1090        ++j;
1091
1092      /* Now [i, j) is the path component */
1093      _dbus_assert (i < j);
1094      _dbus_assert (data[i] != '/');
1095      _dbus_assert (j == len || data[j] == '/');
1096
1097#if VERBOSE_DECOMPOSE
1098      _dbus_verbose ("  (component in [%d,%d))\n",
1099                     i, j);
1100#endif
1101
1102      retval[comp] = _dbus_memdup (&data[i], j - i + 1);
1103      if (retval[comp] == NULL)
1104        {
1105          dbus_free_string_array (retval);
1106          return FALSE;
1107        }
1108      retval[comp][j-i] = '\0';
1109#if VERBOSE_DECOMPOSE
1110      _dbus_verbose ("  (component %d = \"%s\")\n",
1111                     comp, retval[comp]);
1112#endif
1113
1114      ++comp;
1115      i = j;
1116    }
1117  _dbus_assert (i == len);
1118
1119  *path = retval;
1120  if (path_len)
1121    *path_len = n_components;
1122
1123  return TRUE;
1124}
1125
1126/** @} */
1127
1128#ifdef DBUS_BUILD_TESTS
1129#include "dbus-test.h"
1130#include <stdio.h>
1131
1132static char*
1133flatten_path (const char **path)
1134{
1135  DBusString str;
1136  char *s;
1137
1138  if (!_dbus_string_init (&str))
1139    return NULL;
1140
1141  if (path[0] == NULL)
1142    {
1143      if (!_dbus_string_append_byte (&str, '/'))
1144        goto nomem;
1145    }
1146  else
1147    {
1148      int i;
1149
1150      i = 0;
1151      while (path[i])
1152        {
1153          if (!_dbus_string_append_byte (&str, '/'))
1154            goto nomem;
1155
1156          if (!_dbus_string_append (&str, path[i]))
1157            goto nomem;
1158
1159          ++i;
1160        }
1161    }
1162
1163  if (!_dbus_string_steal_data (&str, &s))
1164    goto nomem;
1165
1166  _dbus_string_free (&str);
1167
1168  return s;
1169
1170 nomem:
1171  _dbus_string_free (&str);
1172  return NULL;
1173}
1174
1175
1176typedef enum
1177{
1178  STR_EQUAL,
1179  STR_PREFIX,
1180  STR_DIFFERENT
1181} StrComparison;
1182
1183/* Returns TRUE if container is a parent of child
1184 */
1185static StrComparison
1186path_contains (const char **container,
1187               const char **child)
1188{
1189  int i;
1190
1191  i = 0;
1192  while (child[i] != NULL)
1193    {
1194      int v;
1195
1196      if (container[i] == NULL)
1197        return STR_PREFIX; /* container ran out, child continues;
1198			* thus the container is a parent of the
1199			* child.
1200			*/
1201
1202      _dbus_assert (container[i] != NULL);
1203      _dbus_assert (child[i] != NULL);
1204
1205      v = strcmp (container[i], child[i]);
1206
1207      if (v != 0)
1208        return STR_DIFFERENT; /* they overlap until here and then are different,
1209			   * not overlapping
1210			   */
1211
1212      ++i;
1213    }
1214
1215  /* Child ran out; if container also did, they are equal;
1216   * otherwise, the child is a parent of the container.
1217   */
1218  if (container[i] == NULL)
1219    return STR_EQUAL;
1220  else
1221    return STR_DIFFERENT;
1222}
1223
1224#if 0
1225static void
1226spew_subtree_recurse (DBusObjectSubtree *subtree,
1227                      int                indent)
1228{
1229  int i;
1230
1231  i = 0;
1232  while (i < indent)
1233    {
1234      _dbus_verbose (" ");
1235      ++i;
1236    }
1237
1238  _dbus_verbose ("%s (%d children)\n",
1239                 subtree->name, subtree->n_subtrees);
1240
1241  i = 0;
1242  while (i < subtree->n_subtrees)
1243    {
1244      spew_subtree_recurse (subtree->subtrees[i], indent + 2);
1245
1246      ++i;
1247    }
1248}
1249
1250static void
1251spew_tree (DBusObjectTree *tree)
1252{
1253  spew_subtree_recurse (tree->root, 0);
1254}
1255#endif
1256
1257/**
1258 * Callback data used in tests
1259 */
1260typedef struct
1261{
1262  const char **path; /**< Path */
1263  dbus_bool_t handler_fallback; /**< true if the handler may be called as fallback */
1264  dbus_bool_t message_handled; /**< Gets set to true if message handler called */
1265  dbus_bool_t handler_unregistered; /**< gets set to true if handler is unregistered */
1266} TreeTestData;
1267
1268
1269static void
1270test_unregister_function (DBusConnection  *connection,
1271                          void            *user_data)
1272{
1273  TreeTestData *ttd = user_data;
1274
1275  ttd->handler_unregistered = TRUE;
1276}
1277
1278static DBusHandlerResult
1279test_message_function (DBusConnection  *connection,
1280                       DBusMessage     *message,
1281                       void            *user_data)
1282{
1283  TreeTestData *ttd = user_data;
1284
1285  ttd->message_handled = TRUE;
1286
1287  return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1288}
1289
1290static dbus_bool_t
1291do_register (DBusObjectTree *tree,
1292             const char    **path,
1293             dbus_bool_t     fallback,
1294             int             i,
1295             TreeTestData   *tree_test_data)
1296{
1297  DBusObjectPathVTable vtable = { test_unregister_function,
1298                                  test_message_function, NULL };
1299
1300  tree_test_data[i].message_handled = FALSE;
1301  tree_test_data[i].handler_unregistered = FALSE;
1302  tree_test_data[i].handler_fallback = fallback;
1303  tree_test_data[i].path = path;
1304
1305  if (!_dbus_object_tree_register (tree, fallback, path,
1306                                   &vtable,
1307                                   &tree_test_data[i]))
1308    return FALSE;
1309
1310  return TRUE;
1311}
1312
1313static dbus_bool_t
1314do_test_dispatch (DBusObjectTree *tree,
1315                  const char    **path,
1316                  int             i,
1317                  TreeTestData   *tree_test_data,
1318                  int             n_test_data)
1319{
1320  DBusMessage *message;
1321  int j;
1322  DBusHandlerResult result;
1323  char *flat;
1324
1325  message = NULL;
1326
1327  flat = flatten_path (path);
1328  if (flat == NULL)
1329    goto oom;
1330
1331  message = dbus_message_new_method_call (NULL,
1332                                          flat,
1333                                          "org.freedesktop.TestInterface",
1334                                          "Foo");
1335  dbus_free (flat);
1336  if (message == NULL)
1337    goto oom;
1338
1339  j = 0;
1340  while (j < n_test_data)
1341    {
1342      tree_test_data[j].message_handled = FALSE;
1343      ++j;
1344    }
1345
1346  result = _dbus_object_tree_dispatch_and_unlock (tree, message);
1347  if (result == DBUS_HANDLER_RESULT_NEED_MEMORY)
1348    goto oom;
1349
1350  _dbus_assert (tree_test_data[i].message_handled);
1351
1352  j = 0;
1353  while (j < n_test_data)
1354    {
1355      if (tree_test_data[j].message_handled)
1356	{
1357	  if (tree_test_data[j].handler_fallback)
1358	    _dbus_assert (path_contains (tree_test_data[j].path,
1359					 path) != STR_DIFFERENT);
1360	  else
1361	    _dbus_assert (path_contains (tree_test_data[j].path, path) == STR_EQUAL);
1362	}
1363      else
1364	{
1365	  if (tree_test_data[j].handler_fallback)
1366	    _dbus_assert (path_contains (tree_test_data[j].path,
1367					 path) == STR_DIFFERENT);
1368	  else
1369	    _dbus_assert (path_contains (tree_test_data[j].path, path) != STR_EQUAL);
1370	}
1371
1372      ++j;
1373    }
1374
1375  dbus_message_unref (message);
1376
1377  return TRUE;
1378
1379 oom:
1380  if (message)
1381    dbus_message_unref (message);
1382  return FALSE;
1383}
1384
1385static size_t
1386string_array_length (const char **array)
1387{
1388  size_t i;
1389  for (i = 0; array[i]; i++) ;
1390  return i;
1391}
1392
1393typedef struct
1394{
1395  const char *path;
1396  const char *result[20];
1397} DecomposePathTest;
1398
1399static DecomposePathTest decompose_tests[] = {
1400  { "/foo", { "foo", NULL } },
1401  { "/foo/bar", { "foo", "bar", NULL } },
1402  { "/", { NULL } },
1403  { "/a/b", { "a", "b", NULL } },
1404  { "/a/b/c", { "a", "b", "c", NULL } },
1405  { "/a/b/c/d", { "a", "b", "c", "d", NULL } },
1406  { "/foo/bar/q", { "foo", "bar", "q", NULL } },
1407  { "/foo/bar/this/is/longer", { "foo", "bar", "this", "is", "longer", NULL } }
1408};
1409
1410static dbus_bool_t
1411run_decompose_tests (void)
1412{
1413  int i;
1414
1415  i = 0;
1416  while (i < _DBUS_N_ELEMENTS (decompose_tests))
1417    {
1418      char **result;
1419      int    result_len;
1420      int    expected_len;
1421
1422      if (!_dbus_decompose_path (decompose_tests[i].path,
1423                                 strlen (decompose_tests[i].path),
1424                                 &result, &result_len))
1425        return FALSE;
1426
1427      expected_len = string_array_length (decompose_tests[i].result);
1428
1429      if (result_len != (int) string_array_length ((const char**)result) ||
1430          expected_len != result_len ||
1431          path_contains (decompose_tests[i].result,
1432                         (const char**) result) != STR_EQUAL)
1433        {
1434          int real_len = string_array_length ((const char**)result);
1435          _dbus_warn ("Expected decompose of %s to have len %d, returned %d, appears to have %d\n",
1436                      decompose_tests[i].path, expected_len, result_len,
1437                      real_len);
1438          _dbus_warn ("Decompose resulted in elements: { ");
1439          i = 0;
1440          while (i < real_len)
1441            {
1442              _dbus_warn ("\"%s\"%s", result[i],
1443                          (i + 1) == real_len ? "" : ", ");
1444              ++i;
1445            }
1446          _dbus_warn ("}\n");
1447          _dbus_assert_not_reached ("path decompose failed\n");
1448        }
1449
1450      dbus_free_string_array (result);
1451
1452      ++i;
1453    }
1454
1455  return TRUE;
1456}
1457
1458static dbus_bool_t
1459object_tree_test_iteration (void *data)
1460{
1461  const char *path0[] = { NULL };
1462  const char *path1[] = { "foo", NULL };
1463  const char *path2[] = { "foo", "bar", NULL };
1464  const char *path3[] = { "foo", "bar", "baz", NULL };
1465  const char *path4[] = { "foo", "bar", "boo", NULL };
1466  const char *path5[] = { "blah", NULL };
1467  const char *path6[] = { "blah", "boof", NULL };
1468  const char *path7[] = { "blah", "boof", "this", "is", "really", "long", NULL };
1469  const char *path8[] = { "childless", NULL };
1470  DBusObjectTree *tree;
1471  TreeTestData tree_test_data[9];
1472  int i;
1473  dbus_bool_t exact_match;
1474
1475  if (!run_decompose_tests ())
1476    return FALSE;
1477
1478  tree = NULL;
1479
1480  tree = _dbus_object_tree_new (NULL);
1481  if (tree == NULL)
1482    goto out;
1483
1484  if (!do_register (tree, path0, TRUE, 0, tree_test_data))
1485    goto out;
1486
1487  _dbus_assert (find_subtree (tree, path0, NULL));
1488  _dbus_assert (!find_subtree (tree, path1, NULL));
1489  _dbus_assert (!find_subtree (tree, path2, NULL));
1490  _dbus_assert (!find_subtree (tree, path3, NULL));
1491  _dbus_assert (!find_subtree (tree, path4, NULL));
1492  _dbus_assert (!find_subtree (tree, path5, NULL));
1493  _dbus_assert (!find_subtree (tree, path6, NULL));
1494  _dbus_assert (!find_subtree (tree, path7, NULL));
1495  _dbus_assert (!find_subtree (tree, path8, NULL));
1496
1497  _dbus_assert (find_handler (tree, path0, &exact_match) && exact_match);
1498  _dbus_assert (find_handler (tree, path1, &exact_match) == tree->root && !exact_match);
1499  _dbus_assert (find_handler (tree, path2, &exact_match) == tree->root && !exact_match);
1500  _dbus_assert (find_handler (tree, path3, &exact_match) == tree->root && !exact_match);
1501  _dbus_assert (find_handler (tree, path4, &exact_match) == tree->root && !exact_match);
1502  _dbus_assert (find_handler (tree, path5, &exact_match) == tree->root && !exact_match);
1503  _dbus_assert (find_handler (tree, path6, &exact_match) == tree->root && !exact_match);
1504  _dbus_assert (find_handler (tree, path7, &exact_match) == tree->root && !exact_match);
1505  _dbus_assert (find_handler (tree, path8, &exact_match) == tree->root && !exact_match);
1506
1507  if (!do_register (tree, path1, TRUE, 1, tree_test_data))
1508    goto out;
1509
1510  _dbus_assert (find_subtree (tree, path0, NULL));
1511  _dbus_assert (find_subtree (tree, path1, NULL));
1512  _dbus_assert (!find_subtree (tree, path2, NULL));
1513  _dbus_assert (!find_subtree (tree, path3, NULL));
1514  _dbus_assert (!find_subtree (tree, path4, NULL));
1515  _dbus_assert (!find_subtree (tree, path5, NULL));
1516  _dbus_assert (!find_subtree (tree, path6, NULL));
1517  _dbus_assert (!find_subtree (tree, path7, NULL));
1518  _dbus_assert (!find_subtree (tree, path8, NULL));
1519
1520  _dbus_assert (find_handler (tree, path0, &exact_match) &&  exact_match);
1521  _dbus_assert (find_handler (tree, path1, &exact_match) &&  exact_match);
1522  _dbus_assert (find_handler (tree, path2, &exact_match) && !exact_match);
1523  _dbus_assert (find_handler (tree, path3, &exact_match) && !exact_match);
1524  _dbus_assert (find_handler (tree, path4, &exact_match) && !exact_match);
1525  _dbus_assert (find_handler (tree, path5, &exact_match) == tree->root && !exact_match);
1526  _dbus_assert (find_handler (tree, path6, &exact_match) == tree->root && !exact_match);
1527  _dbus_assert (find_handler (tree, path7, &exact_match) == tree->root && !exact_match);
1528  _dbus_assert (find_handler (tree, path8, &exact_match) == tree->root && !exact_match);
1529
1530  if (!do_register (tree, path2, TRUE, 2, tree_test_data))
1531    goto out;
1532
1533  _dbus_assert (find_subtree (tree, path1, NULL));
1534  _dbus_assert (find_subtree (tree, path2, NULL));
1535  _dbus_assert (!find_subtree (tree, path3, NULL));
1536  _dbus_assert (!find_subtree (tree, path4, NULL));
1537  _dbus_assert (!find_subtree (tree, path5, NULL));
1538  _dbus_assert (!find_subtree (tree, path6, NULL));
1539  _dbus_assert (!find_subtree (tree, path7, NULL));
1540  _dbus_assert (!find_subtree (tree, path8, NULL));
1541
1542  if (!do_register (tree, path3, TRUE, 3, tree_test_data))
1543    goto out;
1544
1545  _dbus_assert (find_subtree (tree, path0, NULL));
1546  _dbus_assert (find_subtree (tree, path1, NULL));
1547  _dbus_assert (find_subtree (tree, path2, NULL));
1548  _dbus_assert (find_subtree (tree, path3, NULL));
1549  _dbus_assert (!find_subtree (tree, path4, NULL));
1550  _dbus_assert (!find_subtree (tree, path5, NULL));
1551  _dbus_assert (!find_subtree (tree, path6, NULL));
1552  _dbus_assert (!find_subtree (tree, path7, NULL));
1553  _dbus_assert (!find_subtree (tree, path8, NULL));
1554
1555  if (!do_register (tree, path4, TRUE, 4, tree_test_data))
1556    goto out;
1557
1558  _dbus_assert (find_subtree (tree, path0, NULL));
1559  _dbus_assert (find_subtree (tree, path1, NULL));
1560  _dbus_assert (find_subtree (tree, path2, NULL));
1561  _dbus_assert (find_subtree (tree, path3, NULL));
1562  _dbus_assert (find_subtree (tree, path4, NULL));
1563  _dbus_assert (!find_subtree (tree, path5, NULL));
1564  _dbus_assert (!find_subtree (tree, path6, NULL));
1565  _dbus_assert (!find_subtree (tree, path7, NULL));
1566  _dbus_assert (!find_subtree (tree, path8, NULL));
1567
1568  if (!do_register (tree, path5, TRUE, 5, tree_test_data))
1569    goto out;
1570
1571  _dbus_assert (find_subtree (tree, path0, NULL));
1572  _dbus_assert (find_subtree (tree, path1, NULL));
1573  _dbus_assert (find_subtree (tree, path2, NULL));
1574  _dbus_assert (find_subtree (tree, path3, NULL));
1575  _dbus_assert (find_subtree (tree, path4, NULL));
1576  _dbus_assert (find_subtree (tree, path5, NULL));
1577  _dbus_assert (!find_subtree (tree, path6, NULL));
1578  _dbus_assert (!find_subtree (tree, path7, NULL));
1579  _dbus_assert (!find_subtree (tree, path8, NULL));
1580
1581  _dbus_assert (find_handler (tree, path0, &exact_match) == tree->root &&  exact_match);
1582  _dbus_assert (find_handler (tree, path1, &exact_match) != tree->root &&  exact_match);
1583  _dbus_assert (find_handler (tree, path2, &exact_match) != tree->root &&  exact_match);
1584  _dbus_assert (find_handler (tree, path3, &exact_match) != tree->root &&  exact_match);
1585  _dbus_assert (find_handler (tree, path4, &exact_match) != tree->root &&  exact_match);
1586  _dbus_assert (find_handler (tree, path5, &exact_match) != tree->root &&  exact_match);
1587  _dbus_assert (find_handler (tree, path6, &exact_match) != tree->root && !exact_match);
1588  _dbus_assert (find_handler (tree, path7, &exact_match) != tree->root && !exact_match);
1589  _dbus_assert (find_handler (tree, path8, &exact_match) == tree->root && !exact_match);
1590
1591  if (!do_register (tree, path6, TRUE, 6, tree_test_data))
1592    goto out;
1593
1594  _dbus_assert (find_subtree (tree, path0, NULL));
1595  _dbus_assert (find_subtree (tree, path1, NULL));
1596  _dbus_assert (find_subtree (tree, path2, NULL));
1597  _dbus_assert (find_subtree (tree, path3, NULL));
1598  _dbus_assert (find_subtree (tree, path4, NULL));
1599  _dbus_assert (find_subtree (tree, path5, NULL));
1600  _dbus_assert (find_subtree (tree, path6, NULL));
1601  _dbus_assert (!find_subtree (tree, path7, NULL));
1602  _dbus_assert (!find_subtree (tree, path8, NULL));
1603
1604  if (!do_register (tree, path7, TRUE, 7, tree_test_data))
1605    goto out;
1606
1607  _dbus_assert (find_subtree (tree, path0, NULL));
1608  _dbus_assert (find_subtree (tree, path1, NULL));
1609  _dbus_assert (find_subtree (tree, path2, NULL));
1610  _dbus_assert (find_subtree (tree, path3, NULL));
1611  _dbus_assert (find_subtree (tree, path4, NULL));
1612  _dbus_assert (find_subtree (tree, path5, NULL));
1613  _dbus_assert (find_subtree (tree, path6, NULL));
1614  _dbus_assert (find_subtree (tree, path7, NULL));
1615  _dbus_assert (!find_subtree (tree, path8, NULL));
1616
1617  if (!do_register (tree, path8, TRUE, 8, tree_test_data))
1618    goto out;
1619
1620  _dbus_assert (find_subtree (tree, path0, NULL));
1621  _dbus_assert (find_subtree (tree, path1, NULL));
1622  _dbus_assert (find_subtree (tree, path2, NULL));
1623  _dbus_assert (find_subtree (tree, path3, NULL));
1624  _dbus_assert (find_subtree (tree, path4, NULL));
1625  _dbus_assert (find_subtree (tree, path5, NULL));
1626  _dbus_assert (find_subtree (tree, path6, NULL));
1627  _dbus_assert (find_subtree (tree, path7, NULL));
1628  _dbus_assert (find_subtree (tree, path8, NULL));
1629
1630  _dbus_assert (find_handler (tree, path0, &exact_match) == tree->root &&  exact_match);
1631  _dbus_assert (find_handler (tree, path1, &exact_match) != tree->root && exact_match);
1632  _dbus_assert (find_handler (tree, path2, &exact_match) != tree->root && exact_match);
1633  _dbus_assert (find_handler (tree, path3, &exact_match) != tree->root && exact_match);
1634  _dbus_assert (find_handler (tree, path4, &exact_match) != tree->root && exact_match);
1635  _dbus_assert (find_handler (tree, path5, &exact_match) != tree->root && exact_match);
1636  _dbus_assert (find_handler (tree, path6, &exact_match) != tree->root && exact_match);
1637  _dbus_assert (find_handler (tree, path7, &exact_match) != tree->root && exact_match);
1638  _dbus_assert (find_handler (tree, path8, &exact_match) != tree->root && exact_match);
1639
1640  /* test the list_registered function */
1641
1642  {
1643    const char *root[] = { NULL };
1644    char **child_entries;
1645    int nb;
1646
1647    _dbus_object_tree_list_registered_unlocked (tree, path1, &child_entries);
1648    if (child_entries != NULL)
1649      {
1650	nb = string_array_length ((const char**)child_entries);
1651	_dbus_assert (nb == 1);
1652	dbus_free_string_array (child_entries);
1653      }
1654
1655    _dbus_object_tree_list_registered_unlocked (tree, path2, &child_entries);
1656    if (child_entries != NULL)
1657      {
1658	nb = string_array_length ((const char**)child_entries);
1659	_dbus_assert (nb == 2);
1660	dbus_free_string_array (child_entries);
1661      }
1662
1663    _dbus_object_tree_list_registered_unlocked (tree, path8, &child_entries);
1664    if (child_entries != NULL)
1665      {
1666	nb = string_array_length ((const char**)child_entries);
1667	_dbus_assert (nb == 0);
1668	dbus_free_string_array (child_entries);
1669      }
1670
1671    _dbus_object_tree_list_registered_unlocked (tree, root, &child_entries);
1672    if (child_entries != NULL)
1673      {
1674	nb = string_array_length ((const char**)child_entries);
1675	_dbus_assert (nb == 3);
1676	dbus_free_string_array (child_entries);
1677      }
1678  }
1679
1680  /* Check that destroying tree calls unregister funcs */
1681  _dbus_object_tree_unref (tree);
1682
1683  i = 0;
1684  while (i < (int) _DBUS_N_ELEMENTS (tree_test_data))
1685    {
1686      _dbus_assert (tree_test_data[i].handler_unregistered);
1687      _dbus_assert (!tree_test_data[i].message_handled);
1688      ++i;
1689    }
1690
1691  /* Now start again and try the individual unregister function */
1692  tree = _dbus_object_tree_new (NULL);
1693  if (tree == NULL)
1694    goto out;
1695
1696  if (!do_register (tree, path0, TRUE, 0, tree_test_data))
1697    goto out;
1698  if (!do_register (tree, path1, TRUE, 1, tree_test_data))
1699    goto out;
1700  if (!do_register (tree, path2, TRUE, 2, tree_test_data))
1701    goto out;
1702  if (!do_register (tree, path3, TRUE, 3, tree_test_data))
1703    goto out;
1704  if (!do_register (tree, path4, TRUE, 4, tree_test_data))
1705    goto out;
1706  if (!do_register (tree, path5, TRUE, 5, tree_test_data))
1707    goto out;
1708  if (!do_register (tree, path6, TRUE, 6, tree_test_data))
1709    goto out;
1710  if (!do_register (tree, path7, TRUE, 7, tree_test_data))
1711    goto out;
1712  if (!do_register (tree, path8, TRUE, 8, tree_test_data))
1713    goto out;
1714
1715  _dbus_object_tree_unregister_and_unlock (tree, path0);
1716
1717  _dbus_assert (!find_subtree (tree, path0, NULL));
1718  _dbus_assert (find_subtree (tree, path1, NULL));
1719  _dbus_assert (find_subtree (tree, path2, NULL));
1720  _dbus_assert (find_subtree (tree, path3, NULL));
1721  _dbus_assert (find_subtree (tree, path4, NULL));
1722  _dbus_assert (find_subtree (tree, path5, NULL));
1723  _dbus_assert (find_subtree (tree, path6, NULL));
1724  _dbus_assert (find_subtree (tree, path7, NULL));
1725  _dbus_assert (find_subtree (tree, path8, NULL));
1726
1727  _dbus_object_tree_unregister_and_unlock (tree, path1);
1728
1729  _dbus_assert (!find_subtree (tree, path0, NULL));
1730  _dbus_assert (!find_subtree (tree, path1, NULL));
1731  _dbus_assert (find_subtree (tree, path2, NULL));
1732  _dbus_assert (find_subtree (tree, path3, NULL));
1733  _dbus_assert (find_subtree (tree, path4, NULL));
1734  _dbus_assert (find_subtree (tree, path5, NULL));
1735  _dbus_assert (find_subtree (tree, path6, NULL));
1736  _dbus_assert (find_subtree (tree, path7, NULL));
1737  _dbus_assert (find_subtree (tree, path8, NULL));
1738
1739  _dbus_object_tree_unregister_and_unlock (tree, path2);
1740
1741  _dbus_assert (!find_subtree (tree, path0, NULL));
1742  _dbus_assert (!find_subtree (tree, path1, NULL));
1743  _dbus_assert (!find_subtree (tree, path2, NULL));
1744  _dbus_assert (find_subtree (tree, path3, NULL));
1745  _dbus_assert (find_subtree (tree, path4, NULL));
1746  _dbus_assert (find_subtree (tree, path5, NULL));
1747  _dbus_assert (find_subtree (tree, path6, NULL));
1748  _dbus_assert (find_subtree (tree, path7, NULL));
1749  _dbus_assert (find_subtree (tree, path8, NULL));
1750
1751  _dbus_object_tree_unregister_and_unlock (tree, path3);
1752
1753  _dbus_assert (!find_subtree (tree, path0, NULL));
1754  _dbus_assert (!find_subtree (tree, path1, NULL));
1755  _dbus_assert (!find_subtree (tree, path2, NULL));
1756  _dbus_assert (!find_subtree (tree, path3, NULL));
1757  _dbus_assert (find_subtree (tree, path4, NULL));
1758  _dbus_assert (find_subtree (tree, path5, NULL));
1759  _dbus_assert (find_subtree (tree, path6, NULL));
1760  _dbus_assert (find_subtree (tree, path7, NULL));
1761  _dbus_assert (find_subtree (tree, path8, NULL));
1762
1763  _dbus_object_tree_unregister_and_unlock (tree, path4);
1764
1765  _dbus_assert (!find_subtree (tree, path0, NULL));
1766  _dbus_assert (!find_subtree (tree, path1, NULL));
1767  _dbus_assert (!find_subtree (tree, path2, NULL));
1768  _dbus_assert (!find_subtree (tree, path3, NULL));
1769  _dbus_assert (!find_subtree (tree, path4, NULL));
1770  _dbus_assert (find_subtree (tree, path5, NULL));
1771  _dbus_assert (find_subtree (tree, path6, NULL));
1772  _dbus_assert (find_subtree (tree, path7, NULL));
1773  _dbus_assert (find_subtree (tree, path8, NULL));
1774
1775  _dbus_object_tree_unregister_and_unlock (tree, path5);
1776
1777  _dbus_assert (!find_subtree (tree, path0, NULL));
1778  _dbus_assert (!find_subtree (tree, path1, NULL));
1779  _dbus_assert (!find_subtree (tree, path2, NULL));
1780  _dbus_assert (!find_subtree (tree, path3, NULL));
1781  _dbus_assert (!find_subtree (tree, path4, NULL));
1782  _dbus_assert (!find_subtree (tree, path5, NULL));
1783  _dbus_assert (find_subtree (tree, path6, NULL));
1784  _dbus_assert (find_subtree (tree, path7, NULL));
1785  _dbus_assert (find_subtree (tree, path8, NULL));
1786
1787  _dbus_object_tree_unregister_and_unlock (tree, path6);
1788
1789  _dbus_assert (!find_subtree (tree, path0, NULL));
1790  _dbus_assert (!find_subtree (tree, path1, NULL));
1791  _dbus_assert (!find_subtree (tree, path2, NULL));
1792  _dbus_assert (!find_subtree (tree, path3, NULL));
1793  _dbus_assert (!find_subtree (tree, path4, NULL));
1794  _dbus_assert (!find_subtree (tree, path5, NULL));
1795  _dbus_assert (!find_subtree (tree, path6, NULL));
1796  _dbus_assert (find_subtree (tree, path7, NULL));
1797  _dbus_assert (find_subtree (tree, path8, NULL));
1798
1799  _dbus_object_tree_unregister_and_unlock (tree, path7);
1800
1801  _dbus_assert (!find_subtree (tree, path0, NULL));
1802  _dbus_assert (!find_subtree (tree, path1, NULL));
1803  _dbus_assert (!find_subtree (tree, path2, NULL));
1804  _dbus_assert (!find_subtree (tree, path3, NULL));
1805  _dbus_assert (!find_subtree (tree, path4, NULL));
1806  _dbus_assert (!find_subtree (tree, path5, NULL));
1807  _dbus_assert (!find_subtree (tree, path6, NULL));
1808  _dbus_assert (!find_subtree (tree, path7, NULL));
1809  _dbus_assert (find_subtree (tree, path8, NULL));
1810
1811  _dbus_object_tree_unregister_and_unlock (tree, path8);
1812
1813  _dbus_assert (!find_subtree (tree, path0, NULL));
1814  _dbus_assert (!find_subtree (tree, path1, NULL));
1815  _dbus_assert (!find_subtree (tree, path2, NULL));
1816  _dbus_assert (!find_subtree (tree, path3, NULL));
1817  _dbus_assert (!find_subtree (tree, path4, NULL));
1818  _dbus_assert (!find_subtree (tree, path5, NULL));
1819  _dbus_assert (!find_subtree (tree, path6, NULL));
1820  _dbus_assert (!find_subtree (tree, path7, NULL));
1821  _dbus_assert (!find_subtree (tree, path8, NULL));
1822
1823  i = 0;
1824  while (i < (int) _DBUS_N_ELEMENTS (tree_test_data))
1825    {
1826      _dbus_assert (tree_test_data[i].handler_unregistered);
1827      _dbus_assert (!tree_test_data[i].message_handled);
1828      ++i;
1829    }
1830
1831  /* Register it all again, and test dispatch */
1832
1833  if (!do_register (tree, path0, TRUE, 0, tree_test_data))
1834    goto out;
1835  if (!do_register (tree, path1, FALSE, 1, tree_test_data))
1836    goto out;
1837  if (!do_register (tree, path2, TRUE, 2, tree_test_data))
1838    goto out;
1839  if (!do_register (tree, path3, TRUE, 3, tree_test_data))
1840    goto out;
1841  if (!do_register (tree, path4, TRUE, 4, tree_test_data))
1842    goto out;
1843  if (!do_register (tree, path5, TRUE, 5, tree_test_data))
1844    goto out;
1845  if (!do_register (tree, path6, FALSE, 6, tree_test_data))
1846    goto out;
1847  if (!do_register (tree, path7, TRUE, 7, tree_test_data))
1848    goto out;
1849  if (!do_register (tree, path8, TRUE, 8, tree_test_data))
1850    goto out;
1851
1852#if 0
1853  spew_tree (tree);
1854#endif
1855
1856  if (!do_test_dispatch (tree, path0, 0, tree_test_data, _DBUS_N_ELEMENTS (tree_test_data)))
1857    goto out;
1858  if (!do_test_dispatch (tree, path1, 1, tree_test_data, _DBUS_N_ELEMENTS (tree_test_data)))
1859    goto out;
1860  if (!do_test_dispatch (tree, path2, 2, tree_test_data, _DBUS_N_ELEMENTS (tree_test_data)))
1861    goto out;
1862  if (!do_test_dispatch (tree, path3, 3, tree_test_data, _DBUS_N_ELEMENTS (tree_test_data)))
1863    goto out;
1864  if (!do_test_dispatch (tree, path4, 4, tree_test_data, _DBUS_N_ELEMENTS (tree_test_data)))
1865    goto out;
1866  if (!do_test_dispatch (tree, path5, 5, tree_test_data, _DBUS_N_ELEMENTS (tree_test_data)))
1867    goto out;
1868  if (!do_test_dispatch (tree, path6, 6, tree_test_data, _DBUS_N_ELEMENTS (tree_test_data)))
1869    goto out;
1870  if (!do_test_dispatch (tree, path7, 7, tree_test_data, _DBUS_N_ELEMENTS (tree_test_data)))
1871    goto out;
1872  if (!do_test_dispatch (tree, path8, 8, tree_test_data, _DBUS_N_ELEMENTS (tree_test_data)))
1873    goto out;
1874
1875 out:
1876  if (tree)
1877    {
1878      /* test ref */
1879      _dbus_object_tree_ref (tree);
1880      _dbus_object_tree_unref (tree);
1881      _dbus_object_tree_unref (tree);
1882    }
1883
1884  return TRUE;
1885}
1886
1887/**
1888 * @ingroup DBusObjectTree
1889 * Unit test for DBusObjectTree
1890 * @returns #TRUE on success.
1891 */
1892dbus_bool_t
1893_dbus_object_tree_test (void)
1894{
1895  _dbus_test_oom_handling ("object tree",
1896                           object_tree_test_iteration,
1897                           NULL);
1898
1899  return TRUE;
1900}
1901
1902#endif /* DBUS_BUILD_TESTS */
1903