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

Generated on Tue Jul 7 15:14:00 2009 for D-BUS by  doxygen 1.4.6