From 0994ffbe7579d1751c4b8482369651757f7a2705 Mon Sep 17 00:00:00 2001 From: Donat Zenichev Date: Mon, 17 Apr 2023 14:56:08 +0200 Subject: [PATCH] MT#57118 Rework the call's deconstruction logic This commit: 6f0ad0db0fc0fce370f6bcf388e9a9e69c56d81d introduced an improved behavior of the call deconstruction when dealing with multiple forked legs. But it also introduced a regression related to TPCC related calls. This is because it takes into consideration existing `->viabranches`, which is not efficient in certain cases. Instead, we just have to ensure, whether there are other monologues of the call object, which are not directly "visible" for this branch being cancelled (so they are not directly associated to that), but they might have own associations present, which means the call mustn't be globally destoroyed. Change-Id: I630f2d88ef3b557af3a95816fc2703daccaff374 --- daemon/call.c | 42 ++++++++++++++++++++++++++++++++---------- 1 file changed, 32 insertions(+), 10 deletions(-) diff --git a/daemon/call.c b/daemon/call.c index 39dfac134..47e6a4e3b 100644 --- a/daemon/call.c +++ b/daemon/call.c @@ -4276,7 +4276,9 @@ static unsigned int monologue_delete_iter(struct call_monologue *a, int delete_d if (!call) return 0; - unsigned int call_viabranches_count = g_hash_table_size(call->viabranches); + unsigned int ml_associated_count = g_hash_table_size(a->associated_tags); + unsigned int call_monologues_count = g_queue_get_length(&call->monologues); + GList *associated = g_hash_table_get_values(a->associated_tags); unsigned int ret = 0; @@ -4295,22 +4297,42 @@ static unsigned int monologue_delete_iter(struct call_monologue *a, int delete_d ret |= 0x2; } - // look at all associated tags: cascade deletion to those which have no other associations left - for (GList *l = associated; l; l = l->next) { + /* first, look at all associated tags: cascade deletion to those which have + * no other associations left */ + for (GList *l = associated; l; l = l->next) + { struct call_monologue *b = l->data; __tags_unassociate(a, b); if (g_hash_table_size(b->associated_tags) == 0) - ret |= monologue_delete_iter(b, delete_delay); + ret |= monologue_delete_iter(b, delete_delay); /* schedule deletion of B */ else ret |= 0x1; } - /* Take into account an amount of forked legs we have now. - * If there's more than 1 forked leg, don't mark the call for a full destruction, - * since other forks might be successful. Only destroy this branch and associated to it monologue(s). - */ - if (call_viabranches_count > 1) - 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;