diff --git a/src/routing_layer/topo_group.c b/src/routing_layer/topo_group.c index 313a9a892..7c00c1069 100644 --- a/src/routing_layer/topo_group.c +++ b/src/routing_layer/topo_group.c @@ -441,7 +441,7 @@ int topo_group_data_allowed(struct TOPO_GROUP* group, struct ETCP_CONN* conn) { } void topo_group_revalidate_members(struct TOPO_GROUP* group) { - if (!group || group->group_type != TOPO_GROUP_TYPE_CHAT || group->stopping) return; + if (!group || group->group_type != TOPO_GROUP_TYPE_CHAT) return; etcp_router_revalidate_group(group->instance, group->group_id); conn_mgr_revalidate_members(group->conn_mgr); radio_revalidate_members(group); @@ -450,6 +450,7 @@ void topo_group_revalidate_members(struct TOPO_GROUP* group) { group_avatar_revalidate_members(group->instance, group->group_id); chat_join_revalidate_members(group->instance, group->group_id); chat_sync_revalidate_join(group->instance, group->group_id); + if (group->stopping) return; /* Удаление вызывает callbacks и меняет список; каждый раз ищем следующего заново. */ for (;;) { struct TOPO_GROUP_CONN_ITEM* invalid = NULL; @@ -680,6 +681,8 @@ fail: static void topo_group_destroy(struct TOPO_GROUP* group) { if (!group) return; group->stopping = 1; + /* Отменить и локальные ожидания без router-сессии до освобождения ресурсов группы. */ + topo_group_revalidate_members(group); multicast_close_group(group->instance, group->group_id); nat_detection_cancel_group(group->instance->nat_det, group->group_id); stream_cancel_group(group->instance, group->group_id); diff --git a/tests/test_chat_group_isolation.c b/tests/test_chat_group_isolation.c index 2bae77690..21c08da84 100644 --- a/tests/test_chat_group_isolation.c +++ b/tests/test_chat_group_isolation.c @@ -492,6 +492,22 @@ static int join_isolation(void) { return 0; } +static int stop_isolation(void) { + struct UTUN_INSTANCE* server = fixture.nodes[0]; + REQUIRE(!chat_join_init(server) && !chat_join_store_local_key(server, 112, 9000)); + int status = 99; + REQUIRE(chat_join_register_key(server, 112, 0, 9001, join_registered, &status)); + REQUIRE(status == 99); + topo_groups_remove_group(server->topo_groups, 112); + fixture.groups[0][1] = NULL; + check("group removal cancels local JOIN before its timer", status == CHAT_JOIN_CANCELLED && + !server->join_keys && !server->join_registrations && !topo_groups_find(server->topo_groups, 112)); + unsigned before = fixture.broadcast[0]; + REQUIRE(!send_broadcast(0, 9002)); + check("removing B preserves A and shared transport", fixture.broadcast[0] == before + 1 && fixture.transport->links_up); + return 0; +} + int main(void) { debug_config_init(); debug_set_level(DEBUG_LEVEL_WARN); debug_set_category_level(DEBUG_CATEGORY_DEBUG, DEBUG_LEVEL_INFO); @@ -517,6 +533,7 @@ int main(void) { #ifdef __linux__ if (!fixture.failed && file_isolation(1)) fixture.failed++; #endif + if (!fixture.failed && stop_isolation()) fixture.failed++; } } pthread_mutex_lock(&fixture.disk_mutex); fixture.disk_released = 1; pthread_cond_signal(&fixture.disk_condition);