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

Generated on Thu Jan 22 16:37:05 2009 for D-Bus by  doxygen 1.5.1