Bug 624473: GDBusSubtreeIntrospectFunc return type

Return a NULL terminated C array instead of a GPtrArray

Also, document that %NULL is a permitted return value and clarify its
meaning.

Finally, avoid calling the enumeration function during dispatch when the
G_DBUS_SUBTREE_FLAGS_DISPATCH_TO_UNENUMERATED_NODES flag was given.
This commit is contained in:
Ryan Lortie 2010-07-15 16:26:42 -04:00
parent 48b1fe948c
commit e6b5546cf5
3 changed files with 74 additions and 54 deletions

View File

@ -5167,7 +5167,7 @@ handle_subtree_introspect (GDBusConnection *connection,
const gchar *sender; const gchar *sender;
const gchar *requested_object_path; const gchar *requested_object_path;
const gchar *requested_node; const gchar *requested_node;
GPtrArray *interfaces; GDBusInterfaceInfo **interfaces;
guint n; guint n;
gchar **subnode_paths; gchar **subnode_paths;
@ -5209,18 +5209,14 @@ handle_subtree_introspect (GDBusConnection *connection,
es->user_data); es->user_data);
if (interfaces != NULL) if (interfaces != NULL)
{ {
if (interfaces->len > 0)
{
/* we're in business */
introspect_append_standard_interfaces (s); introspect_append_standard_interfaces (s);
for (n = 0; n < interfaces->len; n++) for (n = 0; interfaces[n] != NULL; n++)
{ {
const GDBusInterfaceInfo *interface_info = interfaces->pdata[n]; g_dbus_interface_info_generate_xml (interfaces[n], 2, s);
g_dbus_interface_info_generate_xml (interface_info, 2, s); g_dbus_interface_info_unref (interfaces[n]);
} }
} g_free (interfaces);
g_ptr_array_unref (interfaces);
} }
/* then include <node> entries from the Subtree for the root */ /* then include <node> entries from the Subtree for the root */
@ -5265,12 +5261,11 @@ handle_subtree_method_invocation (GDBusConnection *connection,
const gchar *requested_object_path; const gchar *requested_object_path;
const gchar *requested_node; const gchar *requested_node;
gboolean is_root; gboolean is_root;
gchar **children;
const GDBusInterfaceInfo *interface_info; const GDBusInterfaceInfo *interface_info;
const GDBusInterfaceVTable *interface_vtable; const GDBusInterfaceVTable *interface_vtable;
gpointer interface_user_data; gpointer interface_user_data;
guint n; guint n;
GPtrArray *interfaces; GDBusInterfaceInfo **interfaces;
gboolean is_property_get; gboolean is_property_get;
gboolean is_property_set; gboolean is_property_set;
gboolean is_property_get_all; gboolean is_property_get_all;
@ -5298,20 +5293,30 @@ handle_subtree_method_invocation (GDBusConnection *connection,
is_property_get_all = TRUE; is_property_get_all = TRUE;
} }
if (!is_root)
{
requested_node = strrchr (requested_object_path, '/') + 1;
if (~es->flags & G_DBUS_SUBTREE_FLAGS_DISPATCH_TO_UNENUMERATED_NODES)
{
/* We don't want to dispatch to unenumerated
* nodes, so ensure that the child exists.
*/
gchar **children;
gboolean exists;
children = es->vtable->enumerate (es->connection, children = es->vtable->enumerate (es->connection,
sender, sender,
es->object_path, es->object_path,
es->user_data); es->user_data);
if (!is_root) exists = _g_strv_has_string ((const gchar * const *) children, requested_node);
{ g_strfreev (children);
requested_node = strrchr (requested_object_path, '/') + 1;
/* If not dynamic, skip if requested node is not part of children */ if (!exists)
if (!(es->flags & G_DBUS_SUBTREE_FLAGS_DISPATCH_TO_UNENUMERATED_NODES) &&
!_g_strv_has_string ((const gchar * const *) children, requested_node))
goto out; goto out;
} }
}
else else
{ {
requested_node = "/"; requested_node = "/";
@ -5323,13 +5328,15 @@ handle_subtree_method_invocation (GDBusConnection *connection,
requested_object_path, requested_object_path,
requested_node, requested_node,
es->user_data); es->user_data);
g_assert (interfaces != NULL);
if (interfaces == NULL)
goto out;
interface_info = NULL; interface_info = NULL;
for (n = 0; n < interfaces->len; n++) for (n = 0; interfaces[n] != NULL; n++)
{ {
const GDBusInterfaceInfo *id_n = (const GDBusInterfaceInfo *) interfaces->pdata[n]; if (g_strcmp0 (interfaces[n]->name, interface_name) == 0)
if (g_strcmp0 (id_n->name, interface_name) == 0) interface_info = interfaces[n];
interface_info = id_n;
} }
/* dispatch the call if the user wants to handle it */ /* dispatch the call if the user wants to handle it */
@ -5371,11 +5378,10 @@ handle_subtree_method_invocation (GDBusConnection *connection,
g_assert_not_reached (); g_assert_not_reached ();
/* see if the object supports this interface at all */ /* see if the object supports this interface at all */
for (n = 0; n < interfaces->len; n++) for (n = 0; interfaces[n] != NULL; n++)
{ {
const GDBusInterfaceInfo *id_n = (const GDBusInterfaceInfo *) interfaces->pdata[n]; if (g_strcmp0 (interfaces[n]->name, interface_name) == 0)
if (g_strcmp0 (id_n->name, interface_name) == 0) interface_info = interfaces[n];
interface_info = id_n;
} }
/* Fail with org.freedesktop.DBus.Error.InvalidArgs if the user-code /* Fail with org.freedesktop.DBus.Error.InvalidArgs if the user-code
@ -5437,8 +5443,12 @@ handle_subtree_method_invocation (GDBusConnection *connection,
out: out:
if (interfaces != NULL) if (interfaces != NULL)
g_ptr_array_unref (interfaces); {
g_strfreev (children); for (n = 0; interfaces[n] != NULL; n++)
g_dbus_interface_info_unref (interfaces[n]);
g_free (interfaces);
}
return handled; return handled;
} }

View File

@ -325,12 +325,25 @@ typedef gchar** (*GDBusSubtreeEnumerateFunc) (GDBusConnection *connection,
* *
* The type of the @introspect function in #GDBusSubtreeVTable. * The type of the @introspect function in #GDBusSubtreeVTable.
* *
* Returns: A newly-allocated #GPtrArray with pointers to #GDBusInterfaceInfo describing * This function should return %NULL to indicate that there is no object
* the interfaces implemented by @node. * at this node.
*
* If this function returns non-%NULL, the return value is expected to
* be a %NULL-terminated array of pointers to #GDBusInterfaceInfo
* structures describing the interfaces implemented by @node. This
* array will have g_dbus_interface_info_unref() called on each item
* before being freed with g_free().
*
* The difference between returning %NULL and an array containing zero
* items is that the standard DBus interfaces will returned to the
* remote introspector in the empty array case, but not in the %NULL
* case.
*
* Returns: A %NULL-terminated array of pointers to #GDBusInterfaceInfo, or %NULL.
* *
* Since: 2.26 * Since: 2.26
*/ */
typedef GPtrArray *(*GDBusSubtreeIntrospectFunc) (GDBusConnection *connection, typedef GDBusInterfaceInfo ** (*GDBusSubtreeIntrospectFunc) (GDBusConnection *connection,
const gchar *sender, const gchar *sender,
const gchar *object_path, const gchar *object_path,
const gchar *node, const gchar *node,

View File

@ -614,37 +614,38 @@ subtree_enumerate (GDBusConnection *connection,
} }
/* Only allows certain objects, and aborts on unknowns */ /* Only allows certain objects, and aborts on unknowns */
static GPtrArray * static GDBusInterfaceInfo **
subtree_introspect (GDBusConnection *connection, subtree_introspect (GDBusConnection *connection,
const gchar *sender, const gchar *sender,
const gchar *object_path, const gchar *object_path,
const gchar *node, const gchar *node,
gpointer user_data) gpointer user_data)
{ {
GPtrArray *interfaces; const GDBusInterfaceInfo *interfaces[2] = {
NULL /* filled in below */, NULL
};
/* VPs implement the Foo interface, EVPs implement the Bar interface. The root /* VPs implement the Foo interface, EVPs implement the Bar interface. The root
* does not implement any interfaces * does not implement any interfaces
*/ */
interfaces = g_ptr_array_new ();
if (g_str_has_prefix (node, "vp")) if (g_str_has_prefix (node, "vp"))
{ {
g_ptr_array_add (interfaces, (gpointer) &foo_interface_info); interfaces[0] = &foo_interface_info;
} }
else if (g_str_has_prefix (node, "evp")) else if (g_str_has_prefix (node, "evp"))
{ {
g_ptr_array_add (interfaces, (gpointer) &bar_interface_info); interfaces[0] = &bar_interface_info;
} }
else if (g_strcmp0 (node, "/") == 0) else if (g_strcmp0 (node, "/") == 0)
{ {
/* do nothing */ return NULL;
} }
else else
{ {
g_assert_not_reached (); g_assert_not_reached ();
} }
return interfaces; return g_memdup (interfaces, 2 * sizeof (void *));
} }
static const GDBusInterfaceVTable * static const GDBusInterfaceVTable *
@ -691,20 +692,16 @@ dynamic_subtree_enumerate (GDBusConnection *connection,
} }
/* Allow all objects to be introspected */ /* Allow all objects to be introspected */
static GPtrArray * static GDBusInterfaceInfo **
dynamic_subtree_introspect (GDBusConnection *connection, dynamic_subtree_introspect (GDBusConnection *connection,
const gchar *sender, const gchar *sender,
const gchar *object_path, const gchar *object_path,
const gchar *node, const gchar *node,
gpointer user_data) gpointer user_data)
{ {
GPtrArray *interfaces; const GDBusInterfaceInfo *interfaces[2] = { &dyna_interface_info, NULL };
/* All nodes (including the root node) implements the Dyna interface */ return g_memdup (interfaces, 2 * sizeof (void *));
interfaces = g_ptr_array_new ();
g_ptr_array_add (interfaces, (gpointer) &dyna_interface_info);
return interfaces;
} }
static const GDBusInterfaceVTable * static const GDBusInterfaceVTable *