app_queue: Prevent crash when a call is forwarded to an invalid location
authorMatt Jordan <mjordan@digium.com>
Thu, 11 Aug 2016 16:13:07 +0000 (11:13 -0500)
committerMatt Jordan <mjordan@digium.com>
Thu, 11 Aug 2016 18:56:19 +0000 (13:56 -0500)
When a call forward attempt is made from a Queue member, the current
code will hang up the forwarding channel in an off-nominal condition
prior to raising the Stasis events informing the rest of Asterisk that
the call was forwarded. This will result in a slew of dreaded FRACKs,
most likely leading to a crash.

This patch modifies the code such that we don't hang up the forwarding
channel even in an off-nominal condition until we've safely raised the
Stasis messages.

ASTERISK-25797 #close

Change-Id: Ife5abed351691fd79105321636eaa8ea8dcdba38

apps/app_queue.c

index 39413f9..a5cb126 100644 (file)
@@ -4865,6 +4865,7 @@ static struct callattempt *wait_for_answer(struct queue_ent *qe, struct callatte
                                        char tmpchan[256];
                                        char *stuff;
                                        char *tech;
+                                       int failed = 0;
 
                                        ast_copy_string(tmpchan, ast_channel_call_forward(o->chan), sizeof(tmpchan));
                                        ast_copy_string(forwarder, ast_channel_name(o->chan), sizeof(forwarder));
@@ -4977,14 +4978,20 @@ static struct callattempt *wait_for_answer(struct queue_ent *qe, struct callatte
                                                if (ast_call(o->chan, stuff, 0)) {
                                                        ast_log(LOG_NOTICE, "Forwarding failed to dial '%s/%s'\n",
                                                                tech, stuff);
-                                                       do_hang(o);
-                                                       numnochan++;
+                                                       failed = 1;
                                                }
                                        }
 
-                                       ast_channel_publish_dial(qe->chan, o->chan, stuff, NULL);
                                        ast_channel_publish_dial_forward(qe->chan, original, o->chan, NULL,
                                                "CANCEL", ast_channel_call_forward(original));
+                                       if (o->chan) {
+                                               ast_channel_publish_dial(qe->chan, o->chan, stuff, NULL);
+                                       }
+
+                                       if (failed) {
+                                               do_hang(o);
+                                               numnochan++;
+                                       }
 
                                        /* Hangup the original channel now, in case we needed it */
                                        ast_hangup(winner);