summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLuiz Augusto von Dentz <luiz.von.dentz@intel.com>2012-10-04 04:26:32 -0300
committerMarcel Holtmann <marcel@holtmann.org>2012-11-26 15:03:33 +0100
commite2ec6cb0890ec9535f6d53267f500ff0b0d80cce (patch)
tree4051d55fafda688bf6406f81ebb9f5cc4d781834
parentf2960b6e1dc9c4e965ec86719f2044b81defa0e2 (diff)
downloadobexd-e2ec6cb0890ec9535f6d53267f500ff0b0d80cce.tar.gz
gdbus: Add support for org.freedesktop.DBus.ObjectManager interface
This implements initial support for ObjectManager, it automatically adds objects to its parents so no action is needed by daemons to get their objects managed by this interface. ObjectManager is part of D-Bus spec since revision 0.17: http://dbus.freedesktop.org/doc/dbus-specification.html#standard-interfaces-objectmanager
-rw-r--r--gdbus/object.c247
1 files changed, 237 insertions, 10 deletions
diff --git a/gdbus/object.c b/gdbus/object.c
index 662ebe3..214968e 100644
--- a/gdbus/object.c
+++ b/gdbus/object.c
@@ -37,10 +37,16 @@
#define error(fmt...)
#define debug(fmt...)
+#define DBUS_INTERFACE_OBJECT_MANAGER "org.freedesktop.DBus.ObjectManager"
+
struct generic_data {
unsigned int refcount;
+ DBusConnection *conn;
+ char *path;
GSList *interfaces;
+ GSList *objects;
char *introspect;
+ struct generic_data *parent;
};
struct interface_data {
@@ -477,11 +483,28 @@ void g_dbus_pending_property_error(DBusConnection *connection,
va_end(args);
}
+static void reset_parent(gpointer data, gpointer user_data)
+{
+ struct generic_data *child = data;
+ struct generic_data *parent = user_data;
+
+ child->parent = parent;
+}
+
static void generic_unregister(DBusConnection *connection, void *user_data)
{
struct generic_data *data = user_data;
+ struct generic_data *parent = data->parent;
+ if (parent != NULL)
+ parent->objects = g_slist_remove(parent->objects, data);
+
+ g_slist_foreach(data->objects, reset_parent, data->parent);
+ g_slist_free(data->objects);
+
+ dbus_connection_unref(data->conn);
g_free(data->introspect);
+ g_free(data->path);
g_free(data);
}
@@ -563,9 +586,10 @@ static DBusObjectPathVTable generic_table = {
.message_function = generic_message,
};
-static void invalidate_parent_data(DBusConnection *conn, const char *child_path)
+static struct generic_data *invalidate_parent_data(DBusConnection *conn,
+ const char *child_path)
{
- struct generic_data *data = NULL;
+ struct generic_data *data = NULL, *child = NULL, *parent = NULL;
char *parent_path, *slash;
parent_path = g_strdup(child_path);
@@ -586,16 +610,30 @@ static void invalidate_parent_data(DBusConnection *conn, const char *child_path)
goto done;
}
- invalidate_parent_data(conn, parent_path);
+ parent = invalidate_parent_data(conn, parent_path);
- if (data == NULL)
- goto done;
+ if (data == NULL) {
+ data = parent;
+ if (data == NULL)
+ goto done;
+ }
g_free(data->introspect);
data->introspect = NULL;
+ if (!dbus_connection_get_object_path_data(conn, child_path,
+ (void *) &child))
+ goto done;
+
+ if (child == NULL || g_slist_find(data->objects, child) != NULL)
+ goto done;
+
+ data->objects = g_slist_prepend(data->objects, child);
+ child->parent = data;
+
done:
g_free(parent_path);
+ return data;
}
static const GDBusMethodTable introspect_methods[] = {
@@ -822,7 +860,158 @@ static const GDBusSignalTable properties_signals[] = {
{ }
};
-static void add_interface(struct generic_data *data, const char *name,
+static void append_properties(struct interface_data *data,
+ DBusMessageIter *iter)
+{
+ DBusMessageIter dict;
+
+ dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY,
+ DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
+ DBUS_TYPE_STRING_AS_STRING
+ DBUS_TYPE_VARIANT_AS_STRING
+ DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict);
+
+ /* TODO: list properties */
+
+ dbus_message_iter_close_container(iter, &dict);
+}
+
+static void append_interface(gpointer data, gpointer user_data)
+{
+ struct interface_data *iface = data;
+ DBusMessageIter *array = user_data;
+ DBusMessageIter entry;
+
+ dbus_message_iter_open_container(array, DBUS_TYPE_DICT_ENTRY, NULL,
+ &entry);
+ dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &iface->name);
+ append_properties(data, &entry);
+ dbus_message_iter_close_container(array, &entry);
+}
+
+static void append_interfaces(struct generic_data *data, DBusMessageIter *iter)
+{
+ DBusMessageIter array;
+
+ dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY,
+ DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
+ DBUS_TYPE_STRING_AS_STRING
+ DBUS_TYPE_ARRAY_AS_STRING
+ DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
+ DBUS_TYPE_STRING_AS_STRING
+ DBUS_TYPE_VARIANT_AS_STRING
+ DBUS_DICT_ENTRY_END_CHAR_AS_STRING
+ DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &array);
+
+ g_slist_foreach(data->interfaces, append_interface, &array);
+
+ dbus_message_iter_close_container(iter, &array);
+}
+
+static void append_object(gpointer data, gpointer user_data)
+{
+ struct generic_data *child = data;
+ DBusMessageIter *array = user_data;
+ DBusMessageIter entry;
+
+ dbus_message_iter_open_container(array, DBUS_TYPE_DICT_ENTRY, NULL,
+ &entry);
+ dbus_message_iter_append_basic(&entry, DBUS_TYPE_OBJECT_PATH,
+ &child->path);
+ append_interfaces(child, &entry);
+ dbus_message_iter_close_container(array, &entry);
+}
+
+static DBusMessage *get_objects(DBusConnection *connection,
+ DBusMessage *message, void *user_data)
+{
+ struct generic_data *data = user_data;
+ DBusMessage *reply;
+ DBusMessageIter iter;
+ DBusMessageIter array;
+
+ reply = dbus_message_new_method_return(message);
+ if (reply == NULL)
+ return NULL;
+
+ dbus_message_iter_init_append(reply, &iter);
+
+ dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
+ DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
+ DBUS_TYPE_OBJECT_PATH_AS_STRING
+ DBUS_TYPE_ARRAY_AS_STRING
+ DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
+ DBUS_TYPE_STRING_AS_STRING
+ DBUS_TYPE_ARRAY_AS_STRING
+ DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
+ DBUS_TYPE_STRING_AS_STRING
+ DBUS_TYPE_VARIANT_AS_STRING
+ DBUS_DICT_ENTRY_END_CHAR_AS_STRING
+ DBUS_DICT_ENTRY_END_CHAR_AS_STRING
+ DBUS_DICT_ENTRY_END_CHAR_AS_STRING,
+ &array);
+
+ g_slist_foreach(data->objects, append_object, &array);
+
+ dbus_message_iter_close_container(&iter, &array);
+
+ return reply;
+}
+
+static const GDBusMethodTable manager_methods[] = {
+ { GDBUS_METHOD("GetManagedObjects", NULL,
+ GDBUS_ARGS({ "objects", "a{oa{sa{sv}}}" }), get_objects) },
+ { }
+};
+
+static const GDBusSignalTable manager_signals[] = {
+ { GDBUS_SIGNAL("InterfacesAdded",
+ GDBUS_ARGS({ "object", "o" },
+ { "interfaces", "a{sa{sv}}" })) },
+ { GDBUS_SIGNAL("InterfacesRemoved",
+ GDBUS_ARGS({ "object", "o" }, { "interfaces", "as" })) },
+ { }
+};
+
+static void emit_interface_added(struct generic_data *data,
+ struct interface_data *iface)
+{
+ DBusMessage *signal;
+ DBusMessageIter iter, array;
+ struct generic_data *parent = data->parent;
+
+ if (parent == NULL)
+ return;
+
+ signal = dbus_message_new_signal(parent->path,
+ DBUS_INTERFACE_OBJECT_MANAGER,
+ "InterfacesAdded");
+ if (signal == NULL)
+ return;
+
+ dbus_message_iter_init_append(signal, &iter);
+ dbus_message_iter_append_basic(&iter, DBUS_TYPE_OBJECT_PATH,
+ &data->path);
+
+ dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
+ DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
+ DBUS_TYPE_STRING_AS_STRING
+ DBUS_TYPE_ARRAY_AS_STRING
+ DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
+ DBUS_TYPE_STRING_AS_STRING
+ DBUS_TYPE_VARIANT_AS_STRING
+ DBUS_DICT_ENTRY_END_CHAR_AS_STRING
+ DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &array);
+
+ append_interface(iface, &array);
+
+ dbus_message_iter_close_container(&iter, &array);
+
+ g_dbus_send_message(data->conn, signal);
+}
+
+static void add_interface(struct generic_data *data,
+ const char *name,
const GDBusMethodTable *methods,
const GDBusSignalTable *signals,
const GDBusPropertyTable *properties,
@@ -840,6 +1029,8 @@ static void add_interface(struct generic_data *data, const char *name,
iface->destroy = destroy;
data->interfaces = g_slist_append(data->interfaces, iface);
+
+ emit_interface_added(data, iface);
}
static struct generic_data *object_path_ref(DBusConnection *connection,
@@ -856,6 +1047,8 @@ static struct generic_data *object_path_ref(DBusConnection *connection,
}
data = g_new0(struct generic_data, 1);
+ data->conn = dbus_connection_ref(connection);
+ data->path = g_strdup(path);
data->refcount = 1;
data->introspect = g_strdup(DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE "<node></node>");
@@ -869,8 +1062,11 @@ static struct generic_data *object_path_ref(DBusConnection *connection,
invalidate_parent_data(connection, path);
- add_interface(data, DBUS_INTERFACE_INTROSPECTABLE,
- introspect_methods, NULL, NULL, data, NULL);
+ add_interface(data, DBUS_INTERFACE_INTROSPECTABLE, introspect_methods,
+ NULL, NULL, data, NULL);
+
+ add_interface(data, DBUS_INTERFACE_OBJECT_MANAGER, manager_methods,
+ manager_signals, NULL, data, NULL);
add_interface(data, DBUS_INTERFACE_PROPERTIES, properties_methods,
properties_signals, NULL, data, NULL);
@@ -878,6 +1074,34 @@ static struct generic_data *object_path_ref(DBusConnection *connection,
return data;
}
+static void emit_interface_remove(struct generic_data *data,
+ struct interface_data *iface)
+{
+ DBusMessage *signal;
+ DBusMessageIter iter, array;
+ struct generic_data *parent = data->parent;
+
+ if (parent == NULL)
+ return;
+
+ signal = dbus_message_new_signal(parent->path,
+ DBUS_INTERFACE_OBJECT_MANAGER,
+ "InterfacesRemoved");
+ if (signal == NULL)
+ return;
+
+ dbus_message_iter_init_append(signal, &iter);
+ dbus_message_iter_append_basic(&iter, DBUS_TYPE_OBJECT_PATH,
+ &data->path);
+
+ dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
+ DBUS_TYPE_STRING_AS_STRING, &array);
+ dbus_message_iter_append_basic(&array, DBUS_TYPE_STRING, &iface->name);
+ dbus_message_iter_close_container(&iter, &array);
+
+ g_dbus_send_message(data->conn, signal);
+}
+
static gboolean remove_interface(struct generic_data *data, const char *name)
{
struct interface_data *iface;
@@ -886,6 +1110,8 @@ static gboolean remove_interface(struct generic_data *data, const char *name)
if (iface == NULL)
return FALSE;
+ emit_interface_remove(data, iface);
+
data->interfaces = g_slist_remove(data->interfaces, iface);
if (iface->destroy)
@@ -915,6 +1141,7 @@ static void object_path_unref(DBusConnection *connection, const char *path)
remove_interface(data, DBUS_INTERFACE_INTROSPECTABLE);
remove_interface(data, DBUS_INTERFACE_PROPERTIES);
+ remove_interface(data, DBUS_INTERFACE_OBJECT_MANAGER);
invalidate_parent_data(connection, path);
@@ -1013,8 +1240,8 @@ gboolean g_dbus_register_interface(DBusConnection *connection,
return FALSE;
}
- add_interface(data, name, methods, signals,
- properties, user_data, destroy);
+ add_interface(data, name, methods, signals, properties, user_data,
+ destroy);
g_free(data->introspect);
data->introspect = NULL;