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