From: Mark Michelson Date: Sat, 21 Jan 2012 00:04:13 +0000 (+0000) Subject: Fix RTP reference leak. X-Git-Tag: 1.8.10.0-rc1~30 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=27d894d6249b9ea33ec7e29eb46b152ae54019c6;p=thirdparty%2Fasterisk.git Fix RTP reference leak. If a blind transfer were initiated using a REFER without a prior reINVITE to place the call on hold, AND if Asterisk were sending RTCP reports, then there was a reference for the RTP instance of the transferer. This fixes the issue by merging two similar but slightly conflicting sections of code into a single area. It also adds a stop_media_flows() call in the case that the transferer's UA never sends a BYE to us like it is supposed to. (issue ASTERISK-19192) Review: https://reviewboard.asterisk.org/r/1681/ git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/1.8@352014 65c4cc65-6c06-0410-ace0-fbb531ad65f3 --- diff --git a/channels/chan_sip.c b/channels/chan_sip.c index b4602dc069..7280c7a5e7 100644 --- a/channels/chan_sip.c +++ b/channels/chan_sip.c @@ -3860,6 +3860,7 @@ static int __sip_autodestruct(const void *data) ast_channel_unref(owner); } else if (p->refer && !p->alreadygone) { ast_debug(3, "Finally hanging up channel after transfer: %s\n", p->callid); + stop_media_flows(p); transmit_request_with_auth(p, SIP_BYE, 0, XMIT_RELIABLE, 1); append_history(p, "ReferBYE", "Sending BYE on transferer call leg %s", p->callid); sip_scheddestroy(p, DEFAULT_TRANS_TIMEOUT); @@ -20262,15 +20263,22 @@ static void handle_response_notify(struct sip_pvt *p, int resp, const char *rest case 200: /* Notify accepted */ /* They got the notify, this is the end */ if (p->owner) { - if (!p->refer) { - ast_log(LOG_WARNING, "Notify answer on an owned channel? - %s\n", p->owner->name); - ast_queue_hangup_with_cause(p->owner, AST_CAUSE_NORMAL_UNSPECIFIED); + if (p->refer) { + ast_log(LOG_NOTICE, "Got OK on REFER Notify message\n"); } else { - ast_debug(4, "Got OK on REFER Notify message\n"); + ast_log(LOG_WARNING, "Notify answer on an owned channel? - %s\n", p->owner->name); + /* + * XXX There is discrepancy on whether a hangup should be queued + * or not. This code used to be duplicated in two places, and the more + * frequently hit area had this disabled, making it the de facto + * "correct" way to go. + * + * ast_queue_hangup_with_cause(p->owner, AST_CAUSE_NORMAL_UNSPECIFIED); + */ } } else { - if (p->subscribed == NONE) { - ast_debug(4, "Got 200 accepted on NOTIFY\n"); + if (p->subscribed == NONE && !p->refer) { + ast_debug(4, "Got 200 accepted on NOTIFY %s\n", p->callid); pvt_set_needdestroy(p, "received 200 response"); } if (ast_test_flag(&p->flags[1], SIP_PAGE2_STATECHANGEQUEUE)) { @@ -20295,6 +20303,9 @@ static void handle_response_notify(struct sip_pvt *p, int resp, const char *rest pvt_set_needdestroy(p, "failed to authenticate NOTIFY"); } break; + case 481: /* Call leg does not exist */ + pvt_set_needdestroy(p, "Received 481 response for NOTIFY"); + break; } } @@ -20889,6 +20900,9 @@ static void handle_response(struct sip_pvt *p, int resp, const char *rest, struc } else if (sipmethod == SIP_MESSAGE) { /* More good gravy! */ handle_response_message(p, resp, rest, req, seqno); + } else if (sipmethod == SIP_NOTIFY) { + /* The gravy train continues to roll */ + handle_response_notify(p, resp, rest, req, seqno); } else if (ast_test_flag(&p->flags[0], SIP_OUTGOING)) { switch(resp) { case 100: /* 100 Trying */ @@ -20904,8 +20918,6 @@ static void handle_response(struct sip_pvt *p, int resp, const char *rest, struc p->authtries = 0; /* Reset authentication counter */ if (sipmethod == SIP_INVITE) { handle_response_invite(p, resp, rest, req, seqno); - } else if (sipmethod == SIP_NOTIFY) { - handle_response_notify(p, resp, rest, req, seqno); } else if (sipmethod == SIP_REGISTER) { handle_response_register(p, resp, rest, req, seqno); } else if (sipmethod == SIP_SUBSCRIBE) { @@ -20920,8 +20932,6 @@ static void handle_response(struct sip_pvt *p, int resp, const char *rest, struc case 407: /* Proxy auth required */ if (sipmethod == SIP_INVITE) handle_response_invite(p, resp, rest, req, seqno); - else if (sipmethod == SIP_NOTIFY) - handle_response_notify(p, resp, rest, req, seqno); else if (sipmethod == SIP_SUBSCRIBE) handle_response_subscribe(p, resp, rest, req, seqno); else if (p->registry && sipmethod == SIP_REGISTER) @@ -20997,8 +21007,6 @@ static void handle_response(struct sip_pvt *p, int resp, const char *rest, struc handle_response_invite(p, resp, rest, req, seqno); } else if (sipmethod == SIP_SUBSCRIBE) { handle_response_subscribe(p, resp, rest, req, seqno); - } else if (sipmethod == SIP_NOTIFY) { - pvt_set_needdestroy(p, "received 481 response"); } else if (sipmethod == SIP_BYE) { /* The other side has no transaction to bye, just assume it's all right then */ @@ -21155,24 +21163,6 @@ static void handle_response(struct sip_pvt *p, int resp, const char *rest, struc ast_debug(1, "Got 200 OK on CANCEL\n"); /* Wait for 487, then destroy */ - } else if (sipmethod == SIP_NOTIFY) { - /* They got the notify, this is the end */ - if (p->owner) { - if (p->refer) { - ast_debug(1, "Got 200 OK on NOTIFY for transfer\n"); - } else - ast_log(LOG_WARNING, "Notify answer on an owned channel?\n"); - /* ast_queue_hangup(p->owner); Disabled */ - } else { - if (!p->subscribed && !p->refer) { - pvt_set_needdestroy(p, "transaction completed"); - } - if (ast_test_flag(&p->flags[1], SIP_PAGE2_STATECHANGEQUEUE)) { - /* Ready to send the next state we have on queue */ - ast_clear_flag(&p->flags[1], SIP_PAGE2_STATECHANGEQUEUE); - cb_extensionstate((char *)p->context, (char *)p->exten, p->laststate, (void *) p); - } - } } else if (sipmethod == SIP_BYE) { pvt_set_needdestroy(p, "transaction completed"); } @@ -21194,8 +21184,6 @@ static void handle_response(struct sip_pvt *p, int resp, const char *rest, struc handle_response_invite(p, resp, rest, req, seqno); } else if (sipmethod == SIP_BYE) { pvt_set_needdestroy(p, "received 481 response"); - } else if (sipmethod == SIP_NOTIFY) { - pvt_set_needdestroy(p, "received 481 response"); } else if (sipdebug) { ast_debug(1, "Remote host can't match request %s to call '%s'. Giving up\n", sip_methods[sipmethod].text, p->callid); }