From 2ba9881b4d5464530e28c80cfe65c67b1f734100 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Barnab=C3=A1s=20P=C5=91cze?= Date: Sun, 7 May 2023 16:19:06 +0200 Subject: [PATCH] pulse-server: pending-sample: handle client disconnection correctly Previously, a client disconnecting while a sample was playing could lead to issues. For example, if a client disconnected before the "ready" signal of the sample-play arrives, `operation_new_cb()` would be called and that would try to use the client's pw_manager, however, that has previously been destroyed in `client_disconnect()`. If the client disconnected after the "ready" signal but before the reply has been sent, then `sample_play_ready_reply()` would never be called since operations are completed via the client's pw_manager which would already be destroyed at that point. Fix this by installing a listener on the client, and properly cancelling the operation and making sure that the pending_sample is correctly destroyed. --- .../module-protocol-pulse/pending-sample.c | 17 +++++++++++++++++ .../module-protocol-pulse/pending-sample.h | 1 + 2 files changed, 18 insertions(+) diff --git a/src/modules/module-protocol-pulse/pending-sample.c b/src/modules/module-protocol-pulse/pending-sample.c index 4e139b40b..065b460ca 100644 --- a/src/modules/module-protocol-pulse/pending-sample.c +++ b/src/modules/module-protocol-pulse/pending-sample.c @@ -88,6 +88,21 @@ static const struct sample_play_events sample_play_events = { .done = on_sample_play_done, }; +static void on_client_disconnect(void *data) +{ + struct pending_sample *ps = data; + + ps->replied = true; + operation_free_by_tag(ps->client, ps->tag); + + schedule_maybe_finish(ps); +} + +static const struct client_events client_events = { + VERSION_CLIENT_EVENTS, + .disconnect = on_client_disconnect, +}; + int pending_sample_new(struct client *client, struct sample *sample, struct pw_properties *props, uint32_t tag) { struct pending_sample *ps; @@ -100,6 +115,7 @@ int pending_sample_new(struct client *client, struct sample *sample, struct pw_p ps->play = p; ps->tag = tag; sample_play_add_listener(p, &ps->listener, &sample_play_events, ps); + client_add_listener(client, &ps->client_listener, &client_events, ps); spa_list_append(&client->pending_samples, &ps->link); client->ref++; @@ -113,6 +129,7 @@ void pending_sample_free(struct pending_sample *ps) spa_list_remove(&ps->link); spa_hook_remove(&ps->listener); + spa_hook_remove(&ps->client_listener); pw_work_queue_cancel(impl->work_queue, ps, SPA_ID_INVALID); operation_free_by_tag(client, ps->tag); diff --git a/src/modules/module-protocol-pulse/pending-sample.h b/src/modules/module-protocol-pulse/pending-sample.h index 121f20fba..5eb0bc2a6 100644 --- a/src/modules/module-protocol-pulse/pending-sample.h +++ b/src/modules/module-protocol-pulse/pending-sample.h @@ -20,6 +20,7 @@ struct pending_sample { struct client *client; struct sample_play *play; struct spa_hook listener; + struct spa_hook client_listener; uint32_t tag; unsigned replied:1; unsigned done:1;