wireplumber/modules/module-dbus-connection.c

265 lines
7.4 KiB
C
Raw Normal View History

/* WirePlumber
*
* Copyright © 2022-2023 Collabora Ltd.
* @author Julian Bouzas <julian.bouzas@collabora.com>
*
* SPDX-License-Identifier: MIT
*/
#include <wp/wp.h>
#include "dbus-connection-state.h"
#include "dbus-connection-enums.h"
WP_DEFINE_LOCAL_LOG_TOPIC ("m-dbus-connection")
enum
{
PROP_0,
PROP_BUS_TYPE,
PROP_STATE,
PROP_CONNECTION,
};
struct _WpDBusConnection
{
WpPlugin parent;
/* Props */
GBusType bus_type;
WpDBusConnectionState state;
GDBusConnection *connection;
GCancellable *cancellable;
};
static void on_connection_closed (GDBusConnection * connection,
gboolean remote_peer_vanished, GError * error, gpointer data);
G_DECLARE_FINAL_TYPE (WpDBusConnection, wp_dbus_connection,
WP, DBUS_CONNECTION, WpPlugin)
G_DEFINE_TYPE (WpDBusConnection, wp_dbus_connection, WP_TYPE_PLUGIN)
static void
wp_dbus_connection_init (WpDBusConnection * self)
{
}
static void
wp_dbus_connection_set_state (WpDBusConnection * self, WpDBusConnectionState new_state)
{
if (self->state != new_state) {
self->state = new_state;
g_object_notify (G_OBJECT (self), "state");
}
}
static void
on_got_bus (GObject * obj, GAsyncResult * res, gpointer data)
{
WpTransition *transition;
WpDBusConnection *self;
g_autoptr (GError) error = NULL;
if (WP_IS_TRANSITION (data)) {
// coming from wp_dbus_connection_enable
transition = WP_TRANSITION (data);
self = wp_transition_get_source_object (transition);
} else {
// coming from on_sync_reconnect
transition = NULL;
self = WP_DBUS_CONNECTION (data);
}
self->connection = g_dbus_connection_new_for_address_finish (res, &error);
if (!self->connection) {
if (transition) {
g_prefix_error (&error, "Failed to connect to bus: ");
wp_transition_return_error (transition, g_steal_pointer (&error));
}
return;
}
wp_debug_object (self, "Connected to bus");
/* set up connection */
g_signal_connect_object (self->connection, "closed",
G_CALLBACK (on_connection_closed), self, 0);
g_dbus_connection_set_exit_on_close (self->connection, FALSE);
wp_dbus_connection_set_state (self, WP_DBUS_CONNECTION_STATE_CONNECTED);
if (transition)
wp_object_update_features (WP_OBJECT (self), WP_PLUGIN_FEATURE_ENABLED, 0);
}
static gboolean
do_connect (WpDBusConnection * self, GAsyncReadyCallback callback,
gpointer data, GError ** error)
{
g_autofree gchar *address = NULL;
address = g_dbus_address_get_for_bus_sync (self->bus_type, NULL, error);
if (!address) {
g_prefix_error (error, "Error acquiring bus address: ");
return FALSE;
}
wp_dbus_connection_set_state (self, WP_DBUS_CONNECTION_STATE_CONNECTING);
wp_debug_object (self, "Connecting to bus: %s", address);
g_dbus_connection_new_for_address (address,
G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_CLIENT |
G_DBUS_CONNECTION_FLAGS_MESSAGE_BUS_CONNECTION,
NULL, self->cancellable, callback, data);
return TRUE;
}
static void
on_sync_reconnect (WpCore * core, GAsyncResult * res, WpDBusConnection * self)
{
g_autoptr (GError) error = NULL;
if (!wp_core_sync_finish (core, res, &error)) {
wp_warning_object (self, "core sync error: %s", error->message);
return;
}
if (!do_connect (self, on_got_bus, self, &error))
wp_notice_object (self, "Cannot reconnect: %s", error->message);
}
static void
on_connection_closed (GDBusConnection * connection,
gboolean remote_peer_vanished, GError * error, gpointer data)
{
WpDBusConnection *self = WP_DBUS_CONNECTION (data);
g_autoptr (WpCore) core = NULL;
wp_notice_object (self, "DBus connection closed: %s", error->message);
g_clear_object (&self->connection);
wp_dbus_connection_set_state (self, WP_DBUS_CONNECTION_STATE_CLOSED);
/* try to reconnect on idle if connection was closed */
core = wp_object_get_core (WP_OBJECT (self));
if (core && wp_core_is_connected (core)) {
wp_notice_object (self, "Trying to reconnect after core sync");
wp_core_sync_closure (core, NULL, g_cclosure_new_object (
G_CALLBACK (on_sync_reconnect), G_OBJECT (self)));
}
}
static void
wp_dbus_connection_enable (WpPlugin * plugin, WpTransition * transition)
{
WpDBusConnection *self = WP_DBUS_CONNECTION (plugin);
g_autoptr (GError) error = NULL;
if (!do_connect (self, on_got_bus, transition, &error)) {
wp_transition_return_error (transition, g_steal_pointer (&error));
}
}
static void
wp_dbus_connection_disable (WpPlugin * plugin)
{
WpDBusConnection *self = WP_DBUS_CONNECTION (plugin);
g_cancellable_cancel (self->cancellable);
g_clear_object (&self->connection);
wp_dbus_connection_set_state (self, WP_DBUS_CONNECTION_STATE_CLOSED);
g_clear_object (&self->cancellable);
self->cancellable = g_cancellable_new ();
}
static void
wp_dbus_connection_get_property (GObject * object, guint property_id,
GValue * value, GParamSpec * pspec)
{
WpDBusConnection *self = WP_DBUS_CONNECTION (object);
switch (property_id) {
case PROP_BUS_TYPE:
g_value_set_enum (value, self->bus_type);
break;
case PROP_STATE:
g_value_set_enum (value, self->state);
break;
case PROP_CONNECTION:
g_value_set_object (value, self->connection);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
}
}
static void
wp_dbus_connection_set_property (GObject * object, guint property_id,
const GValue * value, GParamSpec * pspec)
{
WpDBusConnection *self = WP_DBUS_CONNECTION (object);
switch (property_id) {
case PROP_BUS_TYPE:
self->bus_type = g_value_get_enum (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
}
}
module-dbus-connection: fix GCancellable leak `wp_dbus_connection_disable()` creates a new GCancellable object at the end, which is never freed if the GObject is then destroyed. To fix this, override `finalize()` and clear everything there as well. Direct leak of 64 byte(s) in 1 object(s) allocated from: 0 0x70e688efd1aa in calloc /usr/src/debug/gcc/gcc/libsanitizer/asan/asan_malloc_linux.cpp:77 1 0x70e6874b3e62 in g_malloc0 (/usr/lib/libglib-2.0.so.0+0x63e62) (BuildId: 7b781c8d1a6e2161838c5d8f3bd797797c132753) 2 0x70e6875dea75 in g_type_create_instance (/usr/lib/libgobject-2.0.so.0+0x3ea75) (BuildId: 5af5e0f7d0a900ecb6083fbd71e22e5522d872e2) 3 0x70e6875c3804 (/usr/lib/libgobject-2.0.so.0+0x23804) (BuildId: 5af5e0f7d0a900ecb6083fbd71e22e5522d872e2) 4 0x70e6875c4e7e in g_object_new_with_properties (/usr/lib/libgobject-2.0.so.0+0x24e7e) (BuildId: 5af5e0f7d0a900ecb6083fbd71e22e5522d872e2) 5 0x70e6875c5ed1 in g_object_new (/usr/lib/libgobject-2.0.so.0+0x25ed1) (BuildId: 5af5e0f7d0a900ecb6083fbd71e22e5522d872e2) 6 0x70e684d2a8a6 in wp_dbus_connection_disable ../subprojects/wireplumber/modules/module-dbus-connection.c:173 7 0x70e688a833cc in wp_plugin_deactivate ../subprojects/wireplumber/lib/wp/plugin.c:144 8 0x70e688a7126c in wp_object_deactivate ../subprojects/wireplumber/lib/wp/object.c:542 9 0x70e688a6e74e in wp_object_dispose ../subprojects/wireplumber/lib/wp/object.c:191 10 0x70e6875c0f6c in g_object_unref (/usr/lib/libgobject-2.0.so.0+0x20f6c) (BuildId: 5af5e0f7d0a900ecb6083fbd71e22e5522d872e2) 11 0x70e6841f7d6d in wp_portal_permissionstore_plugin_disable ../subprojects/wireplumber/modules/module-portal-permissionstore.c:207 12 0x70e688a833cc in wp_plugin_deactivate ../subprojects/wireplumber/lib/wp/plugin.c:144 [...]
2024-09-26 14:49:12 +02:00
static void
wp_dbus_connection_finalize (GObject * object)
{
WpDBusConnection *self = WP_DBUS_CONNECTION (object);
g_cancellable_cancel (self->cancellable);
g_clear_object (&self->connection);
g_clear_object (&self->cancellable);
G_OBJECT_CLASS (wp_dbus_connection_parent_class)->finalize (object);
}
static void
wp_dbus_connection_class_init (WpDBusConnectionClass * klass)
{
GObjectClass *object_class = (GObjectClass *) klass;
WpPluginClass *plugin_class = (WpPluginClass *) klass;
object_class->get_property = wp_dbus_connection_get_property;
object_class->set_property = wp_dbus_connection_set_property;
module-dbus-connection: fix GCancellable leak `wp_dbus_connection_disable()` creates a new GCancellable object at the end, which is never freed if the GObject is then destroyed. To fix this, override `finalize()` and clear everything there as well. Direct leak of 64 byte(s) in 1 object(s) allocated from: 0 0x70e688efd1aa in calloc /usr/src/debug/gcc/gcc/libsanitizer/asan/asan_malloc_linux.cpp:77 1 0x70e6874b3e62 in g_malloc0 (/usr/lib/libglib-2.0.so.0+0x63e62) (BuildId: 7b781c8d1a6e2161838c5d8f3bd797797c132753) 2 0x70e6875dea75 in g_type_create_instance (/usr/lib/libgobject-2.0.so.0+0x3ea75) (BuildId: 5af5e0f7d0a900ecb6083fbd71e22e5522d872e2) 3 0x70e6875c3804 (/usr/lib/libgobject-2.0.so.0+0x23804) (BuildId: 5af5e0f7d0a900ecb6083fbd71e22e5522d872e2) 4 0x70e6875c4e7e in g_object_new_with_properties (/usr/lib/libgobject-2.0.so.0+0x24e7e) (BuildId: 5af5e0f7d0a900ecb6083fbd71e22e5522d872e2) 5 0x70e6875c5ed1 in g_object_new (/usr/lib/libgobject-2.0.so.0+0x25ed1) (BuildId: 5af5e0f7d0a900ecb6083fbd71e22e5522d872e2) 6 0x70e684d2a8a6 in wp_dbus_connection_disable ../subprojects/wireplumber/modules/module-dbus-connection.c:173 7 0x70e688a833cc in wp_plugin_deactivate ../subprojects/wireplumber/lib/wp/plugin.c:144 8 0x70e688a7126c in wp_object_deactivate ../subprojects/wireplumber/lib/wp/object.c:542 9 0x70e688a6e74e in wp_object_dispose ../subprojects/wireplumber/lib/wp/object.c:191 10 0x70e6875c0f6c in g_object_unref (/usr/lib/libgobject-2.0.so.0+0x20f6c) (BuildId: 5af5e0f7d0a900ecb6083fbd71e22e5522d872e2) 11 0x70e6841f7d6d in wp_portal_permissionstore_plugin_disable ../subprojects/wireplumber/modules/module-portal-permissionstore.c:207 12 0x70e688a833cc in wp_plugin_deactivate ../subprojects/wireplumber/lib/wp/plugin.c:144 [...]
2024-09-26 14:49:12 +02:00
object_class->finalize = wp_dbus_connection_finalize;
plugin_class->enable = wp_dbus_connection_enable;
plugin_class->disable = wp_dbus_connection_disable;
g_object_class_install_property (object_class, PROP_BUS_TYPE,
g_param_spec_enum ("bus-type", "bus-type", "The bus type",
G_TYPE_BUS_TYPE, G_BUS_TYPE_NONE,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (object_class, PROP_STATE,
g_param_spec_enum ("state", "state", "The dbus connection state",
WP_TYPE_DBUS_CONNECTION_STATE, WP_DBUS_CONNECTION_STATE_CLOSED,
G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (object_class, PROP_CONNECTION,
g_param_spec_object ("connection", "connection", "The dbus connection",
G_TYPE_DBUS_CONNECTION, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
}
WP_PLUGIN_EXPORT GObject *
wireplumber__module_init (WpCore * core, WpSpaJson * args, GError ** error)
{
return G_OBJECT (g_object_new (
wp_dbus_connection_get_type(),
"name", "dbus-connection",
"core", core,
"bus-type", G_BUS_TYPE_SESSION,
NULL));
}