Skip to content
Snippets Groups Projects
Commit c88d1c83 authored by Matthew Jordan's avatar Matthew Jordan
Browse files

Ensure Asterisk sends a BYE when pending on the final response to a re-INVITE

When Asterisk detects a hangup and cannot send a BYE due to a pending
INVITE, it sets the pendingbye flag and waits for the final response to that
INVITE.  When the response is received, it transmits the BYE.  If, however,
that INVITE request is a pending re-INVITE, it needs to first send a CANCEL
request to terminate the pending re-INVITE.  In that circumstance, Asterisk
was, in some scenarios, clearing the pendingbye flag after processing the
CANCEL request and not checking for a pending BYE when receiving the final
487 response to the INVITE.

This patch ensures that if the pendingbye flag is set, it is honored
regardless of the nature of the INVITE request currently in flight.

(closes issue ASTERISK-19365)
Reported by: Thomas Arimont
Tested by: Thomas Arimont
Patches:
  bugASTERISK-19365_2012_03_08.patch uploaded by mjordan (license 6283)

Review: https://reviewboard.asterisk.org/r/1807
........

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

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


git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@360089 65c4cc65-6c06-0410-ace0-fbb531ad65f3
parent 6ff8f148
Branches
Tags
No related merge requests found
...@@ -12635,7 +12635,7 @@ static int transmit_invite(struct sip_pvt *p, int sipmethod, int sdp, int init, ...@@ -12635,7 +12635,7 @@ static int transmit_invite(struct sip_pvt *p, int sipmethod, int sdp, int init,
/* If init=1, we should not generate a new branch. If it's 0, we need a new branch. */ /* If init=1, we should not generate a new branch. If it's 0, we need a new branch. */
reqprep(&req, p, sipmethod, 0, init ? 0 : 1); reqprep(&req, p, sipmethod, 0, init ? 0 : 1);
} }
if (p->options && p->options->auth) { if (p->options && p->options->auth) {
add_header(&req, p->options->authheader, p->options->auth); add_header(&req, p->options->authheader, p->options->auth);
} }
...@@ -20552,6 +20552,10 @@ static void check_pendings(struct sip_pvt *p) ...@@ -20552,6 +20552,10 @@ static void check_pendings(struct sip_pvt *p)
if (p->invitestate == INV_PROCEEDING || p->invitestate == INV_EARLY_MEDIA) { if (p->invitestate == INV_PROCEEDING || p->invitestate == INV_EARLY_MEDIA) {
p->invitestate = INV_CANCELLED; p->invitestate = INV_CANCELLED;
transmit_request(p, SIP_CANCEL, p->lastinvite, XMIT_RELIABLE, FALSE); transmit_request(p, SIP_CANCEL, p->lastinvite, XMIT_RELIABLE, FALSE);
/* If the cancel occurred on an initial invite, cancel the pending BYE */
if (!ast_test_flag(&p->flags[1], SIP_PAGE2_DIALOG_ESTABLISHED)) {
ast_clear_flag(&p->flags[0], SIP_PENDINGBYE);
}
/* Actually don't destroy us yet, wait for the 487 on our original /* Actually don't destroy us yet, wait for the 487 on our original
INVITE, but do set an autodestruct just in case we never get it. */ INVITE, but do set an autodestruct just in case we never get it. */
} else { } else {
...@@ -20565,8 +20569,8 @@ static void check_pendings(struct sip_pvt *p) ...@@ -20565,8 +20569,8 @@ static void check_pendings(struct sip_pvt *p)
} }
/* Perhaps there is an SD change INVITE outstanding */ /* Perhaps there is an SD change INVITE outstanding */
transmit_request_with_auth(p, SIP_BYE, 0, XMIT_RELIABLE, TRUE); transmit_request_with_auth(p, SIP_BYE, 0, XMIT_RELIABLE, TRUE);
ast_clear_flag(&p->flags[0], SIP_PENDINGBYE);
} }
ast_clear_flag(&p->flags[0], SIP_PENDINGBYE);
sip_scheddestroy(p, DEFAULT_TRANS_TIMEOUT); sip_scheddestroy(p, DEFAULT_TRANS_TIMEOUT);
} else if (ast_test_flag(&p->flags[0], SIP_NEEDREINVITE)) { } else if (ast_test_flag(&p->flags[0], SIP_NEEDREINVITE)) {
/* if we can't REINVITE, hold it for later */ /* if we can't REINVITE, hold it for later */
...@@ -20728,7 +20732,7 @@ static void handle_response_invite(struct sip_pvt *p, int resp, const char *rest ...@@ -20728,7 +20732,7 @@ static void handle_response_invite(struct sip_pvt *p, int resp, const char *rest
int outgoing = ast_test_flag(&p->flags[0], SIP_OUTGOING); int outgoing = ast_test_flag(&p->flags[0], SIP_OUTGOING);
int res = 0; int res = 0;
int xmitres = 0; int xmitres = 0;
int reinvite = (p->owner && ast_channel_state(p->owner) == AST_STATE_UP); int reinvite = ast_test_flag(&p->flags[1], SIP_PAGE2_DIALOG_ESTABLISHED);
char *p_hdrval; char *p_hdrval;
int rtn; int rtn;
struct ast_party_connected_line connected; struct ast_party_connected_line connected;
...@@ -20934,10 +20938,11 @@ static void handle_response_invite(struct sip_pvt *p, int resp, const char *rest ...@@ -20934,10 +20938,11 @@ static void handle_response_invite(struct sip_pvt *p, int resp, const char *rest
p->authtries = 0; p->authtries = 0;
if (find_sdp(req)) { if (find_sdp(req)) {
if ((res = process_sdp(p, req, SDP_T38_ACCEPT)) && !req->ignore) if ((res = process_sdp(p, req, SDP_T38_ACCEPT)) && !req->ignore)
if (!reinvite) if (!reinvite) {
/* This 200 OK's SDP is not acceptable, so we need to ack, then hangup */ /* This 200 OK's SDP is not acceptable, so we need to ack, then hangup */
/* For re-invites, we try to recover */ /* For re-invites, we try to recover */
ast_set_flag(&p->flags[0], SIP_PENDINGBYE); ast_set_flag(&p->flags[0], SIP_PENDINGBYE);
}
ast_rtp_instance_activate(p->rtp); ast_rtp_instance_activate(p->rtp);
} }
   
...@@ -20984,7 +20989,6 @@ static void handle_response_invite(struct sip_pvt *p, int resp, const char *rest ...@@ -20984,7 +20989,6 @@ static void handle_response_invite(struct sip_pvt *p, int resp, const char *rest
if (!reinvite) { if (!reinvite) {
build_route(p, req, 1, resp); build_route(p, req, 1, resp);
} }
if(set_address_from_contact(p)) { if(set_address_from_contact(p)) {
/* Bad contact - we don't know how to reach this device */ /* Bad contact - we don't know how to reach this device */
/* We need to ACK, but then send a bye */ /* We need to ACK, but then send a bye */
...@@ -21138,6 +21142,7 @@ static void handle_response_invite(struct sip_pvt *p, int resp, const char *rest ...@@ -21138,6 +21142,7 @@ static void handle_response_invite(struct sip_pvt *p, int resp, const char *rest
update_call_counter(p, DEC_CALL_LIMIT); update_call_counter(p, DEC_CALL_LIMIT);
append_history(p, "Hangup", "Got 487 on CANCEL request from us on call without owner. Killing this dialog."); append_history(p, "Hangup", "Got 487 on CANCEL request from us on call without owner. Killing this dialog.");
} }
check_pendings(p);
sip_scheddestroy(p, DEFAULT_TRANS_TIMEOUT); sip_scheddestroy(p, DEFAULT_TRANS_TIMEOUT);
break; break;
case 415: /* Unsupported media type */ case 415: /* Unsupported media type */
...@@ -21834,8 +21839,9 @@ static void handle_response(struct sip_pvt *p, int resp, const char *rest, struc ...@@ -21834,8 +21839,9 @@ static void handle_response(struct sip_pvt *p, int resp, const char *rest, struc
} }
   
/* If this is a NOTIFY for a subscription clear the flag that indicates that we have a NOTIFY pending */ /* If this is a NOTIFY for a subscription clear the flag that indicates that we have a NOTIFY pending */
if (!p->owner && sipmethod == SIP_NOTIFY && p->pendinginvite) if (!p->owner && sipmethod == SIP_NOTIFY && p->pendinginvite) {
p->pendinginvite = 0; p->pendinginvite = 0;
}
   
/* Get their tag if we haven't already */ /* Get their tag if we haven't already */
if (ast_strlen_zero(p->theirtag) || (resp >= 200)) { if (ast_strlen_zero(p->theirtag) || (resp >= 200)) {
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment