D-Bus 1.4.14
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 {
00750   char **path;
00751   dbus_bool_t exact_match;
00752   DBusList *list;
00753   DBusList *link;
00754   DBusHandlerResult result;
00755   DBusObjectSubtree *subtree;
00756   
00757 #if 0
00758   _dbus_verbose ("Dispatch of message by object path\n");
00759 #endif
00760   
00761   path = NULL;
00762   if (!dbus_message_get_path_decomposed (message, &path))
00763     {
00764 #ifdef DBUS_BUILD_TESTS
00765       if (tree->connection)
00766 #endif
00767         {
00768           _dbus_verbose ("unlock\n");
00769           _dbus_connection_unlock (tree->connection);
00770         }
00771       
00772       _dbus_verbose ("No memory to get decomposed path\n");
00773 
00774       return DBUS_HANDLER_RESULT_NEED_MEMORY;
00775     }
00776 
00777   if (path == NULL)
00778     {
00779 #ifdef DBUS_BUILD_TESTS
00780       if (tree->connection)
00781 #endif
00782         {
00783           _dbus_verbose ("unlock\n");
00784           _dbus_connection_unlock (tree->connection);
00785         }
00786       
00787       _dbus_verbose ("No path field in message\n");
00788       return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
00789     }
00790   
00791   /* Find the deepest path that covers the path in the message */
00792   subtree = find_handler (tree, (const char**) path, &exact_match);
00793   
00794   /* Build a list of all paths that cover the path in the message */
00795 
00796   list = NULL;
00797 
00798   while (subtree != NULL)
00799     {
00800       if (subtree->message_function != NULL && (exact_match || subtree->invoke_as_fallback))
00801         {
00802           _dbus_object_subtree_ref (subtree);
00803 
00804           /* run deepest paths first */
00805           if (!_dbus_list_append (&list, subtree))
00806             {
00807               result = DBUS_HANDLER_RESULT_NEED_MEMORY;
00808               _dbus_object_subtree_unref (subtree);
00809               goto free_and_return;
00810             }
00811         }
00812 
00813       exact_match = FALSE;
00814       subtree = subtree->parent;
00815     }
00816 
00817   _dbus_verbose ("%d handlers in the path tree for this message\n",
00818                  _dbus_list_get_length (&list));
00819 
00820   /* Invoke each handler in the list */
00821 
00822   result = DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
00823 
00824   link = _dbus_list_get_first_link (&list);
00825   while (link != NULL)
00826     {
00827       DBusList *next = _dbus_list_get_next_link (&list, link);
00828       subtree = link->data;
00829 
00830       /* message_function is NULL if we're unregistered
00831        * due to reentrancy
00832        */
00833       if (subtree->message_function)
00834         {
00835           DBusObjectPathMessageFunction message_function;
00836           void *user_data;
00837 
00838           message_function = subtree->message_function;
00839           user_data = subtree->user_data;
00840 
00841 #if 0
00842           _dbus_verbose ("  (invoking a handler)\n");
00843 #endif
00844           
00845 #ifdef DBUS_BUILD_TESTS
00846           if (tree->connection)
00847 #endif
00848             {
00849               _dbus_verbose ("unlock\n");
00850               _dbus_connection_unlock (tree->connection);
00851             }
00852 
00853           /* FIXME you could unregister the subtree in another thread
00854            * before we invoke the callback, and I can't figure out a
00855            * good way to solve this.
00856            */
00857 
00858           result = (* message_function) (tree->connection,
00859                                          message,
00860                                          user_data);
00861 
00862 #ifdef DBUS_BUILD_TESTS
00863           if (tree->connection)
00864 #endif
00865             _dbus_connection_lock (tree->connection);
00866 
00867           if (result != DBUS_HANDLER_RESULT_NOT_YET_HANDLED)
00868             goto free_and_return;
00869         }
00870 
00871       link = next;
00872     }
00873 
00874  free_and_return:
00875 
00876   if (result == DBUS_HANDLER_RESULT_NOT_YET_HANDLED)
00877     {
00878       /* This hardcoded default handler does a minimal Introspect()
00879        */
00880       result = handle_default_introspect_and_unlock (tree, message,
00881                                                      (const char**) path);
00882     }
00883   else
00884     {
00885 #ifdef DBUS_BUILD_TESTS
00886       if (tree->connection)
00887 #endif
00888         {
00889           _dbus_verbose ("unlock\n");
00890           _dbus_connection_unlock (tree->connection);
00891         }
00892     }
00893   
00894   while (list != NULL)
00895     {
00896       link = _dbus_list_get_first_link (&list);
00897       _dbus_object_subtree_unref (link->data);
00898       _dbus_list_remove_link (&list, link);
00899     }
00900   
00901   dbus_free_string_array (path);
00902 
00903   return result;
00904 }
00905 
00914 void*
00915 _dbus_object_tree_get_user_data_unlocked (DBusObjectTree *tree,
00916                                           const char    **path)
00917 {
00918   dbus_bool_t exact_match;
00919   DBusObjectSubtree *subtree;
00920 
00921   _dbus_assert (tree != NULL);
00922   _dbus_assert (path != NULL);
00923   
00924   /* Find the deepest path that covers the path in the message */
00925   subtree = find_handler (tree, (const char**) path, &exact_match);
00926 
00927   if ((subtree == NULL) || !exact_match)
00928     {
00929       _dbus_verbose ("No object at specified path found\n");
00930       return NULL;
00931     }
00932 
00933   return subtree->user_data;
00934 }
00935 
00942 static DBusObjectSubtree*
00943 allocate_subtree_object (const char *name)
00944 {
00945   int len;
00946   DBusObjectSubtree *subtree;
00947   const size_t front_padding = _DBUS_STRUCT_OFFSET (DBusObjectSubtree, name);
00948 
00949   _dbus_assert (name != NULL);
00950 
00951   len = strlen (name);
00952 
00953   subtree = dbus_malloc0 (MAX (front_padding + (len + 1), sizeof (DBusObjectSubtree)));
00954 
00955   if (subtree == NULL)
00956     return NULL;
00957 
00958   memcpy (subtree->name, name, len + 1);
00959 
00960   return subtree;
00961 }
00962 
00963 static DBusObjectSubtree*
00964 _dbus_object_subtree_new (const char                  *name,
00965                           const DBusObjectPathVTable  *vtable,
00966                           void                        *user_data)
00967 {
00968   DBusObjectSubtree *subtree;
00969 
00970   subtree = allocate_subtree_object (name);
00971   if (subtree == NULL)
00972     goto oom;
00973 
00974   _dbus_assert (name != NULL);
00975 
00976   subtree->parent = NULL;
00977 
00978   if (vtable)
00979     {
00980       subtree->message_function = vtable->message_function;
00981       subtree->unregister_function = vtable->unregister_function;
00982     }
00983   else
00984     {
00985       subtree->message_function = NULL;
00986       subtree->unregister_function = NULL;
00987     }
00988 
00989   subtree->user_data = user_data;
00990   _dbus_atomic_inc (&subtree->refcount);
00991   subtree->subtrees = NULL;
00992   subtree->n_subtrees = 0;
00993   subtree->max_subtrees = 0;
00994   subtree->invoke_as_fallback = FALSE;
00995 
00996   return subtree;
00997 
00998  oom:
00999   return NULL;
01000 }
01001 
01002 static DBusObjectSubtree *
01003 _dbus_object_subtree_ref (DBusObjectSubtree *subtree)
01004 {
01005 #ifdef DBUS_DISABLE_ASSERT
01006   _dbus_atomic_inc (&subtree->refcount);
01007 #else
01008   dbus_int32_t old_value;
01009 
01010   old_value = _dbus_atomic_inc (&subtree->refcount);
01011   _dbus_assert (old_value > 0);
01012 #endif
01013 
01014   return subtree;
01015 }
01016 
01017 static void
01018 _dbus_object_subtree_unref (DBusObjectSubtree *subtree)
01019 {
01020   dbus_int32_t old_value;
01021 
01022   old_value = _dbus_atomic_dec (&subtree->refcount);
01023   _dbus_assert (old_value > 0);
01024 
01025   if (old_value == 1)
01026     {
01027       _dbus_assert (subtree->unregister_function == NULL);
01028       _dbus_assert (subtree->message_function == NULL);
01029 
01030       dbus_free (subtree->subtrees);
01031       dbus_free (subtree);
01032     }
01033 }
01034 
01045 dbus_bool_t
01046 _dbus_object_tree_list_registered_and_unlock (DBusObjectTree *tree,
01047                                               const char    **parent_path,
01048                                               char         ***child_entries)
01049 {
01050   dbus_bool_t result;
01051 
01052   result = _dbus_object_tree_list_registered_unlocked (tree,
01053                                                        parent_path,
01054                                                        child_entries);
01055   
01056 #ifdef DBUS_BUILD_TESTS
01057   if (tree->connection)
01058 #endif
01059     {
01060       _dbus_verbose ("unlock\n");
01061       _dbus_connection_unlock (tree->connection);
01062     }
01063 
01064   return result;
01065 }
01066 
01067 
01069 #define VERBOSE_DECOMPOSE 0
01070 
01081 dbus_bool_t
01082 _dbus_decompose_path (const char*     data,
01083                       int             len,
01084                       char         ***path,
01085                       int            *path_len)
01086 {
01087   char **retval;
01088   int n_components;
01089   int i, j, comp;
01090 
01091   _dbus_assert (data != NULL);
01092   _dbus_assert (path != NULL);
01093   
01094 #if VERBOSE_DECOMPOSE
01095   _dbus_verbose ("Decomposing path \"%s\"\n",
01096                  data);
01097 #endif
01098   
01099   n_components = 0;
01100   if (len > 1) /* if path is not just "/" */
01101     {
01102       i = 0;
01103       while (i < len)
01104         {
01105           _dbus_assert (data[i] != '\0');
01106           if (data[i] == '/')
01107             n_components += 1;
01108           ++i;
01109         }
01110     }
01111   
01112   retval = dbus_new0 (char*, n_components + 1);
01113 
01114   if (retval == NULL)
01115     return FALSE;
01116 
01117   comp = 0;
01118   if (n_components == 0)
01119     i = 1;
01120   else
01121     i = 0;
01122   while (comp < n_components)
01123     {
01124       _dbus_assert (i < len);
01125       
01126       if (data[i] == '/')
01127         ++i;
01128       j = i;
01129 
01130       while (j < len && data[j] != '/')
01131         ++j;
01132 
01133       /* Now [i, j) is the path component */
01134       _dbus_assert (i < j);
01135       _dbus_assert (data[i] != '/');
01136       _dbus_assert (j == len || data[j] == '/');
01137 
01138 #if VERBOSE_DECOMPOSE
01139       _dbus_verbose ("  (component in [%d,%d))\n",
01140                      i, j);
01141 #endif
01142       
01143       retval[comp] = _dbus_memdup (&data[i], j - i + 1);
01144       if (retval[comp] == NULL)
01145         {
01146           dbus_free_string_array (retval);
01147           return FALSE;
01148         }
01149       retval[comp][j-i] = '\0';
01150 #if VERBOSE_DECOMPOSE
01151       _dbus_verbose ("  (component %d = \"%s\")\n",
01152                      comp, retval[comp]);
01153 #endif
01154 
01155       ++comp;
01156       i = j;
01157     }
01158   _dbus_assert (i == len);
01159   
01160   *path = retval;
01161   if (path_len)
01162     *path_len = n_components;
01163   
01164   return TRUE;
01165 }
01166 
01169 static char*
01170 flatten_path (const char **path)
01171 {
01172   DBusString str;
01173   char *s;
01174 
01175   if (!_dbus_string_init (&str))
01176     return NULL;
01177 
01178   if (path[0] == NULL)
01179     {
01180       if (!_dbus_string_append_byte (&str, '/'))
01181         goto nomem;
01182     }
01183   else
01184     {
01185       int i;
01186       
01187       i = 0;
01188       while (path[i])
01189         {
01190           if (!_dbus_string_append_byte (&str, '/'))
01191             goto nomem;
01192           
01193           if (!_dbus_string_append (&str, path[i]))
01194             goto nomem;
01195           
01196           ++i;
01197         }
01198     }
01199 
01200   if (!_dbus_string_steal_data (&str, &s))
01201     goto nomem;
01202 
01203   _dbus_string_free (&str);
01204 
01205   return s;
01206 
01207  nomem:
01208   _dbus_string_free (&str);
01209   return NULL;
01210 }
01211 
01212 
01213 #ifdef DBUS_BUILD_TESTS
01214 
01215 #ifndef DOXYGEN_SHOULD_SKIP_THIS
01216 
01217 #include "dbus-test.h"
01218 #include <stdio.h>
01219 
01220 typedef enum 
01221 {
01222   STR_EQUAL,
01223   STR_PREFIX,
01224   STR_DIFFERENT
01225 } StrComparison;
01226 
01227 /* Returns TRUE if container is a parent of child
01228  */
01229 static StrComparison
01230 path_contains (const char **container,
01231                const char **child)
01232 {
01233   int i;
01234 
01235   i = 0;
01236   while (child[i] != NULL)
01237     {
01238       int v;
01239 
01240       if (container[i] == NULL)
01241         return STR_PREFIX; /* container ran out, child continues;
01242                             * thus the container is a parent of the
01243                             * child.
01244                             */
01245 
01246       _dbus_assert (container[i] != NULL);
01247       _dbus_assert (child[i] != NULL);
01248 
01249       v = strcmp (container[i], child[i]);
01250 
01251       if (v != 0)
01252         return STR_DIFFERENT; /* they overlap until here and then are different,
01253                                * not overlapping
01254                                */
01255 
01256       ++i;
01257     }
01258 
01259   /* Child ran out; if container also did, they are equal;
01260    * otherwise, the child is a parent of the container.
01261    */
01262   if (container[i] == NULL)
01263     return STR_EQUAL;
01264   else
01265     return STR_DIFFERENT;
01266 }
01267 
01268 #if 0
01269 static void
01270 spew_subtree_recurse (DBusObjectSubtree *subtree,
01271                       int                indent)
01272 {
01273   int i;
01274 
01275   i = 0;
01276   while (i < indent)
01277     {
01278       _dbus_verbose (" ");
01279       ++i;
01280     }
01281 
01282   _dbus_verbose ("%s (%d children)\n",
01283                  subtree->name, subtree->n_subtrees);
01284 
01285   i = 0;
01286   while (i < subtree->n_subtrees)
01287     {
01288       spew_subtree_recurse (subtree->subtrees[i], indent + 2);
01289 
01290       ++i;
01291     }
01292 }
01293 
01294 static void
01295 spew_tree (DBusObjectTree *tree)
01296 {
01297   spew_subtree_recurse (tree->root, 0);
01298 }
01299 #endif
01300 
01304 typedef struct
01305 {
01306   const char **path; 
01307   dbus_bool_t handler_fallback; 
01308   dbus_bool_t message_handled; 
01309   dbus_bool_t handler_unregistered; 
01310 } TreeTestData;
01311 
01312 
01313 static void
01314 test_unregister_function (DBusConnection  *connection,
01315                           void            *user_data)
01316 {
01317   TreeTestData *ttd = user_data;
01318 
01319   ttd->handler_unregistered = TRUE;
01320 }
01321 
01322 static DBusHandlerResult
01323 test_message_function (DBusConnection  *connection,
01324                        DBusMessage     *message,
01325                        void            *user_data)
01326 {
01327   TreeTestData *ttd = user_data;
01328 
01329   ttd->message_handled = TRUE;
01330 
01331   return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
01332 }
01333 
01334 static dbus_bool_t
01335 do_register (DBusObjectTree *tree,
01336              const char    **path,
01337              dbus_bool_t     fallback,
01338              int             i,
01339              TreeTestData   *tree_test_data)
01340 {
01341   DBusObjectPathVTable vtable = { test_unregister_function,
01342                                   test_message_function, NULL };
01343 
01344   tree_test_data[i].message_handled = FALSE;
01345   tree_test_data[i].handler_unregistered = FALSE;
01346   tree_test_data[i].handler_fallback = fallback;
01347   tree_test_data[i].path = path;
01348 
01349   if (!_dbus_object_tree_register (tree, fallback, path,
01350                                    &vtable,
01351                                    &tree_test_data[i],
01352                                    NULL))
01353     return FALSE;
01354 
01355   _dbus_assert (_dbus_object_tree_get_user_data_unlocked (tree, path) ==
01356                 &tree_test_data[i]);
01357   
01358   return TRUE;
01359 }
01360 
01361 static dbus_bool_t
01362 do_test_dispatch (DBusObjectTree *tree,
01363                   const char    **path,
01364                   int             i,
01365                   TreeTestData   *tree_test_data,
01366                   int             n_test_data)
01367 {
01368   DBusMessage *message;
01369   int j;
01370   DBusHandlerResult result;
01371   char *flat;
01372 
01373   message = NULL;
01374   
01375   flat = flatten_path (path);
01376   if (flat == NULL)
01377     goto oom;
01378 
01379   message = dbus_message_new_method_call (NULL,
01380                                           flat,
01381                                           "org.freedesktop.TestInterface",
01382                                           "Foo");
01383   dbus_free (flat);
01384   if (message == NULL)
01385     goto oom;
01386 
01387   j = 0;
01388   while (j < n_test_data)
01389     {
01390       tree_test_data[j].message_handled = FALSE;
01391       ++j;
01392     }
01393 
01394   result = _dbus_object_tree_dispatch_and_unlock (tree, message);
01395   if (result == DBUS_HANDLER_RESULT_NEED_MEMORY)
01396     goto oom;
01397 
01398   _dbus_assert (tree_test_data[i].message_handled);
01399 
01400   j = 0;
01401   while (j < n_test_data)
01402     {
01403       if (tree_test_data[j].message_handled)
01404         {
01405           if (tree_test_data[j].handler_fallback)
01406             _dbus_assert (path_contains (tree_test_data[j].path,
01407                                          path) != STR_DIFFERENT);
01408           else
01409             _dbus_assert (path_contains (tree_test_data[j].path, path) == STR_EQUAL);
01410         }
01411       else
01412         {
01413           if (tree_test_data[j].handler_fallback)
01414             _dbus_assert (path_contains (tree_test_data[j].path,
01415                                          path) == STR_DIFFERENT);
01416           else
01417             _dbus_assert (path_contains (tree_test_data[j].path, path) != STR_EQUAL);
01418         }
01419 
01420       ++j;
01421     }
01422 
01423   dbus_message_unref (message);
01424 
01425   return TRUE;
01426 
01427  oom:
01428   if (message)
01429     dbus_message_unref (message);
01430   return FALSE;
01431 }
01432 
01433 static size_t
01434 string_array_length (const char **array)
01435 {
01436   size_t i;
01437   for (i = 0; array[i]; i++) ;
01438   return i;
01439 }
01440 
01441 typedef struct
01442 {
01443   const char *path;
01444   const char *result[20];
01445 } DecomposePathTest;
01446 
01447 static DecomposePathTest decompose_tests[] = {
01448   { "/foo", { "foo", NULL } },
01449   { "/foo/bar", { "foo", "bar", NULL } },
01450   { "/", { NULL } },
01451   { "/a/b", { "a", "b", NULL } },
01452   { "/a/b/c", { "a", "b", "c", NULL } },
01453   { "/a/b/c/d", { "a", "b", "c", "d", NULL } },
01454   { "/foo/bar/q", { "foo", "bar", "q", NULL } },
01455   { "/foo/bar/this/is/longer", { "foo", "bar", "this", "is", "longer", NULL } }
01456 };
01457 
01458 static dbus_bool_t
01459 run_decompose_tests (void)
01460 {
01461   int i;
01462 
01463   i = 0;
01464   while (i < _DBUS_N_ELEMENTS (decompose_tests))
01465     {
01466       char **result;
01467       int    result_len;
01468       int    expected_len;
01469 
01470       if (!_dbus_decompose_path (decompose_tests[i].path,
01471                                  strlen (decompose_tests[i].path),
01472                                  &result, &result_len))
01473         return FALSE;
01474 
01475       expected_len = string_array_length (decompose_tests[i].result);
01476       
01477       if (result_len != (int) string_array_length ((const char**)result) ||
01478           expected_len != result_len ||
01479           path_contains (decompose_tests[i].result,
01480                          (const char**) result) != STR_EQUAL)
01481         {
01482           int real_len = string_array_length ((const char**)result);
01483           _dbus_warn ("Expected decompose of %s to have len %d, returned %d, appears to have %d\n",
01484                       decompose_tests[i].path, expected_len, result_len,
01485                       real_len);
01486           _dbus_warn ("Decompose resulted in elements: { ");
01487           i = 0;
01488           while (i < real_len)
01489             {
01490               _dbus_warn ("\"%s\"%s", result[i],
01491                           (i + 1) == real_len ? "" : ", ");
01492               ++i;
01493             }
01494           _dbus_warn ("}\n");
01495           _dbus_assert_not_reached ("path decompose failed\n");
01496         }
01497 
01498       dbus_free_string_array (result);
01499 
01500       ++i;
01501     }
01502   
01503   return TRUE;
01504 }
01505 
01506 static dbus_bool_t
01507 object_tree_test_iteration (void *data)
01508 {
01509   const char *path0[] = { NULL };
01510   const char *path1[] = { "foo", NULL };
01511   const char *path2[] = { "foo", "bar", NULL };
01512   const char *path3[] = { "foo", "bar", "baz", NULL };
01513   const char *path4[] = { "foo", "bar", "boo", NULL };
01514   const char *path5[] = { "blah", NULL };
01515   const char *path6[] = { "blah", "boof", NULL };
01516   const char *path7[] = { "blah", "boof", "this", "is", "really", "long", NULL };
01517   const char *path8[] = { "childless", NULL };
01518   DBusObjectTree *tree;
01519   TreeTestData tree_test_data[9];
01520   int i;
01521   dbus_bool_t exact_match;
01522 
01523   if (!run_decompose_tests ())
01524     return FALSE;
01525   
01526   tree = NULL;
01527 
01528   tree = _dbus_object_tree_new (NULL);
01529   if (tree == NULL)
01530     goto out;
01531 
01532   if (!do_register (tree, path0, TRUE, 0, tree_test_data))
01533     goto out;
01534 
01535   _dbus_assert (find_subtree (tree, path0, NULL));
01536   _dbus_assert (!find_subtree (tree, path1, NULL));
01537   _dbus_assert (!find_subtree (tree, path2, NULL));
01538   _dbus_assert (!find_subtree (tree, path3, NULL));
01539   _dbus_assert (!find_subtree (tree, path4, NULL));
01540   _dbus_assert (!find_subtree (tree, path5, NULL));
01541   _dbus_assert (!find_subtree (tree, path6, NULL));
01542   _dbus_assert (!find_subtree (tree, path7, NULL));
01543   _dbus_assert (!find_subtree (tree, path8, NULL));
01544 
01545   _dbus_assert (find_handler (tree, path0, &exact_match) && exact_match);
01546   _dbus_assert (find_handler (tree, path1, &exact_match) == tree->root && !exact_match);
01547   _dbus_assert (find_handler (tree, path2, &exact_match) == tree->root && !exact_match);
01548   _dbus_assert (find_handler (tree, path3, &exact_match) == tree->root && !exact_match);
01549   _dbus_assert (find_handler (tree, path4, &exact_match) == tree->root && !exact_match);
01550   _dbus_assert (find_handler (tree, path5, &exact_match) == tree->root && !exact_match);
01551   _dbus_assert (find_handler (tree, path6, &exact_match) == tree->root && !exact_match);
01552   _dbus_assert (find_handler (tree, path7, &exact_match) == tree->root && !exact_match);
01553   _dbus_assert (find_handler (tree, path8, &exact_match) == tree->root && !exact_match);
01554   
01555   if (!do_register (tree, path1, TRUE, 1, tree_test_data))
01556     goto out;
01557 
01558   _dbus_assert (find_subtree (tree, path0, NULL));
01559   _dbus_assert (find_subtree (tree, path1, NULL));
01560   _dbus_assert (!find_subtree (tree, path2, NULL));
01561   _dbus_assert (!find_subtree (tree, path3, NULL));
01562   _dbus_assert (!find_subtree (tree, path4, NULL));
01563   _dbus_assert (!find_subtree (tree, path5, NULL));
01564   _dbus_assert (!find_subtree (tree, path6, NULL));
01565   _dbus_assert (!find_subtree (tree, path7, NULL));
01566   _dbus_assert (!find_subtree (tree, path8, NULL));
01567 
01568   _dbus_assert (find_handler (tree, path0, &exact_match) &&  exact_match);
01569   _dbus_assert (find_handler (tree, path1, &exact_match) &&  exact_match);
01570   _dbus_assert (find_handler (tree, path2, &exact_match) && !exact_match);
01571   _dbus_assert (find_handler (tree, path3, &exact_match) && !exact_match);
01572   _dbus_assert (find_handler (tree, path4, &exact_match) && !exact_match);
01573   _dbus_assert (find_handler (tree, path5, &exact_match) == tree->root && !exact_match);
01574   _dbus_assert (find_handler (tree, path6, &exact_match) == tree->root && !exact_match);
01575   _dbus_assert (find_handler (tree, path7, &exact_match) == tree->root && !exact_match);
01576   _dbus_assert (find_handler (tree, path8, &exact_match) == tree->root && !exact_match);
01577 
01578   if (!do_register (tree, path2, TRUE, 2, tree_test_data))
01579     goto out;
01580 
01581   _dbus_assert (find_subtree (tree, path1, NULL));
01582   _dbus_assert (find_subtree (tree, path2, NULL));
01583   _dbus_assert (!find_subtree (tree, path3, NULL));
01584   _dbus_assert (!find_subtree (tree, path4, NULL));
01585   _dbus_assert (!find_subtree (tree, path5, NULL));
01586   _dbus_assert (!find_subtree (tree, path6, NULL));
01587   _dbus_assert (!find_subtree (tree, path7, NULL));
01588   _dbus_assert (!find_subtree (tree, path8, NULL));
01589 
01590   if (!do_register (tree, path3, TRUE, 3, tree_test_data))
01591     goto out;
01592 
01593   _dbus_assert (find_subtree (tree, path0, NULL));
01594   _dbus_assert (find_subtree (tree, path1, NULL));
01595   _dbus_assert (find_subtree (tree, path2, NULL));
01596   _dbus_assert (find_subtree (tree, path3, NULL));
01597   _dbus_assert (!find_subtree (tree, path4, NULL));
01598   _dbus_assert (!find_subtree (tree, path5, NULL));
01599   _dbus_assert (!find_subtree (tree, path6, NULL));
01600   _dbus_assert (!find_subtree (tree, path7, NULL));
01601   _dbus_assert (!find_subtree (tree, path8, NULL));
01602   
01603   if (!do_register (tree, path4, TRUE, 4, tree_test_data))
01604     goto out;
01605 
01606   _dbus_assert (find_subtree (tree, path0, NULL));
01607   _dbus_assert (find_subtree (tree, path1, NULL));
01608   _dbus_assert (find_subtree (tree, path2, NULL));
01609   _dbus_assert (find_subtree (tree, path3, NULL));  
01610   _dbus_assert (find_subtree (tree, path4, NULL));
01611   _dbus_assert (!find_subtree (tree, path5, NULL));
01612   _dbus_assert (!find_subtree (tree, path6, NULL));
01613   _dbus_assert (!find_subtree (tree, path7, NULL));
01614   _dbus_assert (!find_subtree (tree, path8, NULL));
01615   
01616   if (!do_register (tree, path5, TRUE, 5, tree_test_data))
01617     goto out;
01618 
01619   _dbus_assert (find_subtree (tree, path0, NULL));
01620   _dbus_assert (find_subtree (tree, path1, NULL));
01621   _dbus_assert (find_subtree (tree, path2, NULL));
01622   _dbus_assert (find_subtree (tree, path3, NULL));
01623   _dbus_assert (find_subtree (tree, path4, NULL));
01624   _dbus_assert (find_subtree (tree, path5, NULL));
01625   _dbus_assert (!find_subtree (tree, path6, NULL));
01626   _dbus_assert (!find_subtree (tree, path7, NULL));
01627   _dbus_assert (!find_subtree (tree, path8, NULL));
01628 
01629   _dbus_assert (find_handler (tree, path0, &exact_match) == tree->root &&  exact_match);
01630   _dbus_assert (find_handler (tree, path1, &exact_match) != tree->root &&  exact_match);
01631   _dbus_assert (find_handler (tree, path2, &exact_match) != tree->root &&  exact_match);
01632   _dbus_assert (find_handler (tree, path3, &exact_match) != tree->root &&  exact_match);
01633   _dbus_assert (find_handler (tree, path4, &exact_match) != tree->root &&  exact_match);
01634   _dbus_assert (find_handler (tree, path5, &exact_match) != tree->root &&  exact_match);
01635   _dbus_assert (find_handler (tree, path6, &exact_match) != tree->root && !exact_match);
01636   _dbus_assert (find_handler (tree, path7, &exact_match) != tree->root && !exact_match);
01637   _dbus_assert (find_handler (tree, path8, &exact_match) == tree->root && !exact_match);
01638 
01639   if (!do_register (tree, path6, TRUE, 6, tree_test_data))
01640     goto out;
01641 
01642   _dbus_assert (find_subtree (tree, path0, NULL));
01643   _dbus_assert (find_subtree (tree, path1, NULL));
01644   _dbus_assert (find_subtree (tree, path2, NULL));
01645   _dbus_assert (find_subtree (tree, path3, NULL));
01646   _dbus_assert (find_subtree (tree, path4, NULL));
01647   _dbus_assert (find_subtree (tree, path5, NULL));
01648   _dbus_assert (find_subtree (tree, path6, NULL));
01649   _dbus_assert (!find_subtree (tree, path7, NULL));
01650   _dbus_assert (!find_subtree (tree, path8, NULL));
01651 
01652   if (!do_register (tree, path7, TRUE, 7, tree_test_data))
01653     goto out;
01654 
01655   _dbus_assert (find_subtree (tree, path0, NULL));
01656   _dbus_assert (find_subtree (tree, path1, NULL));
01657   _dbus_assert (find_subtree (tree, path2, NULL));
01658   _dbus_assert (find_subtree (tree, path3, NULL));
01659   _dbus_assert (find_subtree (tree, path4, NULL));
01660   _dbus_assert (find_subtree (tree, path5, NULL));
01661   _dbus_assert (find_subtree (tree, path6, NULL));
01662   _dbus_assert (find_subtree (tree, path7, NULL));
01663   _dbus_assert (!find_subtree (tree, path8, NULL));
01664 
01665   if (!do_register (tree, path8, TRUE, 8, tree_test_data))
01666     goto out;
01667 
01668   _dbus_assert (find_subtree (tree, path0, NULL));
01669   _dbus_assert (find_subtree (tree, path1, NULL));
01670   _dbus_assert (find_subtree (tree, path2, NULL));
01671   _dbus_assert (find_subtree (tree, path3, NULL));
01672   _dbus_assert (find_subtree (tree, path4, NULL));
01673   _dbus_assert (find_subtree (tree, path5, NULL));
01674   _dbus_assert (find_subtree (tree, path6, NULL));
01675   _dbus_assert (find_subtree (tree, path7, NULL));
01676   _dbus_assert (find_subtree (tree, path8, NULL));
01677 
01678   _dbus_assert (find_handler (tree, path0, &exact_match) == tree->root &&  exact_match);
01679   _dbus_assert (find_handler (tree, path1, &exact_match) != tree->root && exact_match);
01680   _dbus_assert (find_handler (tree, path2, &exact_match) != tree->root && exact_match);
01681   _dbus_assert (find_handler (tree, path3, &exact_match) != tree->root && exact_match);
01682   _dbus_assert (find_handler (tree, path4, &exact_match) != tree->root && exact_match);
01683   _dbus_assert (find_handler (tree, path5, &exact_match) != tree->root && exact_match);
01684   _dbus_assert (find_handler (tree, path6, &exact_match) != tree->root && exact_match);
01685   _dbus_assert (find_handler (tree, path7, &exact_match) != tree->root && exact_match);
01686   _dbus_assert (find_handler (tree, path8, &exact_match) != tree->root && exact_match);
01687   
01688   /* test the list_registered function */
01689 
01690   {
01691     const char *root[] = { NULL };
01692     char **child_entries;
01693     int nb;
01694 
01695     _dbus_object_tree_list_registered_unlocked (tree, path1, &child_entries);
01696     if (child_entries != NULL)
01697       {
01698         nb = string_array_length ((const char**)child_entries);
01699         _dbus_assert (nb == 1);
01700         dbus_free_string_array (child_entries);
01701       }
01702 
01703     _dbus_object_tree_list_registered_unlocked (tree, path2, &child_entries);
01704     if (child_entries != NULL)
01705       {
01706         nb = string_array_length ((const char**)child_entries);
01707         _dbus_assert (nb == 2);
01708         dbus_free_string_array (child_entries);
01709       }
01710 
01711     _dbus_object_tree_list_registered_unlocked (tree, path8, &child_entries);
01712     if (child_entries != NULL)
01713       {
01714         nb = string_array_length ((const char**)child_entries);
01715         _dbus_assert (nb == 0);
01716         dbus_free_string_array (child_entries);
01717       }
01718 
01719     _dbus_object_tree_list_registered_unlocked (tree, root, &child_entries);
01720     if (child_entries != NULL)
01721       {
01722         nb = string_array_length ((const char**)child_entries);
01723         _dbus_assert (nb == 3);
01724         dbus_free_string_array (child_entries);
01725       }
01726   }
01727 
01728   /* Check that destroying tree calls unregister funcs */
01729   _dbus_object_tree_unref (tree);
01730 
01731   i = 0;
01732   while (i < (int) _DBUS_N_ELEMENTS (tree_test_data))
01733     {
01734       _dbus_assert (tree_test_data[i].handler_unregistered);
01735       _dbus_assert (!tree_test_data[i].message_handled);
01736       ++i;
01737     }
01738 
01739   /* Now start again and try the individual unregister function */
01740   tree = _dbus_object_tree_new (NULL);
01741   if (tree == NULL)
01742     goto out;
01743 
01744   if (!do_register (tree, path0, TRUE, 0, tree_test_data))
01745     goto out;
01746   if (!do_register (tree, path1, TRUE, 1, tree_test_data))
01747     goto out;
01748   if (!do_register (tree, path2, TRUE, 2, tree_test_data))
01749     goto out;
01750   if (!do_register (tree, path3, TRUE, 3, tree_test_data))
01751     goto out;
01752   if (!do_register (tree, path4, TRUE, 4, tree_test_data))
01753     goto out;
01754   if (!do_register (tree, path5, TRUE, 5, tree_test_data))
01755     goto out;
01756   if (!do_register (tree, path6, TRUE, 6, tree_test_data))
01757     goto out;
01758   if (!do_register (tree, path7, TRUE, 7, tree_test_data))
01759     goto out;
01760   if (!do_register (tree, path8, TRUE, 8, tree_test_data))
01761     goto out;
01762 
01763   _dbus_object_tree_unregister_and_unlock (tree, path0);
01764   _dbus_assert (_dbus_object_tree_get_user_data_unlocked (tree, path0) == NULL);
01765 
01766   _dbus_assert (!find_subtree (tree, path0, NULL));
01767   _dbus_assert (find_subtree (tree, path1, NULL));
01768   _dbus_assert (find_subtree (tree, path2, NULL));
01769   _dbus_assert (find_subtree (tree, path3, NULL));
01770   _dbus_assert (find_subtree (tree, path4, NULL));
01771   _dbus_assert (find_subtree (tree, path5, NULL));
01772   _dbus_assert (find_subtree (tree, path6, NULL));
01773   _dbus_assert (find_subtree (tree, path7, NULL));
01774   _dbus_assert (find_subtree (tree, path8, NULL));
01775   
01776   _dbus_object_tree_unregister_and_unlock (tree, path1);
01777   _dbus_assert (_dbus_object_tree_get_user_data_unlocked (tree, path1) == NULL);
01778 
01779   _dbus_assert (!find_subtree (tree, path0, NULL));
01780   _dbus_assert (!find_subtree (tree, path1, NULL));
01781   _dbus_assert (find_subtree (tree, path2, NULL));
01782   _dbus_assert (find_subtree (tree, path3, NULL));
01783   _dbus_assert (find_subtree (tree, path4, NULL));
01784   _dbus_assert (find_subtree (tree, path5, NULL));
01785   _dbus_assert (find_subtree (tree, path6, NULL));
01786   _dbus_assert (find_subtree (tree, path7, NULL));
01787   _dbus_assert (find_subtree (tree, path8, NULL));
01788 
01789   _dbus_object_tree_unregister_and_unlock (tree, path2);
01790   _dbus_assert (_dbus_object_tree_get_user_data_unlocked (tree, path2) == NULL);
01791 
01792   _dbus_assert (!find_subtree (tree, path0, NULL));
01793   _dbus_assert (!find_subtree (tree, path1, NULL));
01794   _dbus_assert (!find_subtree (tree, path2, NULL));
01795   _dbus_assert (find_subtree (tree, path3, NULL));
01796   _dbus_assert (find_subtree (tree, path4, NULL));
01797   _dbus_assert (find_subtree (tree, path5, NULL));
01798   _dbus_assert (find_subtree (tree, path6, NULL));
01799   _dbus_assert (find_subtree (tree, path7, NULL));
01800   _dbus_assert (find_subtree (tree, path8, NULL));
01801   
01802   _dbus_object_tree_unregister_and_unlock (tree, path3);
01803   _dbus_assert (_dbus_object_tree_get_user_data_unlocked (tree, path3) == NULL);
01804 
01805   _dbus_assert (!find_subtree (tree, path0, NULL));
01806   _dbus_assert (!find_subtree (tree, path1, NULL));
01807   _dbus_assert (!find_subtree (tree, path2, NULL));
01808   _dbus_assert (!find_subtree (tree, path3, NULL));
01809   _dbus_assert (find_subtree (tree, path4, NULL));
01810   _dbus_assert (find_subtree (tree, path5, NULL));
01811   _dbus_assert (find_subtree (tree, path6, NULL));
01812   _dbus_assert (find_subtree (tree, path7, NULL));
01813   _dbus_assert (find_subtree (tree, path8, NULL));
01814   
01815   _dbus_object_tree_unregister_and_unlock (tree, path4);
01816   _dbus_assert (_dbus_object_tree_get_user_data_unlocked (tree, path4) == NULL);
01817 
01818   _dbus_assert (!find_subtree (tree, path0, NULL));
01819   _dbus_assert (!find_subtree (tree, path1, NULL));
01820   _dbus_assert (!find_subtree (tree, path2, NULL));
01821   _dbus_assert (!find_subtree (tree, path3, NULL));
01822   _dbus_assert (!find_subtree (tree, path4, NULL));
01823   _dbus_assert (find_subtree (tree, path5, NULL));
01824   _dbus_assert (find_subtree (tree, path6, NULL));
01825   _dbus_assert (find_subtree (tree, path7, NULL));
01826   _dbus_assert (find_subtree (tree, path8, NULL));
01827   
01828   _dbus_object_tree_unregister_and_unlock (tree, path5);
01829   _dbus_assert (_dbus_object_tree_get_user_data_unlocked (tree, path5) == NULL);
01830 
01831   _dbus_assert (!find_subtree (tree, path0, NULL));
01832   _dbus_assert (!find_subtree (tree, path1, NULL));
01833   _dbus_assert (!find_subtree (tree, path2, NULL));
01834   _dbus_assert (!find_subtree (tree, path3, NULL));
01835   _dbus_assert (!find_subtree (tree, path4, NULL));
01836   _dbus_assert (!find_subtree (tree, path5, NULL));
01837   _dbus_assert (find_subtree (tree, path6, NULL));
01838   _dbus_assert (find_subtree (tree, path7, NULL));
01839   _dbus_assert (find_subtree (tree, path8, NULL));
01840   
01841   _dbus_object_tree_unregister_and_unlock (tree, path6);
01842   _dbus_assert (_dbus_object_tree_get_user_data_unlocked (tree, path6) == NULL);
01843 
01844   _dbus_assert (!find_subtree (tree, path0, NULL));
01845   _dbus_assert (!find_subtree (tree, path1, NULL));
01846   _dbus_assert (!find_subtree (tree, path2, NULL));
01847   _dbus_assert (!find_subtree (tree, path3, NULL));
01848   _dbus_assert (!find_subtree (tree, path4, NULL));
01849   _dbus_assert (!find_subtree (tree, path5, NULL));
01850   _dbus_assert (!find_subtree (tree, path6, NULL));
01851   _dbus_assert (find_subtree (tree, path7, NULL));
01852   _dbus_assert (find_subtree (tree, path8, NULL));
01853 
01854   _dbus_object_tree_unregister_and_unlock (tree, path7);
01855   _dbus_assert (_dbus_object_tree_get_user_data_unlocked (tree, path7) == NULL);
01856 
01857   _dbus_assert (!find_subtree (tree, path0, NULL));
01858   _dbus_assert (!find_subtree (tree, path1, NULL));
01859   _dbus_assert (!find_subtree (tree, path2, NULL));
01860   _dbus_assert (!find_subtree (tree, path3, NULL));
01861   _dbus_assert (!find_subtree (tree, path4, NULL));
01862   _dbus_assert (!find_subtree (tree, path5, NULL));
01863   _dbus_assert (!find_subtree (tree, path6, NULL));
01864   _dbus_assert (!find_subtree (tree, path7, NULL));
01865   _dbus_assert (find_subtree (tree, path8, NULL));
01866 
01867   _dbus_object_tree_unregister_and_unlock (tree, path8);
01868   _dbus_assert (_dbus_object_tree_get_user_data_unlocked (tree, path8) == NULL);
01869 
01870   _dbus_assert (!find_subtree (tree, path0, NULL));
01871   _dbus_assert (!find_subtree (tree, path1, NULL));
01872   _dbus_assert (!find_subtree (tree, path2, NULL));
01873   _dbus_assert (!find_subtree (tree, path3, NULL));
01874   _dbus_assert (!find_subtree (tree, path4, NULL));
01875   _dbus_assert (!find_subtree (tree, path5, NULL));
01876   _dbus_assert (!find_subtree (tree, path6, NULL));
01877   _dbus_assert (!find_subtree (tree, path7, NULL));
01878   _dbus_assert (!find_subtree (tree, path8, NULL));
01879   
01880   i = 0;
01881   while (i < (int) _DBUS_N_ELEMENTS (tree_test_data))
01882     {
01883       _dbus_assert (tree_test_data[i].handler_unregistered);
01884       _dbus_assert (!tree_test_data[i].message_handled);
01885       ++i;
01886     }
01887 
01888   /* Register it all again, and test dispatch */
01889   
01890   if (!do_register (tree, path0, TRUE, 0, tree_test_data))
01891     goto out;
01892   if (!do_register (tree, path1, FALSE, 1, tree_test_data))
01893     goto out;
01894   if (!do_register (tree, path2, TRUE, 2, tree_test_data))
01895     goto out;
01896   if (!do_register (tree, path3, TRUE, 3, tree_test_data))
01897     goto out;
01898   if (!do_register (tree, path4, TRUE, 4, tree_test_data))
01899     goto out;
01900   if (!do_register (tree, path5, TRUE, 5, tree_test_data))
01901     goto out;
01902   if (!do_register (tree, path6, FALSE, 6, tree_test_data))
01903     goto out;
01904   if (!do_register (tree, path7, TRUE, 7, tree_test_data))
01905     goto out;
01906   if (!do_register (tree, path8, TRUE, 8, tree_test_data))
01907     goto out;
01908 
01909 #if 0
01910   spew_tree (tree);
01911 #endif
01912 
01913   if (!do_test_dispatch (tree, path0, 0, tree_test_data, _DBUS_N_ELEMENTS (tree_test_data)))
01914     goto out;
01915   if (!do_test_dispatch (tree, path1, 1, tree_test_data, _DBUS_N_ELEMENTS (tree_test_data)))
01916     goto out;
01917   if (!do_test_dispatch (tree, path2, 2, tree_test_data, _DBUS_N_ELEMENTS (tree_test_data)))
01918     goto out;
01919   if (!do_test_dispatch (tree, path3, 3, tree_test_data, _DBUS_N_ELEMENTS (tree_test_data)))
01920     goto out;
01921   if (!do_test_dispatch (tree, path4, 4, tree_test_data, _DBUS_N_ELEMENTS (tree_test_data)))
01922     goto out;
01923   if (!do_test_dispatch (tree, path5, 5, tree_test_data, _DBUS_N_ELEMENTS (tree_test_data)))
01924     goto out;
01925   if (!do_test_dispatch (tree, path6, 6, tree_test_data, _DBUS_N_ELEMENTS (tree_test_data)))
01926     goto out;
01927   if (!do_test_dispatch (tree, path7, 7, tree_test_data, _DBUS_N_ELEMENTS (tree_test_data)))
01928     goto out;
01929   if (!do_test_dispatch (tree, path8, 8, tree_test_data, _DBUS_N_ELEMENTS (tree_test_data)))
01930     goto out;
01931   
01932  out:
01933   if (tree)
01934     {
01935       /* test ref */
01936       _dbus_object_tree_ref (tree);
01937       _dbus_object_tree_unref (tree);
01938       _dbus_object_tree_unref (tree);
01939     }
01940 
01941   return TRUE;
01942 }
01943 
01949 dbus_bool_t
01950 _dbus_object_tree_test (void)
01951 {
01952   _dbus_test_oom_handling ("object tree",
01953                            object_tree_test_iteration,
01954                            NULL);
01955 
01956   return TRUE;
01957 }
01958 
01959 #endif /* !DOXYGEN_SHOULD_SKIP_THIS */
01960 
01961 #endif /* DBUS_BUILD_TESTS */