dbus-object-tree.c

00001 /* -*- mode: C; c-file-style: "gnu" -*- */
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 
00384 dbus_bool_t
00385 _dbus_object_tree_register (DBusObjectTree              *tree,
00386                             dbus_bool_t                  fallback,
00387                             const char                 **path,
00388                             const DBusObjectPathVTable  *vtable,
00389                             void                        *user_data)
00390 {
00391   DBusObjectSubtree  *subtree;
00392 
00393   _dbus_assert (tree != NULL);
00394   _dbus_assert (vtable->message_function != NULL);
00395   _dbus_assert (path != NULL);
00396 
00397   subtree = ensure_subtree (tree, path);
00398   if (subtree == NULL)
00399     return FALSE;
00400 
00401 #ifndef DBUS_DISABLE_CHECKS
00402   if (subtree->message_function != NULL)
00403     {
00404       _dbus_warn ("A handler is already registered for the path starting with path[0] = \"%s\"\n",
00405                   path[0] ? path[0] : "null");
00406       return FALSE;
00407     }
00408 #else
00409   _dbus_assert (subtree->message_function == NULL);
00410 #endif
00411 
00412   subtree->message_function = vtable->message_function;
00413   subtree->unregister_function = vtable->unregister_function;
00414   subtree->user_data = user_data;
00415   subtree->invoke_as_fallback = fallback != FALSE;
00416   
00417   return TRUE;
00418 }
00419 
00427 void
00428 _dbus_object_tree_unregister_and_unlock (DBusObjectTree          *tree,
00429                                          const char             **path)
00430 {
00431   int i;
00432   DBusObjectSubtree *subtree;
00433   DBusObjectPathUnregisterFunction unregister_function;
00434   void *user_data;
00435   DBusConnection *connection;
00436 
00437   _dbus_assert (path != NULL);
00438 
00439   unregister_function = NULL;
00440   user_data = NULL;
00441 
00442   subtree = find_subtree (tree, path, &i);
00443 
00444 #ifndef DBUS_DISABLE_CHECKS
00445   if (subtree == NULL)
00446     {
00447       _dbus_warn ("Attempted to unregister path (path[0] = %s path[1] = %s) which isn't registered\n",
00448                   path[0] ? path[0] : "null",
00449                   path[1] ? path[1] : "null");
00450       goto unlock;    
00451     }
00452 #else
00453   _dbus_assert (subtree != NULL);
00454 #endif
00455 
00456   _dbus_assert (subtree->parent == NULL ||
00457                 (i >= 0 && subtree->parent->subtrees[i] == subtree));
00458 
00459   subtree->message_function = NULL;
00460 
00461   unregister_function = subtree->unregister_function;
00462   user_data = subtree->user_data;
00463 
00464   subtree->unregister_function = NULL;
00465   subtree->user_data = NULL;
00466 
00467   /* If we have no subtrees of our own, remove from
00468    * our parent (FIXME could also be more aggressive
00469    * and remove our parent if it becomes empty)
00470    */
00471   if (subtree->parent && subtree->n_subtrees == 0)
00472     {
00473       /* assumes a 0-byte memmove is OK */
00474       memmove (&subtree->parent->subtrees[i],
00475                &subtree->parent->subtrees[i+1],
00476                (subtree->parent->n_subtrees - i - 1) *
00477                sizeof (subtree->parent->subtrees[0]));
00478       subtree->parent->n_subtrees -= 1;
00479 
00480       subtree->parent = NULL;
00481 
00482       _dbus_object_subtree_unref (subtree);
00483     }
00484   subtree = NULL;
00485 
00486 unlock:
00487   connection = tree->connection;
00488 
00489   /* Unlock and call application code */
00490 #ifdef DBUS_BUILD_TESTS
00491   if (connection)
00492 #endif
00493     {
00494       _dbus_connection_ref_unlocked (connection);
00495       _dbus_verbose ("unlock %s\n", _DBUS_FUNCTION_NAME);
00496       _dbus_connection_unlock (connection);
00497     }
00498 
00499   if (unregister_function)
00500     (* unregister_function) (connection, user_data);
00501 
00502 #ifdef DBUS_BUILD_TESTS
00503   if (connection)
00504 #endif
00505     dbus_connection_unref (connection);
00506 }
00507 
00508 static void
00509 free_subtree_recurse (DBusConnection    *connection,
00510                       DBusObjectSubtree *subtree)
00511 {
00512   /* Delete them from the end, for slightly
00513    * more robustness against odd reentrancy.
00514    */
00515   while (subtree->n_subtrees > 0)
00516     {
00517       DBusObjectSubtree *child;
00518 
00519       child = subtree->subtrees[subtree->n_subtrees - 1];
00520       subtree->subtrees[subtree->n_subtrees - 1] = NULL;
00521       subtree->n_subtrees -= 1;
00522       child->parent = NULL;
00523 
00524       free_subtree_recurse (connection, child);
00525     }
00526 
00527   /* Call application code */
00528   if (subtree->unregister_function)
00529     (* subtree->unregister_function) (connection,
00530                                       subtree->user_data);
00531 
00532   subtree->message_function = NULL;
00533   subtree->unregister_function = NULL;
00534   subtree->user_data = NULL;
00535 
00536   /* Now free ourselves */
00537   _dbus_object_subtree_unref (subtree);
00538 }
00539 
00546 void
00547 _dbus_object_tree_free_all_unlocked (DBusObjectTree *tree)
00548 {
00549   if (tree->root)
00550     free_subtree_recurse (tree->connection,
00551                           tree->root);
00552   tree->root = NULL;
00553 }
00554 
00555 static dbus_bool_t
00556 _dbus_object_tree_list_registered_unlocked (DBusObjectTree *tree,
00557                                             const char    **parent_path,
00558                                             char         ***child_entries)
00559 {
00560   DBusObjectSubtree *subtree;
00561   char **retval;
00562   
00563   _dbus_assert (parent_path != NULL);
00564   _dbus_assert (child_entries != NULL);
00565 
00566   *child_entries = NULL;
00567   
00568   subtree = lookup_subtree (tree, parent_path);
00569   if (subtree == NULL)
00570     {
00571       retval = dbus_new0 (char *, 1);
00572     }
00573   else
00574     {
00575       int i;
00576       retval = dbus_new0 (char*, subtree->n_subtrees + 1);
00577       if (retval == NULL)
00578         goto out;
00579       i = 0;
00580       while (i < subtree->n_subtrees)
00581         {
00582           retval[i] = _dbus_strdup (subtree->subtrees[i]->name);
00583           if (retval[i] == NULL)
00584             {
00585               dbus_free_string_array (retval);
00586               retval = NULL;
00587               goto out;
00588             }
00589           ++i;
00590         }
00591     }
00592 
00593  out:
00594     
00595   *child_entries = retval;
00596   return retval != NULL;
00597 }
00598 
00599 static DBusHandlerResult
00600 handle_default_introspect_and_unlock (DBusObjectTree          *tree,
00601                                       DBusMessage             *message,
00602                                       const char             **path)
00603 {
00604   DBusString xml;
00605   DBusHandlerResult result;
00606   char **children;
00607   int i;
00608   DBusMessage *reply;
00609   DBusMessageIter iter;
00610   const char *v_STRING;
00611   dbus_bool_t already_unlocked;
00612 
00613   /* We have the connection lock here */
00614 
00615   already_unlocked = FALSE;
00616   
00617   _dbus_verbose (" considering default Introspect() handler...\n");
00618 
00619   reply = NULL;
00620   
00621   if (!dbus_message_is_method_call (message,
00622                                     DBUS_INTERFACE_INTROSPECTABLE,
00623                                     "Introspect"))
00624     {
00625 #ifdef DBUS_BUILD_TESTS
00626       if (tree->connection)
00627 #endif
00628         {
00629           _dbus_verbose ("unlock %s %d\n", _DBUS_FUNCTION_NAME, __LINE__);
00630           _dbus_connection_unlock (tree->connection);
00631         }
00632       
00633       return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
00634     }
00635 
00636   _dbus_verbose (" using default Introspect() handler!\n");
00637   
00638   if (!_dbus_string_init (&xml))
00639     {
00640 #ifdef DBUS_BUILD_TESTS
00641       if (tree->connection)
00642 #endif
00643         {
00644           _dbus_verbose ("unlock %s %d\n", _DBUS_FUNCTION_NAME, __LINE__);
00645           _dbus_connection_unlock (tree->connection);
00646         }
00647 
00648       return DBUS_HANDLER_RESULT_NEED_MEMORY;
00649     }
00650 
00651   result = DBUS_HANDLER_RESULT_NEED_MEMORY;
00652 
00653   children = NULL;
00654   if (!_dbus_object_tree_list_registered_unlocked (tree, path, &children))
00655     goto out;
00656 
00657   if (!_dbus_string_append (&xml, DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE))
00658     goto out;
00659   
00660   if (!_dbus_string_append (&xml, "<node>\n"))
00661     goto out;
00662 
00663   i = 0;
00664   while (children[i] != NULL)
00665     {
00666       if (!_dbus_string_append_printf (&xml, "  <node name=\"%s\"/>\n",
00667                                        children[i]))
00668         goto out;
00669 
00670       ++i;
00671     }
00672 
00673   if (!_dbus_string_append (&xml, "</node>\n"))
00674     goto out;
00675 
00676   reply = dbus_message_new_method_return (message);
00677   if (reply == NULL)
00678     goto out;
00679 
00680   dbus_message_iter_init_append (reply, &iter);
00681   v_STRING = _dbus_string_get_const_data (&xml);
00682   if (!dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &v_STRING))
00683     goto out;
00684   
00685 #ifdef DBUS_BUILD_TESTS
00686   if (tree->connection)
00687 #endif
00688     {
00689       already_unlocked = TRUE;
00690       
00691       if (!_dbus_connection_send_and_unlock (tree->connection, reply, NULL))
00692         goto out;
00693     }
00694   
00695   result = DBUS_HANDLER_RESULT_HANDLED;
00696   
00697  out:
00698 #ifdef DBUS_BUILD_TESTS
00699   if (tree->connection)
00700 #endif
00701     {
00702       if (!already_unlocked)
00703         {
00704           _dbus_verbose ("unlock %s %d\n", _DBUS_FUNCTION_NAME, __LINE__);
00705           _dbus_connection_unlock (tree->connection);
00706         }
00707     }
00708   
00709   _dbus_string_free (&xml);
00710   dbus_free_string_array (children);
00711   if (reply)
00712     dbus_message_unref (reply);
00713   
00714   return result;
00715 }
00716 
00730 DBusHandlerResult
00731 _dbus_object_tree_dispatch_and_unlock (DBusObjectTree          *tree,
00732                                        DBusMessage             *message)
00733 {
00734   char **path;
00735   dbus_bool_t exact_match;
00736   DBusList *list;
00737   DBusList *link;
00738   DBusHandlerResult result;
00739   DBusObjectSubtree *subtree;
00740   
00741 #if 0
00742   _dbus_verbose ("Dispatch of message by object path\n");
00743 #endif
00744   
00745   path = NULL;
00746   if (!dbus_message_get_path_decomposed (message, &path))
00747     {
00748 #ifdef DBUS_BUILD_TESTS
00749       if (tree->connection)
00750 #endif
00751         {
00752           _dbus_verbose ("unlock %s\n", _DBUS_FUNCTION_NAME);
00753           _dbus_connection_unlock (tree->connection);
00754         }
00755       
00756       _dbus_verbose ("No memory to get decomposed path\n");
00757 
00758       return DBUS_HANDLER_RESULT_NEED_MEMORY;
00759     }
00760 
00761   if (path == NULL)
00762     {
00763 #ifdef DBUS_BUILD_TESTS
00764       if (tree->connection)
00765 #endif
00766         {
00767           _dbus_verbose ("unlock %s\n", _DBUS_FUNCTION_NAME);
00768           _dbus_connection_unlock (tree->connection);
00769         }
00770       
00771       _dbus_verbose ("No path field in message\n");
00772       return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
00773     }
00774   
00775   /* Find the deepest path that covers the path in the message */
00776   subtree = find_handler (tree, (const char**) path, &exact_match);
00777   
00778   /* Build a list of all paths that cover the path in the message */
00779 
00780   list = NULL;
00781 
00782   while (subtree != NULL)
00783     {
00784       if (subtree->message_function != NULL && (exact_match || subtree->invoke_as_fallback))
00785         {
00786           _dbus_object_subtree_ref (subtree);
00787 
00788           /* run deepest paths first */
00789           if (!_dbus_list_append (&list, subtree))
00790             {
00791               result = DBUS_HANDLER_RESULT_NEED_MEMORY;
00792               _dbus_object_subtree_unref (subtree);
00793               goto free_and_return;
00794             }
00795         }
00796 
00797       exact_match = FALSE;
00798       subtree = subtree->parent;
00799     }
00800 
00801   _dbus_verbose ("%d handlers in the path tree for this message\n",
00802                  _dbus_list_get_length (&list));
00803 
00804   /* Invoke each handler in the list */
00805 
00806   result = DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
00807 
00808   link = _dbus_list_get_first_link (&list);
00809   while (link != NULL)
00810     {
00811       DBusList *next = _dbus_list_get_next_link (&list, link);
00812       subtree = link->data;
00813 
00814       /* message_function is NULL if we're unregistered
00815        * due to reentrancy
00816        */
00817       if (subtree->message_function)
00818         {
00819           DBusObjectPathMessageFunction message_function;
00820           void *user_data;
00821 
00822           message_function = subtree->message_function;
00823           user_data = subtree->user_data;
00824 
00825 #if 0
00826           _dbus_verbose ("  (invoking a handler)\n");
00827 #endif
00828           
00829 #ifdef DBUS_BUILD_TESTS
00830           if (tree->connection)
00831 #endif
00832             {
00833               _dbus_verbose ("unlock %s\n", _DBUS_FUNCTION_NAME);
00834               _dbus_connection_unlock (tree->connection);
00835             }
00836 
00837           /* FIXME you could unregister the subtree in another thread
00838            * before we invoke the callback, and I can't figure out a
00839            * good way to solve this.
00840            */
00841 
00842           result = (* message_function) (tree->connection,
00843                                          message,
00844                                          user_data);
00845 
00846 #ifdef DBUS_BUILD_TESTS
00847           if (tree->connection)
00848 #endif
00849             _dbus_connection_lock (tree->connection);
00850 
00851           if (result != DBUS_HANDLER_RESULT_NOT_YET_HANDLED)
00852             goto free_and_return;
00853         }
00854 
00855       link = next;
00856     }
00857 
00858  free_and_return:
00859 
00860   if (result == DBUS_HANDLER_RESULT_NOT_YET_HANDLED)
00861     {
00862       /* This hardcoded default handler does a minimal Introspect()
00863        */
00864       result = handle_default_introspect_and_unlock (tree, message,
00865                                                      (const char**) path);
00866     }
00867   else
00868     {
00869 #ifdef DBUS_BUILD_TESTS
00870       if (tree->connection)
00871 #endif
00872         {
00873           _dbus_verbose ("unlock %s\n", _DBUS_FUNCTION_NAME);
00874           _dbus_connection_unlock (tree->connection);
00875         }
00876     }
00877   
00878   while (list != NULL)
00879     {
00880       link = _dbus_list_get_first_link (&list);
00881       _dbus_object_subtree_unref (link->data);
00882       _dbus_list_remove_link (&list, link);
00883     }
00884   
00885   dbus_free_string_array (path);
00886 
00887   return result;
00888 }
00889 
00898 void*
00899 _dbus_object_tree_get_user_data_unlocked (DBusObjectTree *tree,
00900                                           const char    **path)
00901 {
00902   dbus_bool_t exact_match;
00903   DBusObjectSubtree *subtree;
00904 
00905   _dbus_assert (tree != NULL);
00906   _dbus_assert (path != NULL);
00907   
00908   /* Find the deepest path that covers the path in the message */
00909   subtree = find_handler (tree, (const char**) path, &exact_match);
00910 
00911   if ((subtree == NULL) || !exact_match)
00912     {
00913       _dbus_verbose ("%s: No object at specified path found\n",
00914                      _DBUS_FUNCTION_NAME);
00915       return NULL;
00916     }
00917 
00918   return subtree->user_data;
00919 }
00920 
00927 static DBusObjectSubtree*
00928 allocate_subtree_object (const char *name)
00929 {
00930   int len;
00931   DBusObjectSubtree *subtree;
00932   const size_t front_padding = _DBUS_STRUCT_OFFSET (DBusObjectSubtree, name);
00933 
00934   _dbus_assert (name != NULL);
00935 
00936   len = strlen (name);
00937 
00938   subtree = dbus_malloc (MAX (front_padding + (len + 1), sizeof (DBusObjectSubtree)));
00939 
00940   if (subtree == NULL)
00941     return NULL;
00942 
00943   memcpy (subtree->name, name, len + 1);
00944 
00945   return subtree;
00946 }
00947 
00948 static DBusObjectSubtree*
00949 _dbus_object_subtree_new (const char                  *name,
00950                           const DBusObjectPathVTable  *vtable,
00951                           void                        *user_data)
00952 {
00953   DBusObjectSubtree *subtree;
00954 
00955   subtree = allocate_subtree_object (name);
00956   if (subtree == NULL)
00957     goto oom;
00958 
00959   _dbus_assert (name != NULL);
00960 
00961   subtree->parent = NULL;
00962 
00963   if (vtable)
00964     {
00965       subtree->message_function = vtable->message_function;
00966       subtree->unregister_function = vtable->unregister_function;
00967     }
00968   else
00969     {
00970       subtree->message_function = NULL;
00971       subtree->unregister_function = NULL;
00972     }
00973 
00974   subtree->user_data = user_data;
00975   subtree->refcount.value = 1;
00976   subtree->subtrees = NULL;
00977   subtree->n_subtrees = 0;
00978   subtree->max_subtrees = 0;
00979   subtree->invoke_as_fallback = FALSE;
00980 
00981   return subtree;
00982 
00983  oom:
00984   return NULL;
00985 }
00986 
00987 static DBusObjectSubtree *
00988 _dbus_object_subtree_ref (DBusObjectSubtree *subtree)
00989 {
00990   _dbus_assert (subtree->refcount.value > 0);
00991   _dbus_atomic_inc (&subtree->refcount);
00992 
00993   return subtree;
00994 }
00995 
00996 static void
00997 _dbus_object_subtree_unref (DBusObjectSubtree *subtree)
00998 {
00999   _dbus_assert (subtree->refcount.value > 0);
01000 
01001   if (_dbus_atomic_dec (&subtree->refcount) == 1)
01002     {
01003       _dbus_assert (subtree->unregister_function == NULL);
01004       _dbus_assert (subtree->message_function == NULL);
01005 
01006       dbus_free (subtree->subtrees);
01007       dbus_free (subtree);
01008     }
01009 }
01010 
01021 dbus_bool_t
01022 _dbus_object_tree_list_registered_and_unlock (DBusObjectTree *tree,
01023                                               const char    **parent_path,
01024                                               char         ***child_entries)
01025 {
01026   dbus_bool_t result;
01027 
01028   result = _dbus_object_tree_list_registered_unlocked (tree,
01029                                                        parent_path,
01030                                                        child_entries);
01031   
01032 #ifdef DBUS_BUILD_TESTS
01033   if (tree->connection)
01034 #endif
01035     {
01036       _dbus_verbose ("unlock %s\n", _DBUS_FUNCTION_NAME);
01037       _dbus_connection_unlock (tree->connection);
01038     }
01039 
01040   return result;
01041 }
01042 
01043 
01045 #define VERBOSE_DECOMPOSE 0
01046 
01057 dbus_bool_t
01058 _dbus_decompose_path (const char*     data,
01059                       int             len,
01060                       char         ***path,
01061                       int            *path_len)
01062 {
01063   char **retval;
01064   int n_components;
01065   int i, j, comp;
01066 
01067   _dbus_assert (data != NULL);
01068   
01069 #if VERBOSE_DECOMPOSE
01070   _dbus_verbose ("Decomposing path \"%s\"\n",
01071                  data);
01072 #endif
01073   
01074   n_components = 0;
01075   if (len > 1) /* if path is not just "/" */
01076     {
01077       i = 0;
01078       while (i < len)
01079         {
01080           if (data[i] == '/')
01081             n_components += 1;
01082           ++i;
01083         }
01084     }
01085   
01086   retval = dbus_new0 (char*, n_components + 1);
01087 
01088   if (retval == NULL)
01089     return FALSE;
01090 
01091   comp = 0;
01092   if (n_components == 0)
01093     i = 1;
01094   else
01095     i = 0;
01096   while (comp < n_components)
01097     {
01098       _dbus_assert (i < len);
01099       
01100       if (data[i] == '/')
01101         ++i;
01102       j = i;
01103 
01104       while (j < len && data[j] != '/')
01105         ++j;
01106 
01107       /* Now [i, j) is the path component */
01108       _dbus_assert (i < j);
01109       _dbus_assert (data[i] != '/');
01110       _dbus_assert (j == len || data[j] == '/');
01111 
01112 #if VERBOSE_DECOMPOSE
01113       _dbus_verbose ("  (component in [%d,%d))\n",
01114                      i, j);
01115 #endif
01116       
01117       retval[comp] = _dbus_memdup (&data[i], j - i + 1);
01118       if (retval[comp] == NULL)
01119         {
01120           dbus_free_string_array (retval);
01121           return FALSE;
01122         }
01123       retval[comp][j-i] = '\0';
01124 #if VERBOSE_DECOMPOSE
01125       _dbus_verbose ("  (component %d = \"%s\")\n",
01126                      comp, retval[comp]);
01127 #endif
01128 
01129       ++comp;
01130       i = j;
01131     }
01132   _dbus_assert (i == len);
01133   
01134   *path = retval;
01135   if (path_len)
01136     *path_len = n_components;
01137   
01138   return TRUE;
01139 }
01140 
01143 #ifdef DBUS_BUILD_TESTS
01144 #include "dbus-test.h"
01145 #include <stdio.h>
01146 
01147 static char*
01148 flatten_path (const char **path)
01149 {
01150   DBusString str;
01151   char *s;
01152 
01153   if (!_dbus_string_init (&str))
01154     return NULL;
01155 
01156   if (path[0] == NULL)
01157     {
01158       if (!_dbus_string_append_byte (&str, '/'))
01159         goto nomem;
01160     }
01161   else
01162     {
01163       int i;
01164       
01165       i = 0;
01166       while (path[i])
01167         {
01168           if (!_dbus_string_append_byte (&str, '/'))
01169             goto nomem;
01170           
01171           if (!_dbus_string_append (&str, path[i]))
01172             goto nomem;
01173           
01174           ++i;
01175         }
01176     }
01177 
01178   if (!_dbus_string_steal_data (&str, &s))
01179     goto nomem;
01180 
01181   _dbus_string_free (&str);
01182 
01183   return s;
01184 
01185  nomem:
01186   _dbus_string_free (&str);
01187   return NULL;
01188 }
01189 
01190 
01191 typedef enum 
01192 {
01193   STR_EQUAL,
01194   STR_PREFIX,
01195   STR_DIFFERENT
01196 } StrComparison;
01197 
01198 /* Returns TRUE if container is a parent of child
01199  */
01200 static StrComparison
01201 path_contains (const char **container,
01202                const char **child)
01203 {
01204   int i;
01205 
01206   i = 0;
01207   while (child[i] != NULL)
01208     {
01209       int v;
01210 
01211       if (container[i] == NULL)
01212         return STR_PREFIX; /* container ran out, child continues;
01213                             * thus the container is a parent of the
01214                             * child.
01215                             */
01216 
01217       _dbus_assert (container[i] != NULL);
01218       _dbus_assert (child[i] != NULL);
01219 
01220       v = strcmp (container[i], child[i]);
01221 
01222       if (v != 0)
01223         return STR_DIFFERENT; /* they overlap until here and then are different,
01224                                * not overlapping
01225                                */
01226 
01227       ++i;
01228     }
01229 
01230   /* Child ran out; if container also did, they are equal;
01231    * otherwise, the child is a parent of the container.
01232    */
01233   if (container[i] == NULL)
01234     return STR_EQUAL;
01235   else
01236     return STR_DIFFERENT;
01237 }
01238 
01239 #if 0
01240 static void
01241 spew_subtree_recurse (DBusObjectSubtree *subtree,
01242                       int                indent)
01243 {
01244   int i;
01245 
01246   i = 0;
01247   while (i < indent)
01248     {
01249       _dbus_verbose (" ");
01250       ++i;
01251     }
01252 
01253   _dbus_verbose ("%s (%d children)\n",
01254                  subtree->name, subtree->n_subtrees);
01255 
01256   i = 0;
01257   while (i < subtree->n_subtrees)
01258     {
01259       spew_subtree_recurse (subtree->subtrees[i], indent + 2);
01260 
01261       ++i;
01262     }
01263 }
01264 
01265 static void
01266 spew_tree (DBusObjectTree *tree)
01267 {
01268   spew_subtree_recurse (tree->root, 0);
01269 }
01270 #endif
01271 
01275 typedef struct
01276 {
01277   const char **path; 
01278   dbus_bool_t handler_fallback; 
01279   dbus_bool_t message_handled; 
01280   dbus_bool_t handler_unregistered; 
01281 } TreeTestData;
01282 
01283 
01284 static void
01285 test_unregister_function (DBusConnection  *connection,
01286                           void            *user_data)
01287 {
01288   TreeTestData *ttd = user_data;
01289 
01290   ttd->handler_unregistered = TRUE;
01291 }
01292 
01293 static DBusHandlerResult
01294 test_message_function (DBusConnection  *connection,
01295                        DBusMessage     *message,
01296                        void            *user_data)
01297 {
01298   TreeTestData *ttd = user_data;
01299 
01300   ttd->message_handled = TRUE;
01301 
01302   return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
01303 }
01304 
01305 static dbus_bool_t
01306 do_register (DBusObjectTree *tree,
01307              const char    **path,
01308              dbus_bool_t     fallback,
01309              int             i,
01310              TreeTestData   *tree_test_data)
01311 {
01312   DBusObjectPathVTable vtable = { test_unregister_function,
01313                                   test_message_function, NULL };
01314   
01315   tree_test_data[i].message_handled = FALSE;
01316   tree_test_data[i].handler_unregistered = FALSE;
01317   tree_test_data[i].handler_fallback = fallback;
01318   tree_test_data[i].path = path;
01319 
01320   if (!_dbus_object_tree_register (tree, fallback, path,
01321                                    &vtable,
01322                                    &tree_test_data[i]))
01323     return FALSE;
01324 
01325   _dbus_assert (_dbus_object_tree_get_user_data_unlocked (tree, path) ==
01326                 &tree_test_data[i]);
01327   
01328   return TRUE;
01329 }
01330 
01331 static dbus_bool_t
01332 do_test_dispatch (DBusObjectTree *tree,
01333                   const char    **path,
01334                   int             i,
01335                   TreeTestData   *tree_test_data,
01336                   int             n_test_data)
01337 {
01338   DBusMessage *message;
01339   int j;
01340   DBusHandlerResult result;
01341   char *flat;
01342 
01343   message = NULL;
01344   
01345   flat = flatten_path (path);
01346   if (flat == NULL)
01347     goto oom;
01348 
01349   message = dbus_message_new_method_call (NULL,
01350                                           flat,
01351                                           "org.freedesktop.TestInterface",
01352                                           "Foo");
01353   dbus_free (flat);
01354   if (message == NULL)
01355     goto oom;
01356 
01357   j = 0;
01358   while (j < n_test_data)
01359     {
01360       tree_test_data[j].message_handled = FALSE;
01361       ++j;
01362     }
01363 
01364   result = _dbus_object_tree_dispatch_and_unlock (tree, message);
01365   if (result == DBUS_HANDLER_RESULT_NEED_MEMORY)
01366     goto oom;
01367 
01368   _dbus_assert (tree_test_data[i].message_handled);
01369 
01370   j = 0;
01371   while (j < n_test_data)
01372     {
01373       if (tree_test_data[j].message_handled)
01374         {
01375           if (tree_test_data[j].handler_fallback)
01376             _dbus_assert (path_contains (tree_test_data[j].path,
01377                                          path) != STR_DIFFERENT);
01378           else
01379             _dbus_assert (path_contains (tree_test_data[j].path, path) == STR_EQUAL);
01380         }
01381       else
01382         {
01383           if (tree_test_data[j].handler_fallback)
01384             _dbus_assert (path_contains (tree_test_data[j].path,
01385                                          path) == STR_DIFFERENT);
01386           else
01387             _dbus_assert (path_contains (tree_test_data[j].path, path) != STR_EQUAL);
01388         }
01389 
01390       ++j;
01391     }
01392 
01393   dbus_message_unref (message);
01394 
01395   return TRUE;
01396 
01397  oom:
01398   if (message)
01399     dbus_message_unref (message);
01400   return FALSE;
01401 }
01402 
01403 static size_t
01404 string_array_length (const char **array)
01405 {
01406   size_t i;
01407   for (i = 0; array[i]; i++) ;
01408   return i;
01409 }
01410 
01411 typedef struct
01412 {
01413   const char *path;
01414   const char *result[20];
01415 } DecomposePathTest;
01416 
01417 static DecomposePathTest decompose_tests[] = {
01418   { "/foo", { "foo", NULL } },
01419   { "/foo/bar", { "foo", "bar", NULL } },
01420   { "/", { NULL } },
01421   { "/a/b", { "a", "b", NULL } },
01422   { "/a/b/c", { "a", "b", "c", NULL } },
01423   { "/a/b/c/d", { "a", "b", "c", "d", NULL } },
01424   { "/foo/bar/q", { "foo", "bar", "q", NULL } },
01425   { "/foo/bar/this/is/longer", { "foo", "bar", "this", "is", "longer", NULL } }
01426 };
01427 
01428 static dbus_bool_t
01429 run_decompose_tests (void)
01430 {
01431   int i;
01432 
01433   i = 0;
01434   while (i < _DBUS_N_ELEMENTS (decompose_tests))
01435     {
01436       char **result;
01437       int    result_len;
01438       int    expected_len;
01439 
01440       if (!_dbus_decompose_path (decompose_tests[i].path,
01441                                  strlen (decompose_tests[i].path),
01442                                  &result, &result_len))
01443         return FALSE;
01444 
01445       expected_len = string_array_length (decompose_tests[i].result);
01446       
01447       if (result_len != (int) string_array_length ((const char**)result) ||
01448           expected_len != result_len ||
01449           path_contains (decompose_tests[i].result,
01450                          (const char**) result) != STR_EQUAL)
01451         {
01452           int real_len = string_array_length ((const char**)result);
01453           _dbus_warn ("Expected decompose of %s to have len %d, returned %d, appears to have %d\n",
01454                       decompose_tests[i].path, expected_len, result_len,
01455                       real_len);
01456           _dbus_warn ("Decompose resulted in elements: { ");
01457           i = 0;
01458           while (i < real_len)
01459             {
01460               _dbus_warn ("\"%s\"%s", result[i],
01461                           (i + 1) == real_len ? "" : ", ");
01462               ++i;
01463             }
01464           _dbus_warn ("}\n");
01465           _dbus_assert_not_reached ("path decompose failed\n");
01466         }
01467 
01468       dbus_free_string_array (result);
01469 
01470       ++i;
01471     }
01472   
01473   return TRUE;
01474 }
01475 
01476 static dbus_bool_t
01477 object_tree_test_iteration (void *data)
01478 {
01479   const char *path0[] = { NULL };
01480   const char *path1[] = { "foo", NULL };
01481   const char *path2[] = { "foo", "bar", NULL };
01482   const char *path3[] = { "foo", "bar", "baz", NULL };
01483   const char *path4[] = { "foo", "bar", "boo", NULL };
01484   const char *path5[] = { "blah", NULL };
01485   const char *path6[] = { "blah", "boof", NULL };
01486   const char *path7[] = { "blah", "boof", "this", "is", "really", "long", NULL };
01487   const char *path8[] = { "childless", NULL };
01488   DBusObjectTree *tree;
01489   TreeTestData tree_test_data[9];
01490   int i;
01491   dbus_bool_t exact_match;
01492 
01493   if (!run_decompose_tests ())
01494     return FALSE;
01495   
01496   tree = NULL;
01497 
01498   tree = _dbus_object_tree_new (NULL);
01499   if (tree == NULL)
01500     goto out;
01501 
01502   if (!do_register (tree, path0, TRUE, 0, tree_test_data))
01503     goto out;
01504 
01505   _dbus_assert (find_subtree (tree, path0, NULL));
01506   _dbus_assert (!find_subtree (tree, path1, NULL));
01507   _dbus_assert (!find_subtree (tree, path2, NULL));
01508   _dbus_assert (!find_subtree (tree, path3, NULL));
01509   _dbus_assert (!find_subtree (tree, path4, NULL));
01510   _dbus_assert (!find_subtree (tree, path5, NULL));
01511   _dbus_assert (!find_subtree (tree, path6, NULL));
01512   _dbus_assert (!find_subtree (tree, path7, NULL));
01513   _dbus_assert (!find_subtree (tree, path8, NULL));
01514 
01515   _dbus_assert (find_handler (tree, path0, &exact_match) && exact_match);
01516   _dbus_assert (find_handler (tree, path1, &exact_match) == tree->root && !exact_match);
01517   _dbus_assert (find_handler (tree, path2, &exact_match) == tree->root && !exact_match);
01518   _dbus_assert (find_handler (tree, path3, &exact_match) == tree->root && !exact_match);
01519   _dbus_assert (find_handler (tree, path4, &exact_match) == tree->root && !exact_match);
01520   _dbus_assert (find_handler (tree, path5, &exact_match) == tree->root && !exact_match);
01521   _dbus_assert (find_handler (tree, path6, &exact_match) == tree->root && !exact_match);
01522   _dbus_assert (find_handler (tree, path7, &exact_match) == tree->root && !exact_match);
01523   _dbus_assert (find_handler (tree, path8, &exact_match) == tree->root && !exact_match);
01524   
01525   if (!do_register (tree, path1, TRUE, 1, tree_test_data))
01526     goto out;
01527 
01528   _dbus_assert (find_subtree (tree, path0, NULL));
01529   _dbus_assert (find_subtree (tree, path1, NULL));
01530   _dbus_assert (!find_subtree (tree, path2, NULL));
01531   _dbus_assert (!find_subtree (tree, path3, NULL));
01532   _dbus_assert (!find_subtree (tree, path4, NULL));
01533   _dbus_assert (!find_subtree (tree, path5, NULL));
01534   _dbus_assert (!find_subtree (tree, path6, NULL));
01535   _dbus_assert (!find_subtree (tree, path7, NULL));
01536   _dbus_assert (!find_subtree (tree, path8, NULL));
01537 
01538   _dbus_assert (find_handler (tree, path0, &exact_match) &&  exact_match);
01539   _dbus_assert (find_handler (tree, path1, &exact_match) &&  exact_match);
01540   _dbus_assert (find_handler (tree, path2, &exact_match) && !exact_match);
01541   _dbus_assert (find_handler (tree, path3, &exact_match) && !exact_match);
01542   _dbus_assert (find_handler (tree, path4, &exact_match) && !exact_match);
01543   _dbus_assert (find_handler (tree, path5, &exact_match) == tree->root && !exact_match);
01544   _dbus_assert (find_handler (tree, path6, &exact_match) == tree->root && !exact_match);
01545   _dbus_assert (find_handler (tree, path7, &exact_match) == tree->root && !exact_match);
01546   _dbus_assert (find_handler (tree, path8, &exact_match) == tree->root && !exact_match);
01547 
01548   if (!do_register (tree, path2, TRUE, 2, tree_test_data))
01549     goto out;
01550 
01551   _dbus_assert (find_subtree (tree, path1, NULL));
01552   _dbus_assert (find_subtree (tree, path2, NULL));
01553   _dbus_assert (!find_subtree (tree, path3, NULL));
01554   _dbus_assert (!find_subtree (tree, path4, NULL));
01555   _dbus_assert (!find_subtree (tree, path5, NULL));
01556   _dbus_assert (!find_subtree (tree, path6, NULL));
01557   _dbus_assert (!find_subtree (tree, path7, NULL));
01558   _dbus_assert (!find_subtree (tree, path8, NULL));
01559 
01560   if (!do_register (tree, path3, TRUE, 3, tree_test_data))
01561     goto out;
01562 
01563   _dbus_assert (find_subtree (tree, path0, NULL));
01564   _dbus_assert (find_subtree (tree, path1, NULL));
01565   _dbus_assert (find_subtree (tree, path2, NULL));
01566   _dbus_assert (find_subtree (tree, path3, NULL));
01567   _dbus_assert (!find_subtree (tree, path4, NULL));
01568   _dbus_assert (!find_subtree (tree, path5, NULL));
01569   _dbus_assert (!find_subtree (tree, path6, NULL));
01570   _dbus_assert (!find_subtree (tree, path7, NULL));
01571   _dbus_assert (!find_subtree (tree, path8, NULL));
01572   
01573   if (!do_register (tree, path4, TRUE, 4, tree_test_data))
01574     goto out;
01575 
01576   _dbus_assert (find_subtree (tree, path0, NULL));
01577   _dbus_assert (find_subtree (tree, path1, NULL));
01578   _dbus_assert (find_subtree (tree, path2, NULL));
01579   _dbus_assert (find_subtree (tree, path3, NULL));  
01580   _dbus_assert (find_subtree (tree, path4, NULL));
01581   _dbus_assert (!find_subtree (tree, path5, NULL));
01582   _dbus_assert (!find_subtree (tree, path6, NULL));
01583   _dbus_assert (!find_subtree (tree, path7, NULL));
01584   _dbus_assert (!find_subtree (tree, path8, NULL));
01585   
01586   if (!do_register (tree, path5, TRUE, 5, tree_test_data))
01587     goto out;
01588 
01589   _dbus_assert (find_subtree (tree, path0, NULL));
01590   _dbus_assert (find_subtree (tree, path1, NULL));
01591   _dbus_assert (find_subtree (tree, path2, NULL));
01592   _dbus_assert (find_subtree (tree, path3, NULL));
01593   _dbus_assert (find_subtree (tree, path4, NULL));
01594   _dbus_assert (find_subtree (tree, path5, NULL));
01595   _dbus_assert (!find_subtree (tree, path6, NULL));
01596   _dbus_assert (!find_subtree (tree, path7, NULL));
01597   _dbus_assert (!find_subtree (tree, path8, NULL));
01598 
01599   _dbus_assert (find_handler (tree, path0, &exact_match) == tree->root &&  exact_match);
01600   _dbus_assert (find_handler (tree, path1, &exact_match) != tree->root &&  exact_match);
01601   _dbus_assert (find_handler (tree, path2, &exact_match) != tree->root &&  exact_match);
01602   _dbus_assert (find_handler (tree, path3, &exact_match) != tree->root &&  exact_match);
01603   _dbus_assert (find_handler (tree, path4, &exact_match) != tree->root &&  exact_match);
01604   _dbus_assert (find_handler (tree, path5, &exact_match) != tree->root &&  exact_match);
01605   _dbus_assert (find_handler (tree, path6, &exact_match) != tree->root && !exact_match);
01606   _dbus_assert (find_handler (tree, path7, &exact_match) != tree->root && !exact_match);
01607   _dbus_assert (find_handler (tree, path8, &exact_match) == tree->root && !exact_match);
01608 
01609   if (!do_register (tree, path6, TRUE, 6, tree_test_data))
01610     goto out;
01611 
01612   _dbus_assert (find_subtree (tree, path0, NULL));
01613   _dbus_assert (find_subtree (tree, path1, NULL));
01614   _dbus_assert (find_subtree (tree, path2, NULL));
01615   _dbus_assert (find_subtree (tree, path3, NULL));
01616   _dbus_assert (find_subtree (tree, path4, NULL));
01617   _dbus_assert (find_subtree (tree, path5, NULL));
01618   _dbus_assert (find_subtree (tree, path6, NULL));
01619   _dbus_assert (!find_subtree (tree, path7, NULL));
01620   _dbus_assert (!find_subtree (tree, path8, NULL));
01621 
01622   if (!do_register (tree, path7, TRUE, 7, tree_test_data))
01623     goto out;
01624 
01625   _dbus_assert (find_subtree (tree, path0, NULL));
01626   _dbus_assert (find_subtree (tree, path1, NULL));
01627   _dbus_assert (find_subtree (tree, path2, NULL));
01628   _dbus_assert (find_subtree (tree, path3, NULL));
01629   _dbus_assert (find_subtree (tree, path4, NULL));
01630   _dbus_assert (find_subtree (tree, path5, NULL));
01631   _dbus_assert (find_subtree (tree, path6, NULL));
01632   _dbus_assert (find_subtree (tree, path7, NULL));
01633   _dbus_assert (!find_subtree (tree, path8, NULL));
01634 
01635   if (!do_register (tree, path8, TRUE, 8, tree_test_data))
01636     goto out;
01637 
01638   _dbus_assert (find_subtree (tree, path0, NULL));
01639   _dbus_assert (find_subtree (tree, path1, NULL));
01640   _dbus_assert (find_subtree (tree, path2, NULL));
01641   _dbus_assert (find_subtree (tree, path3, NULL));
01642   _dbus_assert (find_subtree (tree, path4, NULL));
01643   _dbus_assert (find_subtree (tree, path5, NULL));
01644   _dbus_assert (find_subtree (tree, path6, NULL));
01645   _dbus_assert (find_subtree (tree, path7, NULL));
01646   _dbus_assert (find_subtree (tree, path8, NULL));
01647 
01648   _dbus_assert (find_handler (tree, path0, &exact_match) == tree->root &&  exact_match);
01649   _dbus_assert (find_handler (tree, path1, &exact_match) != tree->root && exact_match);
01650   _dbus_assert (find_handler (tree, path2, &exact_match) != tree->root && exact_match);
01651   _dbus_assert (find_handler (tree, path3, &exact_match) != tree->root && exact_match);
01652   _dbus_assert (find_handler (tree, path4, &exact_match) != tree->root && exact_match);
01653   _dbus_assert (find_handler (tree, path5, &exact_match) != tree->root && exact_match);
01654   _dbus_assert (find_handler (tree, path6, &exact_match) != tree->root && exact_match);
01655   _dbus_assert (find_handler (tree, path7, &exact_match) != tree->root && exact_match);
01656   _dbus_assert (find_handler (tree, path8, &exact_match) != tree->root && exact_match);
01657   
01658   /* test the list_registered function */
01659 
01660   {
01661     const char *root[] = { NULL };
01662     char **child_entries;
01663     int nb;
01664 
01665     _dbus_object_tree_list_registered_unlocked (tree, path1, &child_entries);
01666     if (child_entries != NULL)
01667       {
01668         nb = string_array_length ((const char**)child_entries);
01669         _dbus_assert (nb == 1);
01670         dbus_free_string_array (child_entries);
01671       }
01672 
01673     _dbus_object_tree_list_registered_unlocked (tree, path2, &child_entries);
01674     if (child_entries != NULL)
01675       {
01676         nb = string_array_length ((const char**)child_entries);
01677         _dbus_assert (nb == 2);
01678         dbus_free_string_array (child_entries);
01679       }
01680 
01681     _dbus_object_tree_list_registered_unlocked (tree, path8, &child_entries);
01682     if (child_entries != NULL)
01683       {
01684         nb = string_array_length ((const char**)child_entries);
01685         _dbus_assert (nb == 0);
01686         dbus_free_string_array (child_entries);
01687       }
01688 
01689     _dbus_object_tree_list_registered_unlocked (tree, root, &child_entries);
01690     if (child_entries != NULL)
01691       {
01692         nb = string_array_length ((const char**)child_entries);
01693         _dbus_assert (nb == 3);
01694         dbus_free_string_array (child_entries);
01695       }
01696   }
01697 
01698   /* Check that destroying tree calls unregister funcs */
01699   _dbus_object_tree_unref (tree);
01700 
01701   i = 0;
01702   while (i < (int) _DBUS_N_ELEMENTS (tree_test_data))
01703     {
01704       _dbus_assert (tree_test_data[i].handler_unregistered);
01705       _dbus_assert (!tree_test_data[i].message_handled);
01706       ++i;
01707     }
01708 
01709   /* Now start again and try the individual unregister function */
01710   tree = _dbus_object_tree_new (NULL);
01711   if (tree == NULL)
01712     goto out;
01713 
01714   if (!do_register (tree, path0, TRUE, 0, tree_test_data))
01715     goto out;
01716   if (!do_register (tree, path1, TRUE, 1, tree_test_data))
01717     goto out;
01718   if (!do_register (tree, path2, TRUE, 2, tree_test_data))
01719     goto out;
01720   if (!do_register (tree, path3, TRUE, 3, tree_test_data))
01721     goto out;
01722   if (!do_register (tree, path4, TRUE, 4, tree_test_data))
01723     goto out;
01724   if (!do_register (tree, path5, TRUE, 5, tree_test_data))
01725     goto out;
01726   if (!do_register (tree, path6, TRUE, 6, tree_test_data))
01727     goto out;
01728   if (!do_register (tree, path7, TRUE, 7, tree_test_data))
01729     goto out;
01730   if (!do_register (tree, path8, TRUE, 8, tree_test_data))
01731     goto out;
01732 
01733   _dbus_object_tree_unregister_and_unlock (tree, path0);
01734   _dbus_assert (_dbus_object_tree_get_user_data_unlocked (tree, path0) == NULL);
01735 
01736   _dbus_assert (!find_subtree (tree, path0, NULL));
01737   _dbus_assert (find_subtree (tree, path1, NULL));
01738   _dbus_assert (find_subtree (tree, path2, NULL));
01739   _dbus_assert (find_subtree (tree, path3, NULL));
01740   _dbus_assert (find_subtree (tree, path4, NULL));
01741   _dbus_assert (find_subtree (tree, path5, NULL));
01742   _dbus_assert (find_subtree (tree, path6, NULL));
01743   _dbus_assert (find_subtree (tree, path7, NULL));
01744   _dbus_assert (find_subtree (tree, path8, NULL));
01745   
01746   _dbus_object_tree_unregister_and_unlock (tree, path1);
01747   _dbus_assert (_dbus_object_tree_get_user_data_unlocked (tree, path1) == NULL);
01748 
01749   _dbus_assert (!find_subtree (tree, path0, NULL));
01750   _dbus_assert (!find_subtree (tree, path1, NULL));
01751   _dbus_assert (find_subtree (tree, path2, NULL));
01752   _dbus_assert (find_subtree (tree, path3, NULL));
01753   _dbus_assert (find_subtree (tree, path4, NULL));
01754   _dbus_assert (find_subtree (tree, path5, NULL));
01755   _dbus_assert (find_subtree (tree, path6, NULL));
01756   _dbus_assert (find_subtree (tree, path7, NULL));
01757   _dbus_assert (find_subtree (tree, path8, NULL));
01758 
01759   _dbus_object_tree_unregister_and_unlock (tree, path2);
01760   _dbus_assert (_dbus_object_tree_get_user_data_unlocked (tree, path2) == NULL);
01761 
01762   _dbus_assert (!find_subtree (tree, path0, NULL));
01763   _dbus_assert (!find_subtree (tree, path1, NULL));
01764   _dbus_assert (!find_subtree (tree, path2, NULL));
01765   _dbus_assert (find_subtree (tree, path3, NULL));
01766   _dbus_assert (find_subtree (tree, path4, NULL));
01767   _dbus_assert (find_subtree (tree, path5, NULL));
01768   _dbus_assert (find_subtree (tree, path6, NULL));
01769   _dbus_assert (find_subtree (tree, path7, NULL));
01770   _dbus_assert (find_subtree (tree, path8, NULL));
01771   
01772   _dbus_object_tree_unregister_and_unlock (tree, path3);
01773   _dbus_assert (_dbus_object_tree_get_user_data_unlocked (tree, path3) == NULL);
01774 
01775   _dbus_assert (!find_subtree (tree, path0, NULL));
01776   _dbus_assert (!find_subtree (tree, path1, NULL));
01777   _dbus_assert (!find_subtree (tree, path2, NULL));
01778   _dbus_assert (!find_subtree (tree, path3, NULL));
01779   _dbus_assert (find_subtree (tree, path4, NULL));
01780   _dbus_assert (find_subtree (tree, path5, NULL));
01781   _dbus_assert (find_subtree (tree, path6, NULL));
01782   _dbus_assert (find_subtree (tree, path7, NULL));
01783   _dbus_assert (find_subtree (tree, path8, NULL));
01784   
01785   _dbus_object_tree_unregister_and_unlock (tree, path4);
01786   _dbus_assert (_dbus_object_tree_get_user_data_unlocked (tree, path4) == NULL);
01787 
01788   _dbus_assert (!find_subtree (tree, path0, NULL));
01789   _dbus_assert (!find_subtree (tree, path1, NULL));
01790   _dbus_assert (!find_subtree (tree, path2, NULL));
01791   _dbus_assert (!find_subtree (tree, path3, NULL));
01792   _dbus_assert (!find_subtree (tree, path4, NULL));
01793   _dbus_assert (find_subtree (tree, path5, NULL));
01794   _dbus_assert (find_subtree (tree, path6, NULL));
01795   _dbus_assert (find_subtree (tree, path7, NULL));
01796   _dbus_assert (find_subtree (tree, path8, NULL));
01797   
01798   _dbus_object_tree_unregister_and_unlock (tree, path5);
01799   _dbus_assert (_dbus_object_tree_get_user_data_unlocked (tree, path5) == NULL);
01800 
01801   _dbus_assert (!find_subtree (tree, path0, NULL));
01802   _dbus_assert (!find_subtree (tree, path1, NULL));
01803   _dbus_assert (!find_subtree (tree, path2, NULL));
01804   _dbus_assert (!find_subtree (tree, path3, NULL));
01805   _dbus_assert (!find_subtree (tree, path4, NULL));
01806   _dbus_assert (!find_subtree (tree, path5, NULL));
01807   _dbus_assert (find_subtree (tree, path6, NULL));
01808   _dbus_assert (find_subtree (tree, path7, NULL));
01809   _dbus_assert (find_subtree (tree, path8, NULL));
01810   
01811   _dbus_object_tree_unregister_and_unlock (tree, path6);
01812   _dbus_assert (_dbus_object_tree_get_user_data_unlocked (tree, path6) == NULL);
01813 
01814   _dbus_assert (!find_subtree (tree, path0, NULL));
01815   _dbus_assert (!find_subtree (tree, path1, NULL));
01816   _dbus_assert (!find_subtree (tree, path2, NULL));
01817   _dbus_assert (!find_subtree (tree, path3, NULL));
01818   _dbus_assert (!find_subtree (tree, path4, NULL));
01819   _dbus_assert (!find_subtree (tree, path5, NULL));
01820   _dbus_assert (!find_subtree (tree, path6, NULL));
01821   _dbus_assert (find_subtree (tree, path7, NULL));
01822   _dbus_assert (find_subtree (tree, path8, NULL));
01823 
01824   _dbus_object_tree_unregister_and_unlock (tree, path7);
01825   _dbus_assert (_dbus_object_tree_get_user_data_unlocked (tree, path7) == NULL);
01826 
01827   _dbus_assert (!find_subtree (tree, path0, NULL));
01828   _dbus_assert (!find_subtree (tree, path1, NULL));
01829   _dbus_assert (!find_subtree (tree, path2, NULL));
01830   _dbus_assert (!find_subtree (tree, path3, NULL));
01831   _dbus_assert (!find_subtree (tree, path4, NULL));
01832   _dbus_assert (!find_subtree (tree, path5, NULL));
01833   _dbus_assert (!find_subtree (tree, path6, NULL));
01834   _dbus_assert (!find_subtree (tree, path7, NULL));
01835   _dbus_assert (find_subtree (tree, path8, NULL));
01836 
01837   _dbus_object_tree_unregister_and_unlock (tree, path8);
01838   _dbus_assert (_dbus_object_tree_get_user_data_unlocked (tree, path8) == NULL);
01839 
01840   _dbus_assert (!find_subtree (tree, path0, NULL));
01841   _dbus_assert (!find_subtree (tree, path1, NULL));
01842   _dbus_assert (!find_subtree (tree, path2, NULL));
01843   _dbus_assert (!find_subtree (tree, path3, NULL));
01844   _dbus_assert (!find_subtree (tree, path4, NULL));
01845   _dbus_assert (!find_subtree (tree, path5, NULL));
01846   _dbus_assert (!find_subtree (tree, path6, NULL));
01847   _dbus_assert (!find_subtree (tree, path7, NULL));
01848   _dbus_assert (!find_subtree (tree, path8, NULL));
01849   
01850   i = 0;
01851   while (i < (int) _DBUS_N_ELEMENTS (tree_test_data))
01852     {
01853       _dbus_assert (tree_test_data[i].handler_unregistered);
01854       _dbus_assert (!tree_test_data[i].message_handled);
01855       ++i;
01856     }
01857 
01858   /* Register it all again, and test dispatch */
01859   
01860   if (!do_register (tree, path0, TRUE, 0, tree_test_data))
01861     goto out;
01862   if (!do_register (tree, path1, FALSE, 1, tree_test_data))
01863     goto out;
01864   if (!do_register (tree, path2, TRUE, 2, tree_test_data))
01865     goto out;
01866   if (!do_register (tree, path3, TRUE, 3, tree_test_data))
01867     goto out;
01868   if (!do_register (tree, path4, TRUE, 4, tree_test_data))
01869     goto out;
01870   if (!do_register (tree, path5, TRUE, 5, tree_test_data))
01871     goto out;
01872   if (!do_register (tree, path6, FALSE, 6, tree_test_data))
01873     goto out;
01874   if (!do_register (tree, path7, TRUE, 7, tree_test_data))
01875     goto out;
01876   if (!do_register (tree, path8, TRUE, 8, tree_test_data))
01877     goto out;
01878 
01879 #if 0
01880   spew_tree (tree);
01881 #endif
01882 
01883   if (!do_test_dispatch (tree, path0, 0, tree_test_data, _DBUS_N_ELEMENTS (tree_test_data)))
01884     goto out;
01885   if (!do_test_dispatch (tree, path1, 1, tree_test_data, _DBUS_N_ELEMENTS (tree_test_data)))
01886     goto out;
01887   if (!do_test_dispatch (tree, path2, 2, tree_test_data, _DBUS_N_ELEMENTS (tree_test_data)))
01888     goto out;
01889   if (!do_test_dispatch (tree, path3, 3, tree_test_data, _DBUS_N_ELEMENTS (tree_test_data)))
01890     goto out;
01891   if (!do_test_dispatch (tree, path4, 4, tree_test_data, _DBUS_N_ELEMENTS (tree_test_data)))
01892     goto out;
01893   if (!do_test_dispatch (tree, path5, 5, tree_test_data, _DBUS_N_ELEMENTS (tree_test_data)))
01894     goto out;
01895   if (!do_test_dispatch (tree, path6, 6, tree_test_data, _DBUS_N_ELEMENTS (tree_test_data)))
01896     goto out;
01897   if (!do_test_dispatch (tree, path7, 7, tree_test_data, _DBUS_N_ELEMENTS (tree_test_data)))
01898     goto out;
01899   if (!do_test_dispatch (tree, path8, 8, tree_test_data, _DBUS_N_ELEMENTS (tree_test_data)))
01900     goto out;
01901   
01902  out:
01903   if (tree)
01904     {
01905       /* test ref */
01906       _dbus_object_tree_ref (tree);
01907       _dbus_object_tree_unref (tree);
01908       _dbus_object_tree_unref (tree);
01909     }
01910 
01911   return TRUE;
01912 }
01913 
01919 dbus_bool_t
01920 _dbus_object_tree_test (void)
01921 {
01922   _dbus_test_oom_handling ("object tree",
01923                            object_tree_test_iteration,
01924                            NULL);
01925 
01926   return TRUE;
01927 }
01928 
01929 #endif /* DBUS_BUILD_TESTS */

Generated on Fri Oct 20 11:46:24 2006 for D-Bus by  doxygen 1.4.7