From 9ad2d9d03e436bb154969e297424c126943f0a51 Mon Sep 17 00:00:00 2001 From: Donat Zenichev Date: Fri, 10 Nov 2023 12:17:04 +0100 Subject: [PATCH] MT#57550 Don't rely on empty from-tag in `call_delete_branch()` Due to introduction of media subscriptions model. Rely on subscription monologue's empty tag, while trying to detect, whether or not to destroy given monologue but with a clause that: - this ml is subscribed to medias of other signle ml It's important to keep this check because if the `delete` is done with from-tag and to-tag, just right away after an `offer` without the to-tag and without use of via-branch, then the call's data can potentially remain dangling without being deleted completely. So looking up the offer side of the call through the from-tag and then checking, if the call has not been answered (answer side has an empty to-tag), gives a clue whether to delete an entire call. Additionally, introduce a helper function: - `ml_medias_subscribed_to_single_ml()` which checks, whether this monologue medias are subscribed to a single other monologue medias. Change-Id: I2474d24ac66ce2cb12bd282f2c0df809fce7880c --- daemon/call.c | 46 +++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 41 insertions(+), 5 deletions(-) diff --git a/daemon/call.c b/daemon/call.c index 8b883abba..401bdad2e 100644 --- a/daemon/call.c +++ b/daemon/call.c @@ -3127,6 +3127,34 @@ static void __unsubscribe_medias_from_all(struct call_monologue *ml) { } } } +/** + * Check whether this monologue medias are subscribed to a single other monologue medias. + */ +static struct call_monologue * ml_medias_subscribed_to_single_ml(struct call_monologue *ml) { + /* detect monologues multiplicity */ + AUTO_CLEANUP(GQueue mls, g_queue_clear) = G_QUEUE_INIT; + struct call_monologue * return_ml = NULL; + for (unsigned int i = 0; i < ml->medias->len; i++) + { + struct call_media *media = ml->medias->pdata[i]; + if (!media) + continue; + for (GList *l = media->media_subscriptions.head; l; l = l->next) + { + struct media_subscription * ms = l->data; + return_ml = ms->monologue; + g_queue_push_tail(&mls, ms->monologue); + /* check if the following mononoluge is different one */ + if (l->next) { + ms = l->next->data; + if (!g_queue_find(&mls, ms->monologue)) { + return NULL; /* subscription to medias of different monologues */ + } + } + } + } + return return_ml; +} void __add_media_subscription(struct call_media * which, struct call_media * to, const struct sink_attrs *attrs) { @@ -4892,13 +4920,21 @@ int call_delete_branch(struct call *c, const str *branch, goto do_delete; } - // last resort: try the from-tag if we tried the to-tag before and see - // if the associated dialogue has an empty tag (unknown) + /* IMPORTANT! + * last resort: try the from-tag, if we tried the to-tag before and see, + * if the associated dialogue has an empty tag (unknown). + * If that condition is met, then we delete the entire call. + * + * A use case for that is: `delete` done with from-tag and to-tag, + * right away after an `offer` without the to-tag and without use of via-branch. + * Then, looking up the offer side of the call through the from-tag + * and then checking, if the call has not been answered (answer side has an empty to-tag), + * gives a clue whether to delete an entire call. */ if (match_tag == totag) { ml = call_get_monologue(c, fromtag); - if (ml && ml->subscriptions.length == 1) { - struct call_subscription *cs = ml->subscriptions.head->data; - if (cs->monologue->tag.len == 0) + if (ml) { + struct call_monologue * sub_ml = ml_medias_subscribed_to_single_ml(ml); + if (sub_ml && !sub_ml->tag.len) goto do_delete; } }