From 6409e7b11a2310196a9978b30a6b79e2760be592 Mon Sep 17 00:00:00 2001
From: Kevin Harwell <kharwell@digium.com>
Date: Thu, 17 Sep 2015 11:31:15 -0500
Subject: [PATCH] app_queue: Crash when transferring

During some transfer scenarios involving queues Asterisk would sometimes
crash when trying to obtain a channel snapshot (could happen on caller or
member channels). This occurred because the underlying channel had already
disappeared when trying to obtain the latest snapshot.

This patch adds a reference to both the member and caller channels that
extends to the lifetime of the queue'd call, thus making sure the channels
will always exist when retrieving the latest snapshots.

ASTERISK-25185 #close
Reported by: Etienne Lessard

Change-Id: Ic397fa68fb4ff35fbc378e745da9246a7b552128
---
 apps/app_queue.c | 17 +++++++++++++++++
 1 file changed, 17 insertions(+)

diff --git a/apps/app_queue.c b/apps/app_queue.c
index c0ee9f35fe..e42bfad34d 100644
--- a/apps/app_queue.c
+++ b/apps/app_queue.c
@@ -5564,6 +5564,10 @@ struct queue_stasis_data {
 	struct local_optimization caller_optimize;
 	/*! Local channel optimization details for the member */
 	struct local_optimization member_optimize;
+	/*! Member channel */
+	struct ast_channel *member_channel;
+	/*! Caller channel */
+	struct ast_channel *caller_channel;
 };
 
 /*!
@@ -5581,6 +5585,9 @@ static void queue_stasis_data_destructor(void *obj)
 	ao2_cleanup(queue_data->member);
 	queue_unref(queue_data->queue);
 	ast_string_field_free_memory(queue_data);
+
+	ao2_ref(queue_data->member_channel, -1);
+	ao2_ref(queue_data->caller_channel, -1);
 }
 
 /*!
@@ -5627,6 +5634,16 @@ static struct queue_stasis_data *queue_stasis_data_alloc(struct queue_ent *qe,
 	queue_data->caller_pos = qe->opos;
 	ao2_ref(mem, +1);
 	queue_data->member = mem;
+
+	/*
+	 * During transfers it's possible for both the member and/or caller
+	 * channel(s) to not be available. Adding a reference here ensures
+	 * that the channels remain until app_queue is completely done with
+	 * them.
+	 */
+	queue_data->member_channel = ao2_bump(peer);
+	queue_data->caller_channel = ao2_bump(qe->chan);
+
 	return queue_data;
 }
 
-- 
GitLab