From f4eb2d5a26bafb4088e9eb4f0c81e1d7fa23ccd6 Mon Sep 17 00:00:00 2001 From: Donat Zenichev Date: Tue, 25 Apr 2023 12:53:40 +0200 Subject: [PATCH] MT#57118 Prevent entire call deletion after `monologue_delete_iter()` Check globally left monologues (with associations left) after the `monologue_delete_iter()` has already done its job. This is needed to prevent cases, when a recursive call of the `monologue_delete_iter()` leads to blocking of the whole call destorying, meanwhile it's required, e.g.: - A is in progress of destorying - B gets recursive call of `monologue_delete_iter()` and sees that A has still one association left with C, which A simply hasn't manage to remove yet. This commit introduces new function: `call_monologues_associations_left()` Change-Id: I0941c18a76fa8c2a78d3864aee9e6433283bec88 --- daemon/call.c | 53 ++++++++++++++++++++++++--------------------------- 1 file changed, 25 insertions(+), 28 deletions(-) diff --git a/daemon/call.c b/daemon/call.c index 47e6a4e3b..a04215234 100644 --- a/daemon/call.c +++ b/daemon/call.c @@ -4297,8 +4297,8 @@ static unsigned int monologue_delete_iter(struct call_monologue *a, int delete_d ret |= 0x2; } - /* first, look at all associated tags: cascade deletion to those which have - * no other associations left */ + /* Look into all associated monologues: cascade deletion to those, + * which have no other associations left */ for (GList *l = associated; l; l = l->next) { struct call_monologue *b = l->data; @@ -4309,31 +4309,6 @@ static unsigned int monologue_delete_iter(struct call_monologue *a, int delete_d ret |= 0x1; } - /* now, if one call object contains some other monologues, which can have own associations, - * not direclty visible for this very monologue, - * then ensure, whether we can afford to destroy the whole call now. - * Maybe some of them still needs a media to flow. */ - if (ml_associated_count < call_monologues_count && !(ret & 0x1)) { - for (GList * l = call->monologues.head; l; l = l->next) - { - struct call_monologue * ml = l->data; - - /* skip those already checked */ - if (g_hash_table_lookup(a->associated_tags, ml)) - continue; - - /* we are not clearing here monologues not associated with us, - * only checking, if we can afford whole call destroy. - */ - if (g_hash_table_size(ml->associated_tags) > 0) { - ret |= 0x1; - break; - } - } - } - /* otherwise, we have only one call leg, so association monologue A to monologue B (no other branches) - * and we can simple destroy the whole call */ - g_list_free(associated); return ret; } @@ -4377,6 +4352,19 @@ static void __tags_associate(struct call_monologue *a, struct call_monologue *b) g_hash_table_insert(b->associated_tags, a, a); } +/** + * Check whether the call object contains some other monologues, which can have own associations. + */ +static bool call_monologues_associations_left(struct call * c) { + for (GList * l = c->monologues.head; l; l = l->next) + { + struct call_monologue * ml = l->data; + if (g_hash_table_size(ml->associated_tags) > 0) + return true; + } + return false; +} + /** * Based on given From-tag create a new monologue for this dialog, * if given tag wasn't present in 'tags' of this call. @@ -4683,10 +4671,19 @@ do_delete: monologue_stop(cs->monologue); } + /* check, if we have some associated monologues left, which have own associations + * which means they need a media to flow */ unsigned int del_ret = monologue_delete_iter(ml, delete_delay); + + /* if there are no associated dialogs, which still require media, then additionally + * ensure, whether we can afford to destroy the whole call now. + * Maybe some of them still need a media to flow */ + bool del_stop = false; + del_stop = call_monologues_associations_left(c); + if ((del_ret & 0x2)) update = true; - if (!(del_ret & 0x1)) + if (!(del_ret & 0x1) && !del_stop) goto del_all; goto success_unlock;