summaryrefslogtreecommitdiff
path: root/src/nm-bus-manager.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/nm-bus-manager.c')
-rw-r--r--src/nm-bus-manager.c273
1 files changed, 156 insertions, 117 deletions
diff --git a/src/nm-bus-manager.c b/src/nm-bus-manager.c
index 584db5e8a6..975637be19 100644
--- a/src/nm-bus-manager.c
+++ b/src/nm-bus-manager.c
@@ -57,7 +57,7 @@ typedef struct _PrivateServer PrivateServer;
typedef struct {
GDBusConnection *connection;
- GHashTable *exported;
+ GDBusObjectManagerServer *manager;
gboolean started;
GSList *private_servers;
@@ -72,7 +72,13 @@ typedef struct {
static gboolean nm_bus_manager_init_bus (NMBusManager *self);
static void nm_bus_manager_cleanup (NMBusManager *self);
static void start_reconnection_timeout (NMBusManager *self);
-static void object_destroyed (NMBusManager *self, gpointer object);
+
+/* The base path for our GDBusObjectManagerServers. They do not contain
+ * "NetworkManager" because GDBusObjectManagerServer requires that all
+ * exported objects be *below* the base path, and eg the Manager object
+ * is the base path already.
+ */
+#define OBJECT_MANAGER_SERVER_BASE_PATH "/org/freedesktop"
NM_DEFINE_SINGLETON_REGISTER (NMBusManager);
@@ -109,17 +115,30 @@ struct _PrivateServer {
GQuark detail;
char *address;
GDBusServer *server;
- GHashTable *connections;
+
+ /* With peer bus connections, we'll get a new connection for each
+ * client. For each connection we create an ObjectManager for
+ * that connection to handle exporting our objects. This table
+ * maps GDBusObjectManager :: 'fake sender'.
+ *
+ * Note that even for connections that don't export any objects
+ * we'll still create GDBusObjectManager since that's where we store
+ * the pointer to the GDBusConnection.
+ */
+ GHashTable *managers;
+
NMBusManager *manager;
};
static void
-private_server_closed (GDBusConnection *conn,
- gboolean remote_peer_vanished,
- GError *error,
- gpointer user_data)
+private_server_closed_connection (GDBusConnection *conn,
+ gboolean remote_peer_vanished,
+ GError *error,
+ gpointer user_data)
{
PrivateServer *s = user_data;
+ GHashTableIter iter;
+ GDBusObjectManagerServer *manager;
/* Clean up after the connection */
nm_log_dbg (LOGD_CORE, "(%s) closed connection %p on private socket.",
@@ -131,7 +150,13 @@ private_server_closed (GDBusConnection *conn,
s->detail,
conn);
- g_hash_table_remove (s->connections, conn);
+ g_hash_table_iter_init (&iter, s->managers);
+ while (g_hash_table_iter_next (&iter, (gpointer) &manager, NULL)) {
+ if (g_dbus_object_manager_server_get_connection (manager) == conn) {
+ g_hash_table_iter_remove (&iter);
+ break;
+ }
+ }
}
static gboolean
@@ -141,13 +166,17 @@ private_server_new_connection (GDBusServer *server,
{
PrivateServer *s = user_data;
static guint32 counter = 0;
+ GDBusObjectManagerServer *manager;
char *sender;
- g_signal_connect (conn, "closed", G_CALLBACK (private_server_closed), s);
+ g_signal_connect (conn, "closed", G_CALLBACK (private_server_closed_connection), s);
/* Fake a sender since private connections don't have one */
sender = g_strdup_printf ("x:y:%d", counter++);
- g_hash_table_insert (s->connections, g_object_ref (conn), sender);
+
+ manager = g_dbus_object_manager_server_new (OBJECT_MANAGER_SERVER_BASE_PATH);
+ g_dbus_object_manager_server_set_connection (manager, conn);
+ g_hash_table_insert (s->managers, manager, sender);
nm_log_dbg (LOGD_CORE, "(%s) accepted connection %p on private socket.",
s->tag, conn);
@@ -156,16 +185,20 @@ private_server_new_connection (GDBusServer *server,
g_signal_emit (s->manager,
signals[PRIVATE_CONNECTION_NEW],
s->detail,
- conn);
+ conn,
+ manager);
return TRUE;
}
static void
-private_server_dbus_connection_destroy (GDBusConnection *conn)
+private_server_manager_destroy (GDBusObjectManagerServer *manager)
{
- if (!g_dbus_connection_is_closed (conn))
- g_dbus_connection_close (conn, NULL, NULL, NULL);
- g_object_unref (conn);
+ GDBusConnection *connection = g_dbus_object_manager_server_get_connection (manager);
+
+ if (!g_dbus_connection_is_closed (connection))
+ g_dbus_connection_close (connection, NULL, NULL, NULL);
+ g_dbus_object_manager_server_set_connection (manager, NULL);
+ g_object_unref (manager);
}
static gboolean
@@ -219,9 +252,9 @@ private_server_new (const char *path,
g_signal_connect (server, "new-connection",
G_CALLBACK (private_server_new_connection), s);
- s->connections = g_hash_table_new_full (g_direct_hash, g_direct_equal,
- (GDestroyNotify) private_server_dbus_connection_destroy,
- g_free);
+ s->managers = g_hash_table_new_full (g_direct_hash, g_direct_equal,
+ (GDestroyNotify) private_server_manager_destroy,
+ g_free);
s->manager = manager;
s->detail = g_quark_from_string (tag);
s->tag = g_quark_to_string (s->detail);
@@ -238,7 +271,7 @@ private_server_free (gpointer ptr)
unlink (s->address);
g_free (s->address);
- g_hash_table_destroy (s->connections);
+ g_hash_table_destroy (s->managers);
g_dbus_server_stop (s->server);
g_object_unref (s->server);
@@ -275,10 +308,56 @@ nm_bus_manager_private_server_register (NMBusManager *self,
static const char *
private_server_get_connection_owner (PrivateServer *s, GDBusConnection *connection)
{
+ GHashTableIter iter;
+ GDBusObjectManagerServer *manager;
+ const char *owner;
+
g_return_val_if_fail (s != NULL, NULL);
g_return_val_if_fail (connection != NULL, NULL);
- return g_hash_table_lookup (s->connections, connection);
+ g_hash_table_iter_init (&iter, s->managers);
+ while (g_hash_table_iter_next (&iter, (gpointer) &manager, (gpointer) &owner)) {
+ if (g_dbus_object_manager_server_get_connection (manager) == connection)
+ return owner;
+ }
+ return NULL;
+}
+
+static GDBusConnection *
+private_server_get_connection_by_owner (PrivateServer *s, const char *owner)
+{
+ GHashTableIter iter;
+ GDBusObjectManagerServer *manager;
+ const char *priv_sender;
+
+ g_hash_table_iter_init (&iter, s->managers);
+ while (g_hash_table_iter_next (&iter, (gpointer) &manager, (gpointer) &priv_sender)) {
+ if (g_strcmp0 (owner, priv_sender) == 0)
+ return g_dbus_object_manager_server_get_connection (manager);
+ }
+ return NULL;
+}
+
+static void
+private_server_register_object (PrivateServer *s, GDBusObjectSkeleton *object)
+{
+ GHashTableIter iter;
+ GDBusObjectManagerServer *manager;
+
+ g_hash_table_iter_init (&iter, s->managers);
+ while (g_hash_table_iter_next (&iter, (gpointer) &manager, NULL))
+ g_dbus_object_manager_server_export (manager, object);
+}
+
+static void
+private_server_unregister_object (PrivateServer *s, const char *path)
+{
+ GHashTableIter iter;
+ GDBusObjectManagerServer *manager;
+
+ g_hash_table_iter_init (&iter, s->managers);
+ while (g_hash_table_iter_next (&iter, (gpointer) &manager, NULL))
+ g_dbus_object_manager_server_unexport (manager, path);
}
/**************************************************************/
@@ -366,7 +445,7 @@ _get_caller_info (NMBusManager *self,
for (iter = priv->private_servers; iter; iter = g_slist_next (iter)) {
PrivateServer *s = iter->data;
- sender = g_hash_table_lookup (s->connections, connection);
+ sender = private_server_get_connection_owner (s, connection);
if (sender) {
if (out_uid)
*out_uid = 0;
@@ -449,17 +528,10 @@ nm_bus_manager_get_unix_user (NMBusManager *self,
g_return_val_if_fail (out_uid != NULL, FALSE);
/* Check if it's a private connection sender, which we fake */
- for (iter = priv->private_servers; iter; iter = g_slist_next (iter)) {
- PrivateServer *s = iter->data;
- GHashTableIter hiter;
- const char *priv_sender;
-
- g_hash_table_iter_init (&hiter, s->connections);
- while (g_hash_table_iter_next (&hiter, NULL, (gpointer) &priv_sender)) {
- if (g_strcmp0 (sender, priv_sender) == 0) {
- *out_uid = 0;
- return TRUE;
- }
+ for (iter = priv->private_servers; iter; iter = iter->next) {
+ if (private_server_get_connection_by_owner (iter->data, sender)) {
+ *out_uid = 0;
+ return TRUE;
}
}
@@ -477,34 +549,30 @@ nm_bus_manager_get_unix_user (NMBusManager *self,
/**************************************************************/
static void
-private_connection_new (NMBusManager *self, GDBusConnection *connection)
+manager_private_connection_new (NMBusManager *self,
+ GDBusConnection *connection,
+ GDBusObjectManagerServer *manager,
+ gpointer user_data)
{
NMBusManagerPrivate *priv = NM_BUS_MANAGER_GET_PRIVATE (self);
- GHashTableIter iter;
- GDBusInterfaceSkeleton *interface;
- const char *path;
- GError *error = NULL;
+ GList *objects, *iter;
- /* Register all exported objects on this private connection */
- g_hash_table_iter_init (&iter, priv->exported);
- while (g_hash_table_iter_next (&iter, (gpointer) &interface, (gpointer) &path)) {
- if (g_dbus_interface_skeleton_export (interface, connection, path, &error)) {
- nm_log_trace (LOGD_CORE, "(%s) registered %p (%s) at '%s' on private socket.",
- PRIV_SOCK_TAG, interface, G_OBJECT_TYPE_NAME (interface), path);
- } else {
- nm_log_warn (LOGD_CORE, "(%s) could not register %p (%s) at '%s' on private socket: %s.",
- PRIV_SOCK_TAG, interface, G_OBJECT_TYPE_NAME (interface), path,
- error->message);
- g_clear_error (&error);
- }
+ /* Register all exported objects on the new private connection */
+ objects = g_dbus_object_manager_get_objects (G_DBUS_OBJECT_MANAGER (priv->manager));
+ for (iter = objects; iter; iter = iter->next) {
+ g_dbus_object_manager_server_export (manager, G_DBUS_OBJECT_SKELETON (iter->data));
+ g_object_unref (G_OBJECT (iter->data));
}
+ g_list_free (objects);
}
static void
-private_server_setup (NMBusManager *self)
+nm_bus_manager_init (NMBusManager *self)
{
NMBusManagerPrivate *priv = NM_BUS_MANAGER_GET_PRIVATE (self);
+ priv->manager = g_dbus_object_manager_server_new (OBJECT_MANAGER_SERVER_BASE_PATH);
+
/* Skip this step if this is just a test program */
if (nm_utils_get_testing ())
return;
@@ -519,37 +587,17 @@ private_server_setup (NMBusManager *self)
priv->private_servers = g_slist_append (priv->private_servers, priv->priv_server);
g_signal_connect (self,
NM_BUS_MANAGER_PRIVATE_CONNECTION_NEW "::" PRIV_SOCK_TAG,
- (GCallback) private_connection_new,
+ (GCallback) manager_private_connection_new,
NULL);
}
}
static void
-nm_bus_manager_init (NMBusManager *self)
-{
- NMBusManagerPrivate *priv = NM_BUS_MANAGER_GET_PRIVATE (self);
-
- priv->exported = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, g_free);
-
- private_server_setup (self);
-}
-
-static void
nm_bus_manager_dispose (GObject *object)
{
NMBusManager *self = NM_BUS_MANAGER (object);
NMBusManagerPrivate *priv = NM_BUS_MANAGER_GET_PRIVATE (self);
- GHashTableIter iter;
- GObject *exported;
-
- if (priv->exported) {
- g_hash_table_iter_init (&iter, priv->exported);
- while (g_hash_table_iter_next (&iter, (gpointer) &exported, NULL))
- g_object_weak_unref (exported, (GWeakNotify) object_destroyed, self);
-
- g_hash_table_destroy (priv->exported);
- priv->exported = NULL;
- }
+ GList *exported, *iter;
g_slist_free_full (priv->private_servers, private_server_free);
priv->private_servers = NULL;
@@ -557,6 +605,20 @@ nm_bus_manager_dispose (GObject *object)
nm_bus_manager_cleanup (self);
+ /* The ObjectManager owns the last reference to many exported
+ * objects, and when that reference is dropped the objects unregister
+ * themselves via nm_bus_manager_unregister_object(). By that time
+ * priv->manager is already NULL and that prints warnings. Unregister
+ * them before clearing the ObjectManager instead.
+ */
+ exported = g_dbus_object_manager_get_objects (G_DBUS_OBJECT_MANAGER (priv->manager));
+ for (iter = exported; iter; iter = iter->next) {
+ nm_bus_manager_unregister_object (self, iter->data);
+ g_object_unref (iter->data);
+ }
+ g_list_free (exported);
+ g_clear_object (&priv->manager);
+
if (priv->reconnect_id) {
g_source_remove (priv->reconnect_id);
priv->reconnect_id = 0;
@@ -586,9 +648,8 @@ nm_bus_manager_class_init (NMBusManagerClass *klass)
g_signal_new (NM_BUS_MANAGER_PRIVATE_CONNECTION_NEW,
G_OBJECT_CLASS_TYPE (object_class),
G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED,
- G_STRUCT_OFFSET (NMBusManagerClass, private_connection_new),
- NULL, NULL, NULL,
- G_TYPE_NONE, 1, G_TYPE_POINTER);
+ 0, NULL, NULL, NULL,
+ G_TYPE_NONE, 2, G_TYPE_DBUS_CONNECTION, G_TYPE_DBUS_OBJECT_MANAGER_SERVER);
signals[PRIVATE_CONNECTION_DISCONNECTED] =
g_signal_new (NM_BUS_MANAGER_PRIVATE_CONNECTION_DISCONNECTED,
@@ -614,6 +675,7 @@ nm_bus_manager_cleanup (NMBusManager *self)
g_clear_object (&priv->connection);
}
+ g_dbus_object_manager_server_set_connection (priv->manager, NULL);
priv->started = FALSE;
}
@@ -715,6 +777,7 @@ nm_bus_manager_init_bus (NMBusManager *self)
return FALSE;
}
+ g_dbus_object_manager_server_set_connection (priv->manager, priv->connection);
return TRUE;
}
@@ -777,41 +840,20 @@ nm_bus_manager_get_connection (NMBusManager *self)
return NM_BUS_MANAGER_GET_PRIVATE (self)->connection;
}
-static void
-object_destroyed (NMBusManager *self, gpointer object)
-{
- g_hash_table_remove (NM_BUS_MANAGER_GET_PRIVATE (self)->exported, object);
-}
-
void
nm_bus_manager_register_object (NMBusManager *self,
- const char *path,
- gpointer object)
+ GDBusObjectSkeleton *object)
{
NMBusManagerPrivate *priv = NM_BUS_MANAGER_GET_PRIVATE (self);
- GHashTableIter iter;
- GDBusConnection *connection;
- g_assert (G_IS_DBUS_INTERFACE_SKELETON (object));
+ g_assert (G_IS_DBUS_OBJECT_SKELETON (object));
- if (g_hash_table_lookup (priv->exported, G_OBJECT (object)))
+ if (g_dbus_object_manager_server_is_exported (priv->manager, object))
g_return_if_reached ();
- g_hash_table_insert (priv->exported, G_OBJECT (object), g_strdup (path));
- g_object_weak_ref (G_OBJECT (object), (GWeakNotify) object_destroyed, self);
-
- if (priv->connection) {
- g_dbus_interface_skeleton_export (G_DBUS_INTERFACE_SKELETON (object),
- priv->connection, path, NULL);
- }
-
- if (priv->priv_server) {
- g_hash_table_iter_init (&iter, priv->priv_server->connections);
- while (g_hash_table_iter_next (&iter, (gpointer) &connection, NULL)) {
- g_dbus_interface_skeleton_export (G_DBUS_INTERFACE_SKELETON (object),
- connection, path, NULL);
- }
- }
+ g_dbus_object_manager_server_export (priv->manager, object);
+ if (priv->priv_server)
+ private_server_register_object (priv->priv_server, object);
}
gpointer
@@ -819,32 +861,29 @@ nm_bus_manager_get_registered_object (NMBusManager *self,
const char *path)
{
NMBusManagerPrivate *priv = NM_BUS_MANAGER_GET_PRIVATE (self);
- GHashTableIter iter;
- GObject *object;
- const char *export_path;
- g_hash_table_iter_init (&iter, priv->exported);
- while (g_hash_table_iter_next (&iter, (gpointer *) &object, (gpointer *) &export_path)) {
- if (!strcmp (path, export_path))
- return object;
- }
- return NULL;
+ return g_dbus_object_manager_get_object (G_DBUS_OBJECT_MANAGER (priv->manager), path);
}
void
-nm_bus_manager_unregister_object (NMBusManager *self, gpointer object)
+nm_bus_manager_unregister_object (NMBusManager *self, GDBusObjectSkeleton *object)
{
NMBusManagerPrivate *priv = NM_BUS_MANAGER_GET_PRIVATE (self);
+ gs_free char *path = NULL;
- g_assert (G_IS_DBUS_INTERFACE_SKELETON (object));
+ g_assert (G_IS_DBUS_OBJECT_SKELETON (object));
- if (!g_hash_table_lookup (priv->exported, G_OBJECT (object)))
+ if (!g_dbus_object_manager_server_is_exported (priv->manager, object))
g_return_if_reached ();
- g_hash_table_remove (priv->exported, G_OBJECT (object));
- g_object_weak_unref (G_OBJECT (object), (GWeakNotify) object_destroyed, self);
+ g_object_get (G_OBJECT (object), "g-object-path", &path, NULL);
+ g_return_if_fail (path != NULL);
+
+ g_dbus_object_manager_server_unexport (priv->manager, path);
+ if (priv->priv_server)
+ private_server_unregister_object (priv->priv_server, path);
- g_dbus_interface_skeleton_unexport (G_DBUS_INTERFACE_SKELETON (object));
+ g_dbus_object_skeleton_set_object_path (object, NULL);
}
/**