summaryrefslogtreecommitdiff
path: root/daemon/gvfsdaemon.c
diff options
context:
space:
mode:
authorTomas Bzatek <tbzatek@redhat.com>2012-04-13 15:03:23 +0200
committerTomas Bzatek <tbzatek@redhat.com>2012-07-31 11:58:20 +0200
commit594c36b2bfbbff1d70a0faf66de2671c906071f0 (patch)
tree0961687b285a75e0e4e79e1c95641df3ce641bc4 /daemon/gvfsdaemon.c
parent7ebe892e2c390963c322a09305f6aa5951913699 (diff)
downloadgvfs-594c36b2bfbbff1d70a0faf66de2671c906071f0.tar.gz
gdbus: Improve registered paths activation on daemon side
This changes the way registered paths (i.e. interface skeleton exports) are activated on daemon side. We're keeping a list of connections on which every registered path is exported so that if connection is closed or the path is unregistered we always free the right interface skeletons. We also keep track of active client (peer-to-peer) connections so that if a new path is registered, it's automatically exported to all active connections. Needed since client connections are usually shared. It also has a nice side-effect of reacting to dirty disconnects (e.g. the client dies). This whole registration machinery needs unique object paths (for the hash table) but that's not a problem in the current state.
Diffstat (limited to 'daemon/gvfsdaemon.c')
-rw-r--r--daemon/gvfsdaemon.c100
1 files changed, 67 insertions, 33 deletions
diff --git a/daemon/gvfsdaemon.c b/daemon/gvfsdaemon.c
index 38191b10..47c3a0ff 100644
--- a/daemon/gvfsdaemon.c
+++ b/daemon/gvfsdaemon.c
@@ -48,10 +48,10 @@ enum {
typedef struct {
char *obj_path;
- char *name;
GVfsRegisterPathCallback callback;
gpointer data;
- GDBusInterfaceSkeleton *skeleton;
+ GDBusInterfaceSkeleton *session_skeleton;
+ GHashTable *client_skeletons;
} RegisteredPath;
struct _GVfsDaemon
@@ -63,6 +63,7 @@ struct _GVfsDaemon
GThreadPool *thread_pool;
GHashTable *registered_paths;
+ GHashTable *client_connections;
GList *jobs;
GList *job_sources;
@@ -124,13 +125,14 @@ static void
registered_path_free (RegisteredPath *data)
{
g_free (data->obj_path);
- g_free (data->name);
- if (data->skeleton)
+ if (data->session_skeleton)
{
/* Unexport the interface skeleton on session bus */
- g_dbus_interface_skeleton_unexport (data->skeleton);
- g_object_unref (data->skeleton);
+ g_dbus_interface_skeleton_unexport (data->session_skeleton);
+ g_object_unref (data->session_skeleton);
}
+ g_hash_table_destroy (data->client_skeletons);
+
g_free (data);
}
@@ -160,6 +162,7 @@ g_vfs_daemon_finalize (GObject *object)
g_object_unref (daemon->conn);
g_hash_table_destroy (daemon->registered_paths);
+ g_hash_table_destroy (daemon->client_connections);
g_mutex_clear (&daemon->lock);
if (G_OBJECT_CLASS (g_vfs_daemon_parent_class)->finalize)
@@ -239,8 +242,12 @@ g_vfs_daemon_init (GVfsDaemon *daemon)
daemon->jobs = NULL;
daemon->registered_paths =
g_hash_table_new_full (g_str_hash, g_str_equal,
- NULL, (GDestroyNotify)registered_path_free);
-
+ g_free, (GDestroyNotify)registered_path_free);
+
+ /* This is where we store active client connections so when a new filter is registered,
+ * we re-register them on all active connections */
+ daemon->client_connections =
+ g_hash_table_new_full (g_direct_hash, g_direct_equal, g_object_unref, NULL);
daemon->conn = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, NULL);
g_assert (daemon->conn != NULL);
@@ -462,11 +469,49 @@ g_vfs_daemon_add_job_source (GVfsDaemon *daemon,
g_mutex_unlock (&daemon->lock);
}
+static void
+unref_skeleton (gpointer object)
+{
+ GDBusInterfaceSkeleton *skeleton = object;
+
+ g_print ("unref_skeleton: unreffing skeleton %p\n", skeleton);
+ g_dbus_interface_skeleton_unexport (skeleton);
+ g_object_unref (skeleton);
+}
+
+static void
+peer_register_skeleton (const gchar *obj_path,
+ RegisteredPath *reg_path,
+ GDBusConnection *dbus_conn)
+{
+ GDBusInterfaceSkeleton *skeleton;
+
+ if (! g_hash_table_contains (reg_path->client_skeletons, dbus_conn))
+ {
+ skeleton = reg_path->callback (dbus_conn, obj_path, reg_path->data);
+ g_print ("registering '%s' on the %p connection\n", obj_path, dbus_conn);
+
+ g_hash_table_insert (reg_path->client_skeletons, dbus_conn, skeleton);
+ }
+ else
+ {
+ g_print ("interface skeleton '%s' already registered on the %p connection, skipping\n", obj_path, dbus_conn);
+ }
+}
+
+static void
+client_conn_register_skeleton (GDBusConnection *dbus_conn,
+ gpointer value,
+ RegisteredPath *reg_path)
+{
+ peer_register_skeleton (reg_path->obj_path, reg_path, dbus_conn);
+}
+
/* This registers a dbus interface skeleton on *all* connections, client and session bus */
+/* The object path needs to be unique globally. */
void
g_vfs_daemon_register_path (GVfsDaemon *daemon,
const char *obj_path,
- const char *name,
GVfsRegisterPathCallback callback,
gpointer user_data)
{
@@ -476,18 +521,20 @@ g_vfs_daemon_register_path (GVfsDaemon *daemon,
data = g_new0 (RegisteredPath, 1);
data->obj_path = g_strdup (obj_path);
- data->name = g_strdup (name);
data->callback = callback;
data->data = user_data;
+ data->client_skeletons = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, (GDestroyNotify)unref_skeleton);
- g_hash_table_insert (daemon->registered_paths, data->obj_path,
- data);
+ g_hash_table_insert (daemon->registered_paths, g_strdup (obj_path), data);
/* Export the newly registered interface skeleton on session bus */
/* TODO: change the way we export skeletons on connections once
* https://bugzilla.gnome.org/show_bug.cgi?id=662718 is in place.
*/
- data->skeleton = callback (daemon->conn, data->obj_path, user_data);
+ data->session_skeleton = callback (daemon->conn, obj_path, user_data);
+
+ /* Export this newly registered path to all active client connections */
+ g_hash_table_foreach (daemon->client_connections, (GHFunc) client_conn_register_skeleton, data);
}
void
@@ -565,16 +612,12 @@ new_connection_data_free (void *memory)
}
static void
-peer_unregister_skeleton (gpointer key,
+peer_unregister_skeleton (const gchar *obj_path,
RegisteredPath *reg_path,
GDBusConnection *dbus_conn)
{
- GDBusInterfaceSkeleton *skeleton;
-
- g_print ("unregistering '%s' on the %p connection\n", reg_path->name, dbus_conn);
-
- skeleton = g_object_get_data (G_OBJECT (dbus_conn), reg_path->name);
- g_dbus_interface_skeleton_unexport (G_DBUS_INTERFACE_SKELETON (skeleton));
+ g_print ("unregistering '%s' on the %p connection\n", obj_path, dbus_conn);
+ g_hash_table_remove (reg_path->client_skeletons, dbus_conn);
}
static void
@@ -606,6 +649,8 @@ peer_connection_closed (GDBusConnection *connection,
/* daemon_skeleton should be always valid in this case */
g_dbus_interface_skeleton_unexport (G_DBUS_INTERFACE_SKELETON (daemon_skeleton));
+ g_hash_table_remove (daemon->client_connections, connection);
+
/* Unexport the registered interface skeletons */
g_hash_table_foreach (daemon->registered_paths, (GHFunc) peer_unregister_skeleton, connection);
@@ -614,19 +659,6 @@ peer_connection_closed (GDBusConnection *connection,
}
static void
-peer_register_skeleton (gpointer key,
- RegisteredPath *reg_path,
- GDBusConnection *dbus_conn)
-{
- GDBusInterfaceSkeleton *skeleton;
-
- g_print ("registering '%s' on the %p connection\n", reg_path->name, dbus_conn);
-
- skeleton = reg_path->callback (dbus_conn, reg_path->obj_path, reg_path->data);
- g_object_set_data_full (G_OBJECT (dbus_conn), reg_path->name, skeleton, (GDestroyNotify) g_object_unref);
-}
-
-static void
daemon_peer_connection_setup (GVfsDaemon *daemon,
GDBusConnection *dbus_conn,
NewConnectionData *data)
@@ -667,6 +699,8 @@ daemon_peer_connection_setup (GVfsDaemon *daemon,
/* Export registered interface skeletons on this new connection */
g_hash_table_foreach (daemon->registered_paths, (GHFunc) peer_register_skeleton, dbus_conn);
+ g_hash_table_insert (daemon->client_connections, g_object_ref (dbus_conn), NULL);
+
g_print ("daemon_peer_connection_setup: interface registration complete.\n");
g_signal_connect (data->conn, "closed", G_CALLBACK (peer_connection_closed), data->daemon);