mirror of
https://gitlab.freedesktop.org/pipewire/wireplumber.git
synced 2025-12-20 06:30:04 +01:00
`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
[...]
264 lines
7.4 KiB
C
264 lines
7.4 KiB
C
/* 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;
|
|
}
|
|
}
|
|
|
|
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;
|
|
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));
|
|
}
|