D-Bus  1.6.8
dbus-object-tree.c
00001 /* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
00002 /* dbus-object-tree.c  DBusObjectTree (internals of DBusConnection)
00003  *
00004  * Copyright (C) 2003, 2005  Red Hat Inc.
00005  *
00006  * Licensed under the Academic Free License version 2.1
00007  *
00008  * This program is free software; you can redistribute it and/or modify
00009  * it under the terms of the GNU General Public License as published by
00010  * the Free Software Foundation; either version 2 of the License, or
00011  * (at your option) any later version.
00012  *
00013  * This program is distributed in the hope that it will be useful,
00014  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00015  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00016  * GNU General Public License for more details.
00017  *
00018  * You should have received a copy of the GNU General Public License
00019  * along with this program; if not, write to the Free Software
00020  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
00021  *
00022  */
00023 
00024 #include <config.h>
00025 #include "dbus-object-tree.h"
00026 #include "dbus-connection-internal.h"
00027 #include "dbus-internals.h"
00028 #include "dbus-hash.h"
00029 #include "dbus-protocol.h"
00030 #include "dbus-string.h"
00031 #include <string.h>
00032 #include <stdlib.h>
00033 
00046 typedef struct DBusObjectSubtree DBusObjectSubtree;
00047 
00048 static DBusObjectSubtree* _dbus_object_subtree_new   (const char                  *name,
00049                                                       const DBusObjectPathVTable  *vtable,
00050                                                       void                        *user_data);
00051 static DBusObjectSubtree* _dbus_object_subtree_ref   (DBusObjectSubtree           *subtree);
00052 static void               _dbus_object_subtree_unref (DBusObjectSubtree           *subtree);
00053 
00057 struct DBusObjectTree
00058 {
00059   int                 refcount;   
00060   DBusConnection     *connection; 
00062   DBusObjectSubtree  *root;       
00063 };
00064 
00070 struct DBusObjectSubtree
00071 {
00072   DBusAtomic                         refcount;            
00073   DBusObjectSubtree                 *parent;              
00074   DBusObjectPathUnregisterFunction   unregister_function; 
00075   DBusObjectPathMessageFunction      message_function;    
00076   void                              *user_data;           
00077   DBusObjectSubtree                **subtrees;            
00078   int                                n_subtrees;          
00079   int                                max_subtrees;        
00080   unsigned int                       invoke_as_fallback : 1; 
00081   char                               name[1]; 
00082 };
00083 
00091 DBusObjectTree*
00092 _dbus_object_tree_new (DBusConnection *connection)
00093 {
00094   DBusObjectTree *tree;
00095 
00096   /* the connection passed in here isn't fully constructed,
00097    * so don't do anything more than store a pointer to
00098    * it
00099    */
00100 
00101   tree = dbus_new0 (DBusObjectTree, 1);
00102   if (tree == NULL)
00103     goto oom;
00104 
00105   tree->refcount = 1;
00106   tree->connection = connection;
00107   tree->root = _dbus_object_subtree_new ("/", NULL, NULL);
00108   if (tree->root == NULL)
00109     goto oom;
00110   tree->root->invoke_as_fallback = TRUE;
00111   
00112   return tree;
00113 
00114  oom:
00115   if (tree)
00116     {
00117       dbus_free (tree);
00118     }
00119 
00120   return NULL;
00121 }
00122 
00128 DBusObjectTree *
00129 _dbus_object_tree_ref (DBusObjectTree *tree)
00130 {
00131   _dbus_assert (tree->refcount > 0);
00132 
00133   tree->refcount += 1;
00134 
00135   return tree;
00136 }
00137 
00142 void
00143 _dbus_object_tree_unref (DBusObjectTree *tree)
00144 {
00145   _dbus_assert (tree->refcount > 0);
00146 
00147   tree->refcount -= 1;
00148 
00149   if (tree->refcount == 0)
00150     {
00151       _dbus_object_tree_free_all_unlocked (tree);
00152 
00153       dbus_free (tree);
00154     }
00155 }
00156 
00160 #define VERBOSE_FIND 0
00161 
00162 static DBusObjectSubtree*
00163 find_subtree_recurse (DBusObjectSubtree  *subtree,
00164                       const char        **path,
00165                       dbus_bool_t         create_if_not_found,
00166                       int                *index_in_parent,
00167                       dbus_bool_t        *exact_match)
00168 {
00169   int i, j;
00170   dbus_bool_t return_deepest_match;
00171 
00172   return_deepest_match = exact_match != NULL;
00173 
00174   _dbus_assert (!(return_deepest_match && create_if_not_found));
00175 
00176   if (path[0] == NULL)
00177     {
00178 #if VERBOSE_FIND
00179       _dbus_verbose ("  path exhausted, returning %s\n",
00180                      subtree->name);
00181 #endif
00182       if (exact_match != NULL)
00183         *exact_match = TRUE;
00184       return subtree;
00185     }
00186 
00187 #if VERBOSE_FIND
00188   _dbus_verbose ("  searching children of %s for %s\n",
00189                  subtree->name, path[0]);
00190 #endif
00191   
00192   i = 0;
00193   j = subtree->n_subtrees;
00194   while (i < j)
00195     {
00196       int k, v;
00197 
00198       k = (i + j) / 2;
00199       v = strcmp (path[0], subtree->subtrees[k]->name);
00200 
00201 #if VERBOSE_FIND
00202       _dbus_verbose ("  %s cmp %s = %d\n",
00203                      path[0], subtree->subtrees[k]->name,
00204                      v);
00205 #endif
00206       
00207       if (v == 0)
00208         {
00209           if (index_in_parent)
00210             {
00211 #if VERBOSE_FIND
00212               _dbus_verbose ("  storing parent index %d\n", k);
00213 #endif
00214               *index_in_parent = k;
00215             }
00216 
00217           if (return_deepest_match)
00218             {
00219               DBusObjectSubtree *next;
00220 
00221               next = find_subtree_recurse (subtree->subtrees[k],
00222                                            &path[1], create_if_not_found, 
00223                                            index_in_parent, exact_match);
00224               if (next == NULL &&
00225                   subtree->invoke_as_fallback)
00226                 {
00227 #if VERBOSE_FIND
00228                   _dbus_verbose ("  no deeper match found, returning %s\n",
00229                                  subtree->name);
00230 #endif
00231                   if (exact_match != NULL)
00232                     *exact_match = FALSE;
00233                   return subtree;
00234                 }
00235               else
00236                 return next;
00237             }
00238           else
00239             return find_subtree_recurse (subtree->subtrees[k],
00240                                          &path[1], create_if_not_found, 
00241                                          index_in_parent, exact_match);
00242         }
00243       else if (v < 0)
00244         {
00245           j = k;
00246         }
00247       else
00248         {
00249           i = k + 1;
00250         }
00251     }
00252 
00253 #if VERBOSE_FIND
00254   _dbus_verbose ("  no match found, current tree %s, create_if_not_found = %d\n",
00255                  subtree->name, create_if_not_found);
00256 #endif
00257   
00258   if (create_if_not_found)
00259     {
00260       DBusObjectSubtree* child;
00261       int child_pos, new_n_subtrees;
00262 
00263 #if VERBOSE_FIND
00264       _dbus_verbose ("  creating subtree %s\n",
00265                      path[0]);
00266 #endif
00267       
00268       child = _dbus_object_subtree_new (path[0],
00269                                         NULL, NULL);
00270       if (child == NULL)
00271         return NULL;
00272 
00273       new_n_subtrees = subtree->n_subtrees + 1;
00274       if (new_n_subtrees > subtree->max_subtrees)
00275         {
00276           int new_max_subtrees;
00277           DBusObjectSubtree **new_subtrees;
00278 
00279           new_max_subtrees = subtree->max_subtrees == 0 ? 1 : 2 * subtree->max_subtrees;
00280           new_subtrees = dbus_realloc (subtree->subtrees,
00281                                        new_max_subtrees * sizeof (DBusObjectSubtree*));
00282           if (new_subtrees == NULL)
00283             {
00284               _dbus_object_subtree_unref (child);
00285               return NULL;
00286             }
00287           subtree->subtrees = new_subtrees;
00288           subtree->max_subtrees = new_max_subtrees;
00289         }
00290 
00291       /* The binary search failed, so i == j points to the 
00292          place the child should be inserted. */
00293       child_pos = i;
00294       _dbus_assert (child_pos < new_n_subtrees &&
00295                     new_n_subtrees <= subtree->max_subtrees);
00296       if (child_pos + 1 < new_n_subtrees)
00297         {
00298           memmove (&subtree->subtrees[child_pos+1], 
00299                    &subtree->subtrees[child_pos], 
00300                    (new_n_subtrees - child_pos - 1) * 
00301                    sizeof subtree->subtrees[0]);
00302         }
00303       subtree->subtrees[child_pos] = child;
00304 
00305       if (index_in_parent)
00306         *index_in_parent = child_pos;
00307       subtree->n_subtrees = new_n_subtrees;
00308       child->parent = subtree;
00309 
00310       return find_subtree_recurse (child,
00311                                    &path[1], create_if_not_found, 
00312                                    index_in_parent, exact_match);
00313     }
00314   else
00315     {
00316       if (exact_match != NULL)
00317         *exact_match = FALSE;
00318       return (return_deepest_match && subtree->invoke_as_fallback) ? subtree : NULL;
00319     }
00320 }
00321 
00322 static DBusObjectSubtree*
00323 find_subtree (DBusObjectTree *tree,
00324               const char    **path,
00325               int            *index_in_parent)
00326 {
00327   DBusObjectSubtree *subtree;
00328 
00329 #if VERBOSE_FIND
00330   _dbus_verbose ("Looking for exact registered subtree\n");
00331 #endif
00332   
00333   subtree = find_subtree_recurse (tree->root, path, FALSE, index_in_parent, NULL);
00334 
00335   if (subtree && subtree->message_function == NULL)
00336     return NULL;
00337   else
00338     return subtree;
00339 }
00340 
00341 static DBusObjectSubtree*
00342 lookup_subtree (DBusObjectTree *tree,
00343                 const char    **path)
00344 {
00345 #if VERBOSE_FIND
00346   _dbus_verbose ("Looking for subtree\n");
00347 #endif
00348   return find_subtree_recurse (tree->root, path, FALSE, NULL, NULL);
00349 }
00350 
00351 static DBusObjectSubtree*
00352 find_handler (DBusObjectTree *tree,
00353               const char    **path,
00354               dbus_bool_t    *exact_match)
00355 {
00356 #if VERBOSE_FIND
00357   _dbus_verbose ("Looking for deepest handler\n");
00358 #endif
00359   _dbus_assert (exact_match != NULL);
00360 
00361   *exact_match = FALSE; /* ensure always initialized */
00362   
00363   return find_subtree_recurse (tree->root, path, FALSE, NULL, exact_match);
00364 }
00365 
00366 static DBusObjectSubtree*
00367 ensure_subtree (DBusObjectTree *tree,
00368                 const char    **path)
00369 {
00370 #if VERBOSE_FIND
00371   _dbus_verbose ("Ensuring subtree\n");
00372 #endif
00373   return find_subtree_recurse (tree->root, path, TRUE, NULL, NULL);
00374 }
00375 
00376 static char *flatten_path (const char **path);
00377 
00390 dbus_bool_t
00391 _dbus_object_tree_register (DBusObjectTree              *tree,
00392                             dbus_bool_t                  fallback,
00393                             const char                 **path,
00394                             const DBusObjectPathVTable  *vtable,
00395                             void                        *user_data,
00396                             DBusError                   *error)
00397 {
00398   DBusObjectSubtree  *subtree;
00399 
00400   _dbus_assert (tree != NULL);
00401   _dbus_assert (vtable->message_function != NULL);
00402   _dbus_assert (path != NULL);
00403 
00404   subtree = ensure_subtree (tree, path);
00405   if (subtree == NULL)
00406     {
00407       _DBUS_SET_OOM (error);
00408       return FALSE;
00409     }
00410 
00411   if (subtree->message_function != NULL)
00412     {
00413       if (error != NULL)
00414         {
00415           char *complete_path = flatten_path (path);
00416 
00417           dbus_set_error (error, DBUS_ERROR_OBJECT_PATH_IN_USE,
00418                           "A handler is already registered for %s",
00419                           complete_path ? complete_path
00420                                         : "(cannot represent path: out of memory!)");
00421 
00422           dbus_free (complete_path);
00423         }
00424 
00425       return FALSE;
00426     }
00427 
00428   subtree->message_function = vtable->message_function;
00429   subtree->unregister_function = vtable->unregister_function;
00430   subtree->user_data = user_data;
00431   subtree->invoke_as_fallback = fallback != FALSE;
00432 
00433   return TRUE;
00434 }
00435 
00443 void
00444 _dbus_object_tree_unregister_and_unlock (DBusObjectTree          *tree,
00445                                          const char             **path)
00446 {
00447   int i;
00448   DBusObjectSubtree *subtree;
00449   DBusObjectPathUnregisterFunction unregister_function;
00450   void *user_data;
00451   DBusConnection *connection;
00452 
00453   _dbus_assert (path != NULL);
00454 
00455   unregister_function = NULL;
00456   user_data = NULL;
00457 
00458   subtree = find_subtree (tree, path, &i);
00459 
00460 #ifndef DBUS_DISABLE_CHECKS
00461   if (subtree == NULL)
00462     {
00463       _dbus_warn ("Attempted to unregister path (path[0] = %s path[1] = %s) which isn't registered\n",
00464                   path[0] ? path[0] : "null",
00465                   path[1] ? path[1] : "null");
00466       goto unlock;    
00467     }
00468 #else
00469   _dbus_assert (subtree != NULL);
00470 #endif
00471 
00472   _dbus_assert (subtree->parent == NULL ||
00473                 (i >= 0 && subtree->parent->subtrees[i] == subtree));
00474 
00475   subtree->message_function = NULL;
00476 
00477   unregister_function = subtree->unregister_function;
00478   user_data = subtree->user_data;
00479 
00480   subtree->unregister_function = NULL;
00481   subtree->user_data = NULL;
00482 
00483   /* If we have no subtrees of our own, remove from
00484    * our parent (FIXME could also be more aggressive
00485    * and remove our parent if it becomes empty)
00486    */
00487   if (subtree->parent && subtree->n_subtrees == 0)
00488     {
00489       /* assumes a 0-byte memmove is OK */
00490       memmove (&subtree->parent->subtrees[i],
00491                &subtree->parent->subtrees[i+1],
00492                (subtree->parent->n_subtrees - i - 1) *
00493                sizeof (subtree->parent->subtrees[0]));
00494       subtree->parent->n_subtrees -= 1;
00495 
00496       subtree->parent = NULL;
00497 
00498       _dbus_object_subtree_unref (subtree);
00499     }
00500   subtree = NULL;
00501 
00502 unlock:
00503   connection = tree->connection;
00504 
00505   /* Unlock and call application code */
00506 #ifdef DBUS_BUILD_TESTS
00507   if (connection)
00508 #endif
00509     {
00510       _dbus_connection_ref_unlocked (connection);
00511       _dbus_verbose ("unlock\n");
00512       _dbus_connection_unlock (connection);
00513     }
00514 
00515   if (unregister_function)
00516     (* unregister_function) (connection, user_data);
00517 
00518 #ifdef DBUS_BUILD_TESTS
00519   if (connection)
00520 #endif
00521     dbus_connection_unref (connection);
00522 }
00523 
00524 static void
00525 free_subtree_recurse (DBusConnection    *connection,
00526                       DBusObjectSubtree *subtree)
00527 {
00528   /* Delete them from the end, for slightly
00529    * more robustness against odd reentrancy.
00530    */
00531   while (subtree->n_subtrees > 0)
00532     {
00533       DBusObjectSubtree *child;
00534 
00535       child = subtree->subtrees[subtree->n_subtrees - 1];
00536       subtree->subtrees[subtree->n_subtrees - 1] = NULL;
00537       subtree->n_subtrees -= 1;
00538       child->parent = NULL;
00539 
00540       free_subtree_recurse (connection, child);
00541     }
00542 
00543   /* Call application code */
00544   if (subtree->unregister_function)
00545     (* subtree->unregister_function) (connection,
00546                                       subtree->user_data);
00547 
00548   subtree->message_function = NULL;
00549   subtree->unregister_function = NULL;
00550   subtree->user_data = NULL;
00551 
00552   /* Now free ourselves */
00553   _dbus_object_subtree_unref (subtree);
00554 }
00555 
00562 void
00563 _dbus_object_tree_free_all_unlocked (DBusObjectTree *tree)
00564 {
00565   if (tree->root)
00566     free_subtree_recurse (tree->connection,
00567                           tree->root);
00568   tree->root = NULL;
00569 }
00570 
00571 static dbus_bool_t
00572 _dbus_object_tree_list_registered_unlocked (DBusObjectTree *tree,
00573                                             const char    **parent_path,
00574                                             char         ***child_entries)
00575 {
00576   DBusObjectSubtree *subtree;
00577   char **retval;
00578   
00579   _dbus_assert (parent_path != NULL);
00580   _dbus_assert (child_entries != NULL);
00581 
00582   *child_entries = NULL;
00583   
00584   subtree = lookup_subtree (tree, parent_path);
00585   if (subtree == NULL)
00586     {
00587       retval = dbus_new0 (char *, 1);
00588     }
00589   else
00590     {
00591       int i;
00592       retval = dbus_new0 (char*, subtree->n_subtrees + 1);
00593       if (retval == NULL)
00594         goto out;
00595       i = 0;
00596       while (i < subtree->n_subtrees)
00597         {
00598           retval[i] = _dbus_strdup (subtree->subtrees[i]->name);
00599           if (retval[i] == NULL)
00600             {
00601               dbus_free_string_array (retval);
00602               retval = NULL;
00603               goto out;
00604             }
00605           ++i;
00606         }
00607     }
00608 
00609  out:
00610     
00611   *child_entries = retval;
00612   return retval != NULL;
00613 }
00614 
00615 static DBusHandlerResult
00616 handle_default_introspect_and_unlock (DBusObjectTree          *tree,
00617                                       DBusMessage             *message,
00618                                       const char             **path)
00619 {
00620   DBusString xml;
00621   DBusHandlerResult result;
00622   char **children;
00623   int i;
00624   DBusMessage *reply;
00625   DBusMessageIter iter;
00626   const char *v_STRING;
00627   dbus_bool_t already_unlocked;
00628 
00629   /* We have the connection lock here */
00630 
00631   already_unlocked = FALSE;
00632   
00633   _dbus_verbose (" considering default Introspect() handler...\n");
00634 
00635   reply = NULL;
00636   
00637   if (!dbus_message_is_method_call (message,
00638                                     DBUS_INTERFACE_INTROSPECTABLE,
00639                                     "Introspect"))
00640     {
00641 #ifdef DBUS_BUILD_TESTS
00642       if (tree->connection)
00643 #endif
00644         {
00645           _dbus_verbose ("unlock\n");
00646           _dbus_connection_unlock (tree->connection);
00647         }
00648       
00649       return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
00650     }
00651 
00652   _dbus_verbose (" using default Introspect() handler!\n");
00653   
00654   if (!_dbus_string_init (&xml))
00655     {
00656 #ifdef DBUS_BUILD_TESTS
00657       if (tree->connection)
00658 #endif
00659         {
00660           _dbus_verbose ("unlock\n");
00661           _dbus_connection_unlock (tree->connection);
00662         }
00663 
00664       return DBUS_HANDLER_RESULT_NEED_MEMORY;
00665     }
00666 
00667   result = DBUS_HANDLER_RESULT_NEED_MEMORY;
00668 
00669   children = NULL;
00670   if (!_dbus_object_tree_list_registered_unlocked (tree, path, &children))
00671     goto out;
00672 
00673   if (!_dbus_string_append (&xml, DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE))
00674     goto out;
00675   
00676   if (!_dbus_string_append (&xml, "<node>\n"))
00677     goto out;
00678 
00679   i = 0;
00680   while (children[i] != NULL)
00681     {
00682       if (!_dbus_string_append_printf (&xml, "  <node name=\"%s\"/>\n",
00683                                        children[i]))
00684         goto out;
00685 
00686       ++i;
00687     }
00688 
00689   if (!_dbus_string_append (&xml, "</node>\n"))
00690     goto out;
00691 
00692   reply = dbus_message_new_method_return (message);
00693   if (reply == NULL)
00694     goto out;
00695 
00696   dbus_message_iter_init_append (reply, &iter);
00697   v_STRING = _dbus_string_get_const_data (&xml);
00698   if (!dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &v_STRING))
00699     goto out;
00700   
00701 #ifdef DBUS_BUILD_TESTS
00702   if (tree->connection)
00703 #endif
00704     {
00705       already_unlocked = TRUE;
00706       
00707       if (!_dbus_connection_send_and_unlock (tree->connection, reply, NULL))
00708         goto out;
00709     }
00710   
00711   result = DBUS_HANDLER_RESULT_HANDLED;
00712   
00713  out:
00714 #ifdef DBUS_BUILD_TESTS
00715   if (tree->connection)
00716 #endif
00717     {
00718       if (!already_unlocked)
00719         {
00720           _dbus_verbose ("unlock\n");
00721           _dbus_connection_unlock (tree->connection);
00722         }
00723     }
00724   
00725   _dbus_string_free (&xml);
00726   dbus_free_string_array (children);
00727   if (reply)
00728     dbus_message_unref (reply);
00729   
00730   return result;
00731 }
00732 
00746 DBusHandlerResult
00747 _dbus_object_tree_dispatch_and_unlock (DBusObjectTree          *tree,
00748                                        DBusMessage             *message,
00749                                        dbus_bool_t             *found_object)
00750 {
00751   char **path;
00752   dbus_bool_t exact_match;
00753   DBusList *list;
00754   DBusList *link;
00755   DBusHandlerResult result;
00756   DBusObjectSubtree *subtree;
00757   
00758 #if 0
00759   _dbus_verbose ("Dispatch of message by object path\n");
00760 #endif
00761   
00762   path = NULL;
00763   if (!dbus_message_get_path_decomposed (message, &path))
00764     {
00765 #ifdef DBUS_BUILD_TESTS
00766       if (tree->connection)
00767 #endif
00768         {
00769           _dbus_verbose ("unlock\n");
00770           _dbus_connection_unlock (tree->connection);
00771         }
00772       
00773       _dbus_verbose ("No memory to get decomposed path\n");
00774 
00775       return DBUS_HANDLER_RESULT_NEED_MEMORY;
00776     }
00777 
00778   if (path == NULL)
00779     {
00780 #ifdef DBUS_BUILD_TESTS
00781       if (tree->connection)
00782 #endif
00783         {
00784           _dbus_verbose ("unlock\n");
00785           _dbus_connection_unlock (tree->connection);
00786         }
00787       
00788       _dbus_verbose ("No path field in message\n");
00789       return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
00790     }
00791   
00792   /* Find the deepest path that covers the path in the message */
00793   subtree = find_handler (tree, (const char**) path, &exact_match);
00794   
00795   if (found_object)
00796     *found_object = !!subtree;
00797 
00798   /* Build a list of all paths that cover the path in the message */
00799 
00800   list = NULL;
00801 
00802   while (subtree != NULL)
00803     {
00804       if (subtree->message_function != NULL && (exact_match || subtree->invoke_as_fallback))
00805         {
00806           _dbus_object_subtree_ref (subtree);
00807 
00808           /* run deepest paths first */
00809           if (!_dbus_list_append (&list, subtree))
00810             {
00811               result = DBUS_HANDLER_RESULT_NEED_MEMORY;
00812               _dbus_object_subtree_unref (subtree);
00813               goto free_and_return;
00814             }
00815         }
00816 
00817       exact_match = FALSE;
00818       subtree = subtree->parent;
00819     }
00820 
00821   _dbus_verbose ("%d handlers in the path tree for this message\n",
00822                  _dbus_list_get_length (&list));
00823 
00824   /* Invoke each handler in the list */
00825 
00826   result = DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
00827 
00828   link = _dbus_list_get_first_link (&list);
00829   while (link != NULL)
00830     {
00831       DBusList *next = _dbus_list_get_next_link (&list, link);
00832       subtree = link->data;
00833 
00834       /* message_function is NULL if we're unregistered
00835        * due to reentrancy
00836        */
00837       if (subtree->message_function)
00838         {
00839           DBusObjectPathMessageFunction message_function;
00840           void *user_data;
00841 
00842           message_function = subtree->message_function;
00843           user_data = subtree->user_data;
00844 
00845 #if 0
00846           _dbus_verbose ("  (invoking a handler)\n");
00847 #endif
00848           
00849 #ifdef DBUS_BUILD_TESTS
00850           if (tree->connection)
00851 #endif
00852             {
00853               _dbus_verbose ("unlock\n");
00854               _dbus_connection_unlock (tree->connection);
00855             }
00856 
00857           /* FIXME you could unregister the subtree in another thread
00858            * before we invoke the callback, and I can't figure out a
00859            * good way to solve this.
00860            */
00861 
00862           result = (* message_function) (tree->connection,
00863                                          message,
00864                                          user_data);
00865 
00866 #ifdef DBUS_BUILD_TESTS
00867           if (tree->connection)
00868 #endif
00869             _dbus_connection_lock (tree->connection);
00870 
00871           if (result != DBUS_HANDLER_RESULT_NOT_YET_HANDLED)
00872             goto free_and_return;
00873         }
00874 
00875       link = next;
00876     }
00877 
00878  free_and_return:
00879 
00880   if (result == DBUS_HANDLER_RESULT_NOT_YET_HANDLED)
00881     {
00882       /* This hardcoded default handler does a minimal Introspect()
00883        */
00884       result = handle_default_introspect_and_unlock (tree, message,
00885                                                      (const char**) path);
00886     }
00887   else
00888     {
00889 #ifdef DBUS_BUILD_TESTS
00890       if (tree->connection)
00891 #endif
00892         {
00893           _dbus_verbose ("unlock\n");
00894           _dbus_connection_unlock (tree->connection);
00895         }
00896     }
00897   
00898   while (list != NULL)
00899     {
00900       link = _dbus_list_get_first_link (&list);
00901       _dbus_object_subtree_unref (link->data);
00902       _dbus_list_remove_link (&list, link);
00903     }
00904   
00905   dbus_free_string_array (path);
00906 
00907   return result;
00908 }
00909 
00918 void*
00919 _dbus_object_tree_get_user_data_unlocked (DBusObjectTree *tree,
00920                                           const char    **path)
00921 {
00922   dbus_bool_t exact_match;
00923   DBusObjectSubtree *subtree;
00924 
00925   _dbus_assert (tree != NULL);
00926   _dbus_assert (path != NULL);
00927   
00928   /* Find the deepest path that covers the path in the message */
00929   subtree = find_handler (tree, (const char**) path, &exact_match);
00930 
00931   if ((subtree == NULL) || !exact_match)
00932     {
00933       _dbus_verbose ("No object at specified path found\n");
00934       return NULL;
00935     }
00936 
00937   return subtree->user_data;
00938 }
00939 
00946 static DBusObjectSubtree*
00947 allocate_subtree_object (const char *name)
00948 {
00949   int len;
00950   DBusObjectSubtree *subtree;
00951   const size_t front_padding = _DBUS_STRUCT_OFFSET (DBusObjectSubtree, name);
00952 
00953   _dbus_assert (name != NULL);
00954 
00955   len = strlen (name);
00956 
00957   subtree = dbus_malloc0 (MAX (front_padding + (len + 1), sizeof (DBusObjectSubtree)));
00958 
00959   if (subtree == NULL)
00960     return NULL;
00961 
00962   memcpy (subtree->name, name, len + 1);
00963 
00964   return subtree;
00965 }
00966 
00967 static DBusObjectSubtree*
00968 _dbus_object_subtree_new (const char                  *name,
00969                           const DBusObjectPathVTable  *vtable,
00970                           void                        *user_data)
00971 {
00972   DBusObjectSubtree *subtree;
00973 
00974   subtree = allocate_subtree_object (name);
00975   if (subtree == NULL)
00976     goto oom;
00977 
00978   _dbus_assert (name != NULL);
00979 
00980   subtree->parent = NULL;
00981 
00982   if (vtable)
00983     {
00984       subtree->message_function = vtable->message_function;
00985       subtree->unregister_function = vtable->unregister_function;
00986     }
00987   else
00988     {
00989       subtree->message_function = NULL;
00990       subtree->unregister_function = NULL;
00991     }
00992 
00993   subtree->user_data = user_data;
00994   _dbus_atomic_inc (&subtree->refcount);
00995   subtree->subtrees = NULL;
00996   subtree->n_subtrees = 0;
00997   subtree->max_subtrees = 0;
00998   subtree->invoke_as_fallback = FALSE;
00999 
01000   return subtree;
01001 
01002  oom:
01003   return NULL;
01004 }
01005 
01006 static DBusObjectSubtree *
01007 _dbus_object_subtree_ref (DBusObjectSubtree *subtree)
01008 {
01009 #ifdef DBUS_DISABLE_ASSERT
01010   _dbus_atomic_inc (&subtree->refcount);
01011 #else
01012   dbus_int32_t old_value;
01013 
01014   old_value = _dbus_atomic_inc (&subtree->refcount);
01015   _dbus_assert (old_value > 0);
01016 #endif
01017 
01018   return subtree;
01019 }
01020 
01021 static void
01022 _dbus_object_subtree_unref (DBusObjectSubtree *subtree)
01023 {
01024   dbus_int32_t old_value;
01025 
01026   old_value = _dbus_atomic_dec (&subtree->refcount);
01027   _dbus_assert (old_value > 0);
01028 
01029   if (old_value == 1)
01030     {
01031       _dbus_assert (subtree->unregister_function == NULL);
01032       _dbus_assert (subtree->message_function == NULL);
01033 
01034       dbus_free (subtree->subtrees);
01035       dbus_free (subtree);
01036     }
01037 }
01038 
01049 dbus_bool_t
01050 _dbus_object_tree_list_registered_and_unlock (DBusObjectTree *tree,
01051                                               const char    **parent_path,
01052                                               char         ***child_entries)
01053 {
01054   dbus_bool_t result;
01055 
01056   result = _dbus_object_tree_list_registered_unlocked (tree,
01057                                                        parent_path,
01058                                                        child_entries);
01059   
01060 #ifdef DBUS_BUILD_TESTS
01061   if (tree->connection)
01062 #endif
01063     {
01064       _dbus_verbose ("unlock\n");
01065       _dbus_connection_unlock (tree->connection);
01066     }
01067 
01068   return result;
01069 }
01070 
01071 
01073 #define VERBOSE_DECOMPOSE 0
01074 
01085 dbus_bool_t
01086 _dbus_decompose_path (const char*     data,
01087                       int             len,
01088                       char         ***path,
01089                       int            *path_len)
01090 {
01091   char **retval;
01092   int n_components;
01093   int i, j, comp;
01094 
01095   _dbus_assert (data != NULL);
01096   _dbus_assert (path != NULL);
01097   
01098 #if VERBOSE_DECOMPOSE
01099   _dbus_verbose ("Decomposing path \"%s\"\n",
01100                  data);
01101 #endif
01102   
01103   n_components = 0;
01104   if (len > 1) /* if path is not just "/" */
01105     {
01106       i = 0;
01107       while (i < len)
01108         {
01109           _dbus_assert (data[i] != '\0');
01110           if (data[i] == '/')
01111             n_components += 1;
01112           ++i;
01113         }
01114     }
01115   
01116   retval = dbus_new0 (char*, n_components + 1);
01117 
01118   if (retval == NULL)
01119     return FALSE;
01120 
01121   comp = 0;
01122   if (n_components == 0)
01123     i = 1;
01124   else
01125     i = 0;
01126   while (comp < n_components)
01127     {
01128       _dbus_assert (i < len);
01129       
01130       if (data[i] == '/')
01131         ++i;
01132       j = i;
01133 
01134       while (j < len && data[j] != '/')
01135         ++j;
01136 
01137       /* Now [i, j) is the path component */
01138       _dbus_assert (i < j);
01139       _dbus_assert (data[i] != '/');
01140       _dbus_assert (j == len || data[j] == '/');
01141 
01142 #if VERBOSE_DECOMPOSE
01143       _dbus_verbose ("  (component in [%d,%d))\n",
01144                      i, j);
01145 #endif
01146       
01147       retval[comp] = _dbus_memdup (&data[i], j - i + 1);
01148       if (retval[comp] == NULL)
01149         {
01150           dbus_free_string_array (retval);
01151           return FALSE;
01152         }
01153       retval[comp][j-i] = '\0';
01154 #if VERBOSE_DECOMPOSE
01155       _dbus_verbose ("  (component %d = \"%s\")\n",
01156                      comp, retval[comp]);
01157 #endif
01158 
01159       ++comp;
01160       i = j;
01161     }
01162   _dbus_assert (i == len);
01163   
01164   *path = retval;
01165   if (path_len)
01166     *path_len = n_components;
01167   
01168   return TRUE;
01169 }
01170 
01173 static char*
01174 flatten_path (const char **path)
01175 {
01176   DBusString str;
01177   char *s;
01178 
01179   if (!_dbus_string_init (&str))
01180     return NULL;
01181 
01182   if (path[0] == NULL)
01183     {
01184       if (!_dbus_string_append_byte (&str, '/'))
01185         goto nomem;
01186     }
01187   else
01188     {
01189       int i;
01190       
01191       i = 0;
01192       while (path[i])
01193         {
01194           if (!_dbus_string_append_byte (&str, '/'))
01195             goto nomem;
01196           
01197           if (!_dbus_string_append (&str, path[i]))
01198             goto nomem;
01199           
01200           ++i;
01201         }
01202     }
01203 
01204   if (!_dbus_string_steal_data (&str, &s))
01205     goto nomem;
01206 
01207   _dbus_string_free (&str);
01208 
01209   return s;
01210 
01211  nomem:
01212   _dbus_string_free (&str);
01213   return NULL;
01214 }
01215 
01216 
01217 #ifdef DBUS_BUILD_TESTS
01218 
01219 #ifndef DOXYGEN_SHOULD_SKIP_THIS
01220 
01221 #include "dbus-test.h"
01222 #include <stdio.h>
01223 
01224 typedef enum 
01225 {
01226   STR_EQUAL,
01227   STR_PREFIX,
01228   STR_DIFFERENT
01229 } StrComparison;
01230 
01231 /* Returns TRUE if container is a parent of child
01232  */
01233 static StrComparison
01234 path_contains (const char **container,
01235                const char **child)
01236 {
01237   int i;
01238 
01239   i = 0;
01240   while (child[i] != NULL)
01241     {
01242       int v;
01243 
01244       if (container[i] == NULL)
01245         return STR_PREFIX; /* container ran out, child continues;
01246                             * thus the container is a parent of the
01247                             * child.
01248                             */
01249 
01250       _dbus_assert (container[i] != NULL);
01251       _dbus_assert (child[i] != NULL);
01252 
01253       v = strcmp (container[i], child[i]);
01254 
01255       if (v != 0)
01256         return STR_DIFFERENT; /* they overlap until here and then are different,
01257                                * not overlapping
01258                                */
01259 
01260       ++i;
01261     }
01262 
01263   /* Child ran out; if container also did, they are equal;
01264    * otherwise, the child is a parent of the container.
01265    */
01266   if (container[i] == NULL)
01267     return STR_EQUAL;
01268   else
01269     return STR_DIFFERENT;
01270 }
01271 
01272 #if 0
01273 static void
01274 spew_subtree_recurse (DBusObjectSubtree *subtree,
01275                       int                indent)
01276 {
01277   int i;
01278 
01279   i = 0;
01280   while (i < indent)
01281     {
01282       _dbus_verbose (" ");
01283       ++i;
01284     }
01285 
01286   _dbus_verbose ("%s (%d children)\n",
01287                  subtree->name, subtree->n_subtrees);
01288 
01289   i = 0;
01290   while (i < subtree->n_subtrees)
01291     {
01292       spew_subtree_recurse (subtree->subtrees[i], indent + 2);
01293 
01294       ++i;
01295     }
01296 }
01297 
01298 static void
01299 spew_tree (DBusObjectTree *tree)
01300 {
01301   spew_subtree_recurse (tree->root, 0);
01302 }
01303 #endif
01304 
01308 typedef struct
01309 {
01310   const char **path; 
01311   dbus_bool_t handler_fallback; 
01312   dbus_bool_t message_handled; 
01313   dbus_bool_t handler_unregistered; 
01314 } TreeTestData;
01315 
01316 
01317 static void
01318 test_unregister_function (DBusConnection  *connection,
01319                           void            *user_data)
01320 {
01321   TreeTestData *ttd = user_data;
01322 
01323   ttd->handler_unregistered = TRUE;
01324 }
01325 
01326 static DBusHandlerResult
01327 test_message_function (DBusConnection  *connection,
01328                        DBusMessage     *message,
01329                        void            *user_data)
01330 {
01331   TreeTestData *ttd = user_data;
01332 
01333   ttd->message_handled = TRUE;
01334 
01335   return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
01336 }
01337 
01338 static dbus_bool_t
01339 do_register (DBusObjectTree *tree,
01340              const char    **path,
01341              dbus_bool_t     fallback,
01342              int             i,
01343              TreeTestData   *tree_test_data)
01344 {
01345   DBusObjectPathVTable vtable = { test_unregister_function,
01346                                   test_message_function, NULL };
01347 
01348   tree_test_data[i].message_handled = FALSE;
01349   tree_test_data[i].handler_unregistered = FALSE;
01350   tree_test_data[i].handler_fallback = fallback;
01351   tree_test_data[i].path = path;
01352 
01353   if (!_dbus_object_tree_register (tree, fallback, path,
01354                                    &vtable,
01355                                    &tree_test_data[i],
01356                                    NULL))
01357     return FALSE;
01358 
01359   _dbus_assert (_dbus_object_tree_get_user_data_unlocked (tree, path) ==
01360                 &tree_test_data[i]);
01361   
01362   return TRUE;
01363 }
01364 
01365 static dbus_bool_t
01366 do_test_dispatch (DBusObjectTree *tree,
01367                   const char    **path,
01368                   int             i,
01369                   TreeTestData   *tree_test_data,
01370                   int             n_test_data)
01371 {
01372   DBusMessage *message;
01373   int j;
01374   DBusHandlerResult result;
01375   char *flat;
01376 
01377   message = NULL;
01378   
01379   flat = flatten_path (path);
01380   if (flat == NULL)
01381     goto oom;
01382 
01383   message = dbus_message_new_method_call (NULL,
01384                                           flat,
01385                                           "org.freedesktop.TestInterface",
01386                                           "Foo");
01387   dbus_free (flat);
01388   if (message == NULL)
01389     goto oom;
01390 
01391   j = 0;
01392   while (j < n_test_data)
01393     {
01394       tree_test_data[j].message_handled = FALSE;
01395       ++j;
01396     }
01397 
01398   result = _dbus_object_tree_dispatch_and_unlock (tree, message, NULL);
01399   if (result == DBUS_HANDLER_RESULT_NEED_MEMORY)
01400     goto oom;
01401 
01402   _dbus_assert (tree_test_data[i].message_handled);
01403 
01404   j = 0;
01405   while (j < n_test_data)
01406     {
01407       if (tree_test_data[j].message_handled)
01408         {
01409           if (tree_test_data[j].handler_fallback)
01410             _dbus_assert (path_contains (tree_test_data[j].path,
01411                                          path) != STR_DIFFERENT);
01412           else
01413             _dbus_assert (path_contains (tree_test_data[j].path, path) == STR_EQUAL);
01414         }
01415       else
01416         {
01417           if (tree_test_data[j].handler_fallback)
01418             _dbus_assert (path_contains (tree_test_data[j].path,
01419                                          path) == STR_DIFFERENT);
01420           else
01421             _dbus_assert (path_contains (tree_test_data[j].path, path) != STR_EQUAL);
01422         }
01423 
01424       ++j;
01425     }
01426 
01427   dbus_message_unref (message);
01428 
01429   return TRUE;
01430 
01431  oom:
01432   if (message)
01433     dbus_message_unref (message);
01434   return FALSE;
01435 }
01436 
01437 static size_t
01438 string_array_length (const char **array)
01439 {
01440   size_t i;
01441   for (i = 0; array[i]; i++) ;
01442   return i;
01443 }
01444 
01445 typedef struct
01446 {
01447   const char *path;
01448   const char *result[20];
01449 } DecomposePathTest;
01450 
01451 static DecomposePathTest decompose_tests[] = {
01452   { "/foo", { "foo", NULL } },
01453   { "/foo/bar", { "foo", "bar", NULL } },
01454   { "/", { NULL } },
01455   { "/a/b", { "a", "b", NULL } },
01456   { "/a/b/c", { "a", "b", "c", NULL } },
01457   { "/a/b/c/d", { "a", "b", "c", "d", NULL } },
01458   { "/foo/bar/q", { "foo", "bar", "q", NULL } },
01459   { "/foo/bar/this/is/longer", { "foo", "bar", "this", "is", "longer", NULL } }
01460 };
01461 
01462 static dbus_bool_t
01463 run_decompose_tests (void)
01464 {
01465   int i;
01466 
01467   i = 0;
01468   while (i < _DBUS_N_ELEMENTS (decompose_tests))
01469     {
01470       char **result;
01471       int    result_len;
01472       int    expected_len;
01473 
01474       if (!_dbus_decompose_path (decompose_tests[i].path,
01475                                  strlen (decompose_tests[i].path),
01476                                  &result, &result_len))
01477         return FALSE;
01478 
01479       expected_len = string_array_length (decompose_tests[i].result);
01480       
01481       if (result_len != (int) string_array_length ((const char**)result) ||
01482           expected_len != result_len ||
01483           path_contains (decompose_tests[i].result,
01484                          (const char**) result) != STR_EQUAL)
01485         {
01486           int real_len = string_array_length ((const char**)result);
01487           _dbus_warn ("Expected decompose of %s to have len %d, returned %d, appears to have %d\n",
01488                       decompose_tests[i].path, expected_len, result_len,
01489                       real_len);
01490           _dbus_warn ("Decompose resulted in elements: { ");
01491           i = 0;
01492           while (i < real_len)
01493             {
01494               _dbus_warn ("\"%s\"%s", result[i],
01495                           (i + 1) == real_len ? "" : ", ");
01496               ++i;
01497             }
01498           _dbus_warn ("}\n");
01499           _dbus_assert_not_reached ("path decompose failed\n");
01500         }
01501 
01502       dbus_free_string_array (result);
01503 
01504       ++i;
01505     }
01506   
01507   return TRUE;
01508 }
01509 
01510 static dbus_bool_t
01511 object_tree_test_iteration (void *data)
01512 {
01513   const char *path0[] = { NULL };
01514   const char *path1[] = { "foo", NULL };
01515   const char *path2[] = { "foo", "bar", NULL };
01516   const char *path3[] = { "foo", "bar", "baz", NULL };
01517   const char *path4[] = { "foo", "bar", "boo", NULL };
01518   const char *path5[] = { "blah", NULL };
01519   const char *path6[] = { "blah", "boof", NULL };
01520   const char *path7[] = { "blah", "boof", "this", "is", "really", "long", NULL };
01521   const char *path8[] = { "childless", NULL };
01522   DBusObjectTree *tree;
01523   TreeTestData tree_test_data[9];
01524   int i;
01525   dbus_bool_t exact_match;
01526 
01527   if (!run_decompose_tests ())
01528     return FALSE;
01529   
01530   tree = NULL;
01531 
01532   tree = _dbus_object_tree_new (NULL);
01533   if (tree == NULL)
01534     goto out;
01535 
01536   if (!do_register (tree, path0, TRUE, 0, tree_test_data))
01537     goto out;
01538 
01539   _dbus_assert (find_subtree (tree, path0, NULL));
01540   _dbus_assert (!find_subtree (tree, path1, NULL));
01541   _dbus_assert (!find_subtree (tree, path2, NULL));
01542   _dbus_assert (!find_subtree (tree, path3, NULL));
01543   _dbus_assert (!find_subtree (tree, path4, NULL));
01544   _dbus_assert (!find_subtree (tree, path5, NULL));
01545   _dbus_assert (!find_subtree (tree, path6, NULL));
01546   _dbus_assert (!find_subtree (tree, path7, NULL));
01547   _dbus_assert (!find_subtree (tree, path8, NULL));
01548 
01549   _dbus_assert (find_handler (tree, path0, &exact_match) && exact_match);
01550   _dbus_assert (find_handler (tree, path1, &exact_match) == tree->root && !exact_match);
01551   _dbus_assert (find_handler (tree, path2, &exact_match) == tree->root && !exact_match);
01552   _dbus_assert (find_handler (tree, path3, &exact_match) == tree->root && !exact_match);
01553   _dbus_assert (find_handler (tree, path4, &exact_match) == tree->root && !exact_match);
01554   _dbus_assert (find_handler (tree, path5, &exact_match) == tree->root && !exact_match);
01555   _dbus_assert (find_handler (tree, path6, &exact_match) == tree->root && !exact_match);
01556   _dbus_assert (find_handler (tree, path7, &exact_match) == tree->root && !exact_match);
01557   _dbus_assert (find_handler (tree, path8, &exact_match) == tree->root && !exact_match);
01558   
01559   if (!do_register (tree, path1, TRUE, 1, tree_test_data))
01560     goto out;
01561 
01562   _dbus_assert (find_subtree (tree, path0, NULL));
01563   _dbus_assert (find_subtree (tree, path1, NULL));
01564   _dbus_assert (!find_subtree (tree, path2, NULL));
01565   _dbus_assert (!find_subtree (tree, path3, NULL));
01566   _dbus_assert (!find_subtree (tree, path4, NULL));
01567   _dbus_assert (!find_subtree (tree, path5, NULL));
01568   _dbus_assert (!find_subtree (tree, path6, NULL));
01569   _dbus_assert (!find_subtree (tree, path7, NULL));
01570   _dbus_assert (!find_subtree (tree, path8, NULL));
01571 
01572   _dbus_assert (find_handler (tree, path0, &exact_match) &&  exact_match);
01573   _dbus_assert (find_handler (tree, path1, &exact_match) &&  exact_match);
01574   _dbus_assert (find_handler (tree, path2, &exact_match) && !exact_match);
01575   _dbus_assert (find_handler (tree, path3, &exact_match) && !exact_match);
01576   _dbus_assert (find_handler (tree, path4, &exact_match) && !exact_match);
01577   _dbus_assert (find_handler (tree, path5, &exact_match) == tree->root && !exact_match);
01578   _dbus_assert (find_handler (tree, path6, &exact_match) == tree->root && !exact_match);
01579   _dbus_assert (find_handler (tree, path7, &exact_match) == tree->root && !exact_match);
01580   _dbus_assert (find_handler (tree, path8, &exact_match) == tree->root && !exact_match);
01581 
01582   if (!do_register (tree, path2, TRUE, 2, tree_test_data))
01583     goto out;
01584 
01585   _dbus_assert (find_subtree (tree, path1, NULL));
01586   _dbus_assert (find_subtree (tree, path2, NULL));
01587   _dbus_assert (!find_subtree (tree, path3, NULL));
01588   _dbus_assert (!find_subtree (tree, path4, NULL));
01589   _dbus_assert (!find_subtree (tree, path5, NULL));
01590   _dbus_assert (!find_subtree (tree, path6, NULL));
01591   _dbus_assert (!find_subtree (tree, path7, NULL));
01592   _dbus_assert (!find_subtree (tree, path8, NULL));
01593 
01594   if (!do_register (tree, path3, TRUE, 3, tree_test_data))
01595     goto out;
01596 
01597   _dbus_assert (find_subtree (tree, path0, NULL));
01598   _dbus_assert (find_subtree (tree, path1, NULL));
01599   _dbus_assert (find_subtree (tree, path2, NULL));
01600   _dbus_assert (find_subtree (tree, path3, NULL));
01601   _dbus_assert (!find_subtree (tree, path4, NULL));
01602   _dbus_assert (!find_subtree (tree, path5, NULL));
01603   _dbus_assert (!find_subtree (tree, path6, NULL));
01604   _dbus_assert (!find_subtree (tree, path7, NULL));
01605   _dbus_assert (!find_subtree (tree, path8, NULL));
01606   
01607   if (!do_register (tree, path4, TRUE, 4, tree_test_data))
01608     goto out;
01609 
01610   _dbus_assert (find_subtree (tree, path0, NULL));
01611   _dbus_assert (find_subtree (tree, path1, NULL));
01612   _dbus_assert (find_subtree (tree, path2, NULL));
01613   _dbus_assert (find_subtree (tree, path3, NULL));  
01614   _dbus_assert (find_subtree (tree, path4, NULL));
01615   _dbus_assert (!find_subtree (tree, path5, NULL));
01616   _dbus_assert (!find_subtree (tree, path6, NULL));
01617   _dbus_assert (!find_subtree (tree, path7, NULL));
01618   _dbus_assert (!find_subtree (tree, path8, NULL));
01619   
01620   if (!do_register (tree, path5, TRUE, 5, tree_test_data))
01621     goto out;
01622 
01623   _dbus_assert (find_subtree (tree, path0, NULL));
01624   _dbus_assert (find_subtree (tree, path1, NULL));
01625   _dbus_assert (find_subtree (tree, path2, NULL));
01626   _dbus_assert (find_subtree (tree, path3, NULL));
01627   _dbus_assert (find_subtree (tree, path4, NULL));
01628   _dbus_assert (find_subtree (tree, path5, NULL));
01629   _dbus_assert (!find_subtree (tree, path6, NULL));
01630   _dbus_assert (!find_subtree (tree, path7, NULL));
01631   _dbus_assert (!find_subtree (tree, path8, NULL));
01632 
01633   _dbus_assert (find_handler (tree, path0, &exact_match) == tree->root &&  exact_match);
01634   _dbus_assert (find_handler (tree, path1, &exact_match) != tree->root &&  exact_match);
01635   _dbus_assert (find_handler (tree, path2, &exact_match) != tree->root &&  exact_match);
01636   _dbus_assert (find_handler (tree, path3, &exact_match) != tree->root &&  exact_match);
01637   _dbus_assert (find_handler (tree, path4, &exact_match) != tree->root &&  exact_match);
01638   _dbus_assert (find_handler (tree, path5, &exact_match) != tree->root &&  exact_match);
01639   _dbus_assert (find_handler (tree, path6, &exact_match) != tree->root && !exact_match);
01640   _dbus_assert (find_handler (tree, path7, &exact_match) != tree->root && !exact_match);
01641   _dbus_assert (find_handler (tree, path8, &exact_match) == tree->root && !exact_match);
01642 
01643   if (!do_register (tree, path6, TRUE, 6, tree_test_data))
01644     goto out;
01645 
01646   _dbus_assert (find_subtree (tree, path0, NULL));
01647   _dbus_assert (find_subtree (tree, path1, NULL));
01648   _dbus_assert (find_subtree (tree, path2, NULL));
01649   _dbus_assert (find_subtree (tree, path3, NULL));
01650   _dbus_assert (find_subtree (tree, path4, NULL));
01651   _dbus_assert (find_subtree (tree, path5, NULL));
01652   _dbus_assert (find_subtree (tree, path6, NULL));
01653   _dbus_assert (!find_subtree (tree, path7, NULL));
01654   _dbus_assert (!find_subtree (tree, path8, NULL));
01655 
01656   if (!do_register (tree, path7, TRUE, 7, tree_test_data))
01657     goto out;
01658 
01659   _dbus_assert (find_subtree (tree, path0, NULL));
01660   _dbus_assert (find_subtree (tree, path1, NULL));
01661   _dbus_assert (find_subtree (tree, path2, NULL));
01662   _dbus_assert (find_subtree (tree, path3, NULL));
01663   _dbus_assert (find_subtree (tree, path4, NULL));
01664   _dbus_assert (find_subtree (tree, path5, NULL));
01665   _dbus_assert (find_subtree (tree, path6, NULL));
01666   _dbus_assert (find_subtree (tree, path7, NULL));
01667   _dbus_assert (!find_subtree (tree, path8, NULL));
01668 
01669   if (!do_register (tree, path8, TRUE, 8, tree_test_data))
01670     goto out;
01671 
01672   _dbus_assert (find_subtree (tree, path0, NULL));
01673   _dbus_assert (find_subtree (tree, path1, NULL));
01674   _dbus_assert (find_subtree (tree, path2, NULL));
01675   _dbus_assert (find_subtree (tree, path3, NULL));
01676   _dbus_assert (find_subtree (tree, path4, NULL));
01677   _dbus_assert (find_subtree (tree, path5, NULL));
01678   _dbus_assert (find_subtree (tree, path6, NULL));
01679   _dbus_assert (find_subtree (tree, path7, NULL));
01680   _dbus_assert (find_subtree (tree, path8, NULL));
01681 
01682   _dbus_assert (find_handler (tree, path0, &exact_match) == tree->root &&  exact_match);
01683   _dbus_assert (find_handler (tree, path1, &exact_match) != tree->root && exact_match);
01684   _dbus_assert (find_handler (tree, path2, &exact_match) != tree->root && exact_match);
01685   _dbus_assert (find_handler (tree, path3, &exact_match) != tree->root && exact_match);
01686   _dbus_assert (find_handler (tree, path4, &exact_match) != tree->root && exact_match);
01687   _dbus_assert (find_handler (tree, path5, &exact_match) != tree->root && exact_match);
01688   _dbus_assert (find_handler (tree, path6, &exact_match) != tree->root && exact_match);
01689   _dbus_assert (find_handler (tree, path7, &exact_match) != tree->root && exact_match);
01690   _dbus_assert (find_handler (tree, path8, &exact_match) != tree->root && exact_match);
01691   
01692   /* test the list_registered function */
01693 
01694   {
01695     const char *root[] = { NULL };
01696     char **child_entries;
01697     int nb;
01698 
01699     _dbus_object_tree_list_registered_unlocked (tree, path1, &child_entries);
01700     if (child_entries != NULL)
01701       {
01702         nb = string_array_length ((const char**)child_entries);
01703         _dbus_assert (nb == 1);
01704         dbus_free_string_array (child_entries);
01705       }
01706 
01707     _dbus_object_tree_list_registered_unlocked (tree, path2, &child_entries);
01708     if (child_entries != NULL)
01709       {
01710         nb = string_array_length ((const char**)child_entries);
01711         _dbus_assert (nb == 2);
01712         dbus_free_string_array (child_entries);
01713       }
01714 
01715     _dbus_object_tree_list_registered_unlocked (tree, path8, &child_entries);
01716     if (child_entries != NULL)
01717       {
01718         nb = string_array_length ((const char**)child_entries);
01719         _dbus_assert (nb == 0);
01720         dbus_free_string_array (child_entries);
01721       }
01722 
01723     _dbus_object_tree_list_registered_unlocked (tree, root, &child_entries);
01724     if (child_entries != NULL)
01725       {
01726         nb = string_array_length ((const char**)child_entries);
01727         _dbus_assert (nb == 3);
01728         dbus_free_string_array (child_entries);
01729       }
01730   }
01731 
01732   /* Check that destroying tree calls unregister funcs */
01733   _dbus_object_tree_unref (tree);
01734 
01735   i = 0;
01736   while (i < (int) _DBUS_N_ELEMENTS (tree_test_data))
01737     {
01738       _dbus_assert (tree_test_data[i].handler_unregistered);
01739       _dbus_assert (!tree_test_data[i].message_handled);
01740       ++i;
01741     }
01742 
01743   /* Now start again and try the individual unregister function */
01744   tree = _dbus_object_tree_new (NULL);
01745   if (tree == NULL)
01746     goto out;
01747 
01748   if (!do_register (tree, path0, TRUE, 0, tree_test_data))
01749     goto out;
01750   if (!do_register (tree, path1, TRUE, 1, tree_test_data))
01751     goto out;
01752   if (!do_register (tree, path2, TRUE, 2, tree_test_data))
01753     goto out;
01754   if (!do_register (tree, path3, TRUE, 3, tree_test_data))
01755     goto out;
01756   if (!do_register (tree, path4, TRUE, 4, tree_test_data))
01757     goto out;
01758   if (!do_register (tree, path5, TRUE, 5, tree_test_data))
01759     goto out;
01760   if (!do_register (tree, path6, TRUE, 6, tree_test_data))
01761     goto out;
01762   if (!do_register (tree, path7, TRUE, 7, tree_test_data))
01763     goto out;
01764   if (!do_register (tree, path8, TRUE, 8, tree_test_data))
01765     goto out;
01766 
01767   _dbus_object_tree_unregister_and_unlock (tree, path0);
01768   _dbus_assert (_dbus_object_tree_get_user_data_unlocked (tree, path0) == NULL);
01769 
01770   _dbus_assert (!find_subtree (tree, path0, NULL));
01771   _dbus_assert (find_subtree (tree, path1, NULL));
01772   _dbus_assert (find_subtree (tree, path2, NULL));
01773   _dbus_assert (find_subtree (tree, path3, NULL));
01774   _dbus_assert (find_subtree (tree, path4, NULL));
01775   _dbus_assert (find_subtree (tree, path5, NULL));
01776   _dbus_assert (find_subtree (tree, path6, NULL));
01777   _dbus_assert (find_subtree (tree, path7, NULL));
01778   _dbus_assert (find_subtree (tree, path8, NULL));
01779   
01780   _dbus_object_tree_unregister_and_unlock (tree, path1);
01781   _dbus_assert (_dbus_object_tree_get_user_data_unlocked (tree, path1) == NULL);
01782 
01783   _dbus_assert (!find_subtree (tree, path0, NULL));
01784   _dbus_assert (!find_subtree (tree, path1, NULL));
01785   _dbus_assert (find_subtree (tree, path2, NULL));
01786   _dbus_assert (find_subtree (tree, path3, NULL));
01787   _dbus_assert (find_subtree (tree, path4, NULL));
01788   _dbus_assert (find_subtree (tree, path5, NULL));
01789   _dbus_assert (find_subtree (tree, path6, NULL));
01790   _dbus_assert (find_subtree (tree, path7, NULL));
01791   _dbus_assert (find_subtree (tree, path8, NULL));
01792 
01793   _dbus_object_tree_unregister_and_unlock (tree, path2);
01794   _dbus_assert (_dbus_object_tree_get_user_data_unlocked (tree, path2) == NULL);
01795 
01796   _dbus_assert (!find_subtree (tree, path0, NULL));
01797   _dbus_assert (!find_subtree (tree, path1, NULL));
01798   _dbus_assert (!find_subtree (tree, path2, NULL));
01799   _dbus_assert (find_subtree (tree, path3, NULL));
01800   _dbus_assert (find_subtree (tree, path4, NULL));
01801   _dbus_assert (find_subtree (tree, path5, NULL));
01802   _dbus_assert (find_subtree (tree, path6, NULL));
01803   _dbus_assert (find_subtree (tree, path7, NULL));
01804   _dbus_assert (find_subtree (tree, path8, NULL));
01805   
01806   _dbus_object_tree_unregister_and_unlock (tree, path3);
01807   _dbus_assert (_dbus_object_tree_get_user_data_unlocked (tree, path3) == NULL);
01808 
01809   _dbus_assert (!find_subtree (tree, path0, NULL));
01810   _dbus_assert (!find_subtree (tree, path1, NULL));
01811   _dbus_assert (!find_subtree (tree, path2, NULL));
01812   _dbus_assert (!find_subtree (tree, path3, NULL));
01813   _dbus_assert (find_subtree (tree, path4, NULL));
01814   _dbus_assert (find_subtree (tree, path5, NULL));
01815   _dbus_assert (find_subtree (tree, path6, NULL));
01816   _dbus_assert (find_subtree (tree, path7, NULL));
01817   _dbus_assert (find_subtree (tree, path8, NULL));
01818   
01819   _dbus_object_tree_unregister_and_unlock (tree, path4);
01820   _dbus_assert (_dbus_object_tree_get_user_data_unlocked (tree, path4) == NULL);
01821 
01822   _dbus_assert (!find_subtree (tree, path0, NULL));
01823   _dbus_assert (!find_subtree (tree, path1, NULL));
01824   _dbus_assert (!find_subtree (tree, path2, NULL));
01825   _dbus_assert (!find_subtree (tree, path3, NULL));
01826   _dbus_assert (!find_subtree (tree, path4, NULL));
01827   _dbus_assert (find_subtree (tree, path5, NULL));
01828   _dbus_assert (find_subtree (tree, path6, NULL));
01829   _dbus_assert (find_subtree (tree, path7, NULL));
01830   _dbus_assert (find_subtree (tree, path8, NULL));
01831   
01832   _dbus_object_tree_unregister_and_unlock (tree, path5);
01833   _dbus_assert (_dbus_object_tree_get_user_data_unlocked (tree, path5) == NULL);
01834 
01835   _dbus_assert (!find_subtree (tree, path0, NULL));
01836   _dbus_assert (!find_subtree (tree, path1, NULL));
01837   _dbus_assert (!find_subtree (tree, path2, NULL));
01838   _dbus_assert (!find_subtree (tree, path3, NULL));
01839   _dbus_assert (!find_subtree (tree, path4, NULL));
01840   _dbus_assert (!find_subtree (tree, path5, NULL));
01841   _dbus_assert (find_subtree (tree, path6, NULL));
01842   _dbus_assert (find_subtree (tree, path7, NULL));
01843   _dbus_assert (find_subtree (tree, path8, NULL));
01844   
01845   _dbus_object_tree_unregister_and_unlock (tree, path6);
01846   _dbus_assert (_dbus_object_tree_get_user_data_unlocked (tree, path6) == NULL);
01847 
01848   _dbus_assert (!find_subtree (tree, path0, NULL));
01849   _dbus_assert (!find_subtree (tree, path1, NULL));
01850   _dbus_assert (!find_subtree (tree, path2, NULL));
01851   _dbus_assert (!find_subtree (tree, path3, NULL));
01852   _dbus_assert (!find_subtree (tree, path4, NULL));
01853   _dbus_assert (!find_subtree (tree, path5, NULL));
01854   _dbus_assert (!find_subtree (tree, path6, NULL));
01855   _dbus_assert (find_subtree (tree, path7, NULL));
01856   _dbus_assert (find_subtree (tree, path8, NULL));
01857 
01858   _dbus_object_tree_unregister_and_unlock (tree, path7);
01859   _dbus_assert (_dbus_object_tree_get_user_data_unlocked (tree, path7) == NULL);
01860 
01861   _dbus_assert (!find_subtree (tree, path0, NULL));
01862   _dbus_assert (!find_subtree (tree, path1, NULL));
01863   _dbus_assert (!find_subtree (tree, path2, NULL));
01864   _dbus_assert (!find_subtree (tree, path3, NULL));
01865   _dbus_assert (!find_subtree (tree, path4, NULL));
01866   _dbus_assert (!find_subtree (tree, path5, NULL));
01867   _dbus_assert (!find_subtree (tree, path6, NULL));
01868   _dbus_assert (!find_subtree (tree, path7, NULL));
01869   _dbus_assert (find_subtree (tree, path8, NULL));
01870 
01871   _dbus_object_tree_unregister_and_unlock (tree, path8);
01872   _dbus_assert (_dbus_object_tree_get_user_data_unlocked (tree, path8) == NULL);
01873 
01874   _dbus_assert (!find_subtree (tree, path0, NULL));
01875   _dbus_assert (!find_subtree (tree, path1, NULL));
01876   _dbus_assert (!find_subtree (tree, path2, NULL));
01877   _dbus_assert (!find_subtree (tree, path3, NULL));
01878   _dbus_assert (!find_subtree (tree, path4, NULL));
01879   _dbus_assert (!find_subtree (tree, path5, NULL));
01880   _dbus_assert (!find_subtree (tree, path6, NULL));
01881   _dbus_assert (!find_subtree (tree, path7, NULL));
01882   _dbus_assert (!find_subtree (tree, path8, NULL));
01883   
01884   i = 0;
01885   while (i < (int) _DBUS_N_ELEMENTS (tree_test_data))
01886     {
01887       _dbus_assert (tree_test_data[i].handler_unregistered);
01888       _dbus_assert (!tree_test_data[i].message_handled);
01889       ++i;
01890     }
01891 
01892   /* Register it all again, and test dispatch */
01893   
01894   if (!do_register (tree, path0, TRUE, 0, tree_test_data))
01895     goto out;
01896   if (!do_register (tree, path1, FALSE, 1, tree_test_data))
01897     goto out;
01898   if (!do_register (tree, path2, TRUE, 2, tree_test_data))
01899     goto out;
01900   if (!do_register (tree, path3, TRUE, 3, tree_test_data))
01901     goto out;
01902   if (!do_register (tree, path4, TRUE, 4, tree_test_data))
01903     goto out;
01904   if (!do_register (tree, path5, TRUE, 5, tree_test_data))
01905     goto out;
01906   if (!do_register (tree, path6, FALSE, 6, tree_test_data))
01907     goto out;
01908   if (!do_register (tree, path7, TRUE, 7, tree_test_data))
01909     goto out;
01910   if (!do_register (tree, path8, TRUE, 8, tree_test_data))
01911     goto out;
01912 
01913 #if 0
01914   spew_tree (tree);
01915 #endif
01916 
01917   if (!do_test_dispatch (tree, path0, 0, tree_test_data, _DBUS_N_ELEMENTS (tree_test_data)))
01918     goto out;
01919   if (!do_test_dispatch (tree, path1, 1, tree_test_data, _DBUS_N_ELEMENTS (tree_test_data)))
01920     goto out;
01921   if (!do_test_dispatch (tree, path2, 2, tree_test_data, _DBUS_N_ELEMENTS (tree_test_data)))
01922     goto out;
01923   if (!do_test_dispatch (tree, path3, 3, tree_test_data, _DBUS_N_ELEMENTS (tree_test_data)))
01924     goto out;
01925   if (!do_test_dispatch (tree, path4, 4, tree_test_data, _DBUS_N_ELEMENTS (tree_test_data)))
01926     goto out;
01927   if (!do_test_dispatch (tree, path5, 5, tree_test_data, _DBUS_N_ELEMENTS (tree_test_data)))
01928     goto out;
01929   if (!do_test_dispatch (tree, path6, 6, tree_test_data, _DBUS_N_ELEMENTS (tree_test_data)))
01930     goto out;
01931   if (!do_test_dispatch (tree, path7, 7, tree_test_data, _DBUS_N_ELEMENTS (tree_test_data)))
01932     goto out;
01933   if (!do_test_dispatch (tree, path8, 8, tree_test_data, _DBUS_N_ELEMENTS (tree_test_data)))
01934     goto out;
01935   
01936  out:
01937   if (tree)
01938     {
01939       /* test ref */
01940       _dbus_object_tree_ref (tree);
01941       _dbus_object_tree_unref (tree);
01942       _dbus_object_tree_unref (tree);
01943     }
01944 
01945   return TRUE;
01946 }
01947 
01953 dbus_bool_t
01954 _dbus_object_tree_test (void)
01955 {
01956   _dbus_test_oom_handling ("object tree",
01957                            object_tree_test_iteration,
01958                            NULL);
01959 
01960   return TRUE;
01961 }
01962 
01963 #endif /* !DOXYGEN_SHOULD_SKIP_THIS */
01964 
01965 #endif /* DBUS_BUILD_TESTS */