Fix potential race condition during call pickup.
authorMark Michelson <mmichelson@digium.com>
Thu, 29 Mar 2012 23:36:37 +0000 (23:36 +0000)
committerMark Michelson <mmichelson@digium.com>
Thu, 29 Mar 2012 23:36:37 +0000 (23:36 +0000)
Prior to this patch, a connected line update was queued during
call pickup and then an answer frame was queued. The original
caller would presumably then have his connected line updated
and then the call would be answered.

In actuality, the answer frame was not how the call ended up
being answered. Rather, an odd section in app_dial that checks
if the called channel's state is up.

The result is that the order of the connected line update and
the answer were variable. In most cases, this wasn't actually
a bad thing. However, if the 'I' option was passed to dial, the
connected line update would be inhibited.

The fix is to queued the connected line after the answer frame is
queued. This way the race in app_dial is between two
conditions resulting in an answer. This way the connected line
update occurs after the answer every time.

(closes issue ASTERISK-19183)
Reported by: Thomas Arimont
Tested by: Thomas Arimont
    Mark Michelson
Patches:
    ASTERISK-19183.patch uploaded by Mark Michelson (license 5049)
........

Merged revisions 360884 from http://svn.asterisk.org/svn/asterisk/branches/1.8
........

Merged revisions 360885 from http://svn.asterisk.org/svn/asterisk/branches/10

git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@360886 65c4cc65-6c06-0410-ace0-fbb531ad65f3

main/features.c

index d23bda4..aea0d1e 100644 (file)
@@ -7384,8 +7384,6 @@ int ast_do_pickup(struct ast_channel *chan, struct ast_channel *target)
        ast_connected_line_copy_from_caller(&connected_caller, ast_channel_caller(chan));
        ast_channel_unlock(chan);
        connected_caller.source = AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER;
-       ast_channel_queue_connected_line_update(chan, &connected_caller, NULL);
-       ast_party_connected_line_free(&connected_caller);
 
        ast_cel_report_event(target, AST_CEL_PICKUP, NULL, NULL, chan);
 
@@ -7399,6 +7397,8 @@ int ast_do_pickup(struct ast_channel *chan, struct ast_channel *target)
                goto pickup_failed;
        }
 
+       ast_channel_queue_connected_line_update(chan, &connected_caller, NULL);
+
        /* setting this flag to generate a reason header in the cancel message to the ringing channel */
        ast_set_flag(ast_channel_flags(chan), AST_FLAG_ANSWERED_ELSEWHERE);
 
@@ -7423,6 +7423,7 @@ pickup_failed:
        if (!ast_channel_datastore_remove(target, ds_pickup)) {
                ast_datastore_free(ds_pickup);
        }
+       ast_party_connected_line_free(&connected_caller);
 
        return res;
 }