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 
01145 #ifndef DOXYGEN_SHOULD_SKIP_THIS
01146 
01147 #include "dbus-test.h"
01148 #include <stdio.h>
01149 
01150 static char*
01151 flatten_path (const char **path)
01152 {
01153   DBusString str;
01154   char *s;
01155 
01156   if (!_dbus_string_init (&str))
01157     return NULL;
01158 
01159   if (path[0] == NULL)
01160     {
01161       if (!_dbus_string_append_byte (&str, '/'))
01162         goto nomem;
01163     }
01164   else
01165     {
01166       int i;
01167       
01168       i = 0;
01169       while (path[i])
01170         {
01171           if (!_dbus_string_append_byte (&str, '/'))
01172             goto nomem;
01173           
01174           if (!_dbus_string_append (&str, path[i]))
01175             goto nomem;
01176           
01177           ++i;
01178         }
01179     }
01180 
01181   if (!_dbus_string_steal_data (&str, &s))
01182     goto nomem;
01183 
01184   _dbus_string_free (&str);
01185 
01186   return s;
01187 
01188  nomem:
01189   _dbus_string_free (&str);
01190   return NULL;
01191 }
01192 
01193 
01194 typedef enum 
01195 {
01196   STR_EQUAL,
01197   STR_PREFIX,
01198   STR_DIFFERENT
01199 } StrComparison;
01200 
01201 /* Returns TRUE if container is a parent of child
01202  */
01203 static StrComparison
01204 path_contains (const char **container,
01205                const char **child)
01206 {
01207   int i;
01208 
01209   i = 0;
01210   while (child[i] != NULL)
01211     {
01212       int v;
01213 
01214       if (container[i] == NULL)
01215         return STR_PREFIX; /* container ran out, child continues;
01216                             * thus the container is a parent of the
01217                             * child.
01218                             */
01219 
01220       _dbus_assert (container[i] != NULL);
01221       _dbus_assert (child[i] != NULL);
01222 
01223       v = strcmp (container[i], child[i]);
01224 
01225       if (v != 0)
01226         return STR_DIFFERENT; /* they overlap until here and then are different,
01227                                * not overlapping
01228                                */
01229 
01230       ++i;
01231     }
01232 
01233   /* Child ran out; if container also did, they are equal;
01234    * otherwise, the child is a parent of the container.
01235    */
01236   if (container[i] == NULL)
01237     return STR_EQUAL;
01238   else
01239     return STR_DIFFERENT;
01240 }
01241 
01242 #if 0
01243 static void
01244 spew_subtree_recurse (DBusObjectSubtree *subtree,
01245                       int                indent)
01246 {
01247   int i;
01248 
01249   i = 0;
01250   while (i < indent)
01251     {
01252       _dbus_verbose (" ");
01253       ++i;
01254     }
01255 
01256   _dbus_verbose ("%s (%d children)\n",
01257                  subtree->name, subtree->n_subtrees);
01258 
01259   i = 0;
01260   while (i < subtree->n_subtrees)
01261     {
01262       spew_subtree_recurse (subtree->subtrees[i], indent + 2);
01263 
01264       ++i;
01265     }
01266 }
01267 
01268 static void
01269 spew_tree (DBusObjectTree *tree)
01270 {
01271   spew_subtree_recurse (tree->root, 0);
01272 }
01273 #endif
01274 
01278 typedef struct
01279 {
01280   const char **path; 
01281   dbus_bool_t handler_fallback; 
01282   dbus_bool_t message_handled; 
01283   dbus_bool_t handler_unregistered; 
01284 } TreeTestData;
01285 
01286 
01287 static void
01288 test_unregister_function (DBusConnection  *connection,
01289                           void            *user_data)
01290 {
01291   TreeTestData *ttd = user_data;
01292 
01293   ttd->handler_unregistered = TRUE;
01294 }
01295 
01296 static DBusHandlerResult
01297 test_message_function (DBusConnection  *connection,
01298                        DBusMessage     *message,
01299                        void            *user_data)
01300 {
01301   TreeTestData *ttd = user_data;
01302 
01303   ttd->message_handled = TRUE;
01304 
01305   return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
01306 }
01307 
01308 static dbus_bool_t
01309 do_register (DBusObjectTree *tree,
01310              const char    **path,
01311              dbus_bool_t     fallback,
01312              int             i,
01313              TreeTestData   *tree_test_data)
01314 {
01315   DBusObjectPathVTable vtable = { test_unregister_function,
01316                                   test_message_function, NULL };
01317   
01318   tree_test_data[i].message_handled = FALSE;
01319   tree_test_data[i].handler_unregistered = FALSE;
01320   tree_test_data[i].handler_fallback = fallback;
01321   tree_test_data[i].path = path;
01322 
01323   if (!_dbus_object_tree_register (tree, fallback, path,
01324                                    &vtable,
01325                                    &tree_test_data[i]))
01326     return FALSE;
01327 
01328   _dbus_assert (_dbus_object_tree_get_user_data_unlocked (tree, path) ==
01329                 &tree_test_data[i]);
01330   
01331   return TRUE;
01332 }
01333 
01334 static dbus_bool_t
01335 do_test_dispatch (DBusObjectTree *tree,
01336                   const char    **path,
01337                   int             i,
01338                   TreeTestData   *tree_test_data,
01339                   int             n_test_data)
01340 {
01341   DBusMessage *message;
01342   int j;
01343   DBusHandlerResult result;
01344   char *flat;
01345 
01346   message = NULL;
01347   
01348   flat = flatten_path (path);
01349   if (flat == NULL)
01350     goto oom;
01351 
01352   message = dbus_message_new_method_call (NULL,
01353                                           flat,
01354                                           "org.freedesktop.TestInterface",
01355                                           "Foo");
01356   dbus_free (flat);
01357   if (message == NULL)
01358     goto oom;
01359 
01360   j = 0;
01361   while (j < n_test_data)
01362     {
01363       tree_test_data[j].message_handled = FALSE;
01364       ++j;
01365     }
01366 
01367   result = _dbus_object_tree_dispatch_and_unlock (tree, message);
01368   if (result == DBUS_HANDLER_RESULT_NEED_MEMORY)
01369     goto oom;
01370 
01371   _dbus_assert (tree_test_data[i].message_handled);
01372 
01373   j = 0;
01374   while (j < n_test_data)
01375     {
01376       if (tree_test_data[j].message_handled)
01377         {
01378           if (tree_test_data[j].handler_fallback)
01379             _dbus_assert (path_contains (tree_test_data[j].path,
01380                                          path) != STR_DIFFERENT);
01381           else
01382             _dbus_assert (path_contains (tree_test_data[j].path, path) == STR_EQUAL);
01383         }
01384       else
01385         {
01386           if (tree_test_data[j].handler_fallback)
01387             _dbus_assert (path_contains (tree_test_data[j].path,
01388                                          path) == STR_DIFFERENT);
01389           else
01390             _dbus_assert (path_contains (tree_test_data[j].path, path) != STR_EQUAL);
01391         }
01392 
01393       ++j;
01394     }
01395 
01396   dbus_message_unref (message);
01397 
01398   return TRUE;
01399 
01400  oom:
01401   if (message)
01402     dbus_message_unref (message);
01403   return FALSE;
01404 }
01405 
01406 static size_t
01407 string_array_length (const char **array)
01408 {
01409   size_t i;
01410   for (i = 0; array[i]; i++) ;
01411   return i;
01412 }
01413 
01414 typedef struct
01415 {
01416   const char *path;
01417   const char *result[20];
01418 } DecomposePathTest;
01419 
01420 static DecomposePathTest decompose_tests[] = {
01421   { "/foo", { "foo", NULL } },
01422   { "/foo/bar", { "foo", "bar", NULL } },
01423   { "/", { NULL } },
01424   { "/a/b", { "a", "b", NULL } },
01425   { "/a/b/c", { "a", "b", "c", NULL } },
01426   { "/a/b/c/d", { "a", "b", "c", "d", NULL } },
01427   { "/foo/bar/q", { "foo", "bar", "q", NULL } },
01428   { "/foo/bar/this/is/longer", { "foo", "bar", "this", "is", "longer", NULL } }
01429 };
01430 
01431 static dbus_bool_t
01432 run_decompose_tests (void)
01433 {
01434   int i;
01435 
01436   i = 0;
01437   while (i < _DBUS_N_ELEMENTS (decompose_tests))
01438     {
01439       char **result;
01440       int    result_len;
01441       int    expected_len;
01442 
01443       if (!_dbus_decompose_path (decompose_tests[i].path,
01444                                  strlen (decompose_tests[i].path),
01445                                  &result, &result_len))
01446         return FALSE;
01447 
01448       expected_len = string_array_length (decompose_tests[i].result);
01449       
01450       if (result_len != (int) string_array_length ((const char**)result) ||
01451           expected_len != result_len ||
01452           path_contains (decompose_tests[i].result,
01453                          (const char**) result) != STR_EQUAL)
01454         {
01455           int real_len = string_array_length ((const char**)result);
01456           _dbus_warn ("Expected decompose of %s to have len %d, returned %d, appears to have %d\n",
01457                       decompose_tests[i].path, expected_len, result_len,
01458                       real_len);
01459           _dbus_warn ("Decompose resulted in elements: { ");
01460           i = 0;
01461           while (i < real_len)
01462             {
01463               _dbus_warn ("\"%s\"%s", result[i],
01464                           (i + 1) == real_len ? "" : ", ");
01465               ++i;
01466             }
01467           _dbus_warn ("}\n");
01468           _dbus_assert_not_reached ("path decompose failed\n");
01469         }
01470 
01471       dbus_free_string_array (result);
01472 
01473       ++i;
01474     }
01475   
01476   return TRUE;
01477 }
01478 
01479 static dbus_bool_t
01480 object_tree_test_iteration (void *data)
01481 {
01482   const char *path0[] = { NULL };
01483   const char *path1[] = { "foo", NULL };
01484   const char *path2[] = { "foo", "bar", NULL };
01485   const char *path3[] = { "foo", "bar", "baz", NULL };
01486   const char *path4[] = { "foo", "bar", "boo", NULL };
01487   const char *path5[] = { "blah", NULL };
01488   const char *path6[] = { "blah", "boof", NULL };
01489   const char *path7[] = { "blah", "boof", "this", "is", "really", "long", NULL };
01490   const char *path8[] = { "childless", NULL };
01491   DBusObjectTree *tree;
01492   TreeTestData tree_test_data[9];
01493   int i;
01494   dbus_bool_t exact_match;
01495 
01496   if (!run_decompose_tests ())
01497     return FALSE;
01498   
01499   tree = NULL;
01500 
01501   tree = _dbus_object_tree_new (NULL);
01502   if (tree == NULL)
01503     goto out;
01504 
01505   if (!do_register (tree, path0, TRUE, 0, tree_test_data))
01506     goto out;
01507 
01508   _dbus_assert (find_subtree (tree, path0, NULL));
01509   _dbus_assert (!find_subtree (tree, path1, NULL));
01510   _dbus_assert (!find_subtree (tree, path2, NULL));
01511   _dbus_assert (!find_subtree (tree, path3, NULL));
01512   _dbus_assert (!find_subtree (tree, path4, NULL));
01513   _dbus_assert (!find_subtree (tree, path5, NULL));
01514   _dbus_assert (!find_subtree (tree, path6, NULL));
01515   _dbus_assert (!find_subtree (tree, path7, NULL));
01516   _dbus_assert (!find_subtree (tree, path8, NULL));
01517 
01518   _dbus_assert (find_handler (tree, path0, &exact_match) && exact_match);
01519   _dbus_assert (find_handler (tree, path1, &exact_match) == tree->root && !exact_match);
01520   _dbus_assert (find_handler (tree, path2, &exact_match) == tree->root && !exact_match);
01521   _dbus_assert (find_handler (tree, path3, &exact_match) == tree->root && !exact_match);
01522   _dbus_assert (find_handler (tree, path4, &exact_match) == tree->root && !exact_match);
01523   _dbus_assert (find_handler (tree, path5, &exact_match) == tree->root && !exact_match);
01524   _dbus_assert (find_handler (tree, path6, &exact_match) == tree->root && !exact_match);
01525   _dbus_assert (find_handler (tree, path7, &exact_match) == tree->root && !exact_match);
01526   _dbus_assert (find_handler (tree, path8, &exact_match) == tree->root && !exact_match);
01527   
01528   if (!do_register (tree, path1, TRUE, 1, tree_test_data))
01529     goto out;
01530 
01531   _dbus_assert (find_subtree (tree, path0, NULL));
01532   _dbus_assert (find_subtree (tree, path1, NULL));
01533   _dbus_assert (!find_subtree (tree, path2, NULL));
01534   _dbus_assert (!find_subtree (tree, path3, NULL));
01535   _dbus_assert (!find_subtree (tree, path4, NULL));
01536   _dbus_assert (!find_subtree (tree, path5, NULL));
01537   _dbus_assert (!find_subtree (tree, path6, NULL));
01538   _dbus_assert (!find_subtree (tree, path7, NULL));
01539   _dbus_assert (!find_subtree (tree, path8, NULL));
01540 
01541   _dbus_assert (find_handler (tree, path0, &exact_match) &&  exact_match);
01542   _dbus_assert (find_handler (tree, path1, &exact_match) &&  exact_match);
01543   _dbus_assert (find_handler (tree, path2, &exact_match) && !exact_match);
01544   _dbus_assert (find_handler (tree, path3, &exact_match) && !exact_match);
01545   _dbus_assert (find_handler (tree, path4, &exact_match) && !exact_match);
01546   _dbus_assert (find_handler (tree, path5, &exact_match) == tree->root && !exact_match);
01547   _dbus_assert (find_handler (tree, path6, &exact_match) == tree->root && !exact_match);
01548   _dbus_assert (find_handler (tree, path7, &exact_match) == tree->root && !exact_match);
01549   _dbus_assert (find_handler (tree, path8, &exact_match) == tree->root && !exact_match);
01550 
01551   if (!do_register (tree, path2, TRUE, 2, tree_test_data))
01552     goto out;
01553 
01554   _dbus_assert (find_subtree (tree, path1, NULL));
01555   _dbus_assert (find_subtree (tree, path2, NULL));
01556   _dbus_assert (!find_subtree (tree, path3, NULL));
01557   _dbus_assert (!find_subtree (tree, path4, NULL));
01558   _dbus_assert (!find_subtree (tree, path5, NULL));
01559   _dbus_assert (!find_subtree (tree, path6, NULL));
01560   _dbus_assert (!find_subtree (tree, path7, NULL));
01561   _dbus_assert (!find_subtree (tree, path8, NULL));
01562 
01563   if (!do_register (tree, path3, TRUE, 3, tree_test_data))
01564     goto out;
01565 
01566   _dbus_assert (find_subtree (tree, path0, NULL));
01567   _dbus_assert (find_subtree (tree, path1, NULL));
01568   _dbus_assert (find_subtree (tree, path2, NULL));
01569   _dbus_assert (find_subtree (tree, path3, NULL));
01570   _dbus_assert (!find_subtree (tree, path4, NULL));
01571   _dbus_assert (!find_subtree (tree, path5, NULL));
01572   _dbus_assert (!find_subtree (tree, path6, NULL));
01573   _dbus_assert (!find_subtree (tree, path7, NULL));
01574   _dbus_assert (!find_subtree (tree, path8, NULL));
01575   
01576   if (!do_register (tree, path4, TRUE, 4, tree_test_data))
01577     goto out;
01578 
01579   _dbus_assert (find_subtree (tree, path0, NULL));
01580   _dbus_assert (find_subtree (tree, path1, NULL));
01581   _dbus_assert (find_subtree (tree, path2, NULL));
01582   _dbus_assert (find_subtree (tree, path3, NULL));  
01583   _dbus_assert (find_subtree (tree, path4, NULL));
01584   _dbus_assert (!find_subtree (tree, path5, NULL));
01585   _dbus_assert (!find_subtree (tree, path6, NULL));
01586   _dbus_assert (!find_subtree (tree, path7, NULL));
01587   _dbus_assert (!find_subtree (tree, path8, NULL));
01588   
01589   if (!do_register (tree, path5, TRUE, 5, tree_test_data))
01590     goto out;
01591 
01592   _dbus_assert (find_subtree (tree, path0, NULL));
01593   _dbus_assert (find_subtree (tree, path1, NULL));
01594   _dbus_assert (find_subtree (tree, path2, NULL));
01595   _dbus_assert (find_subtree (tree, path3, NULL));
01596   _dbus_assert (find_subtree (tree, path4, NULL));
01597   _dbus_assert (find_subtree (tree, path5, NULL));
01598   _dbus_assert (!find_subtree (tree, path6, NULL));
01599   _dbus_assert (!find_subtree (tree, path7, NULL));
01600   _dbus_assert (!find_subtree (tree, path8, NULL));
01601 
01602   _dbus_assert (find_handler (tree, path0, &exact_match) == tree->root &&  exact_match);
01603   _dbus_assert (find_handler (tree, path1, &exact_match) != tree->root &&  exact_match);
01604   _dbus_assert (find_handler (tree, path2, &exact_match) != tree->root &&  exact_match);
01605   _dbus_assert (find_handler (tree, path3, &exact_match) != tree->root &&  exact_match);
01606   _dbus_assert (find_handler (tree, path4, &exact_match) != tree->root &&  exact_match);
01607   _dbus_assert (find_handler (tree, path5, &exact_match) != tree->root &&  exact_match);
01608   _dbus_assert (find_handler (tree, path6, &exact_match) != tree->root && !exact_match);
01609   _dbus_assert (find_handler (tree, path7, &exact_match) != tree->root && !exact_match);
01610   _dbus_assert (find_handler (tree, path8, &exact_match) == tree->root && !exact_match);
01611 
01612   if (!do_register (tree, path6, TRUE, 6, tree_test_data))
01613     goto out;
01614 
01615   _dbus_assert (find_subtree (tree, path0, NULL));
01616   _dbus_assert (find_subtree (tree, path1, NULL));
01617   _dbus_assert (find_subtree (tree, path2, NULL));
01618   _dbus_assert (find_subtree (tree, path3, NULL));
01619   _dbus_assert (find_subtree (tree, path4, NULL));
01620   _dbus_assert (find_subtree (tree, path5, NULL));
01621   _dbus_assert (find_subtree (tree, path6, NULL));
01622   _dbus_assert (!find_subtree (tree, path7, NULL));
01623   _dbus_assert (!find_subtree (tree, path8, NULL));
01624 
01625   if (!do_register (tree, path7, TRUE, 7, tree_test_data))
01626     goto out;
01627 
01628   _dbus_assert (find_subtree (tree, path0, NULL));
01629   _dbus_assert (find_subtree (tree, path1, NULL));
01630   _dbus_assert (find_subtree (tree, path2, NULL));
01631   _dbus_assert (find_subtree (tree, path3, NULL));
01632   _dbus_assert (find_subtree (tree, path4, NULL));
01633   _dbus_assert (find_subtree (tree, path5, NULL));
01634   _dbus_assert (find_subtree (tree, path6, NULL));
01635   _dbus_assert (find_subtree (tree, path7, NULL));
01636   _dbus_assert (!find_subtree (tree, path8, NULL));
01637 
01638   if (!do_register (tree, path8, TRUE, 8, tree_test_data))
01639     goto out;
01640 
01641   _dbus_assert (find_subtree (tree, path0, NULL));
01642   _dbus_assert (find_subtree (tree, path1, NULL));
01643   _dbus_assert (find_subtree (tree, path2, NULL));
01644   _dbus_assert (find_subtree (tree, path3, NULL));
01645   _dbus_assert (find_subtree (tree, path4, NULL));
01646   _dbus_assert (find_subtree (tree, path5, NULL));
01647   _dbus_assert (find_subtree (tree, path6, NULL));
01648   _dbus_assert (find_subtree (tree, path7, NULL));
01649   _dbus_assert (find_subtree (tree, path8, NULL));
01650 
01651   _dbus_assert (find_handler (tree, path0, &exact_match) == tree->root &&  exact_match);
01652   _dbus_assert (find_handler (tree, path1, &exact_match) != tree->root && exact_match);
01653   _dbus_assert (find_handler (tree, path2, &exact_match) != tree->root && exact_match);
01654   _dbus_assert (find_handler (tree, path3, &exact_match) != tree->root && exact_match);
01655   _dbus_assert (find_handler (tree, path4, &exact_match) != tree->root && exact_match);
01656   _dbus_assert (find_handler (tree, path5, &exact_match) != tree->root && exact_match);
01657   _dbus_assert (find_handler (tree, path6, &exact_match) != tree->root && exact_match);
01658   _dbus_assert (find_handler (tree, path7, &exact_match) != tree->root && exact_match);
01659   _dbus_assert (find_handler (tree, path8, &exact_match) != tree->root && exact_match);
01660   
01661   /* test the list_registered function */
01662 
01663   {
01664     const char *root[] = { NULL };
01665     char **child_entries;
01666     int nb;
01667 
01668     _dbus_object_tree_list_registered_unlocked (tree, path1, &child_entries);
01669     if (child_entries != NULL)
01670       {
01671         nb = string_array_length ((const char**)child_entries);
01672         _dbus_assert (nb == 1);
01673         dbus_free_string_array (child_entries);
01674       }
01675 
01676     _dbus_object_tree_list_registered_unlocked (tree, path2, &child_entries);
01677     if (child_entries != NULL)
01678       {
01679         nb = string_array_length ((const char**)child_entries);
01680         _dbus_assert (nb == 2);
01681         dbus_free_string_array (child_entries);
01682       }
01683 
01684     _dbus_object_tree_list_registered_unlocked (tree, path8, &child_entries);
01685     if (child_entries != NULL)
01686       {
01687         nb = string_array_length ((const char**)child_entries);
01688         _dbus_assert (nb == 0);
01689         dbus_free_string_array (child_entries);
01690       }
01691 
01692     _dbus_object_tree_list_registered_unlocked (tree, root, &child_entries);
01693     if (child_entries != NULL)
01694       {
01695         nb = string_array_length ((const char**)child_entries);
01696         _dbus_assert (nb == 3);
01697         dbus_free_string_array (child_entries);
01698       }
01699   }
01700 
01701   /* Check that destroying tree calls unregister funcs */
01702   _dbus_object_tree_unref (tree);
01703 
01704   i = 0;
01705   while (i < (int) _DBUS_N_ELEMENTS (tree_test_data))
01706     {
01707       _dbus_assert (tree_test_data[i].handler_unregistered);
01708       _dbus_assert (!tree_test_data[i].message_handled);
01709       ++i;
01710     }
01711 
01712   /* Now start again and try the individual unregister function */
01713   tree = _dbus_object_tree_new (NULL);
01714   if (tree == NULL)
01715     goto out;
01716 
01717   if (!do_register (tree, path0, TRUE, 0, tree_test_data))
01718     goto out;
01719   if (!do_register (tree, path1, TRUE, 1, tree_test_data))
01720     goto out;
01721   if (!do_register (tree, path2, TRUE, 2, tree_test_data))
01722     goto out;
01723   if (!do_register (tree, path3, TRUE, 3, tree_test_data))
01724     goto out;
01725   if (!do_register (tree, path4, TRUE, 4, tree_test_data))
01726     goto out;
01727   if (!do_register (tree, path5, TRUE, 5, tree_test_data))
01728     goto out;
01729   if (!do_register (tree, path6, TRUE, 6, tree_test_data))
01730     goto out;
01731   if (!do_register (tree, path7, TRUE, 7, tree_test_data))
01732     goto out;
01733   if (!do_register (tree, path8, TRUE, 8, tree_test_data))
01734     goto out;
01735 
01736   _dbus_object_tree_unregister_and_unlock (tree, path0);
01737   _dbus_assert (_dbus_object_tree_get_user_data_unlocked (tree, path0) == NULL);
01738 
01739   _dbus_assert (!find_subtree (tree, path0, NULL));
01740   _dbus_assert (find_subtree (tree, path1, NULL));
01741   _dbus_assert (find_subtree (tree, path2, NULL));
01742   _dbus_assert (find_subtree (tree, path3, NULL));
01743   _dbus_assert (find_subtree (tree, path4, NULL));
01744   _dbus_assert (find_subtree (tree, path5, NULL));
01745   _dbus_assert (find_subtree (tree, path6, NULL));
01746   _dbus_assert (find_subtree (tree, path7, NULL));
01747   _dbus_assert (find_subtree (tree, path8, NULL));
01748   
01749   _dbus_object_tree_unregister_and_unlock (tree, path1);
01750   _dbus_assert (_dbus_object_tree_get_user_data_unlocked (tree, path1) == NULL);
01751 
01752   _dbus_assert (!find_subtree (tree, path0, NULL));
01753   _dbus_assert (!find_subtree (tree, path1, NULL));
01754   _dbus_assert (find_subtree (tree, path2, NULL));
01755   _dbus_assert (find_subtree (tree, path3, NULL));
01756   _dbus_assert (find_subtree (tree, path4, NULL));
01757   _dbus_assert (find_subtree (tree, path5, NULL));
01758   _dbus_assert (find_subtree (tree, path6, NULL));
01759   _dbus_assert (find_subtree (tree, path7, NULL));
01760   _dbus_assert (find_subtree (tree, path8, NULL));
01761 
01762   _dbus_object_tree_unregister_and_unlock (tree, path2);
01763   _dbus_assert (_dbus_object_tree_get_user_data_unlocked (tree, path2) == NULL);
01764 
01765   _dbus_assert (!find_subtree (tree, path0, NULL));
01766   _dbus_assert (!find_subtree (tree, path1, NULL));
01767   _dbus_assert (!find_subtree (tree, path2, NULL));
01768   _dbus_assert (find_subtree (tree, path3, NULL));
01769   _dbus_assert (find_subtree (tree, path4, NULL));
01770   _dbus_assert (find_subtree (tree, path5, NULL));
01771   _dbus_assert (find_subtree (tree, path6, NULL));
01772   _dbus_assert (find_subtree (tree, path7, NULL));
01773   _dbus_assert (find_subtree (tree, path8, NULL));
01774   
01775   _dbus_object_tree_unregister_and_unlock (tree, path3);
01776   _dbus_assert (_dbus_object_tree_get_user_data_unlocked (tree, path3) == NULL);
01777 
01778   _dbus_assert (!find_subtree (tree, path0, NULL));
01779   _dbus_assert (!find_subtree (tree, path1, NULL));
01780   _dbus_assert (!find_subtree (tree, path2, NULL));
01781   _dbus_assert (!find_subtree (tree, path3, NULL));
01782   _dbus_assert (find_subtree (tree, path4, NULL));
01783   _dbus_assert (find_subtree (tree, path5, NULL));
01784   _dbus_assert (find_subtree (tree, path6, NULL));
01785   _dbus_assert (find_subtree (tree, path7, NULL));
01786   _dbus_assert (find_subtree (tree, path8, NULL));
01787   
01788   _dbus_object_tree_unregister_and_unlock (tree, path4);
01789   _dbus_assert (_dbus_object_tree_get_user_data_unlocked (tree, path4) == NULL);
01790 
01791   _dbus_assert (!find_subtree (tree, path0, NULL));
01792   _dbus_assert (!find_subtree (tree, path1, NULL));
01793   _dbus_assert (!find_subtree (tree, path2, NULL));
01794   _dbus_assert (!find_subtree (tree, path3, NULL));
01795   _dbus_assert (!find_subtree (tree, path4, NULL));
01796   _dbus_assert (find_subtree (tree, path5, NULL));
01797   _dbus_assert (find_subtree (tree, path6, NULL));
01798   _dbus_assert (find_subtree (tree, path7, NULL));
01799   _dbus_assert (find_subtree (tree, path8, NULL));
01800   
01801   _dbus_object_tree_unregister_and_unlock (tree, path5);
01802   _dbus_assert (_dbus_object_tree_get_user_data_unlocked (tree, path5) == NULL);
01803 
01804   _dbus_assert (!find_subtree (tree, path0, NULL));
01805   _dbus_assert (!find_subtree (tree, path1, NULL));
01806   _dbus_assert (!find_subtree (tree, path2, NULL));
01807   _dbus_assert (!find_subtree (tree, path3, NULL));
01808   _dbus_assert (!find_subtree (tree, path4, NULL));
01809   _dbus_assert (!find_subtree (tree, path5, NULL));
01810   _dbus_assert (find_subtree (tree, path6, NULL));
01811   _dbus_assert (find_subtree (tree, path7, NULL));
01812   _dbus_assert (find_subtree (tree, path8, NULL));
01813   
01814   _dbus_object_tree_unregister_and_unlock (tree, path6);
01815   _dbus_assert (_dbus_object_tree_get_user_data_unlocked (tree, path6) == NULL);
01816 
01817   _dbus_assert (!find_subtree (tree, path0, NULL));
01818   _dbus_assert (!find_subtree (tree, path1, NULL));
01819   _dbus_assert (!find_subtree (tree, path2, NULL));
01820   _dbus_assert (!find_subtree (tree, path3, NULL));
01821   _dbus_assert (!find_subtree (tree, path4, NULL));
01822   _dbus_assert (!find_subtree (tree, path5, NULL));
01823   _dbus_assert (!find_subtree (tree, path6, NULL));
01824   _dbus_assert (find_subtree (tree, path7, NULL));
01825   _dbus_assert (find_subtree (tree, path8, NULL));
01826 
01827   _dbus_object_tree_unregister_and_unlock (tree, path7);
01828   _dbus_assert (_dbus_object_tree_get_user_data_unlocked (tree, path7) == NULL);
01829 
01830   _dbus_assert (!find_subtree (tree, path0, NULL));
01831   _dbus_assert (!find_subtree (tree, path1, NULL));
01832   _dbus_assert (!find_subtree (tree, path2, NULL));
01833   _dbus_assert (!find_subtree (tree, path3, NULL));
01834   _dbus_assert (!find_subtree (tree, path4, NULL));
01835   _dbus_assert (!find_subtree (tree, path5, NULL));
01836   _dbus_assert (!find_subtree (tree, path6, NULL));
01837   _dbus_assert (!find_subtree (tree, path7, NULL));
01838   _dbus_assert (find_subtree (tree, path8, NULL));
01839 
01840   _dbus_object_tree_unregister_and_unlock (tree, path8);
01841   _dbus_assert (_dbus_object_tree_get_user_data_unlocked (tree, path8) == NULL);
01842 
01843   _dbus_assert (!find_subtree (tree, path0, NULL));
01844   _dbus_assert (!find_subtree (tree, path1, NULL));
01845   _dbus_assert (!find_subtree (tree, path2, NULL));
01846   _dbus_assert (!find_subtree (tree, path3, NULL));
01847   _dbus_assert (!find_subtree (tree, path4, NULL));
01848   _dbus_assert (!find_subtree (tree, path5, NULL));
01849   _dbus_assert (!find_subtree (tree, path6, NULL));
01850   _dbus_assert (!find_subtree (tree, path7, NULL));
01851   _dbus_assert (!find_subtree (tree, path8, NULL));
01852   
01853   i = 0;
01854   while (i < (int) _DBUS_N_ELEMENTS (tree_test_data))
01855     {
01856       _dbus_assert (tree_test_data[i].handler_unregistered);
01857       _dbus_assert (!tree_test_data[i].message_handled);
01858       ++i;
01859     }
01860 
01861   /* Register it all again, and test dispatch */
01862   
01863   if (!do_register (tree, path0, TRUE, 0, tree_test_data))
01864     goto out;
01865   if (!do_register (tree, path1, FALSE, 1, tree_test_data))
01866     goto out;
01867   if (!do_register (tree, path2, TRUE, 2, tree_test_data))
01868     goto out;
01869   if (!do_register (tree, path3, TRUE, 3, tree_test_data))
01870     goto out;
01871   if (!do_register (tree, path4, TRUE, 4, tree_test_data))
01872     goto out;
01873   if (!do_register (tree, path5, TRUE, 5, tree_test_data))
01874     goto out;
01875   if (!do_register (tree, path6, FALSE, 6, tree_test_data))
01876     goto out;
01877   if (!do_register (tree, path7, TRUE, 7, tree_test_data))
01878     goto out;
01879   if (!do_register (tree, path8, TRUE, 8, tree_test_data))
01880     goto out;
01881 
01882 #if 0
01883   spew_tree (tree);
01884 #endif
01885 
01886   if (!do_test_dispatch (tree, path0, 0, tree_test_data, _DBUS_N_ELEMENTS (tree_test_data)))
01887     goto out;
01888   if (!do_test_dispatch (tree, path1, 1, tree_test_data, _DBUS_N_ELEMENTS (tree_test_data)))
01889     goto out;
01890   if (!do_test_dispatch (tree, path2, 2, tree_test_data, _DBUS_N_ELEMENTS (tree_test_data)))
01891     goto out;
01892   if (!do_test_dispatch (tree, path3, 3, tree_test_data, _DBUS_N_ELEMENTS (tree_test_data)))
01893     goto out;
01894   if (!do_test_dispatch (tree, path4, 4, tree_test_data, _DBUS_N_ELEMENTS (tree_test_data)))
01895     goto out;
01896   if (!do_test_dispatch (tree, path5, 5, tree_test_data, _DBUS_N_ELEMENTS (tree_test_data)))
01897     goto out;
01898   if (!do_test_dispatch (tree, path6, 6, tree_test_data, _DBUS_N_ELEMENTS (tree_test_data)))
01899     goto out;
01900   if (!do_test_dispatch (tree, path7, 7, tree_test_data, _DBUS_N_ELEMENTS (tree_test_data)))
01901     goto out;
01902   if (!do_test_dispatch (tree, path8, 8, tree_test_data, _DBUS_N_ELEMENTS (tree_test_data)))
01903     goto out;
01904   
01905  out:
01906   if (tree)
01907     {
01908       /* test ref */
01909       _dbus_object_tree_ref (tree);
01910       _dbus_object_tree_unref (tree);
01911       _dbus_object_tree_unref (tree);
01912     }
01913 
01914   return TRUE;
01915 }
01916 
01922 dbus_bool_t
01923 _dbus_object_tree_test (void)
01924 {
01925   _dbus_test_oom_handling ("object tree",
01926                            object_tree_test_iteration,
01927                            NULL);
01928 
01929   return TRUE;
01930 }
01931 
01932 #endif /* !DOXYGEN_SHOULD_SKIP_THIS */
01933 
01934 #endif /* DBUS_BUILD_TESTS */

Generated on Fri Sep 21 18:12:12 2007 for D-Bus by  doxygen 1.5.1