00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
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 void _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 unsigned int subtrees_sorted : 1;
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
00095
00096
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
00125 void
00126 _dbus_object_tree_ref (DBusObjectTree *tree)
00127 {
00128 _dbus_assert (tree->refcount > 0);
00129
00130 tree->refcount += 1;
00131 }
00132
00137 void
00138 _dbus_object_tree_unref (DBusObjectTree *tree)
00139 {
00140 _dbus_assert (tree->refcount > 0);
00141
00142 tree->refcount -= 1;
00143
00144 if (tree->refcount == 0)
00145 {
00146 _dbus_object_tree_free_all_unlocked (tree);
00147
00148 dbus_free (tree);
00149 }
00150 }
00151
00152 static int
00153 subtree_cmp (DBusObjectSubtree *subtree_a,
00154 DBusObjectSubtree *subtree_b)
00155 {
00156 return strcmp (subtree_a->name, subtree_b->name);
00157 }
00158
00159 static int
00160 subtree_qsort_cmp (const void *a,
00161 const void *b)
00162 {
00163 DBusObjectSubtree **subtree_a_p = (void*) a;
00164 DBusObjectSubtree **subtree_b_p = (void*) b;
00165
00166 return subtree_cmp (*subtree_a_p, *subtree_b_p);
00167 }
00168
00169 static void
00170 ensure_sorted (DBusObjectSubtree *subtree)
00171 {
00172 if (subtree->subtrees && !subtree->subtrees_sorted)
00173 {
00174 qsort (subtree->subtrees,
00175 subtree->n_subtrees,
00176 sizeof (DBusObjectSubtree*),
00177 subtree_qsort_cmp);
00178 subtree->subtrees_sorted = TRUE;
00179 }
00180 }
00181
00185 #define VERBOSE_FIND 0
00186
00187 static DBusObjectSubtree*
00188 find_subtree_recurse (DBusObjectSubtree *subtree,
00189 const char **path,
00190 dbus_bool_t return_deepest_match,
00191 dbus_bool_t create_if_not_found,
00192 int *index_in_parent)
00193 {
00194 int i;
00195
00196 _dbus_assert (!(return_deepest_match && create_if_not_found));
00197
00198 if (path[0] == NULL)
00199 {
00200 #if VERBOSE_FIND
00201 _dbus_verbose (" path exhausted, returning %s\n",
00202 subtree->name);
00203 #endif
00204 return subtree;
00205 }
00206
00207 #if VERBOSE_FIND
00208 _dbus_verbose (" searching children of %s for %s\n",
00209 subtree->name, path[0]);
00210 #endif
00211
00212 ensure_sorted (subtree);
00213
00214
00215
00216
00217
00218 i = 0;
00219 while (i < subtree->n_subtrees)
00220 {
00221 int v;
00222
00223 v = strcmp (path[0], subtree->subtrees[i]->name);
00224
00225 #if VERBOSE_FIND
00226 _dbus_verbose (" %s cmp %s = %d\n",
00227 path[0], subtree->subtrees[i]->name,
00228 v);
00229 #endif
00230
00231 if (v == 0)
00232 {
00233 if (index_in_parent)
00234 {
00235 #if VERBOSE_FIND
00236 _dbus_verbose (" storing parent index %d\n", i);
00237 #endif
00238 *index_in_parent = i;
00239 }
00240
00241 if (return_deepest_match)
00242 {
00243 DBusObjectSubtree *next;
00244
00245 next = find_subtree_recurse (subtree->subtrees[i],
00246 &path[1], return_deepest_match,
00247 create_if_not_found, index_in_parent);
00248 if (next == NULL &&
00249 subtree->invoke_as_fallback)
00250 {
00251 #if VERBOSE_FIND
00252 _dbus_verbose (" no deeper match found, returning %s\n",
00253 subtree->name);
00254 #endif
00255 return subtree;
00256 }
00257 else
00258 return next;
00259 }
00260 else
00261 return find_subtree_recurse (subtree->subtrees[i],
00262 &path[1], return_deepest_match,
00263 create_if_not_found, index_in_parent);
00264 }
00265 else if (v < 0)
00266 {
00267 goto not_found;
00268 }
00269
00270 ++i;
00271 }
00272
00273 not_found:
00274 #if VERBOSE_FIND
00275 _dbus_verbose (" no match found, current tree %s, create_if_not_found = %d\n",
00276 subtree->name, create_if_not_found);
00277 #endif
00278
00279 if (create_if_not_found)
00280 {
00281 DBusObjectSubtree* child;
00282 DBusObjectSubtree **new_subtrees;
00283 int new_n_subtrees;
00284
00285 #if VERBOSE_FIND
00286 _dbus_verbose (" creating subtree %s\n",
00287 path[0]);
00288 #endif
00289
00290 child = _dbus_object_subtree_new (path[0],
00291 NULL, NULL);
00292 if (child == NULL)
00293 return NULL;
00294
00295
00296 new_n_subtrees = subtree->n_subtrees + 1;
00297 new_subtrees = dbus_realloc (subtree->subtrees,
00298 new_n_subtrees * sizeof (DBusObjectSubtree*));
00299 if (new_subtrees == NULL)
00300 {
00301 child->unregister_function = NULL;
00302 child->message_function = NULL;
00303 _dbus_object_subtree_unref (child);
00304 return FALSE;
00305 }
00306
00307 new_subtrees[subtree->n_subtrees] = child;
00308 if (index_in_parent)
00309 *index_in_parent = subtree->n_subtrees;
00310 subtree->subtrees_sorted = FALSE;
00311 subtree->n_subtrees = new_n_subtrees;
00312 subtree->subtrees = new_subtrees;
00313
00314 child->parent = subtree;
00315
00316 return find_subtree_recurse (child,
00317 &path[1], return_deepest_match,
00318 create_if_not_found, index_in_parent);
00319 }
00320 else
00321 return (return_deepest_match && subtree->invoke_as_fallback) ? subtree : NULL;
00322 }
00323
00324 static DBusObjectSubtree*
00325 find_subtree (DBusObjectTree *tree,
00326 const char **path,
00327 int *index_in_parent)
00328 {
00329 DBusObjectSubtree *subtree;
00330
00331 #if VERBOSE_FIND
00332 _dbus_verbose ("Looking for exact registered subtree\n");
00333 #endif
00334
00335 subtree = find_subtree_recurse (tree->root, path, FALSE, FALSE, index_in_parent);
00336
00337 if (subtree && subtree->message_function == NULL)
00338 return NULL;
00339 else
00340 return subtree;
00341 }
00342
00343 static DBusObjectSubtree*
00344 find_handler (DBusObjectTree *tree,
00345 const char **path)
00346 {
00347 #if VERBOSE_FIND
00348 _dbus_verbose ("Looking for deepest handler\n");
00349 #endif
00350 return find_subtree_recurse (tree->root, path, TRUE, FALSE, NULL);
00351 }
00352
00353 static DBusObjectSubtree*
00354 ensure_subtree (DBusObjectTree *tree,
00355 const char **path)
00356 {
00357 #if VERBOSE_FIND
00358 _dbus_verbose ("Ensuring subtree\n");
00359 #endif
00360 return find_subtree_recurse (tree->root, path, FALSE, TRUE, NULL);
00361 }
00362
00373 dbus_bool_t
00374 _dbus_object_tree_register (DBusObjectTree *tree,
00375 dbus_bool_t fallback,
00376 const char **path,
00377 const DBusObjectPathVTable *vtable,
00378 void *user_data)
00379 {
00380 DBusObjectSubtree *subtree;
00381
00382 _dbus_assert (tree != NULL);
00383 _dbus_assert (vtable->message_function != NULL);
00384 _dbus_assert (path != NULL);
00385
00386 subtree = ensure_subtree (tree, path);
00387 if (subtree == NULL)
00388 return FALSE;
00389
00390 #ifndef DBUS_DISABLE_CHECKS
00391 if (subtree->message_function != NULL)
00392 {
00393 _dbus_warn ("A handler is already registered for the path starting with path[0] = \"%s\"\n",
00394 path[0] ? path[0] : "null");
00395 return FALSE;
00396 }
00397 #else
00398 _dbus_assert (subtree->message_function == NULL);
00399 #endif
00400
00401 subtree->message_function = vtable->message_function;
00402 subtree->unregister_function = vtable->unregister_function;
00403 subtree->user_data = user_data;
00404 subtree->invoke_as_fallback = fallback != FALSE;
00405
00406 return TRUE;
00407 }
00408
00416 void
00417 _dbus_object_tree_unregister_and_unlock (DBusObjectTree *tree,
00418 const char **path)
00419 {
00420 int i;
00421 DBusObjectSubtree *subtree;
00422 DBusObjectPathUnregisterFunction unregister_function;
00423 void *user_data;
00424 DBusConnection *connection;
00425
00426 _dbus_assert (path != NULL);
00427
00428 subtree = find_subtree (tree, path, &i);
00429
00430 #ifndef DBUS_DISABLE_CHECKS
00431 if (subtree == NULL)
00432 {
00433 _dbus_warn ("Attempted to unregister path (path[0] = %s path[1] = %s) which isn't registered\n",
00434 path[0] ? path[0] : "null",
00435 path[1] ? path[1] : "null");
00436 return;
00437 }
00438 #else
00439 _dbus_assert (subtree != NULL);
00440 #endif
00441
00442 _dbus_assert (subtree->parent == NULL ||
00443 (i >= 0 && subtree->parent->subtrees[i] == subtree));
00444
00445 subtree->message_function = NULL;
00446
00447 unregister_function = subtree->unregister_function;
00448 user_data = subtree->user_data;
00449
00450 subtree->unregister_function = NULL;
00451 subtree->user_data = NULL;
00452
00453
00454
00455
00456
00457 if (subtree->parent && subtree->n_subtrees == 0)
00458 {
00459
00460 memmove (&subtree->parent->subtrees[i],
00461 &subtree->parent->subtrees[i+1],
00462 (subtree->parent->n_subtrees - i - 1) *
00463 sizeof (subtree->parent->subtrees[0]));
00464 subtree->parent->n_subtrees -= 1;
00465
00466 subtree->parent = NULL;
00467
00468 _dbus_object_subtree_unref (subtree);
00469 }
00470 subtree = NULL;
00471
00472 connection = tree->connection;
00473
00474
00475 #ifdef DBUS_BUILD_TESTS
00476 if (connection)
00477 #endif
00478 {
00479 _dbus_connection_ref_unlocked (connection);
00480 _dbus_connection_unlock (connection);
00481 }
00482
00483 if (unregister_function)
00484 (* unregister_function) (connection, user_data);
00485
00486 #ifdef DBUS_BUILD_TESTS
00487 if (connection)
00488 #endif
00489 dbus_connection_unref (connection);
00490 }
00491
00492 static void
00493 free_subtree_recurse (DBusConnection *connection,
00494 DBusObjectSubtree *subtree)
00495 {
00496
00497
00498
00499 while (subtree->n_subtrees > 0)
00500 {
00501 DBusObjectSubtree *child;
00502
00503 child = subtree->subtrees[subtree->n_subtrees - 1];
00504 subtree->subtrees[subtree->n_subtrees - 1] = NULL;
00505 subtree->n_subtrees -= 1;
00506 child->parent = NULL;
00507
00508 free_subtree_recurse (connection, child);
00509 }
00510
00511
00512 if (subtree->unregister_function)
00513 {
00514 (* subtree->unregister_function) (connection,
00515 subtree->user_data);
00516 subtree->message_function = NULL;
00517 subtree->unregister_function = NULL;
00518 subtree->user_data = NULL;
00519 }
00520
00521
00522 _dbus_object_subtree_unref (subtree);
00523 }
00524
00531 void
00532 _dbus_object_tree_free_all_unlocked (DBusObjectTree *tree)
00533 {
00534 if (tree->root)
00535 free_subtree_recurse (tree->connection,
00536 tree->root);
00537 tree->root = NULL;
00538 }
00539
00540 static dbus_bool_t
00541 _dbus_object_tree_list_registered_unlocked (DBusObjectTree *tree,
00542 const char **parent_path,
00543 char ***child_entries)
00544 {
00545 DBusObjectSubtree *subtree;
00546 char **retval;
00547
00548 _dbus_assert (parent_path != NULL);
00549 _dbus_assert (child_entries != NULL);
00550
00551 *child_entries = NULL;
00552
00553 subtree = find_subtree (tree, parent_path, NULL);
00554 if (subtree == NULL)
00555 {
00556 retval = dbus_new0 (char *, 1);
00557 if (retval == NULL)
00558 goto out;
00559 }
00560 else
00561 {
00562 int i;
00563 retval = dbus_new0 (char*, subtree->n_subtrees + 1);
00564 if (retval == NULL)
00565 goto out;
00566 i = 0;
00567 while (i < subtree->n_subtrees)
00568 {
00569 retval[i] = _dbus_strdup (subtree->subtrees[i]->name);
00570 if (retval[i] == NULL)
00571 {
00572 dbus_free_string_array (retval);
00573 retval = NULL;
00574 goto out;
00575 }
00576 ++i;
00577 }
00578 }
00579
00580 out:
00581
00582 *child_entries = retval;
00583 return retval != NULL;
00584 }
00585
00586 static DBusHandlerResult
00587 handle_default_introspect_unlocked (DBusObjectTree *tree,
00588 DBusMessage *message,
00589 const char **path)
00590 {
00591 DBusString xml;
00592 DBusHandlerResult result;
00593 char **children;
00594 int i;
00595
00596 if (!dbus_message_is_method_call (message,
00597 DBUS_INTERFACE_ORG_FREEDESKTOP_INTROSPECTABLE,
00598 "Introspect"))
00599 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
00600
00601 if (!_dbus_string_init (&xml))
00602 return DBUS_HANDLER_RESULT_NEED_MEMORY;
00603
00604 result = DBUS_HANDLER_RESULT_NEED_MEMORY;
00605
00606 children = NULL;
00607 if (!_dbus_object_tree_list_registered_unlocked (tree, path, &children))
00608 goto out;
00609
00610 if (!_dbus_string_append (&xml, "<node>\n"))
00611 goto out;
00612
00613 i = 0;
00614 while (children[i] != NULL)
00615 {
00616 if (!_dbus_string_append_printf (&xml, " <node name=\"%s\"/>\n",
00617 children[i]))
00618 goto out;
00619
00620 ++i;
00621 }
00622
00623 if (!_dbus_string_append (&xml, "</node>\n"))
00624 goto out;
00625
00626 result = DBUS_HANDLER_RESULT_HANDLED;
00627
00628 out:
00629 _dbus_string_free (&xml);
00630 dbus_free_string_array (children);
00631
00632 return result;
00633 }
00634
00648 DBusHandlerResult
00649 _dbus_object_tree_dispatch_and_unlock (DBusObjectTree *tree,
00650 DBusMessage *message)
00651 {
00652 char **path;
00653 DBusList *list;
00654 DBusList *link;
00655 DBusHandlerResult result;
00656 DBusObjectSubtree *subtree;
00657
00658 #if 0
00659 _dbus_verbose ("Dispatch of message by object path\n");
00660 #endif
00661
00662 path = NULL;
00663 if (!dbus_message_get_path_decomposed (message, &path))
00664 {
00665 #ifdef DBUS_BUILD_TESTS
00666 if (tree->connection)
00667 #endif
00668 _dbus_connection_unlock (tree->connection);
00669
00670 _dbus_verbose ("No memory to get decomposed path\n");
00671
00672 return DBUS_HANDLER_RESULT_NEED_MEMORY;
00673 }
00674
00675 if (path == NULL)
00676 {
00677 #ifdef DBUS_BUILD_TESTS
00678 if (tree->connection)
00679 #endif
00680 _dbus_connection_unlock (tree->connection);
00681
00682 _dbus_verbose ("No path field in message\n");
00683 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
00684 }
00685
00686
00687 subtree = find_handler (tree, (const char**) path);
00688
00689
00690
00691 list = NULL;
00692
00693 while (subtree != NULL)
00694 {
00695 if (subtree->message_function != NULL)
00696 {
00697 _dbus_object_subtree_ref (subtree);
00698
00699
00700 if (!_dbus_list_append (&list, subtree))
00701 {
00702 result = DBUS_HANDLER_RESULT_NEED_MEMORY;
00703 _dbus_object_subtree_unref (subtree);
00704 goto free_and_return;
00705 }
00706 }
00707
00708 subtree = subtree->parent;
00709 }
00710
00711 _dbus_verbose ("%d handlers in the path tree for this message\n",
00712 _dbus_list_get_length (&list));
00713
00714
00715
00716 result = DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
00717
00718 link = _dbus_list_get_first_link (&list);
00719 while (link != NULL)
00720 {
00721 DBusList *next = _dbus_list_get_next_link (&list, link);
00722 subtree = link->data;
00723
00724
00725
00726
00727 if (subtree->message_function)
00728 {
00729 DBusObjectPathMessageFunction message_function;
00730 void *user_data;
00731
00732 message_function = subtree->message_function;
00733 user_data = subtree->user_data;
00734
00735 #if 0
00736 _dbus_verbose (" (invoking a handler)\n");
00737 #endif
00738
00739 #ifdef DBUS_BUILD_TESTS
00740 if (tree->connection)
00741 #endif
00742 _dbus_connection_unlock (tree->connection);
00743
00744
00745
00746
00747
00748
00749 result = (* message_function) (tree->connection,
00750 message,
00751 user_data);
00752
00753 #ifdef DBUS_BUILD_TESTS
00754 if (tree->connection)
00755 #endif
00756 _dbus_connection_lock (tree->connection);
00757
00758 if (result != DBUS_HANDLER_RESULT_NOT_YET_HANDLED)
00759 goto free_and_return;
00760 }
00761
00762 link = next;
00763 }
00764
00765 free_and_return:
00766
00767 if (result == DBUS_HANDLER_RESULT_NOT_YET_HANDLED)
00768 {
00769
00770
00771 result = handle_default_introspect_unlocked (tree, message,
00772 (const char**) path);
00773 }
00774
00775 #ifdef DBUS_BUILD_TESTS
00776 if (tree->connection)
00777 #endif
00778 _dbus_connection_unlock (tree->connection);
00779
00780 while (list != NULL)
00781 {
00782 link = _dbus_list_get_first_link (&list);
00783 _dbus_object_subtree_unref (link->data);
00784 _dbus_list_remove_link (&list, link);
00785 }
00786
00787 dbus_free_string_array (path);
00788
00789 return result;
00790 }
00791
00798 static DBusObjectSubtree*
00799 allocate_subtree_object (const char *name)
00800 {
00801 int len;
00802 DBusObjectSubtree *subtree;
00803 const size_t front_padding = _DBUS_STRUCT_OFFSET (DBusObjectSubtree, name);
00804
00805 _dbus_assert (name != NULL);
00806
00807 len = strlen (name);
00808
00809 subtree = dbus_malloc (front_padding + (len + 1));
00810
00811 if (subtree == NULL)
00812 return NULL;
00813
00814 memcpy (subtree->name, name, len + 1);
00815
00816 return subtree;
00817 }
00818
00819 static DBusObjectSubtree*
00820 _dbus_object_subtree_new (const char *name,
00821 const DBusObjectPathVTable *vtable,
00822 void *user_data)
00823 {
00824 DBusObjectSubtree *subtree;
00825
00826 subtree = allocate_subtree_object (name);
00827 if (subtree == NULL)
00828 goto oom;
00829
00830 _dbus_assert (name != NULL);
00831
00832 subtree->parent = NULL;
00833
00834 if (vtable)
00835 {
00836 subtree->message_function = vtable->message_function;
00837 subtree->unregister_function = vtable->unregister_function;
00838 }
00839 else
00840 {
00841 subtree->message_function = NULL;
00842 subtree->unregister_function = NULL;
00843 }
00844
00845 subtree->user_data = user_data;
00846 subtree->refcount.value = 1;
00847 subtree->subtrees = NULL;
00848 subtree->n_subtrees = 0;
00849 subtree->subtrees_sorted = TRUE;
00850
00851 return subtree;
00852
00853 oom:
00854 if (subtree)
00855 {
00856 dbus_free (subtree);
00857 }
00858
00859 return NULL;
00860 }
00861
00862 static void
00863 _dbus_object_subtree_ref (DBusObjectSubtree *subtree)
00864 {
00865 _dbus_assert (subtree->refcount.value > 0);
00866 _dbus_atomic_inc (&subtree->refcount);
00867 }
00868
00869 static void
00870 _dbus_object_subtree_unref (DBusObjectSubtree *subtree)
00871 {
00872 _dbus_assert (subtree->refcount.value > 0);
00873
00874 if (_dbus_atomic_dec (&subtree->refcount) == 1)
00875 {
00876 _dbus_assert (subtree->unregister_function == NULL);
00877 _dbus_assert (subtree->message_function == NULL);
00878
00879 dbus_free (subtree->subtrees);
00880 dbus_free (subtree);
00881 }
00882 }
00883
00894 dbus_bool_t
00895 _dbus_object_tree_list_registered_and_unlock (DBusObjectTree *tree,
00896 const char **parent_path,
00897 char ***child_entries)
00898 {
00899 dbus_bool_t result;
00900
00901 result = _dbus_object_tree_list_registered_unlocked (tree,
00902 parent_path,
00903 child_entries);
00904
00905 #ifdef DBUS_BUILD_TESTS
00906 if (tree->connection)
00907 #endif
00908 _dbus_connection_unlock (tree->connection);
00909
00910 return result;
00911 }
00912
00915 #ifdef DBUS_BUILD_TESTS
00916 #include "dbus-test.h"
00917 #include <stdio.h>
00918
00919 static char*
00920 flatten_path (const char **path)
00921 {
00922 DBusString str;
00923 int i;
00924 char *s;
00925
00926 if (!_dbus_string_init (&str))
00927 return NULL;
00928
00929 i = 0;
00930 while (path[i])
00931 {
00932 if (!_dbus_string_append_byte (&str, '/'))
00933 goto nomem;
00934
00935 if (!_dbus_string_append (&str, path[i]))
00936 goto nomem;
00937
00938 ++i;
00939 }
00940
00941 if (!_dbus_string_steal_data (&str, &s))
00942 goto nomem;
00943
00944 _dbus_string_free (&str);
00945
00946 return s;
00947
00948 nomem:
00949 _dbus_string_free (&str);
00950 return NULL;
00951 }
00952
00953
00954
00955 static dbus_bool_t
00956 path_contains (const char **container,
00957 const char **child)
00958 {
00959 int i;
00960
00961 i = 0;
00962 while (child[i] != NULL)
00963 {
00964 int v;
00965
00966 if (container[i] == NULL)
00967 return TRUE;
00968
00969
00970
00971
00972 _dbus_assert (container[i] != NULL);
00973 _dbus_assert (child[i] != NULL);
00974
00975 v = strcmp (container[i], child[i]);
00976
00977 if (v != 0)
00978 return FALSE;
00979
00980
00981
00982 ++i;
00983 }
00984
00985
00986
00987
00988 if (container[i] == NULL)
00989 return TRUE;
00990 else
00991 return FALSE;
00992 }
00993
00994 static void
00995 spew_subtree_recurse (DBusObjectSubtree *subtree,
00996 int indent)
00997 {
00998 int i;
00999
01000 i = 0;
01001 while (i < indent)
01002 {
01003 _dbus_verbose (" ");
01004 ++i;
01005 }
01006
01007 _dbus_verbose ("%s (%d children)\n",
01008 subtree->name, subtree->n_subtrees);
01009
01010 i = 0;
01011 while (i < subtree->n_subtrees)
01012 {
01013 spew_subtree_recurse (subtree->subtrees[i], indent + 2);
01014
01015 ++i;
01016 }
01017 }
01018
01019 static void
01020 spew_tree (DBusObjectTree *tree)
01021 {
01022 spew_subtree_recurse (tree->root, 0);
01023 }
01024
01028 typedef struct
01029 {
01030 const char **path;
01031 dbus_bool_t message_handled;
01032 dbus_bool_t handler_unregistered;
01034 } TreeTestData;
01035
01036
01037 static void
01038 test_unregister_function (DBusConnection *connection,
01039 void *user_data)
01040 {
01041 TreeTestData *ttd = user_data;
01042
01043 ttd->handler_unregistered = TRUE;
01044 }
01045
01046 static DBusHandlerResult
01047 test_message_function (DBusConnection *connection,
01048 DBusMessage *message,
01049 void *user_data)
01050 {
01051 TreeTestData *ttd = user_data;
01052
01053 ttd->message_handled = TRUE;
01054
01055 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
01056 }
01057
01058 static dbus_bool_t
01059 do_register (DBusObjectTree *tree,
01060 const char **path,
01061 int i,
01062 TreeTestData *tree_test_data)
01063 {
01064 DBusObjectPathVTable vtable = { test_unregister_function,
01065 test_message_function, NULL };
01066
01067 tree_test_data[i].message_handled = FALSE;
01068 tree_test_data[i].handler_unregistered = FALSE;
01069 tree_test_data[i].path = path;
01070
01071 if (!_dbus_object_tree_register (tree, TRUE, path,
01072 &vtable,
01073 &tree_test_data[i]))
01074 return FALSE;
01075
01076 return TRUE;
01077 }
01078
01079 static dbus_bool_t
01080 do_test_dispatch (DBusObjectTree *tree,
01081 const char **path,
01082 int i,
01083 TreeTestData *tree_test_data,
01084 int n_test_data)
01085 {
01086 DBusMessage *message;
01087 int j;
01088 DBusHandlerResult result;
01089 char *flat;
01090
01091 message = NULL;
01092
01093 flat = flatten_path (path);
01094 if (flat == NULL)
01095 goto oom;
01096
01097 message = dbus_message_new_method_call (NULL,
01098 flat,
01099 "org.freedesktop.TestInterface",
01100 "Foo");
01101 dbus_free (flat);
01102 if (message == NULL)
01103 goto oom;
01104
01105 j = 0;
01106 while (j < n_test_data)
01107 {
01108 tree_test_data[j].message_handled = FALSE;
01109 ++j;
01110 }
01111
01112 result = _dbus_object_tree_dispatch_and_unlock (tree, message);
01113 if (result == DBUS_HANDLER_RESULT_NEED_MEMORY)
01114 goto oom;
01115
01116 _dbus_assert (tree_test_data[i].message_handled);
01117
01118 j = 0;
01119 while (j < n_test_data)
01120 {
01121 if (tree_test_data[j].message_handled)
01122 _dbus_assert (path_contains (tree_test_data[j].path,
01123 path));
01124 else
01125 _dbus_assert (!path_contains (tree_test_data[j].path,
01126 path));
01127
01128 ++j;
01129 }
01130
01131 dbus_message_unref (message);
01132
01133 return TRUE;
01134
01135 oom:
01136 if (message)
01137 dbus_message_unref (message);
01138 return FALSE;
01139 }
01140
01141 static dbus_bool_t
01142 object_tree_test_iteration (void *data)
01143 {
01144 const char *path1[] = { "foo", NULL };
01145 const char *path2[] = { "foo", "bar", NULL };
01146 const char *path3[] = { "foo", "bar", "baz", NULL };
01147 const char *path4[] = { "foo", "bar", "boo", NULL };
01148 const char *path5[] = { "blah", NULL };
01149 const char *path6[] = { "blah", "boof", NULL };
01150 const char *path7[] = { "blah", "boof", "this", "is", "really", "long", NULL };
01151 const char *path8[] = { "childless", NULL };
01152 DBusObjectTree *tree;
01153 TreeTestData tree_test_data[8];
01154 int i;
01155
01156 tree = NULL;
01157
01158 tree = _dbus_object_tree_new (NULL);
01159 if (tree == NULL)
01160 goto out;
01161
01162 if (!do_register (tree, path1, 0, tree_test_data))
01163 goto out;
01164
01165 _dbus_assert (find_subtree (tree, path1, NULL));
01166 _dbus_assert (!find_subtree (tree, path2, NULL));
01167 _dbus_assert (!find_subtree (tree, path3, NULL));
01168 _dbus_assert (!find_subtree (tree, path4, NULL));
01169 _dbus_assert (!find_subtree (tree, path5, NULL));
01170 _dbus_assert (!find_subtree (tree, path6, NULL));
01171 _dbus_assert (!find_subtree (tree, path7, NULL));
01172 _dbus_assert (!find_subtree (tree, path8, NULL));
01173
01174 _dbus_assert (find_handler (tree, path1));
01175 _dbus_assert (find_handler (tree, path2));
01176 _dbus_assert (find_handler (tree, path3));
01177 _dbus_assert (find_handler (tree, path4));
01178 _dbus_assert (find_handler (tree, path5) == tree->root);
01179 _dbus_assert (find_handler (tree, path6) == tree->root);
01180 _dbus_assert (find_handler (tree, path7) == tree->root);
01181 _dbus_assert (find_handler (tree, path8) == tree->root);
01182
01183 if (!do_register (tree, path2, 1, tree_test_data))
01184 goto out;
01185
01186 _dbus_assert (find_subtree (tree, path1, NULL));
01187 _dbus_assert (find_subtree (tree, path2, NULL));
01188 _dbus_assert (!find_subtree (tree, path3, NULL));
01189 _dbus_assert (!find_subtree (tree, path4, NULL));
01190 _dbus_assert (!find_subtree (tree, path5, NULL));
01191 _dbus_assert (!find_subtree (tree, path6, NULL));
01192 _dbus_assert (!find_subtree (tree, path7, NULL));
01193 _dbus_assert (!find_subtree (tree, path8, NULL));
01194
01195 if (!do_register (tree, path3, 2, tree_test_data))
01196 goto out;
01197
01198 _dbus_assert (find_subtree (tree, path1, NULL));
01199 _dbus_assert (find_subtree (tree, path2, NULL));
01200 _dbus_assert (find_subtree (tree, path3, NULL));
01201 _dbus_assert (!find_subtree (tree, path4, NULL));
01202 _dbus_assert (!find_subtree (tree, path5, NULL));
01203 _dbus_assert (!find_subtree (tree, path6, NULL));
01204 _dbus_assert (!find_subtree (tree, path7, NULL));
01205 _dbus_assert (!find_subtree (tree, path8, NULL));
01206
01207 if (!do_register (tree, path4, 3, tree_test_data))
01208 goto out;
01209
01210 _dbus_assert (find_subtree (tree, path1, NULL));
01211 _dbus_assert (find_subtree (tree, path2, NULL));
01212 _dbus_assert (find_subtree (tree, path3, NULL));
01213 _dbus_assert (find_subtree (tree, path4, NULL));
01214 _dbus_assert (!find_subtree (tree, path5, NULL));
01215 _dbus_assert (!find_subtree (tree, path6, NULL));
01216 _dbus_assert (!find_subtree (tree, path7, NULL));
01217 _dbus_assert (!find_subtree (tree, path8, NULL));
01218
01219 if (!do_register (tree, path5, 4, tree_test_data))
01220 goto out;
01221
01222 _dbus_assert (find_subtree (tree, path1, NULL));
01223 _dbus_assert (find_subtree (tree, path2, NULL));
01224 _dbus_assert (find_subtree (tree, path3, NULL));
01225 _dbus_assert (find_subtree (tree, path4, NULL));
01226 _dbus_assert (find_subtree (tree, path5, NULL));
01227 _dbus_assert (!find_subtree (tree, path6, NULL));
01228 _dbus_assert (!find_subtree (tree, path7, NULL));
01229 _dbus_assert (!find_subtree (tree, path8, NULL));
01230
01231 _dbus_assert (find_handler (tree, path1) != tree->root);
01232 _dbus_assert (find_handler (tree, path2) != tree->root);
01233 _dbus_assert (find_handler (tree, path3) != tree->root);
01234 _dbus_assert (find_handler (tree, path4) != tree->root);
01235 _dbus_assert (find_handler (tree, path5) != tree->root);
01236 _dbus_assert (find_handler (tree, path6) != tree->root);
01237 _dbus_assert (find_handler (tree, path7) != tree->root);
01238 _dbus_assert (find_handler (tree, path8) == tree->root);
01239
01240 if (!do_register (tree, path6, 5, tree_test_data))
01241 goto out;
01242
01243 _dbus_assert (find_subtree (tree, path1, NULL));
01244 _dbus_assert (find_subtree (tree, path2, NULL));
01245 _dbus_assert (find_subtree (tree, path3, NULL));
01246 _dbus_assert (find_subtree (tree, path4, NULL));
01247 _dbus_assert (find_subtree (tree, path5, NULL));
01248 _dbus_assert (find_subtree (tree, path6, NULL));
01249 _dbus_assert (!find_subtree (tree, path7, NULL));
01250 _dbus_assert (!find_subtree (tree, path8, NULL));
01251
01252 if (!do_register (tree, path7, 6, tree_test_data))
01253 goto out;
01254
01255 _dbus_assert (find_subtree (tree, path1, NULL));
01256 _dbus_assert (find_subtree (tree, path2, NULL));
01257 _dbus_assert (find_subtree (tree, path3, NULL));
01258 _dbus_assert (find_subtree (tree, path4, NULL));
01259 _dbus_assert (find_subtree (tree, path5, NULL));
01260 _dbus_assert (find_subtree (tree, path6, NULL));
01261 _dbus_assert (find_subtree (tree, path7, NULL));
01262 _dbus_assert (!find_subtree (tree, path8, NULL));
01263
01264 if (!do_register (tree, path8, 7, tree_test_data))
01265 goto out;
01266
01267 _dbus_assert (find_subtree (tree, path1, NULL));
01268 _dbus_assert (find_subtree (tree, path2, NULL));
01269 _dbus_assert (find_subtree (tree, path3, NULL));
01270 _dbus_assert (find_subtree (tree, path4, NULL));
01271 _dbus_assert (find_subtree (tree, path5, NULL));
01272 _dbus_assert (find_subtree (tree, path6, NULL));
01273 _dbus_assert (find_subtree (tree, path7, NULL));
01274 _dbus_assert (find_subtree (tree, path8, NULL));
01275
01276 _dbus_assert (find_handler (tree, path1) != tree->root);
01277 _dbus_assert (find_handler (tree, path2) != tree->root);
01278 _dbus_assert (find_handler (tree, path3) != tree->root);
01279 _dbus_assert (find_handler (tree, path4) != tree->root);
01280 _dbus_assert (find_handler (tree, path5) != tree->root);
01281 _dbus_assert (find_handler (tree, path6) != tree->root);
01282 _dbus_assert (find_handler (tree, path7) != tree->root);
01283 _dbus_assert (find_handler (tree, path8) != tree->root);
01284
01285
01286 _dbus_object_tree_unref (tree);
01287
01288 i = 0;
01289 while (i < (int) _DBUS_N_ELEMENTS (tree_test_data))
01290 {
01291 _dbus_assert (tree_test_data[i].handler_unregistered);
01292 _dbus_assert (!tree_test_data[i].message_handled);
01293 ++i;
01294 }
01295
01296
01297 tree = _dbus_object_tree_new (NULL);
01298 if (tree == NULL)
01299 goto out;
01300
01301 if (!do_register (tree, path1, 0, tree_test_data))
01302 goto out;
01303 if (!do_register (tree, path2, 1, tree_test_data))
01304 goto out;
01305 if (!do_register (tree, path3, 2, tree_test_data))
01306 goto out;
01307 if (!do_register (tree, path4, 3, tree_test_data))
01308 goto out;
01309 if (!do_register (tree, path5, 4, tree_test_data))
01310 goto out;
01311 if (!do_register (tree, path6, 5, tree_test_data))
01312 goto out;
01313 if (!do_register (tree, path7, 6, tree_test_data))
01314 goto out;
01315 if (!do_register (tree, path8, 7, tree_test_data))
01316 goto out;
01317
01318 _dbus_object_tree_unregister_and_unlock (tree, path1);
01319
01320 _dbus_assert (!find_subtree (tree, path1, NULL));
01321 _dbus_assert (find_subtree (tree, path2, NULL));
01322 _dbus_assert (find_subtree (tree, path3, NULL));
01323 _dbus_assert (find_subtree (tree, path4, NULL));
01324 _dbus_assert (find_subtree (tree, path5, NULL));
01325 _dbus_assert (find_subtree (tree, path6, NULL));
01326 _dbus_assert (find_subtree (tree, path7, NULL));
01327 _dbus_assert (find_subtree (tree, path8, NULL));
01328
01329 _dbus_object_tree_unregister_and_unlock (tree, path2);
01330
01331 _dbus_assert (!find_subtree (tree, path1, NULL));
01332 _dbus_assert (!find_subtree (tree, path2, NULL));
01333 _dbus_assert (find_subtree (tree, path3, NULL));
01334 _dbus_assert (find_subtree (tree, path4, NULL));
01335 _dbus_assert (find_subtree (tree, path5, NULL));
01336 _dbus_assert (find_subtree (tree, path6, NULL));
01337 _dbus_assert (find_subtree (tree, path7, NULL));
01338 _dbus_assert (find_subtree (tree, path8, NULL));
01339
01340 _dbus_object_tree_unregister_and_unlock (tree, path3);
01341
01342 _dbus_assert (!find_subtree (tree, path1, NULL));
01343 _dbus_assert (!find_subtree (tree, path2, NULL));
01344 _dbus_assert (!find_subtree (tree, path3, NULL));
01345 _dbus_assert (find_subtree (tree, path4, NULL));
01346 _dbus_assert (find_subtree (tree, path5, NULL));
01347 _dbus_assert (find_subtree (tree, path6, NULL));
01348 _dbus_assert (find_subtree (tree, path7, NULL));
01349 _dbus_assert (find_subtree (tree, path8, NULL));
01350
01351 _dbus_object_tree_unregister_and_unlock (tree, path4);
01352
01353 _dbus_assert (!find_subtree (tree, path1, NULL));
01354 _dbus_assert (!find_subtree (tree, path2, NULL));
01355 _dbus_assert (!find_subtree (tree, path3, NULL));
01356 _dbus_assert (!find_subtree (tree, path4, NULL));
01357 _dbus_assert (find_subtree (tree, path5, NULL));
01358 _dbus_assert (find_subtree (tree, path6, NULL));
01359 _dbus_assert (find_subtree (tree, path7, NULL));
01360 _dbus_assert (find_subtree (tree, path8, NULL));
01361
01362 _dbus_object_tree_unregister_and_unlock (tree, path5);
01363
01364 _dbus_assert (!find_subtree (tree, path1, NULL));
01365 _dbus_assert (!find_subtree (tree, path2, NULL));
01366 _dbus_assert (!find_subtree (tree, path3, NULL));
01367 _dbus_assert (!find_subtree (tree, path4, NULL));
01368 _dbus_assert (!find_subtree (tree, path5, NULL));
01369 _dbus_assert (find_subtree (tree, path6, NULL));
01370 _dbus_assert (find_subtree (tree, path7, NULL));
01371 _dbus_assert (find_subtree (tree, path8, NULL));
01372
01373 _dbus_object_tree_unregister_and_unlock (tree, path6);
01374
01375 _dbus_assert (!find_subtree (tree, path1, NULL));
01376 _dbus_assert (!find_subtree (tree, path2, NULL));
01377 _dbus_assert (!find_subtree (tree, path3, NULL));
01378 _dbus_assert (!find_subtree (tree, path4, NULL));
01379 _dbus_assert (!find_subtree (tree, path5, NULL));
01380 _dbus_assert (!find_subtree (tree, path6, NULL));
01381 _dbus_assert (find_subtree (tree, path7, NULL));
01382 _dbus_assert (find_subtree (tree, path8, NULL));
01383
01384 _dbus_object_tree_unregister_and_unlock (tree, path7);
01385
01386 _dbus_assert (!find_subtree (tree, path1, NULL));
01387 _dbus_assert (!find_subtree (tree, path2, NULL));
01388 _dbus_assert (!find_subtree (tree, path3, NULL));
01389 _dbus_assert (!find_subtree (tree, path4, NULL));
01390 _dbus_assert (!find_subtree (tree, path5, NULL));
01391 _dbus_assert (!find_subtree (tree, path6, NULL));
01392 _dbus_assert (!find_subtree (tree, path7, NULL));
01393 _dbus_assert (find_subtree (tree, path8, NULL));
01394
01395 _dbus_object_tree_unregister_and_unlock (tree, path8);
01396
01397 _dbus_assert (!find_subtree (tree, path1, NULL));
01398 _dbus_assert (!find_subtree (tree, path2, NULL));
01399 _dbus_assert (!find_subtree (tree, path3, NULL));
01400 _dbus_assert (!find_subtree (tree, path4, NULL));
01401 _dbus_assert (!find_subtree (tree, path5, NULL));
01402 _dbus_assert (!find_subtree (tree, path6, NULL));
01403 _dbus_assert (!find_subtree (tree, path7, NULL));
01404 _dbus_assert (!find_subtree (tree, path8, NULL));
01405
01406 i = 0;
01407 while (i < (int) _DBUS_N_ELEMENTS (tree_test_data))
01408 {
01409 _dbus_assert (tree_test_data[i].handler_unregistered);
01410 _dbus_assert (!tree_test_data[i].message_handled);
01411 ++i;
01412 }
01413
01414
01415
01416 if (!do_register (tree, path1, 0, tree_test_data))
01417 goto out;
01418 if (!do_register (tree, path2, 1, tree_test_data))
01419 goto out;
01420 if (!do_register (tree, path3, 2, tree_test_data))
01421 goto out;
01422 if (!do_register (tree, path4, 3, tree_test_data))
01423 goto out;
01424 if (!do_register (tree, path5, 4, tree_test_data))
01425 goto out;
01426 if (!do_register (tree, path6, 5, tree_test_data))
01427 goto out;
01428 if (!do_register (tree, path7, 6, tree_test_data))
01429 goto out;
01430 if (!do_register (tree, path8, 7, tree_test_data))
01431 goto out;
01432
01433 #if 0
01434 spew_tree (tree);
01435 #endif
01436
01437 if (!do_test_dispatch (tree, path1, 0, tree_test_data, _DBUS_N_ELEMENTS (tree_test_data)))
01438 goto out;
01439 if (!do_test_dispatch (tree, path2, 1, tree_test_data, _DBUS_N_ELEMENTS (tree_test_data)))
01440 goto out;
01441 if (!do_test_dispatch (tree, path3, 2, tree_test_data, _DBUS_N_ELEMENTS (tree_test_data)))
01442 goto out;
01443 if (!do_test_dispatch (tree, path4, 3, tree_test_data, _DBUS_N_ELEMENTS (tree_test_data)))
01444 goto out;
01445 if (!do_test_dispatch (tree, path5, 4, tree_test_data, _DBUS_N_ELEMENTS (tree_test_data)))
01446 goto out;
01447 if (!do_test_dispatch (tree, path6, 5, tree_test_data, _DBUS_N_ELEMENTS (tree_test_data)))
01448 goto out;
01449 if (!do_test_dispatch (tree, path7, 6, tree_test_data, _DBUS_N_ELEMENTS (tree_test_data)))
01450 goto out;
01451 if (!do_test_dispatch (tree, path8, 7, tree_test_data, _DBUS_N_ELEMENTS (tree_test_data)))
01452 goto out;
01453
01454 out:
01455 if (tree)
01456 {
01457
01458 _dbus_object_tree_ref (tree);
01459 _dbus_object_tree_unref (tree);
01460 _dbus_object_tree_unref (tree);
01461 }
01462
01463 return TRUE;
01464 }
01465
01471 dbus_bool_t
01472 _dbus_object_tree_test (void)
01473 {
01474 _dbus_test_oom_handling ("object tree",
01475 object_tree_test_iteration,
01476 NULL);
01477
01478 return TRUE;
01479 }
01480
01481 #endif