D-Bus 1.4.0
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_malloc (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   subtree->refcount.value = 1;
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   _dbus_assert (subtree->refcount.value > 0);
01006   _dbus_atomic_inc (&subtree->refcount);
01007 
01008   return subtree;
01009 }
01010 
01011 static void
01012 _dbus_object_subtree_unref (DBusObjectSubtree *subtree)
01013 {
01014   _dbus_assert (subtree->refcount.value > 0);
01015 
01016   if (_dbus_atomic_dec (&subtree->refcount) == 1)
01017     {
01018       _dbus_assert (subtree->unregister_function == NULL);
01019       _dbus_assert (subtree->message_function == NULL);
01020 
01021       dbus_free (subtree->subtrees);
01022       dbus_free (subtree);
01023     }
01024 }
01025 
01036 dbus_bool_t
01037 _dbus_object_tree_list_registered_and_unlock (DBusObjectTree *tree,
01038                                               const char    **parent_path,
01039                                               char         ***child_entries)
01040 {
01041   dbus_bool_t result;
01042 
01043   result = _dbus_object_tree_list_registered_unlocked (tree,
01044                                                        parent_path,
01045                                                        child_entries);
01046   
01047 #ifdef DBUS_BUILD_TESTS
01048   if (tree->connection)
01049 #endif
01050     {
01051       _dbus_verbose ("unlock\n");
01052       _dbus_connection_unlock (tree->connection);
01053     }
01054 
01055   return result;
01056 }
01057 
01058 
01060 #define VERBOSE_DECOMPOSE 0
01061 
01072 dbus_bool_t
01073 _dbus_decompose_path (const char*     data,
01074                       int             len,
01075                       char         ***path,
01076                       int            *path_len)
01077 {
01078   char **retval;
01079   int n_components;
01080   int i, j, comp;
01081 
01082   _dbus_assert (data != NULL);
01083   _dbus_assert (path != NULL);
01084   
01085 #if VERBOSE_DECOMPOSE
01086   _dbus_verbose ("Decomposing path \"%s\"\n",
01087                  data);
01088 #endif
01089   
01090   n_components = 0;
01091   if (len > 1) /* if path is not just "/" */
01092     {
01093       i = 0;
01094       while (i < len)
01095         {
01096           _dbus_assert (data[i] != '\0');
01097           if (data[i] == '/')
01098             n_components += 1;
01099           ++i;
01100         }
01101     }
01102   
01103   retval = dbus_new0 (char*, n_components + 1);
01104 
01105   if (retval == NULL)
01106     return FALSE;
01107 
01108   comp = 0;
01109   if (n_components == 0)
01110     i = 1;
01111   else
01112     i = 0;
01113   while (comp < n_components)
01114     {
01115       _dbus_assert (i < len);
01116       
01117       if (data[i] == '/')
01118         ++i;
01119       j = i;
01120 
01121       while (j < len && data[j] != '/')
01122         ++j;
01123 
01124       /* Now [i, j) is the path component */
01125       _dbus_assert (i < j);
01126       _dbus_assert (data[i] != '/');
01127       _dbus_assert (j == len || data[j] == '/');
01128 
01129 #if VERBOSE_DECOMPOSE
01130       _dbus_verbose ("  (component in [%d,%d))\n",
01131                      i, j);
01132 #endif
01133       
01134       retval[comp] = _dbus_memdup (&data[i], j - i + 1);
01135       if (retval[comp] == NULL)
01136         {
01137           dbus_free_string_array (retval);
01138           return FALSE;
01139         }
01140       retval[comp][j-i] = '\0';
01141 #if VERBOSE_DECOMPOSE
01142       _dbus_verbose ("  (component %d = \"%s\")\n",
01143                      comp, retval[comp]);
01144 #endif
01145 
01146       ++comp;
01147       i = j;
01148     }
01149   _dbus_assert (i == len);
01150   
01151   *path = retval;
01152   if (path_len)
01153     *path_len = n_components;
01154   
01155   return TRUE;
01156 }
01157 
01160 static char*
01161 flatten_path (const char **path)
01162 {
01163   DBusString str;
01164   char *s;
01165 
01166   if (!_dbus_string_init (&str))
01167     return NULL;
01168 
01169   if (path[0] == NULL)
01170     {
01171       if (!_dbus_string_append_byte (&str, '/'))
01172         goto nomem;
01173     }
01174   else
01175     {
01176       int i;
01177       
01178       i = 0;
01179       while (path[i])
01180         {
01181           if (!_dbus_string_append_byte (&str, '/'))
01182             goto nomem;
01183           
01184           if (!_dbus_string_append (&str, path[i]))
01185             goto nomem;
01186           
01187           ++i;
01188         }
01189     }
01190 
01191   if (!_dbus_string_steal_data (&str, &s))
01192     goto nomem;
01193 
01194   _dbus_string_free (&str);
01195 
01196   return s;
01197 
01198  nomem:
01199   _dbus_string_free (&str);
01200   return NULL;
01201 }
01202 
01203 
01204 #ifdef DBUS_BUILD_TESTS
01205 
01206 #ifndef DOXYGEN_SHOULD_SKIP_THIS
01207 
01208 #include "dbus-test.h"
01209 #include <stdio.h>
01210 
01211 typedef enum 
01212 {
01213   STR_EQUAL,
01214   STR_PREFIX,
01215   STR_DIFFERENT
01216 } StrComparison;
01217 
01218 /* Returns TRUE if container is a parent of child
01219  */
01220 static StrComparison
01221 path_contains (const char **container,
01222                const char **child)
01223 {
01224   int i;
01225 
01226   i = 0;
01227   while (child[i] != NULL)
01228     {
01229       int v;
01230 
01231       if (container[i] == NULL)
01232         return STR_PREFIX; /* container ran out, child continues;
01233                             * thus the container is a parent of the
01234                             * child.
01235                             */
01236 
01237       _dbus_assert (container[i] != NULL);
01238       _dbus_assert (child[i] != NULL);
01239 
01240       v = strcmp (container[i], child[i]);
01241 
01242       if (v != 0)
01243         return STR_DIFFERENT; /* they overlap until here and then are different,
01244                                * not overlapping
01245                                */
01246 
01247       ++i;
01248     }
01249 
01250   /* Child ran out; if container also did, they are equal;
01251    * otherwise, the child is a parent of the container.
01252    */
01253   if (container[i] == NULL)
01254     return STR_EQUAL;
01255   else
01256     return STR_DIFFERENT;
01257 }
01258 
01259 #if 0
01260 static void
01261 spew_subtree_recurse (DBusObjectSubtree *subtree,
01262                       int                indent)
01263 {
01264   int i;
01265 
01266   i = 0;
01267   while (i < indent)
01268     {
01269       _dbus_verbose (" ");
01270       ++i;
01271     }
01272 
01273   _dbus_verbose ("%s (%d children)\n",
01274                  subtree->name, subtree->n_subtrees);
01275 
01276   i = 0;
01277   while (i < subtree->n_subtrees)
01278     {
01279       spew_subtree_recurse (subtree->subtrees[i], indent + 2);
01280 
01281       ++i;
01282     }
01283 }
01284 
01285 static void
01286 spew_tree (DBusObjectTree *tree)
01287 {
01288   spew_subtree_recurse (tree->root, 0);
01289 }
01290 #endif
01291 
01295 typedef struct
01296 {
01297   const char **path; 
01298   dbus_bool_t handler_fallback; 
01299   dbus_bool_t message_handled; 
01300   dbus_bool_t handler_unregistered; 
01301 } TreeTestData;
01302 
01303 
01304 static void
01305 test_unregister_function (DBusConnection  *connection,
01306                           void            *user_data)
01307 {
01308   TreeTestData *ttd = user_data;
01309 
01310   ttd->handler_unregistered = TRUE;
01311 }
01312 
01313 static DBusHandlerResult
01314 test_message_function (DBusConnection  *connection,
01315                        DBusMessage     *message,
01316                        void            *user_data)
01317 {
01318   TreeTestData *ttd = user_data;
01319 
01320   ttd->message_handled = TRUE;
01321 
01322   return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
01323 }
01324 
01325 static dbus_bool_t
01326 do_register (DBusObjectTree *tree,
01327              const char    **path,
01328              dbus_bool_t     fallback,
01329              int             i,
01330              TreeTestData   *tree_test_data)
01331 {
01332   DBusObjectPathVTable vtable = { test_unregister_function,
01333                                   test_message_function, NULL };
01334 
01335   tree_test_data[i].message_handled = FALSE;
01336   tree_test_data[i].handler_unregistered = FALSE;
01337   tree_test_data[i].handler_fallback = fallback;
01338   tree_test_data[i].path = path;
01339 
01340   if (!_dbus_object_tree_register (tree, fallback, path,
01341                                    &vtable,
01342                                    &tree_test_data[i],
01343                                    NULL))
01344     return FALSE;
01345 
01346   _dbus_assert (_dbus_object_tree_get_user_data_unlocked (tree, path) ==
01347                 &tree_test_data[i]);
01348   
01349   return TRUE;
01350 }
01351 
01352 static dbus_bool_t
01353 do_test_dispatch (DBusObjectTree *tree,
01354                   const char    **path,
01355                   int             i,
01356                   TreeTestData   *tree_test_data,
01357                   int             n_test_data)
01358 {
01359   DBusMessage *message;
01360   int j;
01361   DBusHandlerResult result;
01362   char *flat;
01363 
01364   message = NULL;
01365   
01366   flat = flatten_path (path);
01367   if (flat == NULL)
01368     goto oom;
01369 
01370   message = dbus_message_new_method_call (NULL,
01371                                           flat,
01372                                           "org.freedesktop.TestInterface",
01373                                           "Foo");
01374   dbus_free (flat);
01375   if (message == NULL)
01376     goto oom;
01377 
01378   j = 0;
01379   while (j < n_test_data)
01380     {
01381       tree_test_data[j].message_handled = FALSE;
01382       ++j;
01383     }
01384 
01385   result = _dbus_object_tree_dispatch_and_unlock (tree, message);
01386   if (result == DBUS_HANDLER_RESULT_NEED_MEMORY)
01387     goto oom;
01388 
01389   _dbus_assert (tree_test_data[i].message_handled);
01390 
01391   j = 0;
01392   while (j < n_test_data)
01393     {
01394       if (tree_test_data[j].message_handled)
01395         {
01396           if (tree_test_data[j].handler_fallback)
01397             _dbus_assert (path_contains (tree_test_data[j].path,
01398                                          path) != STR_DIFFERENT);
01399           else
01400             _dbus_assert (path_contains (tree_test_data[j].path, path) == STR_EQUAL);
01401         }
01402       else
01403         {
01404           if (tree_test_data[j].handler_fallback)
01405             _dbus_assert (path_contains (tree_test_data[j].path,
01406                                          path) == STR_DIFFERENT);
01407           else
01408             _dbus_assert (path_contains (tree_test_data[j].path, path) != STR_EQUAL);
01409         }
01410 
01411       ++j;
01412     }
01413 
01414   dbus_message_unref (message);
01415 
01416   return TRUE;
01417 
01418  oom:
01419   if (message)
01420     dbus_message_unref (message);
01421   return FALSE;
01422 }
01423 
01424 static size_t
01425 string_array_length (const char **array)
01426 {
01427   size_t i;
01428   for (i = 0; array[i]; i++) ;
01429   return i;
01430 }
01431 
01432 typedef struct
01433 {
01434   const char *path;
01435   const char *result[20];
01436 } DecomposePathTest;
01437 
01438 static DecomposePathTest decompose_tests[] = {
01439   { "/foo", { "foo", NULL } },
01440   { "/foo/bar", { "foo", "bar", NULL } },
01441   { "/", { NULL } },
01442   { "/a/b", { "a", "b", NULL } },
01443   { "/a/b/c", { "a", "b", "c", NULL } },
01444   { "/a/b/c/d", { "a", "b", "c", "d", NULL } },
01445   { "/foo/bar/q", { "foo", "bar", "q", NULL } },
01446   { "/foo/bar/this/is/longer", { "foo", "bar", "this", "is", "longer", NULL } }
01447 };
01448 
01449 static dbus_bool_t
01450 run_decompose_tests (void)
01451 {
01452   int i;
01453 
01454   i = 0;
01455   while (i < _DBUS_N_ELEMENTS (decompose_tests))
01456     {
01457       char **result;
01458       int    result_len;
01459       int    expected_len;
01460 
01461       if (!_dbus_decompose_path (decompose_tests[i].path,
01462                                  strlen (decompose_tests[i].path),
01463                                  &result, &result_len))
01464         return FALSE;
01465 
01466       expected_len = string_array_length (decompose_tests[i].result);
01467       
01468       if (result_len != (int) string_array_length ((const char**)result) ||
01469           expected_len != result_len ||
01470           path_contains (decompose_tests[i].result,
01471                          (const char**) result) != STR_EQUAL)
01472         {
01473           int real_len = string_array_length ((const char**)result);
01474           _dbus_warn ("Expected decompose of %s to have len %d, returned %d, appears to have %d\n",
01475                       decompose_tests[i].path, expected_len, result_len,
01476                       real_len);
01477           _dbus_warn ("Decompose resulted in elements: { ");
01478           i = 0;
01479           while (i < real_len)
01480             {
01481               _dbus_warn ("\"%s\"%s", result[i],
01482                           (i + 1) == real_len ? "" : ", ");
01483               ++i;
01484             }
01485           _dbus_warn ("}\n");
01486           _dbus_assert_not_reached ("path decompose failed\n");
01487         }
01488 
01489       dbus_free_string_array (result);
01490 
01491       ++i;
01492     }
01493   
01494   return TRUE;
01495 }
01496 
01497 static dbus_bool_t
01498 object_tree_test_iteration (void *data)
01499 {
01500   const char *path0[] = { NULL };
01501   const char *path1[] = { "foo", NULL };
01502   const char *path2[] = { "foo", "bar", NULL };
01503   const char *path3[] = { "foo", "bar", "baz", NULL };
01504   const char *path4[] = { "foo", "bar", "boo", NULL };
01505   const char *path5[] = { "blah", NULL };
01506   const char *path6[] = { "blah", "boof", NULL };
01507   const char *path7[] = { "blah", "boof", "this", "is", "really", "long", NULL };
01508   const char *path8[] = { "childless", NULL };
01509   DBusObjectTree *tree;
01510   TreeTestData tree_test_data[9];
01511   int i;
01512   dbus_bool_t exact_match;
01513 
01514   if (!run_decompose_tests ())
01515     return FALSE;
01516   
01517   tree = NULL;
01518 
01519   tree = _dbus_object_tree_new (NULL);
01520   if (tree == NULL)
01521     goto out;
01522 
01523   if (!do_register (tree, path0, TRUE, 0, tree_test_data))
01524     goto out;
01525 
01526   _dbus_assert (find_subtree (tree, path0, NULL));
01527   _dbus_assert (!find_subtree (tree, path1, NULL));
01528   _dbus_assert (!find_subtree (tree, path2, NULL));
01529   _dbus_assert (!find_subtree (tree, path3, NULL));
01530   _dbus_assert (!find_subtree (tree, path4, NULL));
01531   _dbus_assert (!find_subtree (tree, path5, NULL));
01532   _dbus_assert (!find_subtree (tree, path6, NULL));
01533   _dbus_assert (!find_subtree (tree, path7, NULL));
01534   _dbus_assert (!find_subtree (tree, path8, NULL));
01535 
01536   _dbus_assert (find_handler (tree, path0, &exact_match) && exact_match);
01537   _dbus_assert (find_handler (tree, path1, &exact_match) == tree->root && !exact_match);
01538   _dbus_assert (find_handler (tree, path2, &exact_match) == tree->root && !exact_match);
01539   _dbus_assert (find_handler (tree, path3, &exact_match) == tree->root && !exact_match);
01540   _dbus_assert (find_handler (tree, path4, &exact_match) == tree->root && !exact_match);
01541   _dbus_assert (find_handler (tree, path5, &exact_match) == tree->root && !exact_match);
01542   _dbus_assert (find_handler (tree, path6, &exact_match) == tree->root && !exact_match);
01543   _dbus_assert (find_handler (tree, path7, &exact_match) == tree->root && !exact_match);
01544   _dbus_assert (find_handler (tree, path8, &exact_match) == tree->root && !exact_match);
01545   
01546   if (!do_register (tree, path1, TRUE, 1, tree_test_data))
01547     goto out;
01548 
01549   _dbus_assert (find_subtree (tree, path0, NULL));
01550   _dbus_assert (find_subtree (tree, path1, NULL));
01551   _dbus_assert (!find_subtree (tree, path2, NULL));
01552   _dbus_assert (!find_subtree (tree, path3, NULL));
01553   _dbus_assert (!find_subtree (tree, path4, NULL));
01554   _dbus_assert (!find_subtree (tree, path5, NULL));
01555   _dbus_assert (!find_subtree (tree, path6, NULL));
01556   _dbus_assert (!find_subtree (tree, path7, NULL));
01557   _dbus_assert (!find_subtree (tree, path8, NULL));
01558 
01559   _dbus_assert (find_handler (tree, path0, &exact_match) &&  exact_match);
01560   _dbus_assert (find_handler (tree, path1, &exact_match) &&  exact_match);
01561   _dbus_assert (find_handler (tree, path2, &exact_match) && !exact_match);
01562   _dbus_assert (find_handler (tree, path3, &exact_match) && !exact_match);
01563   _dbus_assert (find_handler (tree, path4, &exact_match) && !exact_match);
01564   _dbus_assert (find_handler (tree, path5, &exact_match) == tree->root && !exact_match);
01565   _dbus_assert (find_handler (tree, path6, &exact_match) == tree->root && !exact_match);
01566   _dbus_assert (find_handler (tree, path7, &exact_match) == tree->root && !exact_match);
01567   _dbus_assert (find_handler (tree, path8, &exact_match) == tree->root && !exact_match);
01568 
01569   if (!do_register (tree, path2, TRUE, 2, tree_test_data))
01570     goto out;
01571 
01572   _dbus_assert (find_subtree (tree, path1, NULL));
01573   _dbus_assert (find_subtree (tree, path2, NULL));
01574   _dbus_assert (!find_subtree (tree, path3, NULL));
01575   _dbus_assert (!find_subtree (tree, path4, NULL));
01576   _dbus_assert (!find_subtree (tree, path5, NULL));
01577   _dbus_assert (!find_subtree (tree, path6, NULL));
01578   _dbus_assert (!find_subtree (tree, path7, NULL));
01579   _dbus_assert (!find_subtree (tree, path8, NULL));
01580 
01581   if (!do_register (tree, path3, TRUE, 3, tree_test_data))
01582     goto out;
01583 
01584   _dbus_assert (find_subtree (tree, path0, NULL));
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, path4, TRUE, 4, 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, path5, TRUE, 5, 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   _dbus_assert (find_handler (tree, path0, &exact_match) == tree->root &&  exact_match);
01621   _dbus_assert (find_handler (tree, path1, &exact_match) != tree->root &&  exact_match);
01622   _dbus_assert (find_handler (tree, path2, &exact_match) != tree->root &&  exact_match);
01623   _dbus_assert (find_handler (tree, path3, &exact_match) != tree->root &&  exact_match);
01624   _dbus_assert (find_handler (tree, path4, &exact_match) != tree->root &&  exact_match);
01625   _dbus_assert (find_handler (tree, path5, &exact_match) != tree->root &&  exact_match);
01626   _dbus_assert (find_handler (tree, path6, &exact_match) != tree->root && !exact_match);
01627   _dbus_assert (find_handler (tree, path7, &exact_match) != tree->root && !exact_match);
01628   _dbus_assert (find_handler (tree, path8, &exact_match) == tree->root && !exact_match);
01629 
01630   if (!do_register (tree, path6, TRUE, 6, tree_test_data))
01631     goto out;
01632 
01633   _dbus_assert (find_subtree (tree, path0, NULL));
01634   _dbus_assert (find_subtree (tree, path1, NULL));
01635   _dbus_assert (find_subtree (tree, path2, NULL));
01636   _dbus_assert (find_subtree (tree, path3, NULL));
01637   _dbus_assert (find_subtree (tree, path4, NULL));
01638   _dbus_assert (find_subtree (tree, path5, NULL));
01639   _dbus_assert (find_subtree (tree, path6, NULL));
01640   _dbus_assert (!find_subtree (tree, path7, NULL));
01641   _dbus_assert (!find_subtree (tree, path8, NULL));
01642 
01643   if (!do_register (tree, path7, TRUE, 7, 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, path8, TRUE, 8, 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   _dbus_assert (find_handler (tree, path0, &exact_match) == tree->root &&  exact_match);
01670   _dbus_assert (find_handler (tree, path1, &exact_match) != tree->root && exact_match);
01671   _dbus_assert (find_handler (tree, path2, &exact_match) != tree->root && exact_match);
01672   _dbus_assert (find_handler (tree, path3, &exact_match) != tree->root && exact_match);
01673   _dbus_assert (find_handler (tree, path4, &exact_match) != tree->root && exact_match);
01674   _dbus_assert (find_handler (tree, path5, &exact_match) != tree->root && exact_match);
01675   _dbus_assert (find_handler (tree, path6, &exact_match) != tree->root && exact_match);
01676   _dbus_assert (find_handler (tree, path7, &exact_match) != tree->root && exact_match);
01677   _dbus_assert (find_handler (tree, path8, &exact_match) != tree->root && exact_match);
01678   
01679   /* test the list_registered function */
01680 
01681   {
01682     const char *root[] = { NULL };
01683     char **child_entries;
01684     int nb;
01685 
01686     _dbus_object_tree_list_registered_unlocked (tree, path1, &child_entries);
01687     if (child_entries != NULL)
01688       {
01689         nb = string_array_length ((const char**)child_entries);
01690         _dbus_assert (nb == 1);
01691         dbus_free_string_array (child_entries);
01692       }
01693 
01694     _dbus_object_tree_list_registered_unlocked (tree, path2, &child_entries);
01695     if (child_entries != NULL)
01696       {
01697         nb = string_array_length ((const char**)child_entries);
01698         _dbus_assert (nb == 2);
01699         dbus_free_string_array (child_entries);
01700       }
01701 
01702     _dbus_object_tree_list_registered_unlocked (tree, path8, &child_entries);
01703     if (child_entries != NULL)
01704       {
01705         nb = string_array_length ((const char**)child_entries);
01706         _dbus_assert (nb == 0);
01707         dbus_free_string_array (child_entries);
01708       }
01709 
01710     _dbus_object_tree_list_registered_unlocked (tree, root, &child_entries);
01711     if (child_entries != NULL)
01712       {
01713         nb = string_array_length ((const char**)child_entries);
01714         _dbus_assert (nb == 3);
01715         dbus_free_string_array (child_entries);
01716       }
01717   }
01718 
01719   /* Check that destroying tree calls unregister funcs */
01720   _dbus_object_tree_unref (tree);
01721 
01722   i = 0;
01723   while (i < (int) _DBUS_N_ELEMENTS (tree_test_data))
01724     {
01725       _dbus_assert (tree_test_data[i].handler_unregistered);
01726       _dbus_assert (!tree_test_data[i].message_handled);
01727       ++i;
01728     }
01729 
01730   /* Now start again and try the individual unregister function */
01731   tree = _dbus_object_tree_new (NULL);
01732   if (tree == NULL)
01733     goto out;
01734 
01735   if (!do_register (tree, path0, TRUE, 0, tree_test_data))
01736     goto out;
01737   if (!do_register (tree, path1, TRUE, 1, tree_test_data))
01738     goto out;
01739   if (!do_register (tree, path2, TRUE, 2, tree_test_data))
01740     goto out;
01741   if (!do_register (tree, path3, TRUE, 3, tree_test_data))
01742     goto out;
01743   if (!do_register (tree, path4, TRUE, 4, tree_test_data))
01744     goto out;
01745   if (!do_register (tree, path5, TRUE, 5, tree_test_data))
01746     goto out;
01747   if (!do_register (tree, path6, TRUE, 6, tree_test_data))
01748     goto out;
01749   if (!do_register (tree, path7, TRUE, 7, tree_test_data))
01750     goto out;
01751   if (!do_register (tree, path8, TRUE, 8, tree_test_data))
01752     goto out;
01753 
01754   _dbus_object_tree_unregister_and_unlock (tree, path0);
01755   _dbus_assert (_dbus_object_tree_get_user_data_unlocked (tree, path0) == NULL);
01756 
01757   _dbus_assert (!find_subtree (tree, path0, NULL));
01758   _dbus_assert (find_subtree (tree, path1, NULL));
01759   _dbus_assert (find_subtree (tree, path2, NULL));
01760   _dbus_assert (find_subtree (tree, path3, NULL));
01761   _dbus_assert (find_subtree (tree, path4, NULL));
01762   _dbus_assert (find_subtree (tree, path5, NULL));
01763   _dbus_assert (find_subtree (tree, path6, NULL));
01764   _dbus_assert (find_subtree (tree, path7, NULL));
01765   _dbus_assert (find_subtree (tree, path8, NULL));
01766   
01767   _dbus_object_tree_unregister_and_unlock (tree, path1);
01768   _dbus_assert (_dbus_object_tree_get_user_data_unlocked (tree, path1) == 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, path2);
01781   _dbus_assert (_dbus_object_tree_get_user_data_unlocked (tree, path2) == 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, path3);
01794   _dbus_assert (_dbus_object_tree_get_user_data_unlocked (tree, path3) == 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, path4);
01807   _dbus_assert (_dbus_object_tree_get_user_data_unlocked (tree, path4) == 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, path5);
01820   _dbus_assert (_dbus_object_tree_get_user_data_unlocked (tree, path5) == 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, path6);
01833   _dbus_assert (_dbus_object_tree_get_user_data_unlocked (tree, path6) == 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, path7);
01846   _dbus_assert (_dbus_object_tree_get_user_data_unlocked (tree, path7) == 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, path8);
01859   _dbus_assert (_dbus_object_tree_get_user_data_unlocked (tree, path8) == 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   i = 0;
01872   while (i < (int) _DBUS_N_ELEMENTS (tree_test_data))
01873     {
01874       _dbus_assert (tree_test_data[i].handler_unregistered);
01875       _dbus_assert (!tree_test_data[i].message_handled);
01876       ++i;
01877     }
01878 
01879   /* Register it all again, and test dispatch */
01880   
01881   if (!do_register (tree, path0, TRUE, 0, tree_test_data))
01882     goto out;
01883   if (!do_register (tree, path1, FALSE, 1, tree_test_data))
01884     goto out;
01885   if (!do_register (tree, path2, TRUE, 2, tree_test_data))
01886     goto out;
01887   if (!do_register (tree, path3, TRUE, 3, tree_test_data))
01888     goto out;
01889   if (!do_register (tree, path4, TRUE, 4, tree_test_data))
01890     goto out;
01891   if (!do_register (tree, path5, TRUE, 5, tree_test_data))
01892     goto out;
01893   if (!do_register (tree, path6, FALSE, 6, tree_test_data))
01894     goto out;
01895   if (!do_register (tree, path7, TRUE, 7, tree_test_data))
01896     goto out;
01897   if (!do_register (tree, path8, TRUE, 8, tree_test_data))
01898     goto out;
01899 
01900 #if 0
01901   spew_tree (tree);
01902 #endif
01903 
01904   if (!do_test_dispatch (tree, path0, 0, tree_test_data, _DBUS_N_ELEMENTS (tree_test_data)))
01905     goto out;
01906   if (!do_test_dispatch (tree, path1, 1, tree_test_data, _DBUS_N_ELEMENTS (tree_test_data)))
01907     goto out;
01908   if (!do_test_dispatch (tree, path2, 2, tree_test_data, _DBUS_N_ELEMENTS (tree_test_data)))
01909     goto out;
01910   if (!do_test_dispatch (tree, path3, 3, tree_test_data, _DBUS_N_ELEMENTS (tree_test_data)))
01911     goto out;
01912   if (!do_test_dispatch (tree, path4, 4, tree_test_data, _DBUS_N_ELEMENTS (tree_test_data)))
01913     goto out;
01914   if (!do_test_dispatch (tree, path5, 5, tree_test_data, _DBUS_N_ELEMENTS (tree_test_data)))
01915     goto out;
01916   if (!do_test_dispatch (tree, path6, 6, tree_test_data, _DBUS_N_ELEMENTS (tree_test_data)))
01917     goto out;
01918   if (!do_test_dispatch (tree, path7, 7, tree_test_data, _DBUS_N_ELEMENTS (tree_test_data)))
01919     goto out;
01920   if (!do_test_dispatch (tree, path8, 8, tree_test_data, _DBUS_N_ELEMENTS (tree_test_data)))
01921     goto out;
01922   
01923  out:
01924   if (tree)
01925     {
01926       /* test ref */
01927       _dbus_object_tree_ref (tree);
01928       _dbus_object_tree_unref (tree);
01929       _dbus_object_tree_unref (tree);
01930     }
01931 
01932   return TRUE;
01933 }
01934 
01940 dbus_bool_t
01941 _dbus_object_tree_test (void)
01942 {
01943   _dbus_test_oom_handling ("object tree",
01944                            object_tree_test_iteration,
01945                            NULL);
01946 
01947   return TRUE;
01948 }
01949 
01950 #endif /* !DOXYGEN_SHOULD_SKIP_THIS */
01951 
01952 #endif /* DBUS_BUILD_TESTS */