@ -6225,6 +6225,21 @@ const char *hangup_cause2sip(int cause)
return 0 ;
}
static int reinvite_timeout ( const void * data )
{
struct sip_pvt * dialog = ( struct sip_pvt * ) data ;
struct ast_channel * owner = sip_pvt_lock_full ( dialog ) ;
check_pendings ( dialog ) ;
dialog - > reinviteid = - 1 ;
if ( owner ) {
ast_channel_unlock ( owner ) ;
ast_channel_unref ( owner ) ;
}
ao2_unlock ( dialog ) ;
dialog_unref ( dialog , " unref for reinvite timeout " ) ;
return 0 ;
}
/*! \brief sip_hangup: Hangup SIP call
* Part of PBX interface , called from ast_hangup */
static int sip_hangup ( struct ast_channel * ast )
@ -6352,7 +6367,7 @@ static int sip_hangup(struct ast_channel *ast)
stop_session_timer ( p ) ;
}
if ( ! p - > pendinginvite | | p - > ongoing_reinvite ) {
if ( ! p - > pendinginvite ) {
struct ast_channel * bridge = ast_bridged_channel ( oldowner ) ;
char quality_buf [ AST_MAX_USER_FIELD ] , * quality ;
@ -6414,8 +6429,16 @@ static int sip_hangup(struct ast_channel *ast)
ast_set_flag ( & p - > flags [ 0 ] , SIP_PENDINGBYE ) ;
ast_clear_flag ( & p - > flags [ 0 ] , SIP_NEEDREINVITE ) ;
AST_SCHED_DEL_UNREF ( sched , p - > waitid , dialog_unref ( p , " when you delete the waitid sched, you should dec the refcount for the stored dialog ptr " ) ) ;
if ( sip_cancel_destroy ( p ) )
if ( sip_cancel_destroy ( p ) ) {
ast_log ( LOG_WARNING , " Unable to cancel SIP destruction. Expect bad things. \n " ) ;
}
/* If we have an ongoing reinvite, there is a chance that we have gotten a provisional
* response , but something weird has happened and we will never receive a final response .
* So , just in case , check for pending actions after a bit of time to trigger the pending
* bye that we are setting above */
if ( p - > ongoing_reinvite & & p - > reinviteid < 0 ) {
p - > reinviteid = ast_sched_add ( sched , 32 * p - > timer_t1 , reinvite_timeout , dialog_ref ( p , " ref for reinvite_timeout " ) ) ;
}
}
}
}
@ -7688,6 +7711,7 @@ struct sip_pvt *sip_alloc(ast_string_field callid, struct ast_sockaddr *addr,
p - > method = intended_method ;
p - > initid = - 1 ;
p - > waitid = - 1 ;
p - > reinviteid = - 1 ;
p - > autokillid = - 1 ;
p - > request_queue_sched_id = - 1 ;
p - > provisional_keepalive_sched_id = - 1 ;
@ -19852,8 +19876,9 @@ static void check_pendings(struct sip_pvt *p)
INVITE , but do set an autodestruct just in case we never get it . */
} else {
/* We have a pending outbound invite, don't send something
new in - transaction */
if ( p - > pendinginvite )
* new in - transaction , unless it is a pending reinvite , then
* by the time we are called here , we should probably just hang up . */
if ( p - > pendinginvite & & ! p - > ongoing_reinvite )
return ;
if ( p - > owner ) {
@ -20093,12 +20118,19 @@ static void handle_response_invite(struct sip_pvt *p, int resp, const char *rest
if ( resp > = 300 & & ( p - > invitestate = = INV_CALLING | | p - > invitestate = = INV_PROCEEDING | | p - > invitestate = = INV_EARLY_MEDIA ) )
p - > invitestate = INV_COMPLETED ;
if ( ( resp > = 200 & & reinvite ) ) {
p - > ongoing_reinvite = 0 ;
if ( p - > reinviteid > - 1 ) {
AST_SCHED_DEL_UNREF ( sched , p - > reinviteid , dialog_unref ( p , " unref dialog for reinvite timeout because of a final response " ) ) ;
/* Since we got a final response to the reinvite, but were relying on the reinvite_timeout
* function to clean up after the reinvite , we need to make sure and call check_pendings */
check_pendings ( p ) ;
}
}
/* Final response, clear out pending invite */
if ( ( resp = = 200 | | resp > = 300 ) & & p - > pendinginvite & & seqno = = p - > pendinginvite ) {
p - > pendinginvite = 0 ;
if ( reinvite ) {
p - > ongoing_reinvite = 0 ;
}
}
/* If this is a response to our initial INVITE, we need to set what we can use